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 * 1000);
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     if (type == FrontendScanType::SCAN_BLIND)
132         EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
133     mScanMessageReceived = false;
134     mScanMsgProcessed = true;
135 }
136 
getTargetFrequency(FrontendSettings settings,FrontendType type)137 uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
138     switch (type) {
139         case FrontendType::ANALOG:
140             return settings.analog().frequency;
141         case FrontendType::ATSC:
142             return settings.atsc().frequency;
143         case FrontendType::ATSC3:
144             return settings.atsc3().frequency;
145         case FrontendType::DVBC:
146             return settings.dvbc().frequency;
147         case FrontendType::DVBS:
148             return settings.dvbs().frequency;
149         case FrontendType::DVBT:
150             return settings.dvbt().frequency;
151         case FrontendType::ISDBS:
152             return settings.isdbs().frequency;
153         case FrontendType::ISDBS3:
154             return settings.isdbs3().frequency;
155         case FrontendType::ISDBT:
156             return settings.isdbt().frequency;
157         default:
158             return 0;
159     }
160 }
161 
resetBlindScanStartingFrequency(FrontendConfig & config,uint32_t resetingFreq)162 void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
163                                                        uint32_t resetingFreq) {
164     switch (config.type) {
165         case FrontendType::ANALOG:
166             config.settings.analog().frequency = resetingFreq;
167             break;
168         case FrontendType::ATSC:
169             config.settings.atsc().frequency = resetingFreq;
170             break;
171         case FrontendType::ATSC3:
172             config.settings.atsc3().frequency = resetingFreq;
173             break;
174         case FrontendType::DVBC:
175             config.settings.dvbc().frequency = resetingFreq;
176             break;
177         case FrontendType::DVBS:
178             config.settings.dvbs().frequency = resetingFreq;
179             break;
180         case FrontendType::DVBT:
181             config.settings.dvbt().frequency = resetingFreq;
182             break;
183         case FrontendType::ISDBS:
184             config.settings.isdbs().frequency = resetingFreq;
185             break;
186         case FrontendType::ISDBS3:
187             config.settings.isdbs3().frequency = resetingFreq;
188             break;
189         case FrontendType::ISDBT:
190             config.settings.isdbt().frequency = resetingFreq;
191             break;
192         default:
193             // do nothing
194             return;
195     }
196 }
197 
getFrontendIds()198 AssertionResult FrontendTests::getFrontendIds() {
199     Result status;
200     mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
201         status = result;
202         mFeIds = frontendIds;
203     });
204     return AssertionResult(status == Result::SUCCESS);
205 }
206 
getFrontendInfo(uint32_t frontendId)207 AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
208     Result status;
209     mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
210         mFrontendInfo = frontendInfo;
211         status = result;
212     });
213     return AssertionResult(status == Result::SUCCESS);
214 }
215 
openFrontendById(uint32_t frontendId)216 AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
217     Result status;
218     mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
219         mFrontend = frontend;
220         status = result;
221     });
222     return AssertionResult(status == Result::SUCCESS);
223 }
224 
setFrontendCallback()225 AssertionResult FrontendTests::setFrontendCallback() {
226     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
227     mFrontendCallback = new FrontendCallback();
228     auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
229     return AssertionResult(callbackStatus.isOk());
230 }
231 
scanFrontend(FrontendConfig config,FrontendScanType type)232 AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
233     EXPECT_TRUE(mFrontendCallback)
234             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
235 
236     EXPECT_TRUE(mFrontendInfo.type == config.type)
237             << "FrontendConfig does not match the frontend info of the given id.";
238 
239     mFrontendCallback->scanTest(mFrontend, config, type);
240     return AssertionResult(true);
241 }
242 
stopScanFrontend()243 AssertionResult FrontendTests::stopScanFrontend() {
244     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
245     Result status;
246     status = mFrontend->stopScan();
247     return AssertionResult(status == Result::SUCCESS);
248 }
249 
verifyFrontendStatus(vector<FrontendStatusType> statusTypes,vector<FrontendStatus> expectStatuses)250 void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
251                                          vector<FrontendStatus> expectStatuses) {
252     ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
253     Result status;
254     vector<FrontendStatus> realStatuses;
255 
256     mFrontend->getStatus(statusTypes, [&](Result result, const hidl_vec<FrontendStatus>& statuses) {
257         status = result;
258         realStatuses = statuses;
259     });
260 
261     ASSERT_TRUE(realStatuses.size() == statusTypes.size());
262     for (int i = 0; i < statusTypes.size(); i++) {
263         FrontendStatusType type = statusTypes[i];
264         switch (type) {
265             case FrontendStatusType::DEMOD_LOCK: {
266                 ASSERT_TRUE(realStatuses[i].isDemodLocked() == expectStatuses[i].isDemodLocked());
267                 break;
268             }
269             case FrontendStatusType::SNR: {
270                 ASSERT_TRUE(realStatuses[i].snr() == expectStatuses[i].snr());
271                 break;
272             }
273             case FrontendStatusType::BER: {
274                 ASSERT_TRUE(realStatuses[i].ber() == expectStatuses[i].ber());
275                 break;
276             }
277             case FrontendStatusType::PER: {
278                 ASSERT_TRUE(realStatuses[i].per() == expectStatuses[i].per());
279                 break;
280             }
281             case FrontendStatusType::PRE_BER: {
282                 ASSERT_TRUE(realStatuses[i].preBer() == expectStatuses[i].preBer());
283                 break;
284             }
285             case FrontendStatusType::SIGNAL_QUALITY: {
286                 ASSERT_TRUE(realStatuses[i].signalQuality() == expectStatuses[i].signalQuality());
287                 break;
288             }
289             case FrontendStatusType::SIGNAL_STRENGTH: {
290                 ASSERT_TRUE(realStatuses[i].signalStrength() == expectStatuses[i].signalStrength());
291                 break;
292             }
293             case FrontendStatusType::SYMBOL_RATE: {
294                 ASSERT_TRUE(realStatuses[i].symbolRate() == expectStatuses[i].symbolRate());
295                 break;
296             }
297             case FrontendStatusType::FEC: {
298                 ASSERT_TRUE(realStatuses[i].innerFec() == expectStatuses[i].innerFec());
299                 break;
300             }
301             case FrontendStatusType::MODULATION: {
302                 // TODO: check modulation status
303                 break;
304             }
305             case FrontendStatusType::SPECTRAL: {
306                 ASSERT_TRUE(realStatuses[i].inversion() == expectStatuses[i].inversion());
307                 break;
308             }
309             case FrontendStatusType::LNB_VOLTAGE: {
310                 ASSERT_TRUE(realStatuses[i].lnbVoltage() == expectStatuses[i].lnbVoltage());
311                 break;
312             }
313             case FrontendStatusType::PLP_ID: {
314                 ASSERT_TRUE(realStatuses[i].plpId() == expectStatuses[i].plpId());
315                 break;
316             }
317             case FrontendStatusType::EWBS: {
318                 ASSERT_TRUE(realStatuses[i].isEWBS() == expectStatuses[i].isEWBS());
319                 break;
320             }
321             case FrontendStatusType::AGC: {
322                 ASSERT_TRUE(realStatuses[i].agc() == expectStatuses[i].agc());
323                 break;
324             }
325             case FrontendStatusType::LNA: {
326                 ASSERT_TRUE(realStatuses[i].isLnaOn() == expectStatuses[i].isLnaOn());
327                 break;
328             }
329             case FrontendStatusType::LAYER_ERROR: {
330                 vector<bool> realLayberError = realStatuses[i].isLayerError();
331                 vector<bool> expectLayerError = expectStatuses[i].isLayerError();
332                 ASSERT_TRUE(realLayberError.size() == expectLayerError.size());
333                 for (int i = 0; i < realLayberError.size(); i++) {
334                     ASSERT_TRUE(realLayberError[i] == expectLayerError[i]);
335                 }
336                 break;
337             }
338             case FrontendStatusType::MER: {
339                 ASSERT_TRUE(realStatuses[i].mer() == expectStatuses[i].mer());
340                 break;
341             }
342             case FrontendStatusType::FREQ_OFFSET: {
343                 ASSERT_TRUE(realStatuses[i].freqOffset() == expectStatuses[i].freqOffset());
344                 break;
345             }
346             case FrontendStatusType::HIERARCHY: {
347                 ASSERT_TRUE(realStatuses[i].hierarchy() == expectStatuses[i].hierarchy());
348                 break;
349             }
350             case FrontendStatusType::RF_LOCK: {
351                 ASSERT_TRUE(realStatuses[i].isRfLocked() == expectStatuses[i].isRfLocked());
352                 break;
353             }
354             case FrontendStatusType::ATSC3_PLP_INFO:
355                 // TODO: verify plpinfo
356                 break;
357             default:
358                 continue;
359         }
360     }
361     ASSERT_TRUE(status == Result::SUCCESS);
362 }
363 
tuneFrontend(FrontendConfig config,bool testWithDemux)364 AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
365     EXPECT_TRUE(mFrontendCallback)
366             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
367 
368     EXPECT_TRUE(mFrontendInfo.type == config.type)
369             << "FrontendConfig does not match the frontend info of the given id.";
370 
371     mIsSoftwareFe = config.isSoftwareFe;
372     bool result = true;
373     if (mIsSoftwareFe && testWithDemux) {
374         result &=
375                 getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
376         result &= getDvrTests()->configDvrPlayback(mDvrConfig.settings) == success();
377         result &= getDvrTests()->getDvrPlaybackMQDescriptor() == success();
378         getDvrTests()->startPlaybackInputThread(mDvrConfig.playbackInputFile,
379                                                 mDvrConfig.settings.playback());
380         getDvrTests()->startDvrPlayback();
381         if (!result) {
382             ALOGW("[vts] Software frontend dvr configure failed.");
383             return failure();
384         }
385     }
386     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
387     return AssertionResult(true);
388 }
389 
setLnb(uint32_t lnbId)390 AssertionResult FrontendTests::setLnb(uint32_t lnbId) {
391     if (!mFrontendCallback) {
392         ALOGW("[vts] open and set frontend callback first.");
393         return failure();
394     }
395     return AssertionResult(mFrontend->setLnb(lnbId) == Result::SUCCESS);
396 }
397 
stopTuneFrontend(bool testWithDemux)398 AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
399     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
400     Result status;
401     status = mFrontend->stopTune();
402     if (mIsSoftwareFe && testWithDemux) {
403         getDvrTests()->stopPlaybackThread();
404         getDvrTests()->stopDvrPlayback();
405         getDvrTests()->closeDvrPlayback();
406     }
407     return AssertionResult(status == Result::SUCCESS);
408 }
409 
closeFrontend()410 AssertionResult FrontendTests::closeFrontend() {
411     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
412     Result status;
413     status = mFrontend->close();
414     mFrontend = nullptr;
415     mFrontendCallback = nullptr;
416     return AssertionResult(status == Result::SUCCESS);
417 }
418 
getFrontendIdByType(FrontendType feType,uint32_t & feId)419 void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
420     ASSERT_TRUE(getFrontendIds());
421     for (size_t i = 0; i < mFeIds.size(); i++) {
422         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
423         if (mFrontendInfo.type != feType) {
424             continue;
425         }
426         feId = mFeIds[i];
427         return;
428     }
429     feId = INVALID_ID;
430 }
431 
tuneTest(FrontendConfig frontendConf)432 void FrontendTests::tuneTest(FrontendConfig frontendConf) {
433     uint32_t feId;
434     getFrontendIdByType(frontendConf.type, feId);
435     ASSERT_TRUE(feId != INVALID_ID);
436     ASSERT_TRUE(openFrontendById(feId));
437     ASSERT_TRUE(setFrontendCallback());
438     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
439     verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
440     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
441     ASSERT_TRUE(closeFrontend());
442 }
443 
scanTest(FrontendConfig frontendConf,FrontendScanType scanType)444 void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
445     uint32_t feId;
446     getFrontendIdByType(frontendConf.type, feId);
447     ASSERT_TRUE(feId != INVALID_ID);
448     ASSERT_TRUE(openFrontendById(feId));
449     ASSERT_TRUE(setFrontendCallback());
450     ASSERT_TRUE(scanFrontend(frontendConf, scanType));
451     ASSERT_TRUE(stopScanFrontend());
452     ASSERT_TRUE(closeFrontend());
453 }
454