blob: f1c3595f0605a3f82263110f3c16de1d6bbf3872 [file] [log] [blame]
Hongguang600a6ae2021-07-08 18:51:51 -07001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "FrontendTests.h"
18
19ndk::ScopedAStatus FrontendCallback::onEvent(FrontendEventType frontendEventType) {
20 android::Mutex::Autolock autoLock(mMsgLock);
21 ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
22 mEventReceived = true;
23 mMsgCondition.signal();
24 switch (frontendEventType) {
25 case FrontendEventType::LOCKED:
26 mLockMsgReceived = true;
27 mLockMsgCondition.signal();
28 break;
29 default:
30 // do nothing
31 break;
32 }
33 return ndk::ScopedAStatus::ok();
34}
35
36ndk::ScopedAStatus FrontendCallback::onScanMessage(FrontendScanMessageType type,
37 const FrontendScanMessage& message) {
38 android::Mutex::Autolock autoLock(mMsgLock);
39 while (!mScanMsgProcessed) {
40 mMsgCondition.wait(mMsgLock);
41 }
42 ALOGD("[vts] frontend scan message. Type: %d", type);
43 switch (message.getTag()) {
44 case FrontendScanMessage::modulation:
45 readFrontendScanMessage_Modulation(message.get<FrontendScanMessage::Tag::modulation>());
46 break;
47 case FrontendScanMessage::Tag::isHighPriority:
48 ALOGD("[vts] frontend scan message high priority: %d",
49 message.get<FrontendScanMessage::Tag::isHighPriority>());
50 break;
51 case FrontendScanMessage::Tag::annex:
52 ALOGD("[vts] frontend scan message dvbc annex: %hhu",
53 message.get<FrontendScanMessage::Tag::annex>());
54 break;
55 default:
56 break;
57 }
58 mScanMessageReceived = true;
59 mScanMsgProcessed = false;
60 mScanMessageType = type;
61 mScanMessage = message;
62 mMsgCondition.signal();
63 return ndk::ScopedAStatus::ok();
64}
65
66void FrontendCallback::readFrontendScanMessage_Modulation(FrontendModulation modulation) {
67 switch (modulation.getTag()) {
68 case FrontendModulation::Tag::dvbc:
69 ALOGD("[vts] frontend scan message modulation dvbc: %d",
70 modulation.get<FrontendModulation::Tag::dvbc>());
71 break;
72 case FrontendModulation::Tag::dvbs:
73 ALOGD("[vts] frontend scan message modulation dvbs: %d",
74 modulation.get<FrontendModulation::Tag::dvbs>());
75 break;
76 case FrontendModulation::Tag::isdbs:
77 ALOGD("[vts] frontend scan message modulation isdbs: %d",
78 modulation.get<FrontendModulation::Tag::isdbs>());
79 break;
80 case FrontendModulation::Tag::isdbs3:
81 ALOGD("[vts] frontend scan message modulation isdbs3: %d",
82 modulation.get<FrontendModulation::Tag::isdbs3>());
83 break;
84 case FrontendModulation::Tag::isdbt:
85 ALOGD("[vts] frontend scan message modulation isdbt: %d",
86 modulation.get<FrontendModulation::Tag::isdbt>());
87 break;
88 case FrontendModulation::Tag::atsc:
89 ALOGD("[vts] frontend scan message modulation atsc: %d",
90 modulation.get<FrontendModulation::Tag::atsc>());
91 break;
92 case FrontendModulation::Tag::atsc3:
93 ALOGD("[vts] frontend scan message modulation atsc3: %d",
94 modulation.get<FrontendModulation::Tag::atsc3>());
95 break;
96 case FrontendModulation::Tag::dvbt:
97 ALOGD("[vts] frontend scan message modulation dvbt: %d",
98 modulation.get<FrontendModulation::Tag::dvbt>());
99 break;
100 default:
101 break;
102 }
103}
104
105void FrontendCallback::tuneTestOnLock(std::shared_ptr<IFrontend>& frontend,
106 FrontendSettings settings) {
107 ndk::ScopedAStatus result = frontend->tune(settings);
108 EXPECT_TRUE(result.isOk());
109
110 android::Mutex::Autolock autoLock(mMsgLock);
111 while (!mLockMsgReceived) {
112 if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
113 EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
114 mLockMsgReceived = false;
115 return;
116 }
117 }
118 mLockMsgReceived = false;
119}
120
121void FrontendCallback::scanTest(std::shared_ptr<IFrontend>& frontend, FrontendConfig config,
122 FrontendScanType type) {
Hongguang11da2cb2021-08-05 19:05:12 -0700123 int64_t targetFrequency = getTargetFrequency(config.settings);
Hongguang600a6ae2021-07-08 18:51:51 -0700124 if (type == FrontendScanType::SCAN_BLIND) {
125 // reset the frequency in the scan configuration to test blind scan. The settings param of
126 // passed in means the real input config on the transponder connected to the DUT.
127 // We want the blind the test to start from lower frequency than this to check the blind
128 // scan implementation.
Gareth Fenn282fb372021-09-27 15:14:11 +0100129 resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
Hongguang600a6ae2021-07-08 18:51:51 -0700130 }
131
132 ndk::ScopedAStatus result = frontend->scan(config.settings, type);
133 EXPECT_TRUE(result.isOk());
134
135 bool scanMsgLockedReceived = false;
136 bool targetFrequencyReceived = false;
137
138 android::Mutex::Autolock autoLock(mMsgLock);
139wait:
140 while (!mScanMessageReceived) {
141 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
142 EXPECT_TRUE(false) << "Scan message not received within timeout";
143 mScanMessageReceived = false;
144 mScanMsgProcessed = true;
145 return;
146 }
147 }
148
149 if (mScanMessageType != FrontendScanMessageType::END) {
150 if (mScanMessageType == FrontendScanMessageType::LOCKED) {
151 scanMsgLockedReceived = true;
152 result = frontend->scan(config.settings, type);
153 EXPECT_TRUE(result.isOk());
154 }
155
156 if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
157 targetFrequencyReceived =
158 mScanMessage.get<FrontendScanMessage::Tag::frequencies>().size() > 0 &&
159 mScanMessage.get<FrontendScanMessage::Tag::frequencies>()[0] == targetFrequency;
160 }
161
162 if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
163 ALOGD("[vts] Scan in progress...[%d%%]",
164 mScanMessage.get<FrontendScanMessage::Tag::progressPercent>());
165 }
166
167 mScanMessageReceived = false;
168 mScanMsgProcessed = true;
169 mMsgCondition.signal();
170 goto wait;
171 }
172
173 EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
174 EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
175 mScanMessageReceived = false;
176 mScanMsgProcessed = true;
177}
178
Hongguang11da2cb2021-08-05 19:05:12 -0700179int64_t FrontendCallback::getTargetFrequency(FrontendSettings& settings) {
Hongguang600a6ae2021-07-08 18:51:51 -0700180 switch (settings.getTag()) {
181 case FrontendSettings::Tag::analog:
182 return settings.get<FrontendSettings::Tag::analog>().frequency;
183 case FrontendSettings::Tag::atsc:
184 return settings.get<FrontendSettings::Tag::atsc>().frequency;
185 case FrontendSettings::Tag::atsc3:
186 return settings.get<FrontendSettings::Tag::atsc3>().frequency;
187 case FrontendSettings::Tag::dvbc:
188 return settings.get<FrontendSettings::Tag::dvbc>().frequency;
189 case FrontendSettings::Tag::dvbs:
190 return settings.get<FrontendSettings::Tag::dvbs>().frequency;
191 case FrontendSettings::Tag::dvbt:
192 return settings.get<FrontendSettings::Tag::dvbt>().frequency;
193 case FrontendSettings::Tag::isdbs:
194 return settings.get<FrontendSettings::Tag::isdbs>().frequency;
195 case FrontendSettings::Tag::isdbs3:
196 return settings.get<FrontendSettings::Tag::isdbs3>().frequency;
197 case FrontendSettings::Tag::isdbt:
198 return settings.get<FrontendSettings::Tag::isdbt>().frequency;
199 default:
200 return 0;
201 }
202}
203
204void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
Hongguang11da2cb2021-08-05 19:05:12 -0700205 int64_t resetingFreq) {
Hongguang600a6ae2021-07-08 18:51:51 -0700206 switch (config.settings.getTag()) {
207 case FrontendSettings::Tag::analog:
208 config.settings.get<FrontendSettings::Tag::analog>().frequency = resetingFreq;
209 break;
210 case FrontendSettings::Tag::atsc:
211 config.settings.get<FrontendSettings::Tag::atsc>().frequency = resetingFreq;
212 break;
213 case FrontendSettings::Tag::atsc3:
214 config.settings.get<FrontendSettings::Tag::atsc3>().frequency = resetingFreq;
215 break;
216 case FrontendSettings::Tag::dvbc:
217 config.settings.get<FrontendSettings::Tag::dvbc>().frequency = resetingFreq;
218 break;
219 case FrontendSettings::Tag::dvbs:
220 config.settings.get<FrontendSettings::Tag::dvbs>().frequency = resetingFreq;
221 break;
222 case FrontendSettings::Tag::dvbt:
223 config.settings.get<FrontendSettings::Tag::dvbt>().frequency = resetingFreq;
224 break;
225 case FrontendSettings::Tag::isdbs:
226 config.settings.get<FrontendSettings::Tag::isdbs>().frequency = resetingFreq;
227 break;
228 case FrontendSettings::Tag::isdbs3:
229 config.settings.get<FrontendSettings::Tag::isdbs3>().frequency = resetingFreq;
230 break;
231 case FrontendSettings::Tag::isdbt:
232 config.settings.get<FrontendSettings::Tag::isdbt>().frequency = resetingFreq;
233 break;
234 default:
235 break;
236 }
237}
238
239AssertionResult FrontendTests::getFrontendIds() {
240 ndk::ScopedAStatus status;
241 status = mService->getFrontendIds(&mFeIds);
242 return AssertionResult(status.isOk());
243}
244
245AssertionResult FrontendTests::getFrontendInfo(int32_t frontendId) {
246 ndk::ScopedAStatus status;
247 status = mService->getFrontendInfo(frontendId, &mFrontendInfo);
248 return AssertionResult(status.isOk());
249}
250
251AssertionResult FrontendTests::openFrontendById(int32_t frontendId) {
252 ndk::ScopedAStatus status;
253 status = mService->openFrontendById(frontendId, &mFrontend);
254 return AssertionResult(status.isOk());
255}
256
257AssertionResult FrontendTests::setFrontendCallback() {
258 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
259 mFrontendCallback = ndk::SharedRefBase::make<FrontendCallback>();
260 auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
261 return AssertionResult(callbackStatus.isOk());
262}
263
264AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
265 EXPECT_TRUE(mFrontendCallback)
266 << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
267
268 EXPECT_TRUE(mFrontendInfo.type == config.type)
269 << "FrontendConfig does not match the frontend info of the given id.";
270
271 mFrontendCallback->scanTest(mFrontend, config, type);
272 return AssertionResult(true);
273}
274
275AssertionResult FrontendTests::stopScanFrontend() {
276 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
277 ndk::ScopedAStatus status;
278 status = mFrontend->stopScan();
279
280 return AssertionResult(status.isOk());
281}
282
283AssertionResult FrontendTests::setLnb(int32_t lnbId) {
284 if (!mFrontendCallback) {
285 ALOGW("[vts] open and set frontend callback first.");
286 return failure();
287 }
288 return AssertionResult(mFrontend->setLnb(lnbId).isOk());
289}
290
291AssertionResult FrontendTests::linkCiCam(int32_t ciCamId) {
292 ndk::ScopedAStatus status;
293 int32_t ltsId;
294 status = mFrontend->linkCiCam(ciCamId, &ltsId);
295 return AssertionResult(status.isOk());
296}
297
298AssertionResult FrontendTests::unlinkCiCam(int32_t ciCamId) {
299 ndk::ScopedAStatus status = mFrontend->unlinkCiCam(ciCamId);
300 return AssertionResult(status.isOk());
301}
302
303void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
304 vector<FrontendStatus> expectStatuses) {
305 ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
306 ndk::ScopedAStatus status;
307 vector<FrontendStatus> realStatuses;
308
309 status = mFrontend->getStatus(statusTypes, &realStatuses);
310 ASSERT_TRUE(status.isOk() && realStatuses.size() == statusTypes.size());
311
312 for (int i = 0; i < statusTypes.size(); i++) {
313 FrontendStatusType type = statusTypes[i];
314 switch (type) {
315 case FrontendStatusType::MODULATIONS: {
316 // TODO: verify modulations
317 break;
318 }
319 case FrontendStatusType::BERS: {
320 ASSERT_TRUE(std::equal(realStatuses[i].get<FrontendStatus::Tag::bers>().begin(),
321 realStatuses[i].get<FrontendStatus::Tag::bers>().end(),
322 expectStatuses[i].get<FrontendStatus::Tag::bers>().begin()));
323 break;
324 }
325 case FrontendStatusType::CODERATES: {
326 ASSERT_TRUE(std::equal(
327 realStatuses[i].get<FrontendStatus::Tag::codeRates>().begin(),
328 realStatuses[i].get<FrontendStatus::Tag::codeRates>().end(),
329 expectStatuses[i].get<FrontendStatus::Tag::codeRates>().begin()));
330 break;
331 }
332 case FrontendStatusType::GUARD_INTERVAL: {
333 // TODO: verify interval
334 break;
335 }
336 case FrontendStatusType::TRANSMISSION_MODE: {
337 // TODO: verify tranmission mode
338 break;
339 }
340 case FrontendStatusType::UEC: {
341 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::uec>() ==
342 expectStatuses[i].get<FrontendStatus::Tag::uec>());
343 break;
344 }
345 case FrontendStatusType::T2_SYSTEM_ID: {
346 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::systemId>() ==
347 expectStatuses[i].get<FrontendStatus::Tag::systemId>());
348 break;
349 }
350 case FrontendStatusType::INTERLEAVINGS: {
351 ASSERT_TRUE(std::equal(
352 realStatuses[i].get<FrontendStatus::Tag::interleaving>().begin(),
353 realStatuses[i].get<FrontendStatus::Tag::interleaving>().end(),
354 expectStatuses[i].get<FrontendStatus::Tag::interleaving>().begin()));
355 break;
356 }
357 case FrontendStatusType::ISDBT_SEGMENTS: {
358 ASSERT_TRUE(std::equal(
359 realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin(),
360 realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().end(),
361 expectStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin()));
362 break;
363 }
364 case FrontendStatusType::TS_DATA_RATES: {
365 ASSERT_TRUE(std::equal(
366 realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin(),
367 realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().end(),
368 expectStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin()));
369 break;
370 }
371 case FrontendStatusType::ROLL_OFF: {
372 // TODO: verify roll off
373 break;
374 }
375 case FrontendStatusType::IS_MISO: {
376 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isMiso>() ==
377 expectStatuses[i].get<FrontendStatus::Tag::isMiso>());
378 break;
379 }
380 case FrontendStatusType::IS_LINEAR: {
381 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isLinear>() ==
382 expectStatuses[i].get<FrontendStatus::Tag::isLinear>());
383 break;
384 }
385 case FrontendStatusType::IS_SHORT_FRAMES: {
386 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isShortFrames>() ==
387 expectStatuses[i].get<FrontendStatus::Tag::isShortFrames>());
388 break;
389 }
Hongguang788284f2021-10-28 15:03:29 -0700390 case FrontendStatusType::ISDBT_MODE: {
391 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isdbtMode>() ==
392 expectStatuses[i].get<FrontendStatus::Tag::isdbtMode>());
393 break;
394 }
395 case FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG: {
396 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>() ==
397 expectStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>());
398 break;
399 }
Hongguang600a6ae2021-07-08 18:51:51 -0700400 default: {
401 continue;
402 }
403 }
404 }
405 ASSERT_TRUE(status.isOk());
406}
407
408AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
409 EXPECT_TRUE(mFrontendCallback)
410 << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
411
412 EXPECT_TRUE(mFrontendInfo.type == config.type)
413 << "FrontendConfig does not match the frontend info of the given id.";
414
415 mIsSoftwareFe = config.isSoftwareFe;
416 if (mIsSoftwareFe && testWithDemux) {
417 if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
418 ALOGW("[vts] Software frontend dvr configure openDvr failed.");
419 return failure();
420 }
421 if (getDvrTests()->configDvrPlayback(mDvrConfig.settings) != success()) {
422 ALOGW("[vts] Software frontend dvr configure Dvr playback failed.");
423 return failure();
424 }
425 if (getDvrTests()->getDvrPlaybackMQDescriptor() != success()) {
426 ALOGW("[vts] Software frontend dvr configure get MQDesc failed.");
427 return failure();
428 }
429 getDvrTests()->startPlaybackInputThread(
430 mDvrConfig.playbackInputFile,
431 mDvrConfig.settings.get<DvrSettings::Tag::playback>());
432 }
433 mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
434 return AssertionResult(true);
435}
436
437AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
438 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
439 ndk::ScopedAStatus status;
440 status = mFrontend->stopTune();
441 if (mIsSoftwareFe && testWithDemux) {
442 getDvrTests()->stopPlaybackThread();
443 getDvrTests()->closeDvrPlayback();
444 }
445 return AssertionResult(status.isOk());
446}
447
448AssertionResult FrontendTests::closeFrontend() {
449 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
450 ndk::ScopedAStatus status;
451 status = mFrontend->close();
452 mFrontend = nullptr;
453 mFrontendCallback = nullptr;
454 return AssertionResult(status.isOk());
455}
456
457void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
458 ASSERT_TRUE(getFrontendIds());
Hongguang600a6ae2021-07-08 18:51:51 -0700459 for (size_t i = 0; i < mFeIds.size(); i++) {
460 ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
461 if (mFrontendInfo.type != feType) {
462 continue;
463 }
464 feId = mFeIds[i];
465 return;
466 }
467 feId = INVALID_ID;
468}
469
470void FrontendTests::tuneTest(FrontendConfig frontendConf) {
471 int32_t feId;
472 getFrontendIdByType(frontendConf.type, feId);
473 ASSERT_TRUE(feId != INVALID_ID);
474 ASSERT_TRUE(openFrontendById(feId));
475 ASSERT_TRUE(setFrontendCallback());
476 if (frontendConf.canConnectToCiCam) {
477 ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
478 ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
479 }
480 ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
481 verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
482 ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
483 ASSERT_TRUE(closeFrontend());
484}
485
486void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
487 int32_t feId;
488 getFrontendIdByType(frontendConf.type, feId);
489 ASSERT_TRUE(feId != INVALID_ID);
490 ASSERT_TRUE(openFrontendById(feId));
491 ASSERT_TRUE(setFrontendCallback());
492 ASSERT_TRUE(scanFrontend(frontendConf, scanType));
493 ASSERT_TRUE(stopScanFrontend());
494 ASSERT_TRUE(closeFrontend());
495}