/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "android.hardware.tv.tuner@1.1-Frontend" #include "Frontend.h" #include #include namespace android { namespace hardware { namespace tv { namespace tuner { namespace V1_0 { namespace implementation { Frontend::Frontend(FrontendType type, FrontendId id, sp tuner) { mType = type; mId = id; mTunerService = tuner; // Init callback to nullptr mCallback = nullptr; } Frontend::~Frontend() {} Return Frontend::close() { ALOGV("%s", __FUNCTION__); // Reset callback mCallback = nullptr; mIsLocked = false; mTunerService->removeFrontend(mId); return Result::SUCCESS; } Return Frontend::setCallback(const sp& callback) { ALOGV("%s", __FUNCTION__); if (callback == nullptr) { ALOGW("[ WARN ] Set Frontend callback with nullptr"); return Result::INVALID_ARGUMENT; } mCallback = callback; return Result::SUCCESS; } Return Frontend::tune(const FrontendSettings& /* settings */) { ALOGV("%s", __FUNCTION__); if (mCallback == nullptr) { ALOGW("[ WARN ] Frontend callback is not set when tune"); return Result::INVALID_STATE; } mTunerService->frontendStartTune(mId); mCallback->onEvent(FrontendEventType::LOCKED); mIsLocked = true; return Result::SUCCESS; } Return Frontend::tune_1_1(const FrontendSettings& settings, const V1_1::FrontendSettingsExt1_1& /*settingsExt1_1*/) { ALOGV("%s", __FUNCTION__); return tune(settings); } Return Frontend::stopTune() { ALOGV("%s", __FUNCTION__); mTunerService->frontendStopTune(mId); mIsLocked = false; return Result::SUCCESS; } Return Frontend::scan(const FrontendSettings& settings, FrontendScanType type) { ALOGV("%s", __FUNCTION__); // If it's in middle of scanning, stop it first. if (mScanThread.joinable()) { mScanThread.join(); } mFrontendSettings = settings; mFrontendScanType = type; mScanThread = std::thread(&Frontend::scanThreadLoop, this); return Result::SUCCESS; } void Frontend::scanThreadLoop() { FrontendScanMessage msg; if (mIsLocked) { msg.isEnd(true); mCallback->onScanMessage(FrontendScanMessageType::END, msg); return; } uint32_t frequency; switch (mFrontendSettings.getDiscriminator()) { case FrontendSettings::hidl_discriminator::analog: frequency = mFrontendSettings.analog().frequency; break; case FrontendSettings::hidl_discriminator::atsc: frequency = mFrontendSettings.atsc().frequency; break; case FrontendSettings::hidl_discriminator::atsc3: frequency = mFrontendSettings.atsc3().frequency; break; case FrontendSettings::hidl_discriminator::dvbs: frequency = mFrontendSettings.dvbs().frequency; break; case FrontendSettings::hidl_discriminator::dvbc: frequency = mFrontendSettings.dvbc().frequency; break; case FrontendSettings::hidl_discriminator::dvbt: frequency = mFrontendSettings.dvbt().frequency; break; case FrontendSettings::hidl_discriminator::isdbs: frequency = mFrontendSettings.isdbs().frequency; break; case FrontendSettings::hidl_discriminator::isdbs3: frequency = mFrontendSettings.isdbs3().frequency; break; case FrontendSettings::hidl_discriminator::isdbt: frequency = mFrontendSettings.isdbt().frequency; break; } if (mFrontendScanType == FrontendScanType::SCAN_BLIND) { frequency += 100 * 1000; } msg.frequencies({frequency}); mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg); msg.progressPercent(20); mCallback->onScanMessage(FrontendScanMessageType::PROGRESS_PERCENT, msg); msg.symbolRates({30}); mCallback->onScanMessage(FrontendScanMessageType::SYMBOL_RATE, msg); if (mType == FrontendType::DVBT) { msg.hierarchy(FrontendDvbtHierarchy::HIERARCHY_NON_NATIVE); mCallback->onScanMessage(FrontendScanMessageType::HIERARCHY, msg); } if (mType == FrontendType::ANALOG) { msg.analogType(FrontendAnalogType::PAL); mCallback->onScanMessage(FrontendScanMessageType::ANALOG_TYPE, msg); } msg.plpIds({3}); mCallback->onScanMessage(FrontendScanMessageType::PLP_IDS, msg); msg.groupIds({2}); mCallback->onScanMessage(FrontendScanMessageType::GROUP_IDS, msg); msg.inputStreamIds({1}); mCallback->onScanMessage(FrontendScanMessageType::INPUT_STREAM_IDS, msg); FrontendScanMessage::Standard s; switch (mType) { case FrontendType::DVBT: s.tStd(FrontendDvbtStandard::AUTO); msg.std(s); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; case FrontendType::DVBS: s.sStd(FrontendDvbsStandard::AUTO); msg.std(s); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; case FrontendType::ANALOG: s.sifStd(FrontendAnalogSifStandard::AUTO); msg.std(s); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; default: break; } FrontendScanAtsc3PlpInfo info{ .plpId = 1, .bLlsFlag = false, }; msg.atsc3PlpInfos({info}); mCallback->onScanMessage(FrontendScanMessageType::ATSC3_PLP_INFO, msg); sp frontendCallback_v1_1 = V1_1::IFrontendCallback::castFrom(mCallback); if (frontendCallback_v1_1 != NULL) { V1_1::FrontendScanMessageExt1_1 msg; msg.modulation().dvbc(FrontendDvbcModulation::MOD_16QAM); frontendCallback_v1_1->onScanMessageExt1_1(V1_1::FrontendScanMessageTypeExt1_1::MODULATION, msg); msg.isHighPriority(true); frontendCallback_v1_1->onScanMessageExt1_1( V1_1::FrontendScanMessageTypeExt1_1::HIGH_PRIORITY, msg); } else { ALOGD("[Frontend] Couldn't cast to V1_1 IFrontendCallback"); } msg.isLocked(true); mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); mIsLocked = true; } Return Frontend::scan_1_1(const FrontendSettings& settings, FrontendScanType type, const V1_1::FrontendSettingsExt1_1& settingsExt1_1) { ALOGV("%s", __FUNCTION__); ALOGD("[Frontend] scan_1_1 end frequency %d", settingsExt1_1.endFrequency); return scan(settings, type); } Return Frontend::stopScan() { ALOGV("%s", __FUNCTION__); if (mScanThread.joinable()) { mScanThread.join(); } mIsLocked = false; return Result::SUCCESS; } Return Frontend::getStatus(const hidl_vec& statusTypes, getStatus_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); vector statuses; for (int i = 0; i < statusTypes.size(); i++) { FrontendStatusType type = statusTypes[i]; FrontendStatus status; // assign randomly selected values for testing. switch (type) { case FrontendStatusType::DEMOD_LOCK: { status.isDemodLocked(true); break; } case FrontendStatusType::SNR: { status.snr(221); break; } case FrontendStatusType::BER: { status.ber(1); break; } case FrontendStatusType::PER: { status.per(2); break; } case FrontendStatusType::PRE_BER: { status.preBer(3); break; } case FrontendStatusType::SIGNAL_QUALITY: { status.signalQuality(4); break; } case FrontendStatusType::SIGNAL_STRENGTH: { status.signalStrength(5); break; } case FrontendStatusType::SYMBOL_RATE: { status.symbolRate(6); break; } case FrontendStatusType::FEC: { status.innerFec(FrontendInnerFec::FEC_2_9); // value = 1 << 7 break; } case FrontendStatusType::MODULATION: { FrontendModulationStatus modulationStatus; switch (mType) { case FrontendType::ISDBS: { modulationStatus.isdbs( FrontendIsdbsModulation::MOD_BPSK); // value = 1 << 1 status.modulation(modulationStatus); break; } case FrontendType::DVBC: { modulationStatus.dvbc(FrontendDvbcModulation::MOD_16QAM); // value = 1 << 1 status.modulation(modulationStatus); break; } case FrontendType::DVBS: { modulationStatus.dvbs(FrontendDvbsModulation::MOD_QPSK); // value = 1 << 1 status.modulation(modulationStatus); break; } case FrontendType::ISDBS3: { modulationStatus.isdbs3( FrontendIsdbs3Modulation::MOD_BPSK); // value = 1 << 1 status.modulation(modulationStatus); break; } case FrontendType::ISDBT: { modulationStatus.isdbt( FrontendIsdbtModulation::MOD_DQPSK); // value = 1 << 1 status.modulation(modulationStatus); break; } default: break; } break; } case FrontendStatusType::SPECTRAL: { status.inversion(FrontendDvbcSpectralInversion::NORMAL); break; } case FrontendStatusType::LNB_VOLTAGE: { status.lnbVoltage(LnbVoltage::VOLTAGE_5V); break; } case FrontendStatusType::PLP_ID: { status.plpId(101); // type uint8_t break; } case FrontendStatusType::EWBS: { status.isEWBS(false); break; } case FrontendStatusType::AGC: { status.agc(7); break; } case FrontendStatusType::LNA: { status.isLnaOn(false); break; } case FrontendStatusType::LAYER_ERROR: { vector v = {false, true, true}; status.isLayerError(v); break; } case FrontendStatusType::MER: { status.mer(8); break; } case FrontendStatusType::FREQ_OFFSET: { status.freqOffset(9); break; } case FrontendStatusType::HIERARCHY: { status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE); break; } case FrontendStatusType::RF_LOCK: { status.isRfLocked(false); break; } case FrontendStatusType::ATSC3_PLP_INFO: { vector v; FrontendStatusAtsc3PlpInfo info1{ .plpId = 3, .isLocked = false, .uec = 313, }; FrontendStatusAtsc3PlpInfo info2{ .plpId = 5, .isLocked = true, .uec = 515, }; v.push_back(info1); v.push_back(info2); status.plpInfo(v); break; } default: { continue; } } statuses.push_back(status); } _hidl_cb(Result::SUCCESS, statuses); return Void(); } Return Frontend::getStatusExt1_1(const hidl_vec& statusTypes, V1_1::IFrontend::getStatusExt1_1_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); vector statuses; for (int i = 0; i < statusTypes.size(); i++) { V1_1::FrontendStatusTypeExt1_1 type = statusTypes[i]; V1_1::FrontendStatusExt1_1 status; switch (type) { case V1_1::FrontendStatusTypeExt1_1::MODULATIONS: { vector modulations; V1_1::FrontendModulation modulation; switch ((int)mType) { case (int)FrontendType::ISDBS: { modulation.isdbs(FrontendIsdbsModulation::MOD_BPSK); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::DVBC: { modulation.dvbc(FrontendDvbcModulation::MOD_16QAM); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::DVBS: { modulation.dvbs(FrontendDvbsModulation::MOD_QPSK); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::DVBT: { // value = 1 << 16 modulation.dvbt(V1_1::FrontendDvbtConstellation::CONSTELLATION_16QAM_R); modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::ISDBS3: { modulation.isdbs3(FrontendIsdbs3Modulation::MOD_BPSK); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::ISDBT: { modulation.isdbt(FrontendIsdbtModulation::MOD_DQPSK); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::ATSC: { modulation.atsc(FrontendAtscModulation::MOD_8VSB); // value = 1 << 2 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)FrontendType::ATSC3: { modulation.atsc3(FrontendAtsc3Modulation::MOD_QPSK); // value = 1 << 1 modulations.push_back(modulation); status.modulations(modulations); break; } case (int)V1_1::FrontendType::DTMB: { // value = 1 << 1 modulation.dtmb(V1_1::FrontendDtmbModulation::CONSTELLATION_4QAM); modulations.push_back(modulation); status.modulations(modulations); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::BERS: { vector bers = {1}; status.bers(bers); break; } case V1_1::FrontendStatusTypeExt1_1::CODERATES: { // value = 1 << 39 vector codeRates = {V1_1::FrontendInnerFec::FEC_6_15}; status.codeRates(codeRates); break; } case V1_1::FrontendStatusTypeExt1_1::BANDWIDTH: { V1_1::FrontendBandwidth bandwidth; switch ((int)mType) { case (int)FrontendType::DVBC: { // value = 1 << 1 bandwidth.dvbc(V1_1::FrontendDvbcBandwidth::BANDWIDTH_6MHZ); status.bandwidth(bandwidth); break; } case (int)FrontendType::DVBT: { // value = 1 << 1 bandwidth.dvbt(FrontendDvbtBandwidth::BANDWIDTH_8MHZ); status.bandwidth(bandwidth); break; } case (int)FrontendType::ISDBT: { bandwidth.isdbt(FrontendIsdbtBandwidth::BANDWIDTH_8MHZ); // value = 1 << 1 status.bandwidth(bandwidth); break; } case (int)FrontendType::ATSC3: { bandwidth.atsc3(FrontendAtsc3Bandwidth::BANDWIDTH_6MHZ); // value = 1 << 1 status.bandwidth(bandwidth); break; } case (int)V1_1::FrontendType::DTMB: { // value = 1 << 1 bandwidth.dtmb(V1_1::FrontendDtmbBandwidth::BANDWIDTH_8MHZ); status.bandwidth(bandwidth); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::GUARD_INTERVAL: { V1_1::FrontendGuardInterval interval; switch ((int)mType) { case (int)FrontendType::DVBT: { interval.dvbt(FrontendDvbtGuardInterval::INTERVAL_1_32); // value = 1 << 1 status.interval(interval); break; } case (int)FrontendType::ISDBT: { interval.isdbt(FrontendDvbtGuardInterval::INTERVAL_1_32); // value = 1 << 1 status.interval(interval); break; } case (int)V1_1::FrontendType::DTMB: { // value = 1 << 1 interval.dtmb(V1_1::FrontendDtmbGuardInterval::PN_420_VARIOUS); status.interval(interval); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::TRANSMISSION_MODE: { V1_1::FrontendTransmissionMode transMode; switch ((int)mType) { case (int)FrontendType::DVBT: { // value = 1 << 8 transMode.dvbt(V1_1::FrontendDvbtTransmissionMode::MODE_16K_E); status.transmissionMode(transMode); break; } case (int)FrontendType::ISDBT: { transMode.isdbt(FrontendIsdbtMode::MODE_1); // value = 1 << 1 status.transmissionMode(transMode); break; } case (int)V1_1::FrontendType::DTMB: { transMode.dtmb(V1_1::FrontendDtmbTransmissionMode::C1); // value = 1 << 1 status.transmissionMode(transMode); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::UEC: { status.uec(4); break; } case V1_1::FrontendStatusTypeExt1_1::T2_SYSTEM_ID: { status.systemId(5); break; } case V1_1::FrontendStatusTypeExt1_1::INTERLEAVINGS: { V1_1::FrontendInterleaveMode interleave; switch ((int)mType) { case (int)FrontendType::DVBC: { // value = 1 << 1 interleave.dvbc( V1_1::FrontendCableTimeInterleaveMode::INTERLEAVING_128_1_0); vector interleaving = {interleave}; status.interleaving(interleaving); break; } case (int)FrontendType::ATSC3: { // value = 1 << 1 interleave.atsc3(FrontendAtsc3TimeInterleaveMode::CTI); vector interleaving = {interleave}; status.interleaving(interleaving); break; } case (int)V1_1::FrontendType::DTMB: { // value = 1 << 1 interleave.dtmb(V1_1::FrontendDtmbTimeInterleaveMode::TIMER_INT_240); vector interleaving = {interleave}; status.interleaving(interleaving); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::ISDBT_SEGMENTS: { vector segments = {2, 3}; status.isdbtSegment(segments); break; } case V1_1::FrontendStatusTypeExt1_1::TS_DATA_RATES: { vector dataRates = {4, 5}; status.tsDataRate(dataRates); break; } case V1_1::FrontendStatusTypeExt1_1::ROLL_OFF: { V1_1::FrontendRollOff rollOff; switch (mType) { case FrontendType::DVBS: { // value = 1 rollOff.dvbs(FrontendDvbsRolloff::ROLLOFF_0_35); status.rollOff(rollOff); break; } case FrontendType::ISDBS: { // value = 1 rollOff.isdbs(FrontendIsdbsRolloff::ROLLOFF_0_35); status.rollOff(rollOff); break; } case FrontendType::ISDBS3: { // value = 1 rollOff.isdbs3(FrontendIsdbs3Rolloff::ROLLOFF_0_03); status.rollOff(rollOff); break; } default: break; } break; } case V1_1::FrontendStatusTypeExt1_1::IS_MISO: { status.isMiso(true); break; } case V1_1::FrontendStatusTypeExt1_1::IS_LINEAR: { status.isLinear(true); break; } case V1_1::FrontendStatusTypeExt1_1::IS_SHORT_FRAMES: { status.isShortFrames(true); break; } default: { continue; } } statuses.push_back(status); } _hidl_cb(Result::SUCCESS, statuses); return Void(); } Return Frontend::setLna(bool /* bEnable */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } Return Frontend::setLnb(uint32_t /* lnb */) { ALOGV("%s", __FUNCTION__); if (!supportsSatellite()) { return Result::INVALID_STATE; } return Result::SUCCESS; } Return Frontend::linkCiCam(uint32_t ciCamId, linkCiCam_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); mCiCamId = ciCamId; _hidl_cb(Result::SUCCESS, 0 /*ltsId*/); return Void(); } Return Frontend::unlinkCiCam(uint32_t /*ciCamId*/) { ALOGV("%s", __FUNCTION__); mCiCamId = -1; return Result::SUCCESS; } FrontendType Frontend::getFrontendType() { return mType; } FrontendId Frontend::getFrontendId() { return mId; } bool Frontend::supportsSatellite() { return mType == FrontendType::DVBS || mType == FrontendType::ISDBS || mType == FrontendType::ISDBS3; } bool Frontend::isLocked() { return mIsLocked; } } // namespace implementation } // namespace V1_0 } // namespace tuner } // namespace tv } // namespace hardware } // namespace android