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