1 /*
2  * Copyright (C) 2019 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 #define LOG_TAG "[email protected]"
18 
19 #include "Frontend.h"
20 #include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
21 #include <utils/Log.h>
22 
23 namespace android {
24 namespace hardware {
25 namespace tv {
26 namespace tuner {
27 namespace V1_0 {
28 namespace implementation {
29 
Frontend(FrontendType type,FrontendId id,sp<Tuner> tuner)30 Frontend::Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner) {
31     mType = type;
32     mId = id;
33     mTunerService = tuner;
34     // Init callback to nullptr
35     mCallback = nullptr;
36 }
37 
~Frontend()38 Frontend::~Frontend() {}
39 
close()40 Return<Result> Frontend::close() {
41     ALOGV("%s", __FUNCTION__);
42     // Reset callback
43     mCallback = nullptr;
44     mIsLocked = false;
45 
46     return Result::SUCCESS;
47 }
48 
setCallback(const sp<IFrontendCallback> & callback)49 Return<Result> Frontend::setCallback(const sp<IFrontendCallback>& callback) {
50     ALOGV("%s", __FUNCTION__);
51     if (callback == nullptr) {
52         ALOGW("[   WARN   ] Set Frontend callback with nullptr");
53         return Result::INVALID_ARGUMENT;
54     }
55 
56     mCallback = callback;
57     return Result::SUCCESS;
58 }
59 
tune(const FrontendSettings &)60 Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
61     ALOGV("%s", __FUNCTION__);
62     if (mCallback == nullptr) {
63         ALOGW("[   WARN   ] Frontend callback is not set when tune");
64         return Result::INVALID_STATE;
65     }
66 
67     mTunerService->frontendStartTune(mId);
68     mCallback->onEvent(FrontendEventType::LOCKED);
69     mIsLocked = true;
70     return Result::SUCCESS;
71 }
72 
stopTune()73 Return<Result> Frontend::stopTune() {
74     ALOGV("%s", __FUNCTION__);
75 
76     mTunerService->frontendStopTune(mId);
77     mIsLocked = false;
78 
79     return Result::SUCCESS;
80 }
81 
scan(const FrontendSettings & settings,FrontendScanType type)82 Return<Result> Frontend::scan(const FrontendSettings& settings, FrontendScanType type) {
83     ALOGV("%s", __FUNCTION__);
84 
85     if (mType == FrontendType::ATSC) {
86         FrontendScanMessage msg;
87         msg.isLocked(true);
88         mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
89         mIsLocked = true;
90         return Result::SUCCESS;
91     }
92     if (mType != FrontendType::DVBT) {
93         return Result::UNAVAILABLE;
94     }
95 
96     FrontendScanMessage msg;
97 
98     if (mIsLocked) {
99         msg.isEnd(true);
100         mCallback->onScanMessage(FrontendScanMessageType::END, msg);
101         return Result::SUCCESS;
102     }
103 
104     uint32_t frequency = settings.dvbt().frequency;
105     if (type == FrontendScanType::SCAN_BLIND) {
106         frequency += 100;
107     }
108     msg.frequencies({frequency});
109     mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
110     msg.isLocked(true);
111     mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
112     mIsLocked = true;
113 
114     return Result::SUCCESS;
115 }
116 
stopScan()117 Return<Result> Frontend::stopScan() {
118     ALOGV("%s", __FUNCTION__);
119 
120     mIsLocked = false;
121     return Result::SUCCESS;
122 }
123 
getStatus(const hidl_vec<FrontendStatusType> & statusTypes,getStatus_cb _hidl_cb)124 Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
125                                  getStatus_cb _hidl_cb) {
126     ALOGV("%s", __FUNCTION__);
127 
128     vector<FrontendStatus> statuses;
129     for (int i = 0; i < statusTypes.size(); i++) {
130         FrontendStatusType type = statusTypes[i];
131         FrontendStatus status;
132         // assign randomly selected values for testing.
133         switch (type) {
134             case FrontendStatusType::DEMOD_LOCK: {
135                 status.isDemodLocked(true);
136                 break;
137             }
138             case FrontendStatusType::SNR: {
139                 status.snr(221);
140                 break;
141             }
142             case FrontendStatusType::BER: {
143                 status.ber(1);
144                 break;
145             }
146             case FrontendStatusType::PER: {
147                 status.per(2);
148                 break;
149             }
150             case FrontendStatusType::PRE_BER: {
151                 status.preBer(3);
152                 break;
153             }
154             case FrontendStatusType::SIGNAL_QUALITY: {
155                 status.signalQuality(4);
156                 break;
157             }
158             case FrontendStatusType::SIGNAL_STRENGTH: {
159                 status.signalStrength(5);
160                 break;
161             }
162             case FrontendStatusType::SYMBOL_RATE: {
163                 status.symbolRate(6);
164                 break;
165             }
166             case FrontendStatusType::FEC: {
167                 status.innerFec(FrontendInnerFec::FEC_2_9);  // value = 1 << 7
168                 break;
169             }
170             case FrontendStatusType::MODULATION: {
171                 FrontendModulationStatus modulationStatus;
172                 modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM);  // value = 1 << 3
173                 status.modulation(modulationStatus);
174                 break;
175             }
176             case FrontendStatusType::SPECTRAL: {
177                 status.inversion(FrontendDvbcSpectralInversion::NORMAL);
178                 break;
179             }
180             case FrontendStatusType::LNB_VOLTAGE: {
181                 status.lnbVoltage(LnbVoltage::VOLTAGE_5V);
182                 break;
183             }
184             case FrontendStatusType::PLP_ID: {
185                 status.plpId(101);  // type uint8_t
186                 break;
187             }
188             case FrontendStatusType::EWBS: {
189                 status.isEWBS(false);
190                 break;
191             }
192             case FrontendStatusType::AGC: {
193                 status.agc(7);
194                 break;
195             }
196             case FrontendStatusType::LNA: {
197                 status.isLnaOn(false);
198                 break;
199             }
200             case FrontendStatusType::LAYER_ERROR: {
201                 vector<bool> v = {false, true, true};
202                 status.isLayerError(v);
203                 break;
204             }
205             case FrontendStatusType::MER: {
206                 status.mer(8);
207                 break;
208             }
209             case FrontendStatusType::FREQ_OFFSET: {
210                 status.freqOffset(9);
211                 break;
212             }
213             case FrontendStatusType::HIERARCHY: {
214                 status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE);
215                 break;
216             }
217             case FrontendStatusType::RF_LOCK: {
218                 status.isRfLocked(false);
219                 break;
220             }
221             case FrontendStatusType::ATSC3_PLP_INFO: {
222                 vector<FrontendStatusAtsc3PlpInfo> v;
223                 FrontendStatusAtsc3PlpInfo info1{
224                         .plpId = 3,
225                         .isLocked = false,
226                         .uec = 313,
227                 };
228                 FrontendStatusAtsc3PlpInfo info2{
229                         .plpId = 5,
230                         .isLocked = true,
231                         .uec = 515,
232                 };
233                 v.push_back(info1);
234                 v.push_back(info2);
235                 status.plpInfo(v);
236                 break;
237             }
238             default: {
239                 continue;
240             }
241         }
242         statuses.push_back(status);
243     }
244     _hidl_cb(Result::SUCCESS, statuses);
245 
246     return Void();
247 }
248 
setLna(bool)249 Return<Result> Frontend::setLna(bool /* bEnable */) {
250     ALOGV("%s", __FUNCTION__);
251 
252     return Result::SUCCESS;
253 }
254 
setLnb(uint32_t)255 Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
256     ALOGV("%s", __FUNCTION__);
257     if (!supportsSatellite()) {
258         return Result::INVALID_STATE;
259     }
260     return Result::SUCCESS;
261 }
262 
getFrontendType()263 FrontendType Frontend::getFrontendType() {
264     return mType;
265 }
266 
getFrontendId()267 FrontendId Frontend::getFrontendId() {
268     return mId;
269 }
270 
supportsSatellite()271 bool Frontend::supportsSatellite() {
272     return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
273            mType == FrontendType::ISDBS3;
274 }
275 
isLocked()276 bool Frontend::isLocked() {
277     return mIsLocked;
278 }
279 }  // namespace implementation
280 }  // namespace V1_0
281 }  // namespace tuner
282 }  // namespace tv
283 }  // namespace hardware
284 }  // namespace android
285