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