blob: 7dce4fb4ff0bc6e94c1b5f1b1704ccbd60cee806 [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.
129 resetBlindScanStartingFrequency(config, targetFrequency - 100);
130 }
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 }
390 default: {
391 continue;
392 }
393 }
394 }
395 ASSERT_TRUE(status.isOk());
396}
397
398AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
399 EXPECT_TRUE(mFrontendCallback)
400 << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
401
402 EXPECT_TRUE(mFrontendInfo.type == config.type)
403 << "FrontendConfig does not match the frontend info of the given id.";
404
405 mIsSoftwareFe = config.isSoftwareFe;
406 if (mIsSoftwareFe && testWithDemux) {
407 if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
408 ALOGW("[vts] Software frontend dvr configure openDvr failed.");
409 return failure();
410 }
411 if (getDvrTests()->configDvrPlayback(mDvrConfig.settings) != success()) {
412 ALOGW("[vts] Software frontend dvr configure Dvr playback failed.");
413 return failure();
414 }
415 if (getDvrTests()->getDvrPlaybackMQDescriptor() != success()) {
416 ALOGW("[vts] Software frontend dvr configure get MQDesc failed.");
417 return failure();
418 }
419 getDvrTests()->startPlaybackInputThread(
420 mDvrConfig.playbackInputFile,
421 mDvrConfig.settings.get<DvrSettings::Tag::playback>());
422 }
423 mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
424 return AssertionResult(true);
425}
426
427AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
428 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
429 ndk::ScopedAStatus status;
430 status = mFrontend->stopTune();
431 if (mIsSoftwareFe && testWithDemux) {
432 getDvrTests()->stopPlaybackThread();
433 getDvrTests()->closeDvrPlayback();
434 }
435 return AssertionResult(status.isOk());
436}
437
438AssertionResult FrontendTests::closeFrontend() {
439 EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
440 ndk::ScopedAStatus status;
441 status = mFrontend->close();
442 mFrontend = nullptr;
443 mFrontendCallback = nullptr;
444 return AssertionResult(status.isOk());
445}
446
447void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
448 ASSERT_TRUE(getFrontendIds());
449 ASSERT_TRUE(mFeIds.size() > 0);
450 for (size_t i = 0; i < mFeIds.size(); i++) {
451 ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
452 if (mFrontendInfo.type != feType) {
453 continue;
454 }
455 feId = mFeIds[i];
456 return;
457 }
458 feId = INVALID_ID;
459}
460
461void FrontendTests::tuneTest(FrontendConfig frontendConf) {
462 int32_t feId;
463 getFrontendIdByType(frontendConf.type, feId);
464 ASSERT_TRUE(feId != INVALID_ID);
465 ASSERT_TRUE(openFrontendById(feId));
466 ASSERT_TRUE(setFrontendCallback());
467 if (frontendConf.canConnectToCiCam) {
468 ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
469 ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
470 }
471 ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
472 verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
473 ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
474 ASSERT_TRUE(closeFrontend());
475}
476
477void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
478 int32_t feId;
479 getFrontendIdByType(frontendConf.type, feId);
480 ASSERT_TRUE(feId != INVALID_ID);
481 ASSERT_TRUE(openFrontendById(feId));
482 ASSERT_TRUE(setFrontendCallback());
483 ASSERT_TRUE(scanFrontend(frontendConf, scanType));
484 ASSERT_TRUE(stopScanFrontend());
485 ASSERT_TRUE(closeFrontend());
486}