1 /*
2  * Copyright 2020 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 
onEvent(FrontendEventType frontendEventType)19 Return<void> 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             return Void();
29         default:
30             // do nothing
31             return Void();
32     }
33 }
34 
onScanMessage(FrontendScanMessageType type,const FrontendScanMessage & message)35 Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type,
36                                              const FrontendScanMessage& message) {
37     android::Mutex::Autolock autoLock(mMsgLock);
38     while (!mScanMsgProcessed) {
39         mMsgCondition.wait(mMsgLock);
40     }
41     ALOGD("[vts] frontend scan message. Type: %d", type);
42     mScanMessageReceived = true;
43     mScanMsgProcessed = false;
44     mScanMessageType = type;
45     mScanMessage = message;
46     mMsgCondition.signal();
47     return Void();
48 }
49 
tuneTestOnEventReceive(sp<IFrontend> & frontend,FrontendSettings settings)50 void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) {
51     Result result = frontend->tune(settings);
52     EXPECT_TRUE(result == Result::SUCCESS);
53 
54     android::Mutex::Autolock autoLock(mMsgLock);
55     while (!mEventReceived) {
56         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
57             EXPECT_TRUE(false) << "Event not received within timeout";
58             mLockMsgReceived = false;
59             return;
60         }
61     }
62     mEventReceived = false;
63 }
64 
tuneTestOnLock(sp<IFrontend> & frontend,FrontendSettings settings)65 void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) {
66     Result result = frontend->tune(settings);
67     EXPECT_TRUE(result == Result::SUCCESS);
68 
69     android::Mutex::Autolock autoLock(mMsgLock);
70     while (!mLockMsgReceived) {
71         if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
72             EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
73             mLockMsgReceived = false;
74             return;
75         }
76     }
77     mLockMsgReceived = false;
78 }
79 
scanTest(sp<IFrontend> & frontend,FrontendConfig config,FrontendScanType type)80 void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config,
81                                 FrontendScanType type) {
82     uint32_t targetFrequency = getTargetFrequency(config.settings, config.type);
83     if (type == FrontendScanType::SCAN_BLIND) {
84         // reset the frequency in the scan configuration to test blind scan. The settings param of
85         // passed in means the real input config on the transponder connected to the DUT.
86         // We want the blind the test to start from lower frequency than this to check the blind
87         // scan implementation.
88         resetBlindScanStartingFrequency(config, targetFrequency - 100);
89     }
90 
91     Result result = frontend->scan(config.settings, type);
92     EXPECT_TRUE(result == Result::SUCCESS);
93 
94     bool scanMsgLockedReceived = false;
95     bool targetFrequencyReceived = false;
96 
97     android::Mutex::Autolock autoLock(mMsgLock);
98 wait:
99     while (!mScanMessageReceived) {
100         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
101             EXPECT_TRUE(false) << "Scan message not received within timeout";
102             mScanMessageReceived = false;
103             mScanMsgProcessed = true;
104             return;
105         }
106     }
107 
108     if (mScanMessageType != FrontendScanMessageType::END) {
109         if (mScanMessageType == FrontendScanMessageType::LOCKED) {
110             scanMsgLockedReceived = true;
111             Result result = frontend->scan(config.settings, type);
112             EXPECT_TRUE(result == Result::SUCCESS);
113         }
114 
115         if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
116             targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
117                                       mScanMessage.frequencies()[0] == targetFrequency;
118         }
119 
120         if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
121             ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
122         }
123 
124         mScanMessageReceived = false;
125         mScanMsgProcessed = true;
126         mMsgCondition.signal();
127         goto wait;
128     }
129 
130     EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
131     EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
132     mScanMessageReceived = false;
133     mScanMsgProcessed = true;
134 }
135 
getTargetFrequency(FrontendSettings settings,FrontendType type)136 uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
137     switch (type) {
138         case FrontendType::ANALOG:
139             return settings.analog().frequency;
140         case FrontendType::ATSC:
141             return settings.atsc().frequency;
142         case FrontendType::ATSC3:
143             return settings.atsc3().frequency;
144         case FrontendType::DVBC:
145             return settings.dvbc().frequency;
146         case FrontendType::DVBS:
147             return settings.dvbs().frequency;
148         case FrontendType::DVBT:
149             return settings.dvbt().frequency;
150         case FrontendType::ISDBS:
151             return settings.isdbs().frequency;
152         case FrontendType::ISDBS3:
153             return settings.isdbs3().frequency;
154         case FrontendType::ISDBT:
155             return settings.isdbt().frequency;
156         default:
157             return 0;
158     }
159 }
160 
resetBlindScanStartingFrequency(FrontendConfig & config,uint32_t resetingFreq)161 void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
162                                                        uint32_t resetingFreq) {
163     switch (config.type) {
164         case FrontendType::ANALOG:
165             config.settings.analog().frequency = resetingFreq;
166             break;
167         case FrontendType::ATSC:
168             config.settings.atsc().frequency = resetingFreq;
169             break;
170         case FrontendType::ATSC3:
171             config.settings.atsc3().frequency = resetingFreq;
172             break;
173         case FrontendType::DVBC:
174             config.settings.dvbc().frequency = resetingFreq;
175             break;
176         case FrontendType::DVBS:
177             config.settings.dvbs().frequency = resetingFreq;
178             break;
179         case FrontendType::DVBT:
180             config.settings.dvbt().frequency = resetingFreq;
181             break;
182         case FrontendType::ISDBS:
183             config.settings.isdbs().frequency = resetingFreq;
184             break;
185         case FrontendType::ISDBS3:
186             config.settings.isdbs3().frequency = resetingFreq;
187             break;
188         case FrontendType::ISDBT:
189             config.settings.isdbt().frequency = resetingFreq;
190             break;
191         default:
192             // do nothing
193             return;
194     }
195 }
196 
getFrontendIds()197 AssertionResult FrontendTests::getFrontendIds() {
198     Result status;
199     mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
200         status = result;
201         mFeIds = frontendIds;
202     });
203     return AssertionResult(status == Result::SUCCESS);
204 }
205 
getFrontendInfo(uint32_t frontendId)206 AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
207     Result status;
208     mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
209         mFrontendInfo = frontendInfo;
210         status = result;
211     });
212     return AssertionResult(status == Result::SUCCESS);
213 }
214 
openFrontendById(uint32_t frontendId)215 AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
216     Result status;
217     mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
218         mFrontend = frontend;
219         status = result;
220     });
221     return AssertionResult(status == Result::SUCCESS);
222 }
223 
setFrontendCallback()224 AssertionResult FrontendTests::setFrontendCallback() {
225     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
226     mFrontendCallback = new FrontendCallback();
227     auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
228     return AssertionResult(callbackStatus.isOk());
229 }
230 
scanFrontend(FrontendConfig config,FrontendScanType type)231 AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
232     EXPECT_TRUE(mFrontendCallback)
233             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
234 
235     EXPECT_TRUE(mFrontendInfo.type == config.type)
236             << "FrontendConfig does not match the frontend info of the given id.";
237 
238     mFrontendCallback->scanTest(mFrontend, config, type);
239     return AssertionResult(true);
240 }
241 
stopScanFrontend()242 AssertionResult FrontendTests::stopScanFrontend() {
243     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
244     Result status;
245     status = mFrontend->stopScan();
246     return AssertionResult(status == Result::SUCCESS);
247 }
248 
verifyFrontendStatus(vector<FrontendStatusType> statusTypes,vector<FrontendStatus> expectStatuses)249 void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
250                                          vector<FrontendStatus> expectStatuses) {
251     ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
252     Result status;
253     vector<FrontendStatus> realStatuses;
254 
255     mFrontend->getStatus(statusTypes, [&](Result result, const hidl_vec<FrontendStatus>& statuses) {
256         status = result;
257         realStatuses = statuses;
258     });
259 
260     ASSERT_TRUE(realStatuses.size() == statusTypes.size());
261     for (int i = 0; i < statusTypes.size(); i++) {
262         FrontendStatusType type = statusTypes[i];
263         switch (type) {
264             case FrontendStatusType::DEMOD_LOCK: {
265                 ASSERT_TRUE(realStatuses[i].isDemodLocked() == expectStatuses[i].isDemodLocked());
266                 break;
267             }
268             case FrontendStatusType::SNR: {
269                 ASSERT_TRUE(realStatuses[i].snr() == expectStatuses[i].snr());
270                 break;
271             }
272             case FrontendStatusType::BER: {
273                 ASSERT_TRUE(realStatuses[i].ber() == expectStatuses[i].ber());
274                 break;
275             }
276             case FrontendStatusType::PER: {
277                 ASSERT_TRUE(realStatuses[i].per() == expectStatuses[i].per());
278                 break;
279             }
280             case FrontendStatusType::PRE_BER: {
281                 ASSERT_TRUE(realStatuses[i].preBer() == expectStatuses[i].preBer());
282                 break;
283             }
284             case FrontendStatusType::SIGNAL_QUALITY: {
285                 ASSERT_TRUE(realStatuses[i].signalQuality() == expectStatuses[i].signalQuality());
286                 break;
287             }
288             case FrontendStatusType::SIGNAL_STRENGTH: {
289                 ASSERT_TRUE(realStatuses[i].signalStrength() == expectStatuses[i].signalStrength());
290                 break;
291             }
292             case FrontendStatusType::SYMBOL_RATE: {
293                 ASSERT_TRUE(realStatuses[i].symbolRate() == expectStatuses[i].symbolRate());
294                 break;
295             }
296             case FrontendStatusType::FEC: {
297                 ASSERT_TRUE(realStatuses[i].innerFec() == expectStatuses[i].innerFec());
298                 break;
299             }
300             case FrontendStatusType::MODULATION: {
301                 // TODO: check modulation status
302                 break;
303             }
304             case FrontendStatusType::SPECTRAL: {
305                 ASSERT_TRUE(realStatuses[i].inversion() == expectStatuses[i].inversion());
306                 break;
307             }
308             case FrontendStatusType::LNB_VOLTAGE: {
309                 ASSERT_TRUE(realStatuses[i].lnbVoltage() == expectStatuses[i].lnbVoltage());
310                 break;
311             }
312             case FrontendStatusType::PLP_ID: {
313                 ASSERT_TRUE(realStatuses[i].plpId() == expectStatuses[i].plpId());
314                 break;
315             }
316             case FrontendStatusType::EWBS: {
317                 ASSERT_TRUE(realStatuses[i].isEWBS() == expectStatuses[i].isEWBS());
318                 break;
319             }
320             case FrontendStatusType::AGC: {
321                 ASSERT_TRUE(realStatuses[i].agc() == expectStatuses[i].agc());
322                 break;
323             }
324             case FrontendStatusType::LNA: {
325                 ASSERT_TRUE(realStatuses[i].isLnaOn() == expectStatuses[i].isLnaOn());
326                 break;
327             }
328             case FrontendStatusType::LAYER_ERROR: {
329                 vector<bool> realLayberError = realStatuses[i].isLayerError();
330                 vector<bool> expectLayerError = expectStatuses[i].isLayerError();
331                 ASSERT_TRUE(realLayberError.size() == expectLayerError.size());
332                 for (int i = 0; i < realLayberError.size(); i++) {
333                     ASSERT_TRUE(realLayberError[i] == expectLayerError[i]);
334                 }
335                 break;
336             }
337             case FrontendStatusType::MER: {
338                 ASSERT_TRUE(realStatuses[i].mer() == expectStatuses[i].mer());
339                 break;
340             }
341             case FrontendStatusType::FREQ_OFFSET: {
342                 ASSERT_TRUE(realStatuses[i].freqOffset() == expectStatuses[i].freqOffset());
343                 break;
344             }
345             case FrontendStatusType::HIERARCHY: {
346                 ASSERT_TRUE(realStatuses[i].hierarchy() == expectStatuses[i].hierarchy());
347                 break;
348             }
349             case FrontendStatusType::RF_LOCK: {
350                 ASSERT_TRUE(realStatuses[i].isRfLocked() == expectStatuses[i].isRfLocked());
351                 break;
352             }
353             case FrontendStatusType::ATSC3_PLP_INFO:
354                 // TODO: verify plpinfo
355                 break;
356             default:
357                 continue;
358         }
359     }
360     ASSERT_TRUE(status == Result::SUCCESS);
361 }
362 
tuneFrontend(FrontendConfig config,bool testWithDemux)363 AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
364     EXPECT_TRUE(mFrontendCallback)
365             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
366 
367     EXPECT_TRUE(mFrontendInfo.type == config.type)
368             << "FrontendConfig does not match the frontend info of the given id.";
369 
370     mIsSoftwareFe = config.isSoftwareFe;
371     bool result = true;
372     if (mIsSoftwareFe && testWithDemux) {
373         result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
374         result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
375         result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
376         mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
377                                            mDvrConfig.settings.playback());
378         if (!result) {
379             ALOGW("[vts] Software frontend dvr configure failed.");
380             return failure();
381         }
382     }
383     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
384     return AssertionResult(true);
385 }
386 
setLnb(uint32_t lnbId)387 AssertionResult FrontendTests::setLnb(uint32_t lnbId) {
388     if (!mFrontendCallback) {
389         ALOGW("[vts] open and set frontend callback first.");
390         return failure();
391     }
392     return AssertionResult(mFrontend->setLnb(lnbId) == Result::SUCCESS);
393 }
394 
stopTuneFrontend(bool testWithDemux)395 AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
396     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
397     Result status;
398     status = mFrontend->stopTune();
399     if (mIsSoftwareFe && testWithDemux) {
400         mDvrTests.stopPlaybackThread();
401         mDvrTests.closeDvrPlayback();
402     }
403     return AssertionResult(status == Result::SUCCESS);
404 }
405 
closeFrontend()406 AssertionResult FrontendTests::closeFrontend() {
407     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
408     Result status;
409     status = mFrontend->close();
410     mFrontend = nullptr;
411     mFrontendCallback = nullptr;
412     return AssertionResult(status == Result::SUCCESS);
413 }
414 
getFrontendIdByType(FrontendType feType,uint32_t & feId)415 void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
416     ASSERT_TRUE(getFrontendIds());
417     ASSERT_TRUE(mFeIds.size() > 0);
418     for (size_t i = 0; i < mFeIds.size(); i++) {
419         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
420         if (mFrontendInfo.type != feType) {
421             continue;
422         }
423         feId = mFeIds[i];
424         return;
425     }
426     feId = INVALID_ID;
427 }
428 
tuneTest(FrontendConfig frontendConf)429 void FrontendTests::tuneTest(FrontendConfig frontendConf) {
430     uint32_t feId;
431     getFrontendIdByType(frontendConf.type, feId);
432     ASSERT_TRUE(feId != INVALID_ID);
433     ASSERT_TRUE(openFrontendById(feId));
434     ASSERT_TRUE(setFrontendCallback());
435     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
436     verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
437     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
438     ASSERT_TRUE(closeFrontend());
439 }
440 
scanTest(FrontendConfig frontendConf,FrontendScanType scanType)441 void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
442     uint32_t feId;
443     getFrontendIdByType(frontendConf.type, feId);
444     ASSERT_TRUE(feId != INVALID_ID);
445     ASSERT_TRUE(openFrontendById(feId));
446     ASSERT_TRUE(setFrontendCallback());
447     ASSERT_TRUE(scanFrontend(frontendConf, scanType));
448     ASSERT_TRUE(stopScanFrontend());
449     ASSERT_TRUE(closeFrontend());
450 }
451