xref: /aosp_15_r20/hardware/interfaces/broadcastradio/common/utils1x/Utils.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "BroadcastRadioDefault.utils"
17*4d7e907cSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <broadcastradio-utils-1x/Utils.h>
20*4d7e907cSAndroid Build Coastguard Worker 
21*4d7e907cSAndroid Build Coastguard Worker #include <log/log.h>
22*4d7e907cSAndroid Build Coastguard Worker 
23*4d7e907cSAndroid Build Coastguard Worker namespace android {
24*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
25*4d7e907cSAndroid Build Coastguard Worker namespace broadcastradio {
26*4d7e907cSAndroid Build Coastguard Worker namespace utils {
27*4d7e907cSAndroid Build Coastguard Worker 
28*4d7e907cSAndroid Build Coastguard Worker using V1_0::Band;
29*4d7e907cSAndroid Build Coastguard Worker using V1_1::IdentifierType;
30*4d7e907cSAndroid Build Coastguard Worker using V1_1::ProgramIdentifier;
31*4d7e907cSAndroid Build Coastguard Worker using V1_1::ProgramSelector;
32*4d7e907cSAndroid Build Coastguard Worker using V1_1::ProgramType;
33*4d7e907cSAndroid Build Coastguard Worker 
isCompatibleProgramType(const uint32_t ia,const uint32_t ib)34*4d7e907cSAndroid Build Coastguard Worker static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
35*4d7e907cSAndroid Build Coastguard Worker     auto a = static_cast<ProgramType>(ia);
36*4d7e907cSAndroid Build Coastguard Worker     auto b = static_cast<ProgramType>(ib);
37*4d7e907cSAndroid Build Coastguard Worker 
38*4d7e907cSAndroid Build Coastguard Worker     if (a == b) return true;
39*4d7e907cSAndroid Build Coastguard Worker     if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
40*4d7e907cSAndroid Build Coastguard Worker     if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
41*4d7e907cSAndroid Build Coastguard Worker     if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
42*4d7e907cSAndroid Build Coastguard Worker     if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
43*4d7e907cSAndroid Build Coastguard Worker     return false;
44*4d7e907cSAndroid Build Coastguard Worker }
45*4d7e907cSAndroid Build Coastguard Worker 
bothHaveId(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType type)46*4d7e907cSAndroid Build Coastguard Worker static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
47*4d7e907cSAndroid Build Coastguard Worker                        const IdentifierType type) {
48*4d7e907cSAndroid Build Coastguard Worker     return hasId(a, type) && hasId(b, type);
49*4d7e907cSAndroid Build Coastguard Worker }
50*4d7e907cSAndroid Build Coastguard Worker 
anyHaveId(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType type)51*4d7e907cSAndroid Build Coastguard Worker static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
52*4d7e907cSAndroid Build Coastguard Worker                       const IdentifierType type) {
53*4d7e907cSAndroid Build Coastguard Worker     return hasId(a, type) || hasId(b, type);
54*4d7e907cSAndroid Build Coastguard Worker }
55*4d7e907cSAndroid Build Coastguard Worker 
haveEqualIds(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType type)56*4d7e907cSAndroid Build Coastguard Worker static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
57*4d7e907cSAndroid Build Coastguard Worker                          const IdentifierType type) {
58*4d7e907cSAndroid Build Coastguard Worker     if (!bothHaveId(a, b, type)) return false;
59*4d7e907cSAndroid Build Coastguard Worker     /* We should check all Ids of a given type (ie. other AF),
60*4d7e907cSAndroid Build Coastguard Worker      * but it doesn't matter for default implementation.
61*4d7e907cSAndroid Build Coastguard Worker      */
62*4d7e907cSAndroid Build Coastguard Worker     return getId(a, type) == getId(b, type);
63*4d7e907cSAndroid Build Coastguard Worker }
64*4d7e907cSAndroid Build Coastguard Worker 
tunesTo(const ProgramSelector & a,const ProgramSelector & b)65*4d7e907cSAndroid Build Coastguard Worker bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
66*4d7e907cSAndroid Build Coastguard Worker     if (!isCompatibleProgramType(a.programType, b.programType)) return false;
67*4d7e907cSAndroid Build Coastguard Worker 
68*4d7e907cSAndroid Build Coastguard Worker     auto type = getType(a);
69*4d7e907cSAndroid Build Coastguard Worker 
70*4d7e907cSAndroid Build Coastguard Worker     switch (type) {
71*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::AM:
72*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::AM_HD:
73*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::FM:
74*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::FM_HD:
75*4d7e907cSAndroid Build Coastguard Worker             if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
76*4d7e907cSAndroid Build Coastguard Worker 
77*4d7e907cSAndroid Build Coastguard Worker             // if HD Radio subchannel is specified, it must match
78*4d7e907cSAndroid Build Coastguard Worker             if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
79*4d7e907cSAndroid Build Coastguard Worker                 // missing subchannel (analog) is an equivalent of first subchannel (MPS)
80*4d7e907cSAndroid Build Coastguard Worker                 auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
81*4d7e907cSAndroid Build Coastguard Worker                 auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
82*4d7e907cSAndroid Build Coastguard Worker                 if (aCh != bCh) return false;
83*4d7e907cSAndroid Build Coastguard Worker             }
84*4d7e907cSAndroid Build Coastguard Worker 
85*4d7e907cSAndroid Build Coastguard Worker             if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
86*4d7e907cSAndroid Build Coastguard Worker 
87*4d7e907cSAndroid Build Coastguard Worker             return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
88*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::DAB:
89*4d7e907cSAndroid Build Coastguard Worker             return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
90*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::DRMO:
91*4d7e907cSAndroid Build Coastguard Worker             return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
92*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::SXM:
93*4d7e907cSAndroid Build Coastguard Worker             if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
94*4d7e907cSAndroid Build Coastguard Worker                 return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
95*4d7e907cSAndroid Build Coastguard Worker             }
96*4d7e907cSAndroid Build Coastguard Worker             return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
97*4d7e907cSAndroid Build Coastguard Worker         default:  // includes all vendor types
98*4d7e907cSAndroid Build Coastguard Worker             ALOGW("Unsupported program type: %s", toString(type).c_str());
99*4d7e907cSAndroid Build Coastguard Worker             return false;
100*4d7e907cSAndroid Build Coastguard Worker     }
101*4d7e907cSAndroid Build Coastguard Worker }
102*4d7e907cSAndroid Build Coastguard Worker 
getType(const ProgramSelector & sel)103*4d7e907cSAndroid Build Coastguard Worker ProgramType getType(const ProgramSelector& sel) {
104*4d7e907cSAndroid Build Coastguard Worker     return static_cast<ProgramType>(sel.programType);
105*4d7e907cSAndroid Build Coastguard Worker }
106*4d7e907cSAndroid Build Coastguard Worker 
isAmFm(const ProgramType type)107*4d7e907cSAndroid Build Coastguard Worker bool isAmFm(const ProgramType type) {
108*4d7e907cSAndroid Build Coastguard Worker     switch (type) {
109*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::AM:
110*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::FM:
111*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::AM_HD:
112*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::FM_HD:
113*4d7e907cSAndroid Build Coastguard Worker             return true;
114*4d7e907cSAndroid Build Coastguard Worker         default:
115*4d7e907cSAndroid Build Coastguard Worker             return false;
116*4d7e907cSAndroid Build Coastguard Worker     }
117*4d7e907cSAndroid Build Coastguard Worker }
118*4d7e907cSAndroid Build Coastguard Worker 
isAm(const Band band)119*4d7e907cSAndroid Build Coastguard Worker bool isAm(const Band band) {
120*4d7e907cSAndroid Build Coastguard Worker     return band == Band::AM || band == Band::AM_HD;
121*4d7e907cSAndroid Build Coastguard Worker }
122*4d7e907cSAndroid Build Coastguard Worker 
isFm(const Band band)123*4d7e907cSAndroid Build Coastguard Worker bool isFm(const Band band) {
124*4d7e907cSAndroid Build Coastguard Worker     return band == Band::FM || band == Band::FM_HD;
125*4d7e907cSAndroid Build Coastguard Worker }
126*4d7e907cSAndroid Build Coastguard Worker 
maybeGetId(const ProgramSelector & sel,const IdentifierType type,uint64_t * val)127*4d7e907cSAndroid Build Coastguard Worker static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
128*4d7e907cSAndroid Build Coastguard Worker     auto itype = static_cast<uint32_t>(type);
129*4d7e907cSAndroid Build Coastguard Worker 
130*4d7e907cSAndroid Build Coastguard Worker     if (sel.primaryId.type == itype) {
131*4d7e907cSAndroid Build Coastguard Worker         if (val) *val = sel.primaryId.value;
132*4d7e907cSAndroid Build Coastguard Worker         return true;
133*4d7e907cSAndroid Build Coastguard Worker     }
134*4d7e907cSAndroid Build Coastguard Worker 
135*4d7e907cSAndroid Build Coastguard Worker     // not optimal, but we don't care in default impl
136*4d7e907cSAndroid Build Coastguard Worker     for (auto&& id : sel.secondaryIds) {
137*4d7e907cSAndroid Build Coastguard Worker         if (id.type == itype) {
138*4d7e907cSAndroid Build Coastguard Worker             if (val) *val = id.value;
139*4d7e907cSAndroid Build Coastguard Worker             return true;
140*4d7e907cSAndroid Build Coastguard Worker         }
141*4d7e907cSAndroid Build Coastguard Worker     }
142*4d7e907cSAndroid Build Coastguard Worker 
143*4d7e907cSAndroid Build Coastguard Worker     return false;
144*4d7e907cSAndroid Build Coastguard Worker }
145*4d7e907cSAndroid Build Coastguard Worker 
hasId(const ProgramSelector & sel,const IdentifierType type)146*4d7e907cSAndroid Build Coastguard Worker bool hasId(const ProgramSelector& sel, const IdentifierType type) {
147*4d7e907cSAndroid Build Coastguard Worker     return maybeGetId(sel, type, nullptr);
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker 
getId(const ProgramSelector & sel,const IdentifierType type)150*4d7e907cSAndroid Build Coastguard Worker uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
151*4d7e907cSAndroid Build Coastguard Worker     uint64_t val;
152*4d7e907cSAndroid Build Coastguard Worker 
153*4d7e907cSAndroid Build Coastguard Worker     if (maybeGetId(sel, type, &val)) {
154*4d7e907cSAndroid Build Coastguard Worker         return val;
155*4d7e907cSAndroid Build Coastguard Worker     }
156*4d7e907cSAndroid Build Coastguard Worker 
157*4d7e907cSAndroid Build Coastguard Worker     ALOGW("Identifier %s not found", toString(type).c_str());
158*4d7e907cSAndroid Build Coastguard Worker     return 0;
159*4d7e907cSAndroid Build Coastguard Worker }
160*4d7e907cSAndroid Build Coastguard Worker 
getId(const ProgramSelector & sel,const IdentifierType type,uint64_t defval)161*4d7e907cSAndroid Build Coastguard Worker uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
162*4d7e907cSAndroid Build Coastguard Worker     if (!hasId(sel, type)) return defval;
163*4d7e907cSAndroid Build Coastguard Worker     return getId(sel, type);
164*4d7e907cSAndroid Build Coastguard Worker }
165*4d7e907cSAndroid Build Coastguard Worker 
make_selector(Band band,uint32_t channel,uint32_t subChannel)166*4d7e907cSAndroid Build Coastguard Worker ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
167*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector sel = {};
168*4d7e907cSAndroid Build Coastguard Worker 
169*4d7e907cSAndroid Build Coastguard Worker     ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
170*4d7e907cSAndroid Build Coastguard Worker              "got subChannel for non-HD AM/FM");
171*4d7e907cSAndroid Build Coastguard Worker 
172*4d7e907cSAndroid Build Coastguard Worker     // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
173*4d7e907cSAndroid Build Coastguard Worker     ProgramType type;
174*4d7e907cSAndroid Build Coastguard Worker     if (isAm(band)) {
175*4d7e907cSAndroid Build Coastguard Worker         type = ProgramType::AM;
176*4d7e907cSAndroid Build Coastguard Worker     } else if (isFm(band)) {
177*4d7e907cSAndroid Build Coastguard Worker         type = ProgramType::FM;
178*4d7e907cSAndroid Build Coastguard Worker     } else {
179*4d7e907cSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
180*4d7e907cSAndroid Build Coastguard Worker     }
181*4d7e907cSAndroid Build Coastguard Worker 
182*4d7e907cSAndroid Build Coastguard Worker     sel.programType = static_cast<uint32_t>(type);
183*4d7e907cSAndroid Build Coastguard Worker     sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
184*4d7e907cSAndroid Build Coastguard Worker     sel.primaryId.value = channel;
185*4d7e907cSAndroid Build Coastguard Worker     if (subChannel > 0) {
186*4d7e907cSAndroid Build Coastguard Worker         /* stating sub channel for AM/FM channel does not give any guarantees,
187*4d7e907cSAndroid Build Coastguard Worker          * but we can't do much more without HD station ID
188*4d7e907cSAndroid Build Coastguard Worker          *
189*4d7e907cSAndroid Build Coastguard Worker          * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
190*4d7e907cSAndroid Build Coastguard Worker          */
191*4d7e907cSAndroid Build Coastguard Worker         sel.secondaryIds = hidl_vec<ProgramIdentifier>{
192*4d7e907cSAndroid Build Coastguard Worker             {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1},
193*4d7e907cSAndroid Build Coastguard Worker         };
194*4d7e907cSAndroid Build Coastguard Worker     }
195*4d7e907cSAndroid Build Coastguard Worker 
196*4d7e907cSAndroid Build Coastguard Worker     return sel;
197*4d7e907cSAndroid Build Coastguard Worker }
198*4d7e907cSAndroid Build Coastguard Worker 
getLegacyChannel(const ProgramSelector & sel,uint32_t * channelOut,uint32_t * subChannelOut)199*4d7e907cSAndroid Build Coastguard Worker bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) {
200*4d7e907cSAndroid Build Coastguard Worker     if (channelOut) *channelOut = 0;
201*4d7e907cSAndroid Build Coastguard Worker     if (subChannelOut) *subChannelOut = 0;
202*4d7e907cSAndroid Build Coastguard Worker     if (isAmFm(getType(sel))) {
203*4d7e907cSAndroid Build Coastguard Worker         if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
204*4d7e907cSAndroid Build Coastguard Worker         if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) {
205*4d7e907cSAndroid Build Coastguard Worker             // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
206*4d7e907cSAndroid Build Coastguard Worker             *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1;
207*4d7e907cSAndroid Build Coastguard Worker         }
208*4d7e907cSAndroid Build Coastguard Worker         return true;
209*4d7e907cSAndroid Build Coastguard Worker     }
210*4d7e907cSAndroid Build Coastguard Worker     return false;
211*4d7e907cSAndroid Build Coastguard Worker }
212*4d7e907cSAndroid Build Coastguard Worker 
isDigital(const ProgramSelector & sel)213*4d7e907cSAndroid Build Coastguard Worker bool isDigital(const ProgramSelector& sel) {
214*4d7e907cSAndroid Build Coastguard Worker     switch (getType(sel)) {
215*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::AM:
216*4d7e907cSAndroid Build Coastguard Worker         case ProgramType::FM:
217*4d7e907cSAndroid Build Coastguard Worker             return false;
218*4d7e907cSAndroid Build Coastguard Worker         default:
219*4d7e907cSAndroid Build Coastguard Worker             // VENDOR might not be digital, but it doesn't matter for default impl.
220*4d7e907cSAndroid Build Coastguard Worker             return true;
221*4d7e907cSAndroid Build Coastguard Worker     }
222*4d7e907cSAndroid Build Coastguard Worker }
223*4d7e907cSAndroid Build Coastguard Worker 
224*4d7e907cSAndroid Build Coastguard Worker }  // namespace utils
225*4d7e907cSAndroid Build Coastguard Worker 
226*4d7e907cSAndroid Build Coastguard Worker namespace V1_0 {
227*4d7e907cSAndroid Build Coastguard Worker 
operator ==(const BandConfig & l,const BandConfig & r)228*4d7e907cSAndroid Build Coastguard Worker bool operator==(const BandConfig& l, const BandConfig& r) {
229*4d7e907cSAndroid Build Coastguard Worker     using namespace utils;
230*4d7e907cSAndroid Build Coastguard Worker 
231*4d7e907cSAndroid Build Coastguard Worker     if (l.type != r.type) return false;
232*4d7e907cSAndroid Build Coastguard Worker     if (l.antennaConnected != r.antennaConnected) return false;
233*4d7e907cSAndroid Build Coastguard Worker     if (l.lowerLimit != r.lowerLimit) return false;
234*4d7e907cSAndroid Build Coastguard Worker     if (l.upperLimit != r.upperLimit) return false;
235*4d7e907cSAndroid Build Coastguard Worker     if (l.spacings != r.spacings) return false;
236*4d7e907cSAndroid Build Coastguard Worker     if (isAm(l.type)) {
237*4d7e907cSAndroid Build Coastguard Worker         return l.ext.am == r.ext.am;
238*4d7e907cSAndroid Build Coastguard Worker     } else if (isFm(l.type)) {
239*4d7e907cSAndroid Build Coastguard Worker         return l.ext.fm == r.ext.fm;
240*4d7e907cSAndroid Build Coastguard Worker     } else {
241*4d7e907cSAndroid Build Coastguard Worker         ALOGW("Unsupported band config type: %s", toString(l.type).c_str());
242*4d7e907cSAndroid Build Coastguard Worker         return false;
243*4d7e907cSAndroid Build Coastguard Worker     }
244*4d7e907cSAndroid Build Coastguard Worker }
245*4d7e907cSAndroid Build Coastguard Worker 
246*4d7e907cSAndroid Build Coastguard Worker }  // namespace V1_0
247*4d7e907cSAndroid Build Coastguard Worker }  // namespace broadcastradio
248*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
249*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
250