blob: f24dea14da17d0fc9aa51779dc945b721c6210a4 [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";
ming.lod4c22d82021-11-05 16:22:38 +0800174 if (type == FrontendScanType::SCAN_BLIND)
175 EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
Hongguang600a6ae2021-07-08 18:51:51 -0700176 mScanMessageReceived = false;
177 mScanMsgProcessed = true;
178}
179
Hongguang11da2cb2021-08-05 19:05:12 -0700180int64_t FrontendCallback::getTargetFrequency(FrontendSettings& settings) {
Hongguang600a6ae2021-07-08 18:51:51 -0700181 switch (settings.getTag()) {
182 case FrontendSettings::Tag::analog:
183 return settings.get<FrontendSettings::Tag::analog>().frequency;
184 case FrontendSettings::Tag::atsc:
185 return settings.get<FrontendSettings::Tag::atsc>().frequency;
186 case FrontendSettings::Tag::atsc3:
187 return settings.get<FrontendSettings::Tag::atsc3>().frequency;
188 case FrontendSettings::Tag::dvbc:
189 return settings.get<FrontendSettings::Tag::dvbc>().frequency;
190 case FrontendSettings::Tag::dvbs:
191 return settings.get<FrontendSettings::Tag::dvbs>().frequency;
192 case FrontendSettings::Tag::dvbt:
193 return settings.get<FrontendSettings::Tag::dvbt>().frequency;
194 case FrontendSettings::Tag::isdbs:
195 return settings.get<FrontendSettings::Tag::isdbs>().frequency;
196 case FrontendSettings::Tag::isdbs3:
197 return settings.get<FrontendSettings::Tag::isdbs3>().frequency;
198 case FrontendSettings::Tag::isdbt:
199 return settings.get<FrontendSettings::Tag::isdbt>().frequency;
200 default:
201 return 0;
202 }
203}
204
205void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
Hongguang11da2cb2021-08-05 19:05:12 -0700206 int64_t resetingFreq) {
Hongguang600a6ae2021-07-08 18:51:51 -0700207 switch (config.settings.getTag()) {
208 case FrontendSettings::Tag::analog:
209 config.settings.get<FrontendSettings::Tag::analog>().frequency = resetingFreq;
210 break;
211 case FrontendSettings::Tag::atsc:
212 config.settings.get<FrontendSettings::Tag::atsc>().frequency = resetingFreq;
213 break;
214 case FrontendSettings::Tag::atsc3:
215 config.settings.get<FrontendSettings::Tag::atsc3>().frequency = resetingFreq;
216 break;
217 case FrontendSettings::Tag::dvbc:
218 config.settings.get<FrontendSettings::Tag::dvbc>().frequency = resetingFreq;
219 break;
220 case FrontendSettings::Tag::dvbs:
221 config.settings.get<FrontendSettings::Tag::dvbs>().frequency = resetingFreq;
222 break;
223 case FrontendSettings::Tag::dvbt:
224 config.settings.get<FrontendSettings::Tag::dvbt>().frequency = resetingFreq;
225 break;
226 case FrontendSettings::Tag::isdbs:
227 config.settings.get<FrontendSettings::Tag::isdbs>().frequency = resetingFreq;
228 break;
229 case FrontendSettings::Tag::isdbs3:
230 config.settings.get<FrontendSettings::Tag::isdbs3>().frequency = resetingFreq;
231 break;
232 case FrontendSettings::Tag::isdbt:
233 config.settings.get<FrontendSettings::Tag::isdbt>().frequency = resetingFreq;
234 break;
235 default:
236 break;
237 }
238}
239
240AssertionResult FrontendTests::getFrontendIds() {
241 ndk::ScopedAStatus status;
242 status = mService->getFrontendIds(&mFeIds);
243 return AssertionResult(status.isOk());
244}
245
246AssertionResult FrontendTests::getFrontendInfo(int32_t frontendId) {
247 ndk::ScopedAStatus status;
248 status = mService->getFrontendInfo(frontendId, &mFrontendInfo);
249 return AssertionResult(status.isOk());
250}
251
252AssertionResult FrontendTests::openFrontendById(int32_t frontendId) {
253 ndk::ScopedAStatus status;
254 status = mService->openFrontendById(frontendId, &mFrontend);
255 return AssertionResult(status.isOk());
256}
257
258AssertionResult FrontendTests::setFrontendCallback() {
259 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
260 mFrontendCallback = ndk::SharedRefBase::make<FrontendCallback>();
261 auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
262 return AssertionResult(callbackStatus.isOk());
263}
264
265AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
266 EXPECT_TRUE(mFrontendCallback)
267 << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
268
269 EXPECT_TRUE(mFrontendInfo.type == config.type)
270 << "FrontendConfig does not match the frontend info of the given id.";
271
272 mFrontendCallback->scanTest(mFrontend, config, type);
273 return AssertionResult(true);
274}
275
276AssertionResult FrontendTests::stopScanFrontend() {
277 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
278 ndk::ScopedAStatus status;
279 status = mFrontend->stopScan();
280
281 return AssertionResult(status.isOk());
282}
283
284AssertionResult FrontendTests::setLnb(int32_t lnbId) {
285 if (!mFrontendCallback) {
286 ALOGW("[vts] open and set frontend callback first.");
287 return failure();
288 }
289 return AssertionResult(mFrontend->setLnb(lnbId).isOk());
290}
291
292AssertionResult FrontendTests::linkCiCam(int32_t ciCamId) {
293 ndk::ScopedAStatus status;
294 int32_t ltsId;
295 status = mFrontend->linkCiCam(ciCamId, &ltsId);
296 return AssertionResult(status.isOk());
297}
298
299AssertionResult FrontendTests::unlinkCiCam(int32_t ciCamId) {
300 ndk::ScopedAStatus status = mFrontend->unlinkCiCam(ciCamId);
301 return AssertionResult(status.isOk());
302}
303
304void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
305 vector<FrontendStatus> expectStatuses) {
306 ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
307 ndk::ScopedAStatus status;
308 vector<FrontendStatus> realStatuses;
309
310 status = mFrontend->getStatus(statusTypes, &realStatuses);
311 ASSERT_TRUE(status.isOk() && realStatuses.size() == statusTypes.size());
312
313 for (int i = 0; i < statusTypes.size(); i++) {
314 FrontendStatusType type = statusTypes[i];
315 switch (type) {
316 case FrontendStatusType::MODULATIONS: {
317 // TODO: verify modulations
318 break;
319 }
320 case FrontendStatusType::BERS: {
321 ASSERT_TRUE(std::equal(realStatuses[i].get<FrontendStatus::Tag::bers>().begin(),
322 realStatuses[i].get<FrontendStatus::Tag::bers>().end(),
323 expectStatuses[i].get<FrontendStatus::Tag::bers>().begin()));
324 break;
325 }
326 case FrontendStatusType::CODERATES: {
327 ASSERT_TRUE(std::equal(
328 realStatuses[i].get<FrontendStatus::Tag::codeRates>().begin(),
329 realStatuses[i].get<FrontendStatus::Tag::codeRates>().end(),
330 expectStatuses[i].get<FrontendStatus::Tag::codeRates>().begin()));
331 break;
332 }
333 case FrontendStatusType::GUARD_INTERVAL: {
334 // TODO: verify interval
335 break;
336 }
337 case FrontendStatusType::TRANSMISSION_MODE: {
338 // TODO: verify tranmission mode
339 break;
340 }
341 case FrontendStatusType::UEC: {
342 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::uec>() ==
343 expectStatuses[i].get<FrontendStatus::Tag::uec>());
344 break;
345 }
346 case FrontendStatusType::T2_SYSTEM_ID: {
347 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::systemId>() ==
348 expectStatuses[i].get<FrontendStatus::Tag::systemId>());
349 break;
350 }
351 case FrontendStatusType::INTERLEAVINGS: {
352 ASSERT_TRUE(std::equal(
353 realStatuses[i].get<FrontendStatus::Tag::interleaving>().begin(),
354 realStatuses[i].get<FrontendStatus::Tag::interleaving>().end(),
355 expectStatuses[i].get<FrontendStatus::Tag::interleaving>().begin()));
356 break;
357 }
358 case FrontendStatusType::ISDBT_SEGMENTS: {
359 ASSERT_TRUE(std::equal(
360 realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin(),
361 realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().end(),
362 expectStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin()));
363 break;
364 }
365 case FrontendStatusType::TS_DATA_RATES: {
366 ASSERT_TRUE(std::equal(
367 realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin(),
368 realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().end(),
369 expectStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin()));
370 break;
371 }
372 case FrontendStatusType::ROLL_OFF: {
373 // TODO: verify roll off
374 break;
375 }
376 case FrontendStatusType::IS_MISO: {
377 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isMiso>() ==
378 expectStatuses[i].get<FrontendStatus::Tag::isMiso>());
379 break;
380 }
381 case FrontendStatusType::IS_LINEAR: {
382 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isLinear>() ==
383 expectStatuses[i].get<FrontendStatus::Tag::isLinear>());
384 break;
385 }
386 case FrontendStatusType::IS_SHORT_FRAMES: {
387 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isShortFrames>() ==
388 expectStatuses[i].get<FrontendStatus::Tag::isShortFrames>());
389 break;
390 }
Hongguang788284f2021-10-28 15:03:29 -0700391 case FrontendStatusType::ISDBT_MODE: {
392 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isdbtMode>() ==
393 expectStatuses[i].get<FrontendStatus::Tag::isdbtMode>());
394 break;
395 }
396 case FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG: {
397 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>() ==
398 expectStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>());
399 break;
400 }
Hongguang2ecfc392021-11-23 10:29:15 -0800401 case FrontendStatusType::STREAM_ID_LIST: {
402 ASSERT_TRUE(std::equal(
403 realStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin(),
404 realStatuses[i].get<FrontendStatus::Tag::streamIdList>().end(),
405 expectStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin()));
406 break;
407 }
Hongguang7eda7822021-12-20 14:48:14 -0800408 case FrontendStatusType::DVBT_CELL_IDS: {
409 ASSERT_TRUE(std::equal(
410 realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin(),
411 realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().end(),
412 expectStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin()));
413 break;
414 }
Hongguang600a6ae2021-07-08 18:51:51 -0700415 default: {
416 continue;
417 }
418 }
419 }
420 ASSERT_TRUE(status.isOk());
421}
422
423AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
424 EXPECT_TRUE(mFrontendCallback)
425 << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
426
427 EXPECT_TRUE(mFrontendInfo.type == config.type)
428 << "FrontendConfig does not match the frontend info of the given id.";
429
430 mIsSoftwareFe = config.isSoftwareFe;
431 if (mIsSoftwareFe && testWithDemux) {
432 if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
433 ALOGW("[vts] Software frontend dvr configure openDvr failed.");
434 return failure();
435 }
436 if (getDvrTests()->configDvrPlayback(mDvrConfig.settings) != success()) {
437 ALOGW("[vts] Software frontend dvr configure Dvr playback failed.");
438 return failure();
439 }
440 if (getDvrTests()->getDvrPlaybackMQDescriptor() != success()) {
441 ALOGW("[vts] Software frontend dvr configure get MQDesc failed.");
442 return failure();
443 }
444 getDvrTests()->startPlaybackInputThread(
445 mDvrConfig.playbackInputFile,
446 mDvrConfig.settings.get<DvrSettings::Tag::playback>());
Treehugger Robot4cdc4f22021-12-17 00:28:32 +0000447 getDvrTests()->startDvrPlayback();
Hongguang600a6ae2021-07-08 18:51:51 -0700448 }
449 mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
450 return AssertionResult(true);
451}
452
453AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
454 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
455 ndk::ScopedAStatus status;
456 status = mFrontend->stopTune();
457 if (mIsSoftwareFe && testWithDemux) {
458 getDvrTests()->stopPlaybackThread();
Treehugger Robot4cdc4f22021-12-17 00:28:32 +0000459 getDvrTests()->stopDvrPlayback();
Hongguang600a6ae2021-07-08 18:51:51 -0700460 getDvrTests()->closeDvrPlayback();
461 }
462 return AssertionResult(status.isOk());
463}
464
465AssertionResult FrontendTests::closeFrontend() {
466 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
467 ndk::ScopedAStatus status;
468 status = mFrontend->close();
469 mFrontend = nullptr;
470 mFrontendCallback = nullptr;
471 return AssertionResult(status.isOk());
472}
473
474void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
475 ASSERT_TRUE(getFrontendIds());
Hongguang600a6ae2021-07-08 18:51:51 -0700476 for (size_t i = 0; i < mFeIds.size(); i++) {
477 ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
478 if (mFrontendInfo.type != feType) {
479 continue;
480 }
481 feId = mFeIds[i];
482 return;
483 }
484 feId = INVALID_ID;
485}
486
487void FrontendTests::tuneTest(FrontendConfig frontendConf) {
488 int32_t feId;
489 getFrontendIdByType(frontendConf.type, feId);
490 ASSERT_TRUE(feId != INVALID_ID);
491 ASSERT_TRUE(openFrontendById(feId));
492 ASSERT_TRUE(setFrontendCallback());
493 if (frontendConf.canConnectToCiCam) {
494 ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
495 ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
496 }
497 ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
498 verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
499 ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
500 ASSERT_TRUE(closeFrontend());
501}
502
503void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
504 int32_t feId;
505 getFrontendIdByType(frontendConf.type, feId);
506 ASSERT_TRUE(feId != INVALID_ID);
507 ASSERT_TRUE(openFrontendById(feId));
508 ASSERT_TRUE(setFrontendCallback());
509 ASSERT_TRUE(scanFrontend(frontendConf, scanType));
510 ASSERT_TRUE(stopScanFrontend());
511 ASSERT_TRUE(closeFrontend());
512}