1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2022 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
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "BcRadioAidlDef.utils"
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include "broadcastradio-utils-aidl/Utils.h"
20*4d7e907cSAndroid Build Coastguard Worker
21*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <android-base/parsedouble.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <android-base/parseint.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
25*4d7e907cSAndroid Build Coastguard Worker
26*4d7e907cSAndroid Build Coastguard Worker #include <math/HashCombine.h>
27*4d7e907cSAndroid Build Coastguard Worker
28*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::broadcastradio {
29*4d7e907cSAndroid Build Coastguard Worker
30*4d7e907cSAndroid Build Coastguard Worker namespace utils {
31*4d7e907cSAndroid Build Coastguard Worker
32*4d7e907cSAndroid Build Coastguard Worker namespace {
33*4d7e907cSAndroid Build Coastguard Worker
34*4d7e907cSAndroid Build Coastguard Worker using ::android::base::EqualsIgnoreCase;
35*4d7e907cSAndroid Build Coastguard Worker using ::std::vector;
36*4d7e907cSAndroid Build Coastguard Worker
37*4d7e907cSAndroid Build Coastguard Worker const int64_t kValueForNotFoundIdentifier = 0;
38*4d7e907cSAndroid Build Coastguard Worker
bothHaveId(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType & type)39*4d7e907cSAndroid Build Coastguard Worker bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
40*4d7e907cSAndroid Build Coastguard Worker return hasId(a, type) && hasId(b, type);
41*4d7e907cSAndroid Build Coastguard Worker }
42*4d7e907cSAndroid Build Coastguard Worker
haveEqualIds(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType & type)43*4d7e907cSAndroid Build Coastguard Worker bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
44*4d7e907cSAndroid Build Coastguard Worker if (!bothHaveId(a, b, type)) {
45*4d7e907cSAndroid Build Coastguard Worker return false;
46*4d7e907cSAndroid Build Coastguard Worker }
47*4d7e907cSAndroid Build Coastguard Worker /* We should check all Ids of a given type (ie. other AF),
48*4d7e907cSAndroid Build Coastguard Worker * but it doesn't matter for default implementation.
49*4d7e907cSAndroid Build Coastguard Worker */
50*4d7e907cSAndroid Build Coastguard Worker return getId(a, type) == getId(b, type);
51*4d7e907cSAndroid Build Coastguard Worker }
52*4d7e907cSAndroid Build Coastguard Worker
maybeGetId(const ProgramSelector & sel,const IdentifierType & type,int64_t * val)53*4d7e907cSAndroid Build Coastguard Worker bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
54*4d7e907cSAndroid Build Coastguard Worker // iterate through primaryId and secondaryIds
55*4d7e907cSAndroid Build Coastguard Worker for (auto it = begin(sel); it != end(sel); it++) {
56*4d7e907cSAndroid Build Coastguard Worker if (it->type == type) {
57*4d7e907cSAndroid Build Coastguard Worker if (val != nullptr) {
58*4d7e907cSAndroid Build Coastguard Worker *val = it->value;
59*4d7e907cSAndroid Build Coastguard Worker }
60*4d7e907cSAndroid Build Coastguard Worker return true;
61*4d7e907cSAndroid Build Coastguard Worker }
62*4d7e907cSAndroid Build Coastguard Worker }
63*4d7e907cSAndroid Build Coastguard Worker
64*4d7e907cSAndroid Build Coastguard Worker return false;
65*4d7e907cSAndroid Build Coastguard Worker }
66*4d7e907cSAndroid Build Coastguard Worker
67*4d7e907cSAndroid Build Coastguard Worker } // namespace
68*4d7e907cSAndroid Build Coastguard Worker
IdentifierIterator(const ProgramSelector & sel)69*4d7e907cSAndroid Build Coastguard Worker IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
70*4d7e907cSAndroid Build Coastguard Worker
IdentifierIterator(const ProgramSelector & sel,size_t pos)71*4d7e907cSAndroid Build Coastguard Worker IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
72*4d7e907cSAndroid Build Coastguard Worker : mSel(sel), mPos(pos) {}
73*4d7e907cSAndroid Build Coastguard Worker
operator ++(int)74*4d7e907cSAndroid Build Coastguard Worker const IdentifierIterator IdentifierIterator::operator++(int) {
75*4d7e907cSAndroid Build Coastguard Worker IdentifierIterator i = *this;
76*4d7e907cSAndroid Build Coastguard Worker mPos++;
77*4d7e907cSAndroid Build Coastguard Worker return i;
78*4d7e907cSAndroid Build Coastguard Worker }
79*4d7e907cSAndroid Build Coastguard Worker
operator ++()80*4d7e907cSAndroid Build Coastguard Worker IdentifierIterator& IdentifierIterator::operator++() {
81*4d7e907cSAndroid Build Coastguard Worker ++mPos;
82*4d7e907cSAndroid Build Coastguard Worker return *this;
83*4d7e907cSAndroid Build Coastguard Worker }
84*4d7e907cSAndroid Build Coastguard Worker
operator *() const85*4d7e907cSAndroid Build Coastguard Worker IdentifierIterator::refType IdentifierIterator::operator*() const {
86*4d7e907cSAndroid Build Coastguard Worker if (mPos == 0) {
87*4d7e907cSAndroid Build Coastguard Worker return getSelector().primaryId;
88*4d7e907cSAndroid Build Coastguard Worker }
89*4d7e907cSAndroid Build Coastguard Worker
90*4d7e907cSAndroid Build Coastguard Worker // mPos is 1-based for secondary identifiers
91*4d7e907cSAndroid Build Coastguard Worker DCHECK(mPos <= getSelector().secondaryIds.size());
92*4d7e907cSAndroid Build Coastguard Worker return getSelector().secondaryIds[mPos - 1];
93*4d7e907cSAndroid Build Coastguard Worker }
94*4d7e907cSAndroid Build Coastguard Worker
operator ==(const IdentifierIterator & rhs) const95*4d7e907cSAndroid Build Coastguard Worker bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
96*4d7e907cSAndroid Build Coastguard Worker // Check, if both iterators points at the same selector.
97*4d7e907cSAndroid Build Coastguard Worker if (reinterpret_cast<intptr_t>(&getSelector()) !=
98*4d7e907cSAndroid Build Coastguard Worker reinterpret_cast<intptr_t>(&rhs.getSelector())) {
99*4d7e907cSAndroid Build Coastguard Worker return false;
100*4d7e907cSAndroid Build Coastguard Worker }
101*4d7e907cSAndroid Build Coastguard Worker
102*4d7e907cSAndroid Build Coastguard Worker return mPos == rhs.mPos;
103*4d7e907cSAndroid Build Coastguard Worker }
104*4d7e907cSAndroid Build Coastguard Worker
resultToInt(Result result)105*4d7e907cSAndroid Build Coastguard Worker int32_t resultToInt(Result result) {
106*4d7e907cSAndroid Build Coastguard Worker return static_cast<int32_t>(result);
107*4d7e907cSAndroid Build Coastguard Worker }
108*4d7e907cSAndroid Build Coastguard Worker
getBand(int64_t freq)109*4d7e907cSAndroid Build Coastguard Worker FrequencyBand getBand(int64_t freq) {
110*4d7e907cSAndroid Build Coastguard Worker // keep in sync with
111*4d7e907cSAndroid Build Coastguard Worker // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
112*4d7e907cSAndroid Build Coastguard Worker if (freq < 30) return FrequencyBand::UNKNOWN;
113*4d7e907cSAndroid Build Coastguard Worker if (freq < 500) return FrequencyBand::AM_LW;
114*4d7e907cSAndroid Build Coastguard Worker if (freq < 1705) return FrequencyBand::AM_MW;
115*4d7e907cSAndroid Build Coastguard Worker if (freq < 30000) return FrequencyBand::AM_SW;
116*4d7e907cSAndroid Build Coastguard Worker if (freq < 60000) return FrequencyBand::UNKNOWN;
117*4d7e907cSAndroid Build Coastguard Worker if (freq < 110000) return FrequencyBand::FM;
118*4d7e907cSAndroid Build Coastguard Worker return FrequencyBand::UNKNOWN;
119*4d7e907cSAndroid Build Coastguard Worker }
120*4d7e907cSAndroid Build Coastguard Worker
tunesTo(const ProgramSelector & a,const ProgramSelector & b)121*4d7e907cSAndroid Build Coastguard Worker bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
122*4d7e907cSAndroid Build Coastguard Worker IdentifierType type = b.primaryId.type;
123*4d7e907cSAndroid Build Coastguard Worker
124*4d7e907cSAndroid Build Coastguard Worker switch (type) {
125*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::HD_STATION_ID_EXT:
126*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::RDS_PI:
127*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::AMFM_FREQUENCY_KHZ:
128*4d7e907cSAndroid Build Coastguard Worker if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
129*4d7e907cSAndroid Build Coastguard Worker if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
130*4d7e907cSAndroid Build Coastguard Worker if (getHdSubchannel(b) != 0) { // supplemental program services
131*4d7e907cSAndroid Build Coastguard Worker return false;
132*4d7e907cSAndroid Build Coastguard Worker }
133*4d7e907cSAndroid Build Coastguard Worker return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ) ||
134*4d7e907cSAndroid Build Coastguard Worker (b.primaryId.type == IdentifierType::HD_STATION_ID_EXT &&
135*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(getId(a, IdentifierType::AMFM_FREQUENCY_KHZ)) ==
136*4d7e907cSAndroid Build Coastguard Worker getAmFmFrequency(b));
137*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DAB_SID_EXT:
138*4d7e907cSAndroid Build Coastguard Worker if (!haveEqualIds(a, b, IdentifierType::DAB_SID_EXT)) {
139*4d7e907cSAndroid Build Coastguard Worker return false;
140*4d7e907cSAndroid Build Coastguard Worker }
141*4d7e907cSAndroid Build Coastguard Worker if (hasId(a, IdentifierType::DAB_ENSEMBLE) &&
142*4d7e907cSAndroid Build Coastguard Worker !haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE)) {
143*4d7e907cSAndroid Build Coastguard Worker return false;
144*4d7e907cSAndroid Build Coastguard Worker }
145*4d7e907cSAndroid Build Coastguard Worker if (hasId(a, IdentifierType::DAB_FREQUENCY_KHZ) &&
146*4d7e907cSAndroid Build Coastguard Worker !haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ)) {
147*4d7e907cSAndroid Build Coastguard Worker return false;
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker return true;
150*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DRMO_SERVICE_ID:
151*4d7e907cSAndroid Build Coastguard Worker return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
152*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::SXM_SERVICE_ID:
153*4d7e907cSAndroid Build Coastguard Worker return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
154*4d7e907cSAndroid Build Coastguard Worker default: // includes all vendor types
155*4d7e907cSAndroid Build Coastguard Worker LOG(WARNING) << "unsupported program type: " << toString(type);
156*4d7e907cSAndroid Build Coastguard Worker return false;
157*4d7e907cSAndroid Build Coastguard Worker }
158*4d7e907cSAndroid Build Coastguard Worker }
159*4d7e907cSAndroid Build Coastguard Worker
hasId(const ProgramSelector & sel,const IdentifierType & type)160*4d7e907cSAndroid Build Coastguard Worker bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
161*4d7e907cSAndroid Build Coastguard Worker return maybeGetId(sel, type, /* val */ nullptr);
162*4d7e907cSAndroid Build Coastguard Worker }
163*4d7e907cSAndroid Build Coastguard Worker
getId(const ProgramSelector & sel,const IdentifierType & type)164*4d7e907cSAndroid Build Coastguard Worker int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
165*4d7e907cSAndroid Build Coastguard Worker int64_t val;
166*4d7e907cSAndroid Build Coastguard Worker
167*4d7e907cSAndroid Build Coastguard Worker if (maybeGetId(sel, type, &val)) {
168*4d7e907cSAndroid Build Coastguard Worker return val;
169*4d7e907cSAndroid Build Coastguard Worker }
170*4d7e907cSAndroid Build Coastguard Worker
171*4d7e907cSAndroid Build Coastguard Worker LOG(WARNING) << "identifier not found: " << toString(type);
172*4d7e907cSAndroid Build Coastguard Worker return kValueForNotFoundIdentifier;
173*4d7e907cSAndroid Build Coastguard Worker }
174*4d7e907cSAndroid Build Coastguard Worker
getId(const ProgramSelector & sel,const IdentifierType & type,int64_t defaultValue)175*4d7e907cSAndroid Build Coastguard Worker int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
176*4d7e907cSAndroid Build Coastguard Worker if (!hasId(sel, type)) {
177*4d7e907cSAndroid Build Coastguard Worker return defaultValue;
178*4d7e907cSAndroid Build Coastguard Worker }
179*4d7e907cSAndroid Build Coastguard Worker return getId(sel, type);
180*4d7e907cSAndroid Build Coastguard Worker }
181*4d7e907cSAndroid Build Coastguard Worker
getAllIds(const ProgramSelector & sel,const IdentifierType & type)182*4d7e907cSAndroid Build Coastguard Worker vector<int64_t> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
183*4d7e907cSAndroid Build Coastguard Worker vector<int64_t> ret;
184*4d7e907cSAndroid Build Coastguard Worker
185*4d7e907cSAndroid Build Coastguard Worker // iterate through primaryId and secondaryIds
186*4d7e907cSAndroid Build Coastguard Worker for (auto it = begin(sel); it != end(sel); it++) {
187*4d7e907cSAndroid Build Coastguard Worker if (it->type == type) {
188*4d7e907cSAndroid Build Coastguard Worker ret.push_back(it->value);
189*4d7e907cSAndroid Build Coastguard Worker }
190*4d7e907cSAndroid Build Coastguard Worker }
191*4d7e907cSAndroid Build Coastguard Worker
192*4d7e907cSAndroid Build Coastguard Worker return ret;
193*4d7e907cSAndroid Build Coastguard Worker }
194*4d7e907cSAndroid Build Coastguard Worker
isSupported(const Properties & prop,const ProgramSelector & sel)195*4d7e907cSAndroid Build Coastguard Worker bool isSupported(const Properties& prop, const ProgramSelector& sel) {
196*4d7e907cSAndroid Build Coastguard Worker for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
197*4d7e907cSAndroid Build Coastguard Worker it++) {
198*4d7e907cSAndroid Build Coastguard Worker if (hasId(sel, *it)) {
199*4d7e907cSAndroid Build Coastguard Worker return true;
200*4d7e907cSAndroid Build Coastguard Worker }
201*4d7e907cSAndroid Build Coastguard Worker }
202*4d7e907cSAndroid Build Coastguard Worker return false;
203*4d7e907cSAndroid Build Coastguard Worker }
204*4d7e907cSAndroid Build Coastguard Worker
isValid(const ProgramIdentifier & id)205*4d7e907cSAndroid Build Coastguard Worker bool isValid(const ProgramIdentifier& id) {
206*4d7e907cSAndroid Build Coastguard Worker uint64_t val = static_cast<uint64_t>(id.value);
207*4d7e907cSAndroid Build Coastguard Worker bool valid = true;
208*4d7e907cSAndroid Build Coastguard Worker
209*4d7e907cSAndroid Build Coastguard Worker auto expect = [&valid](bool condition, const std::string& message) {
210*4d7e907cSAndroid Build Coastguard Worker if (!condition) {
211*4d7e907cSAndroid Build Coastguard Worker valid = false;
212*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "identifier not valid, expected " << message;
213*4d7e907cSAndroid Build Coastguard Worker }
214*4d7e907cSAndroid Build Coastguard Worker };
215*4d7e907cSAndroid Build Coastguard Worker
216*4d7e907cSAndroid Build Coastguard Worker switch (id.type) {
217*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::INVALID:
218*4d7e907cSAndroid Build Coastguard Worker expect(false, "IdentifierType::INVALID");
219*4d7e907cSAndroid Build Coastguard Worker break;
220*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DAB_FREQUENCY_KHZ:
221*4d7e907cSAndroid Build Coastguard Worker expect(val > 100000u, "f > 100MHz");
222*4d7e907cSAndroid Build Coastguard Worker [[fallthrough]];
223*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::AMFM_FREQUENCY_KHZ:
224*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DRMO_FREQUENCY_KHZ:
225*4d7e907cSAndroid Build Coastguard Worker expect(val > 100u, "f > 100kHz");
226*4d7e907cSAndroid Build Coastguard Worker expect(val < 10000000u, "f < 10GHz");
227*4d7e907cSAndroid Build Coastguard Worker break;
228*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::RDS_PI:
229*4d7e907cSAndroid Build Coastguard Worker expect(val != 0u, "RDS PI != 0");
230*4d7e907cSAndroid Build Coastguard Worker expect(val <= 0xFFFFu, "16bit id");
231*4d7e907cSAndroid Build Coastguard Worker break;
232*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::HD_STATION_ID_EXT: {
233*4d7e907cSAndroid Build Coastguard Worker uint64_t stationId = val & 0xFFFFFFFF; // 32bit
234*4d7e907cSAndroid Build Coastguard Worker val >>= 32;
235*4d7e907cSAndroid Build Coastguard Worker uint64_t subchannel = val & 0xF; // 4bit
236*4d7e907cSAndroid Build Coastguard Worker val >>= 4;
237*4d7e907cSAndroid Build Coastguard Worker uint64_t freq = val & 0x3FFFF; // 18bit
238*4d7e907cSAndroid Build Coastguard Worker expect(stationId != 0u, "HD station id != 0");
239*4d7e907cSAndroid Build Coastguard Worker expect(subchannel < 8u, "HD subch < 8");
240*4d7e907cSAndroid Build Coastguard Worker expect(freq > 100u, "f > 100kHz");
241*4d7e907cSAndroid Build Coastguard Worker expect(freq < 10000000u, "f < 10GHz");
242*4d7e907cSAndroid Build Coastguard Worker break;
243*4d7e907cSAndroid Build Coastguard Worker }
244*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::HD_STATION_NAME: {
245*4d7e907cSAndroid Build Coastguard Worker while (val > 0) {
246*4d7e907cSAndroid Build Coastguard Worker char ch = static_cast<char>(val & 0xFF);
247*4d7e907cSAndroid Build Coastguard Worker val >>= 8;
248*4d7e907cSAndroid Build Coastguard Worker expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
249*4d7e907cSAndroid Build Coastguard Worker "HD_STATION_NAME does not match [A-Z0-9]+");
250*4d7e907cSAndroid Build Coastguard Worker }
251*4d7e907cSAndroid Build Coastguard Worker break;
252*4d7e907cSAndroid Build Coastguard Worker }
253*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DAB_SID_EXT: {
254*4d7e907cSAndroid Build Coastguard Worker uint64_t sid = val & 0xFFFFFFFF; // 32bit
255*4d7e907cSAndroid Build Coastguard Worker val >>= 32;
256*4d7e907cSAndroid Build Coastguard Worker uint64_t ecc = val & 0xFF; // 8bit
257*4d7e907cSAndroid Build Coastguard Worker expect(sid != 0u, "DAB SId != 0");
258*4d7e907cSAndroid Build Coastguard Worker expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
259*4d7e907cSAndroid Build Coastguard Worker break;
260*4d7e907cSAndroid Build Coastguard Worker }
261*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DAB_ENSEMBLE:
262*4d7e907cSAndroid Build Coastguard Worker expect(val != 0u, "DAB ensemble != 0");
263*4d7e907cSAndroid Build Coastguard Worker expect(val <= 0xFFFFu, "16bit id");
264*4d7e907cSAndroid Build Coastguard Worker break;
265*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DAB_SCID:
266*4d7e907cSAndroid Build Coastguard Worker expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
267*4d7e907cSAndroid Build Coastguard Worker expect(val <= 0xFFFu, "12bit id");
268*4d7e907cSAndroid Build Coastguard Worker break;
269*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::DRMO_SERVICE_ID:
270*4d7e907cSAndroid Build Coastguard Worker expect(val != 0u, "DRM SId != 0");
271*4d7e907cSAndroid Build Coastguard Worker expect(val <= 0xFFFFFFu, "24bit id");
272*4d7e907cSAndroid Build Coastguard Worker break;
273*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::SXM_SERVICE_ID:
274*4d7e907cSAndroid Build Coastguard Worker expect(val != 0u, "SXM SId != 0");
275*4d7e907cSAndroid Build Coastguard Worker expect(val <= 0xFFFFFFFFu, "32bit id");
276*4d7e907cSAndroid Build Coastguard Worker break;
277*4d7e907cSAndroid Build Coastguard Worker case IdentifierType::SXM_CHANNEL:
278*4d7e907cSAndroid Build Coastguard Worker expect(val < 1000u, "SXM channel < 1000");
279*4d7e907cSAndroid Build Coastguard Worker break;
280*4d7e907cSAndroid Build Coastguard Worker default:
281*4d7e907cSAndroid Build Coastguard Worker expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
282*4d7e907cSAndroid Build Coastguard Worker "Undefined identifier type");
283*4d7e907cSAndroid Build Coastguard Worker break;
284*4d7e907cSAndroid Build Coastguard Worker }
285*4d7e907cSAndroid Build Coastguard Worker
286*4d7e907cSAndroid Build Coastguard Worker return valid;
287*4d7e907cSAndroid Build Coastguard Worker }
288*4d7e907cSAndroid Build Coastguard Worker
isValid(const ProgramSelector & sel)289*4d7e907cSAndroid Build Coastguard Worker bool isValid(const ProgramSelector& sel) {
290*4d7e907cSAndroid Build Coastguard Worker if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
291*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type != IdentifierType::RDS_PI &&
292*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
293*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
294*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
295*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
296*4d7e907cSAndroid Build Coastguard Worker (sel.primaryId.type < IdentifierType::VENDOR_START ||
297*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type > IdentifierType::VENDOR_END)) {
298*4d7e907cSAndroid Build Coastguard Worker return false;
299*4d7e907cSAndroid Build Coastguard Worker }
300*4d7e907cSAndroid Build Coastguard Worker for (auto it = begin(sel); it != end(sel); it++) {
301*4d7e907cSAndroid Build Coastguard Worker if (!isValid(*it)) {
302*4d7e907cSAndroid Build Coastguard Worker return false;
303*4d7e907cSAndroid Build Coastguard Worker }
304*4d7e907cSAndroid Build Coastguard Worker }
305*4d7e907cSAndroid Build Coastguard Worker return true;
306*4d7e907cSAndroid Build Coastguard Worker }
307*4d7e907cSAndroid Build Coastguard Worker
makeIdentifier(IdentifierType type,int64_t value)308*4d7e907cSAndroid Build Coastguard Worker ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
309*4d7e907cSAndroid Build Coastguard Worker return {type, value};
310*4d7e907cSAndroid Build Coastguard Worker }
311*4d7e907cSAndroid Build Coastguard Worker
makeSelectorAmfm(uint32_t frequency)312*4d7e907cSAndroid Build Coastguard Worker ProgramSelector makeSelectorAmfm(uint32_t frequency) {
313*4d7e907cSAndroid Build Coastguard Worker ProgramSelector sel = {};
314*4d7e907cSAndroid Build Coastguard Worker sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
315*4d7e907cSAndroid Build Coastguard Worker return sel;
316*4d7e907cSAndroid Build Coastguard Worker }
317*4d7e907cSAndroid Build Coastguard Worker
makeSelectorDab(uint64_t sidExt)318*4d7e907cSAndroid Build Coastguard Worker ProgramSelector makeSelectorDab(uint64_t sidExt) {
319*4d7e907cSAndroid Build Coastguard Worker ProgramSelector sel = {};
320*4d7e907cSAndroid Build Coastguard Worker sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
321*4d7e907cSAndroid Build Coastguard Worker return sel;
322*4d7e907cSAndroid Build Coastguard Worker }
323*4d7e907cSAndroid Build Coastguard Worker
makeSelectorHd(uint64_t stationId,uint64_t subChannel,uint64_t frequency)324*4d7e907cSAndroid Build Coastguard Worker ProgramSelector makeSelectorHd(uint64_t stationId, uint64_t subChannel, uint64_t frequency) {
325*4d7e907cSAndroid Build Coastguard Worker ProgramSelector sel = {};
326*4d7e907cSAndroid Build Coastguard Worker uint64_t sidExt = stationId | (subChannel << 32) | (frequency << 36);
327*4d7e907cSAndroid Build Coastguard Worker sel.primaryId = makeIdentifier(IdentifierType::HD_STATION_ID_EXT, sidExt);
328*4d7e907cSAndroid Build Coastguard Worker return sel;
329*4d7e907cSAndroid Build Coastguard Worker }
330*4d7e907cSAndroid Build Coastguard Worker
makeSelectorDab(uint64_t sidExt,uint32_t ensemble,uint64_t freq)331*4d7e907cSAndroid Build Coastguard Worker ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
332*4d7e907cSAndroid Build Coastguard Worker ProgramSelector sel = {};
333*4d7e907cSAndroid Build Coastguard Worker sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
334*4d7e907cSAndroid Build Coastguard Worker vector<ProgramIdentifier> secondaryIds = {
335*4d7e907cSAndroid Build Coastguard Worker makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
336*4d7e907cSAndroid Build Coastguard Worker makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
337*4d7e907cSAndroid Build Coastguard Worker sel.secondaryIds = std::move(secondaryIds);
338*4d7e907cSAndroid Build Coastguard Worker return sel;
339*4d7e907cSAndroid Build Coastguard Worker }
340*4d7e907cSAndroid Build Coastguard Worker
satisfies(const ProgramFilter & filter,const ProgramSelector & sel)341*4d7e907cSAndroid Build Coastguard Worker bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
342*4d7e907cSAndroid Build Coastguard Worker if (filter.identifierTypes.size() > 0) {
343*4d7e907cSAndroid Build Coastguard Worker auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
344*4d7e907cSAndroid Build Coastguard Worker return id.type == type;
345*4d7e907cSAndroid Build Coastguard Worker };
346*4d7e907cSAndroid Build Coastguard Worker auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
347*4d7e907cSAndroid Build Coastguard Worker filter.identifierTypes.end(), typeEquals);
348*4d7e907cSAndroid Build Coastguard Worker if (it == end(sel)) {
349*4d7e907cSAndroid Build Coastguard Worker return false;
350*4d7e907cSAndroid Build Coastguard Worker }
351*4d7e907cSAndroid Build Coastguard Worker }
352*4d7e907cSAndroid Build Coastguard Worker
353*4d7e907cSAndroid Build Coastguard Worker if (filter.identifiers.size() > 0) {
354*4d7e907cSAndroid Build Coastguard Worker auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
355*4d7e907cSAndroid Build Coastguard Worker filter.identifiers.end());
356*4d7e907cSAndroid Build Coastguard Worker if (it == end(sel)) {
357*4d7e907cSAndroid Build Coastguard Worker return false;
358*4d7e907cSAndroid Build Coastguard Worker }
359*4d7e907cSAndroid Build Coastguard Worker }
360*4d7e907cSAndroid Build Coastguard Worker
361*4d7e907cSAndroid Build Coastguard Worker return true;
362*4d7e907cSAndroid Build Coastguard Worker }
363*4d7e907cSAndroid Build Coastguard Worker
operator ()(const ProgramSelector & lhs,const ProgramSelector & rhs) const364*4d7e907cSAndroid Build Coastguard Worker bool ProgramSelectorComparator::operator()(const ProgramSelector& lhs,
365*4d7e907cSAndroid Build Coastguard Worker const ProgramSelector& rhs) const {
366*4d7e907cSAndroid Build Coastguard Worker if ((utils::hasId(lhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
367*4d7e907cSAndroid Build Coastguard Worker lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT) &&
368*4d7e907cSAndroid Build Coastguard Worker (utils::hasId(rhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
369*4d7e907cSAndroid Build Coastguard Worker rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT)) {
370*4d7e907cSAndroid Build Coastguard Worker uint32_t freq1 = utils::getAmFmFrequency(lhs);
371*4d7e907cSAndroid Build Coastguard Worker int subChannel1 = lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
372*4d7e907cSAndroid Build Coastguard Worker ? utils::getHdSubchannel(lhs)
373*4d7e907cSAndroid Build Coastguard Worker : 0;
374*4d7e907cSAndroid Build Coastguard Worker uint32_t freq2 = utils::getAmFmFrequency(rhs);
375*4d7e907cSAndroid Build Coastguard Worker int subChannel2 = rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
376*4d7e907cSAndroid Build Coastguard Worker ? utils::getHdSubchannel(rhs)
377*4d7e907cSAndroid Build Coastguard Worker : 0;
378*4d7e907cSAndroid Build Coastguard Worker return freq1 < freq2 || (freq1 == freq2 && (lhs.primaryId.type < rhs.primaryId.type ||
379*4d7e907cSAndroid Build Coastguard Worker subChannel1 < subChannel2));
380*4d7e907cSAndroid Build Coastguard Worker }
381*4d7e907cSAndroid Build Coastguard Worker if (lhs.primaryId.type == IdentifierType::DAB_SID_EXT &&
382*4d7e907cSAndroid Build Coastguard Worker rhs.primaryId.type == IdentifierType::DAB_SID_EXT) {
383*4d7e907cSAndroid Build Coastguard Worker uint64_t dabFreq1 = utils::getId(lhs, IdentifierType::DAB_FREQUENCY_KHZ);
384*4d7e907cSAndroid Build Coastguard Worker uint64_t dabFreq2 = utils::getId(rhs, IdentifierType::DAB_FREQUENCY_KHZ);
385*4d7e907cSAndroid Build Coastguard Worker if (dabFreq1 != dabFreq2) {
386*4d7e907cSAndroid Build Coastguard Worker return dabFreq1 < dabFreq2;
387*4d7e907cSAndroid Build Coastguard Worker }
388*4d7e907cSAndroid Build Coastguard Worker uint32_t ecc1 = utils::getDabEccCode(lhs);
389*4d7e907cSAndroid Build Coastguard Worker uint32_t ecc2 = utils::getDabEccCode(rhs);
390*4d7e907cSAndroid Build Coastguard Worker if (ecc1 != ecc2) {
391*4d7e907cSAndroid Build Coastguard Worker return ecc1 < ecc2;
392*4d7e907cSAndroid Build Coastguard Worker }
393*4d7e907cSAndroid Build Coastguard Worker uint64_t dabEnsemble1 = utils::getId(lhs, IdentifierType::DAB_ENSEMBLE);
394*4d7e907cSAndroid Build Coastguard Worker uint64_t dabEnsemble2 = utils::getId(rhs, IdentifierType::DAB_ENSEMBLE);
395*4d7e907cSAndroid Build Coastguard Worker if (dabEnsemble1 != dabEnsemble2) {
396*4d7e907cSAndroid Build Coastguard Worker return dabEnsemble1 < dabEnsemble2;
397*4d7e907cSAndroid Build Coastguard Worker }
398*4d7e907cSAndroid Build Coastguard Worker uint32_t sId1 = utils::getDabSId(lhs);
399*4d7e907cSAndroid Build Coastguard Worker uint32_t sId2 = utils::getDabSId(rhs);
400*4d7e907cSAndroid Build Coastguard Worker return sId1 < sId2 || (sId1 == sId2 && utils::getDabSCIdS(lhs) < utils::getDabSCIdS(rhs));
401*4d7e907cSAndroid Build Coastguard Worker }
402*4d7e907cSAndroid Build Coastguard Worker
403*4d7e907cSAndroid Build Coastguard Worker if (lhs.primaryId.type != rhs.primaryId.type) {
404*4d7e907cSAndroid Build Coastguard Worker return lhs.primaryId.type < rhs.primaryId.type;
405*4d7e907cSAndroid Build Coastguard Worker }
406*4d7e907cSAndroid Build Coastguard Worker return lhs.primaryId.value < rhs.primaryId.value;
407*4d7e907cSAndroid Build Coastguard Worker }
408*4d7e907cSAndroid Build Coastguard Worker
operator ()(const ProgramInfo & lhs,const ProgramInfo & rhs) const409*4d7e907cSAndroid Build Coastguard Worker bool ProgramInfoComparator::operator()(const ProgramInfo& lhs, const ProgramInfo& rhs) const {
410*4d7e907cSAndroid Build Coastguard Worker return ProgramSelectorComparator()(lhs.selector, rhs.selector);
411*4d7e907cSAndroid Build Coastguard Worker }
412*4d7e907cSAndroid Build Coastguard Worker
operator ()(const ProgramInfo & info) const413*4d7e907cSAndroid Build Coastguard Worker size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
414*4d7e907cSAndroid Build Coastguard Worker const ProgramIdentifier& id = info.selector.primaryId;
415*4d7e907cSAndroid Build Coastguard Worker
416*4d7e907cSAndroid Build Coastguard Worker // This is not the best hash implementation, but good enough for default HAL
417*4d7e907cSAndroid Build Coastguard Worker // implementation and tests.
418*4d7e907cSAndroid Build Coastguard Worker size_t h = 0;
419*4d7e907cSAndroid Build Coastguard Worker ::android::hashCombineSingle(h, id.type);
420*4d7e907cSAndroid Build Coastguard Worker ::android::hashCombineSingle(h, id.value);
421*4d7e907cSAndroid Build Coastguard Worker return h;
422*4d7e907cSAndroid Build Coastguard Worker }
423*4d7e907cSAndroid Build Coastguard Worker
operator ()(const ProgramInfo & info1,const ProgramInfo & info2) const424*4d7e907cSAndroid Build Coastguard Worker bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
425*4d7e907cSAndroid Build Coastguard Worker const ProgramIdentifier& id1 = info1.selector.primaryId;
426*4d7e907cSAndroid Build Coastguard Worker const ProgramIdentifier& id2 = info2.selector.primaryId;
427*4d7e907cSAndroid Build Coastguard Worker return id1.type == id2.type && id1.value == id2.value;
428*4d7e907cSAndroid Build Coastguard Worker }
429*4d7e907cSAndroid Build Coastguard Worker
updateProgramList(const ProgramListChunk & chunk,ProgramInfoSet * list)430*4d7e907cSAndroid Build Coastguard Worker void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
431*4d7e907cSAndroid Build Coastguard Worker if (chunk.purge) {
432*4d7e907cSAndroid Build Coastguard Worker list->clear();
433*4d7e907cSAndroid Build Coastguard Worker }
434*4d7e907cSAndroid Build Coastguard Worker
435*4d7e907cSAndroid Build Coastguard Worker list->insert(chunk.modified.begin(), chunk.modified.end());
436*4d7e907cSAndroid Build Coastguard Worker
437*4d7e907cSAndroid Build Coastguard Worker if (!chunk.removed.has_value()) {
438*4d7e907cSAndroid Build Coastguard Worker return;
439*4d7e907cSAndroid Build Coastguard Worker }
440*4d7e907cSAndroid Build Coastguard Worker
441*4d7e907cSAndroid Build Coastguard Worker for (auto& id : chunk.removed.value()) {
442*4d7e907cSAndroid Build Coastguard Worker if (id.has_value()) {
443*4d7e907cSAndroid Build Coastguard Worker ProgramInfo info = {};
444*4d7e907cSAndroid Build Coastguard Worker info.selector.primaryId = id.value();
445*4d7e907cSAndroid Build Coastguard Worker list->erase(info);
446*4d7e907cSAndroid Build Coastguard Worker }
447*4d7e907cSAndroid Build Coastguard Worker }
448*4d7e907cSAndroid Build Coastguard Worker }
449*4d7e907cSAndroid Build Coastguard Worker
getMetadataString(const ProgramInfo & info,const Metadata::Tag & tag)450*4d7e907cSAndroid Build Coastguard Worker std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
451*4d7e907cSAndroid Build Coastguard Worker auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
452*4d7e907cSAndroid Build Coastguard Worker
453*4d7e907cSAndroid Build Coastguard Worker auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
454*4d7e907cSAndroid Build Coastguard Worker if (it == info.metadata.end()) {
455*4d7e907cSAndroid Build Coastguard Worker return std::nullopt;
456*4d7e907cSAndroid Build Coastguard Worker }
457*4d7e907cSAndroid Build Coastguard Worker
458*4d7e907cSAndroid Build Coastguard Worker std::string metadataString;
459*4d7e907cSAndroid Build Coastguard Worker switch (it->getTag()) {
460*4d7e907cSAndroid Build Coastguard Worker case Metadata::rdsPs:
461*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::rdsPs>();
462*4d7e907cSAndroid Build Coastguard Worker break;
463*4d7e907cSAndroid Build Coastguard Worker case Metadata::rdsPty:
464*4d7e907cSAndroid Build Coastguard Worker metadataString = std::to_string(it->get<Metadata::rdsPty>());
465*4d7e907cSAndroid Build Coastguard Worker break;
466*4d7e907cSAndroid Build Coastguard Worker case Metadata::rbdsPty:
467*4d7e907cSAndroid Build Coastguard Worker metadataString = std::to_string(it->get<Metadata::rbdsPty>());
468*4d7e907cSAndroid Build Coastguard Worker break;
469*4d7e907cSAndroid Build Coastguard Worker case Metadata::rdsRt:
470*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::rdsRt>();
471*4d7e907cSAndroid Build Coastguard Worker break;
472*4d7e907cSAndroid Build Coastguard Worker case Metadata::songTitle:
473*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::songTitle>();
474*4d7e907cSAndroid Build Coastguard Worker break;
475*4d7e907cSAndroid Build Coastguard Worker case Metadata::songArtist:
476*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::songArtist>();
477*4d7e907cSAndroid Build Coastguard Worker break;
478*4d7e907cSAndroid Build Coastguard Worker case Metadata::songAlbum:
479*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::songAlbum>();
480*4d7e907cSAndroid Build Coastguard Worker break;
481*4d7e907cSAndroid Build Coastguard Worker case Metadata::stationIcon:
482*4d7e907cSAndroid Build Coastguard Worker metadataString = std::to_string(it->get<Metadata::stationIcon>());
483*4d7e907cSAndroid Build Coastguard Worker break;
484*4d7e907cSAndroid Build Coastguard Worker case Metadata::albumArt:
485*4d7e907cSAndroid Build Coastguard Worker metadataString = std::to_string(it->get<Metadata::albumArt>());
486*4d7e907cSAndroid Build Coastguard Worker break;
487*4d7e907cSAndroid Build Coastguard Worker case Metadata::programName:
488*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::programName>();
489*4d7e907cSAndroid Build Coastguard Worker break;
490*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabEnsembleName:
491*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabEnsembleName>();
492*4d7e907cSAndroid Build Coastguard Worker break;
493*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabEnsembleNameShort:
494*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabEnsembleNameShort>();
495*4d7e907cSAndroid Build Coastguard Worker break;
496*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabServiceName:
497*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabServiceName>();
498*4d7e907cSAndroid Build Coastguard Worker break;
499*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabServiceNameShort:
500*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabServiceNameShort>();
501*4d7e907cSAndroid Build Coastguard Worker break;
502*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabComponentName:
503*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabComponentName>();
504*4d7e907cSAndroid Build Coastguard Worker break;
505*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabComponentNameShort:
506*4d7e907cSAndroid Build Coastguard Worker metadataString = it->get<Metadata::dabComponentNameShort>();
507*4d7e907cSAndroid Build Coastguard Worker break;
508*4d7e907cSAndroid Build Coastguard Worker default:
509*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
510*4d7e907cSAndroid Build Coastguard Worker return std::nullopt;
511*4d7e907cSAndroid Build Coastguard Worker }
512*4d7e907cSAndroid Build Coastguard Worker return metadataString;
513*4d7e907cSAndroid Build Coastguard Worker }
514*4d7e907cSAndroid Build Coastguard Worker
makeHdRadioStationName(const std::string & name)515*4d7e907cSAndroid Build Coastguard Worker ProgramIdentifier makeHdRadioStationName(const std::string& name) {
516*4d7e907cSAndroid Build Coastguard Worker constexpr size_t maxlen = 8;
517*4d7e907cSAndroid Build Coastguard Worker
518*4d7e907cSAndroid Build Coastguard Worker std::string shortName;
519*4d7e907cSAndroid Build Coastguard Worker shortName.reserve(maxlen);
520*4d7e907cSAndroid Build Coastguard Worker
521*4d7e907cSAndroid Build Coastguard Worker const auto& loc = std::locale::classic();
522*4d7e907cSAndroid Build Coastguard Worker for (const char& ch : name) {
523*4d7e907cSAndroid Build Coastguard Worker if (!std::isalnum(ch, loc)) {
524*4d7e907cSAndroid Build Coastguard Worker continue;
525*4d7e907cSAndroid Build Coastguard Worker }
526*4d7e907cSAndroid Build Coastguard Worker shortName.push_back(std::toupper(ch, loc));
527*4d7e907cSAndroid Build Coastguard Worker if (shortName.length() >= maxlen) {
528*4d7e907cSAndroid Build Coastguard Worker break;
529*4d7e907cSAndroid Build Coastguard Worker }
530*4d7e907cSAndroid Build Coastguard Worker }
531*4d7e907cSAndroid Build Coastguard Worker
532*4d7e907cSAndroid Build Coastguard Worker // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
533*4d7e907cSAndroid Build Coastguard Worker // in little-endian order. For example, "Abc" is converted to 0x434241.
534*4d7e907cSAndroid Build Coastguard Worker int64_t val = 0;
535*4d7e907cSAndroid Build Coastguard Worker for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
536*4d7e907cSAndroid Build Coastguard Worker val <<= 8;
537*4d7e907cSAndroid Build Coastguard Worker val |= static_cast<char>(*rit);
538*4d7e907cSAndroid Build Coastguard Worker }
539*4d7e907cSAndroid Build Coastguard Worker
540*4d7e907cSAndroid Build Coastguard Worker return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
541*4d7e907cSAndroid Build Coastguard Worker }
542*4d7e907cSAndroid Build Coastguard Worker
getType(int typeAsInt)543*4d7e907cSAndroid Build Coastguard Worker IdentifierType getType(int typeAsInt) {
544*4d7e907cSAndroid Build Coastguard Worker return static_cast<IdentifierType>(typeAsInt);
545*4d7e907cSAndroid Build Coastguard Worker }
546*4d7e907cSAndroid Build Coastguard Worker
getDabSId(const ProgramSelector & sel)547*4d7e907cSAndroid Build Coastguard Worker uint32_t getDabSId(const ProgramSelector& sel) {
548*4d7e907cSAndroid Build Coastguard Worker int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
549*4d7e907cSAndroid Build Coastguard Worker return static_cast<uint32_t>(dabSidExt & 0xFFFFFFFF);
550*4d7e907cSAndroid Build Coastguard Worker }
551*4d7e907cSAndroid Build Coastguard Worker
getDabEccCode(const ProgramSelector & sel)552*4d7e907cSAndroid Build Coastguard Worker int getDabEccCode(const ProgramSelector& sel) {
553*4d7e907cSAndroid Build Coastguard Worker int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
554*4d7e907cSAndroid Build Coastguard Worker return static_cast<uint32_t>((dabSidExt >> 32) & 0xFF);
555*4d7e907cSAndroid Build Coastguard Worker }
556*4d7e907cSAndroid Build Coastguard Worker
getDabSCIdS(const ProgramSelector & sel)557*4d7e907cSAndroid Build Coastguard Worker int getDabSCIdS(const ProgramSelector& sel) {
558*4d7e907cSAndroid Build Coastguard Worker int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
559*4d7e907cSAndroid Build Coastguard Worker return static_cast<uint32_t>((dabSidExt >> 40) & 0xF);
560*4d7e907cSAndroid Build Coastguard Worker }
561*4d7e907cSAndroid Build Coastguard Worker
getHdSubchannel(const ProgramSelector & sel)562*4d7e907cSAndroid Build Coastguard Worker int getHdSubchannel(const ProgramSelector& sel) {
563*4d7e907cSAndroid Build Coastguard Worker int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
564*4d7e907cSAndroid Build Coastguard Worker hdSidExt >>= 32; // Station ID number
565*4d7e907cSAndroid Build Coastguard Worker return hdSidExt & 0xF; // HD Radio subchannel
566*4d7e907cSAndroid Build Coastguard Worker }
567*4d7e907cSAndroid Build Coastguard Worker
getHdFrequency(const ProgramSelector & sel)568*4d7e907cSAndroid Build Coastguard Worker uint32_t getHdFrequency(const ProgramSelector& sel) {
569*4d7e907cSAndroid Build Coastguard Worker int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
570*4d7e907cSAndroid Build Coastguard Worker if (hdSidExt == kValueForNotFoundIdentifier) {
571*4d7e907cSAndroid Build Coastguard Worker return kValueForNotFoundIdentifier;
572*4d7e907cSAndroid Build Coastguard Worker }
573*4d7e907cSAndroid Build Coastguard Worker return static_cast<uint32_t>((hdSidExt >> 36) & 0x3FFFF); // HD Radio subchannel
574*4d7e907cSAndroid Build Coastguard Worker }
575*4d7e907cSAndroid Build Coastguard Worker
hasAmFmFrequency(const ProgramSelector & sel)576*4d7e907cSAndroid Build Coastguard Worker bool hasAmFmFrequency(const ProgramSelector& sel) {
577*4d7e907cSAndroid Build Coastguard Worker return hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ) ||
578*4d7e907cSAndroid Build Coastguard Worker sel.primaryId.type == IdentifierType::HD_STATION_ID_EXT;
579*4d7e907cSAndroid Build Coastguard Worker }
580*4d7e907cSAndroid Build Coastguard Worker
getAmFmFrequency(const ProgramSelector & sel)581*4d7e907cSAndroid Build Coastguard Worker uint32_t getAmFmFrequency(const ProgramSelector& sel) {
582*4d7e907cSAndroid Build Coastguard Worker if (hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ)) {
583*4d7e907cSAndroid Build Coastguard Worker return static_cast<uint32_t>(getId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
584*4d7e907cSAndroid Build Coastguard Worker }
585*4d7e907cSAndroid Build Coastguard Worker return getHdFrequency(sel);
586*4d7e907cSAndroid Build Coastguard Worker }
587*4d7e907cSAndroid Build Coastguard Worker
isValidMetadata(const Metadata & metadata)588*4d7e907cSAndroid Build Coastguard Worker bool isValidMetadata(const Metadata& metadata) {
589*4d7e907cSAndroid Build Coastguard Worker bool valid = true;
590*4d7e907cSAndroid Build Coastguard Worker
591*4d7e907cSAndroid Build Coastguard Worker auto expect = [&valid](bool condition, const std::string& message) {
592*4d7e907cSAndroid Build Coastguard Worker if (!condition) {
593*4d7e907cSAndroid Build Coastguard Worker valid = false;
594*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "metadata not valid, expected " << message;
595*4d7e907cSAndroid Build Coastguard Worker }
596*4d7e907cSAndroid Build Coastguard Worker };
597*4d7e907cSAndroid Build Coastguard Worker
598*4d7e907cSAndroid Build Coastguard Worker switch (metadata.getTag()) {
599*4d7e907cSAndroid Build Coastguard Worker case Metadata::rdsPty:
600*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::rdsPty>() >= 0, "RDS PTY >= 0");
601*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::rdsPty>() <= std::numeric_limits<uint8_t>::max(),
602*4d7e907cSAndroid Build Coastguard Worker "8bit RDS PTY");
603*4d7e907cSAndroid Build Coastguard Worker break;
604*4d7e907cSAndroid Build Coastguard Worker case Metadata::rbdsPty:
605*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::rbdsPty>() >= 0, "RBDS PTY >= 0");
606*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::rbdsPty>() <= std::numeric_limits<uint8_t>::max(),
607*4d7e907cSAndroid Build Coastguard Worker "8bit RBDS PTY");
608*4d7e907cSAndroid Build Coastguard Worker break;
609*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabEnsembleNameShort:
610*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::dabEnsembleNameShort>().size() <= 8,
611*4d7e907cSAndroid Build Coastguard Worker "Dab ensemble name abbreviated length <= 8");
612*4d7e907cSAndroid Build Coastguard Worker break;
613*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabServiceNameShort:
614*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::dabServiceNameShort>().size() <= 8,
615*4d7e907cSAndroid Build Coastguard Worker "Dab component name abbreviated length <= 8");
616*4d7e907cSAndroid Build Coastguard Worker break;
617*4d7e907cSAndroid Build Coastguard Worker case Metadata::dabComponentNameShort:
618*4d7e907cSAndroid Build Coastguard Worker expect(metadata.get<Metadata::dabComponentNameShort>().size() <= 8,
619*4d7e907cSAndroid Build Coastguard Worker "Dab component name abbreviated length <= 8");
620*4d7e907cSAndroid Build Coastguard Worker break;
621*4d7e907cSAndroid Build Coastguard Worker default:
622*4d7e907cSAndroid Build Coastguard Worker break;
623*4d7e907cSAndroid Build Coastguard Worker }
624*4d7e907cSAndroid Build Coastguard Worker return valid;
625*4d7e907cSAndroid Build Coastguard Worker }
626*4d7e907cSAndroid Build Coastguard Worker
parseArgInt(const std::string & s,int * out)627*4d7e907cSAndroid Build Coastguard Worker bool parseArgInt(const std::string& s, int* out) {
628*4d7e907cSAndroid Build Coastguard Worker return ::android::base::ParseInt(s, out);
629*4d7e907cSAndroid Build Coastguard Worker }
630*4d7e907cSAndroid Build Coastguard Worker
parseArgLong(const std::string & s,long * out)631*4d7e907cSAndroid Build Coastguard Worker bool parseArgLong(const std::string& s, long* out) {
632*4d7e907cSAndroid Build Coastguard Worker return ::android::base::ParseInt(s, out);
633*4d7e907cSAndroid Build Coastguard Worker }
634*4d7e907cSAndroid Build Coastguard Worker
parseArgDouble(const std::string & s,double * out)635*4d7e907cSAndroid Build Coastguard Worker bool parseArgDouble(const std::string& s, double* out) {
636*4d7e907cSAndroid Build Coastguard Worker return ::android::base::ParseDouble(s, out);
637*4d7e907cSAndroid Build Coastguard Worker }
638*4d7e907cSAndroid Build Coastguard Worker
parseArgBool(const std::string & s,bool * out)639*4d7e907cSAndroid Build Coastguard Worker bool parseArgBool(const std::string& s, bool* out) {
640*4d7e907cSAndroid Build Coastguard Worker if (EqualsIgnoreCase(s, "true")) {
641*4d7e907cSAndroid Build Coastguard Worker *out = true;
642*4d7e907cSAndroid Build Coastguard Worker } else if (EqualsIgnoreCase(s, "false")) {
643*4d7e907cSAndroid Build Coastguard Worker *out = false;
644*4d7e907cSAndroid Build Coastguard Worker } else {
645*4d7e907cSAndroid Build Coastguard Worker return false;
646*4d7e907cSAndroid Build Coastguard Worker }
647*4d7e907cSAndroid Build Coastguard Worker return true;
648*4d7e907cSAndroid Build Coastguard Worker }
649*4d7e907cSAndroid Build Coastguard Worker
parseArgDirection(const std::string & s,bool * out)650*4d7e907cSAndroid Build Coastguard Worker bool parseArgDirection(const std::string& s, bool* out) {
651*4d7e907cSAndroid Build Coastguard Worker if (EqualsIgnoreCase(s, "up")) {
652*4d7e907cSAndroid Build Coastguard Worker *out = true;
653*4d7e907cSAndroid Build Coastguard Worker } else if (EqualsIgnoreCase(s, "down")) {
654*4d7e907cSAndroid Build Coastguard Worker *out = false;
655*4d7e907cSAndroid Build Coastguard Worker } else {
656*4d7e907cSAndroid Build Coastguard Worker return false;
657*4d7e907cSAndroid Build Coastguard Worker }
658*4d7e907cSAndroid Build Coastguard Worker return true;
659*4d7e907cSAndroid Build Coastguard Worker }
660*4d7e907cSAndroid Build Coastguard Worker
parseArgIdentifierTypeArray(const std::string & s,vector<IdentifierType> * out)661*4d7e907cSAndroid Build Coastguard Worker bool parseArgIdentifierTypeArray(const std::string& s, vector<IdentifierType>* out) {
662*4d7e907cSAndroid Build Coastguard Worker for (const std::string& val : ::android::base::Split(s, ",")) {
663*4d7e907cSAndroid Build Coastguard Worker int outInt;
664*4d7e907cSAndroid Build Coastguard Worker if (!parseArgInt(val, &outInt)) {
665*4d7e907cSAndroid Build Coastguard Worker return false;
666*4d7e907cSAndroid Build Coastguard Worker }
667*4d7e907cSAndroid Build Coastguard Worker out->push_back(getType(outInt));
668*4d7e907cSAndroid Build Coastguard Worker }
669*4d7e907cSAndroid Build Coastguard Worker return true;
670*4d7e907cSAndroid Build Coastguard Worker }
671*4d7e907cSAndroid Build Coastguard Worker
parseProgramIdentifierList(const std::string & s,vector<ProgramIdentifier> * out)672*4d7e907cSAndroid Build Coastguard Worker bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
673*4d7e907cSAndroid Build Coastguard Worker for (const std::string& idStr : ::android::base::Split(s, ",")) {
674*4d7e907cSAndroid Build Coastguard Worker const vector<std::string> idStrPair = ::android::base::Split(idStr, ":");
675*4d7e907cSAndroid Build Coastguard Worker if (idStrPair.size() != 2) {
676*4d7e907cSAndroid Build Coastguard Worker return false;
677*4d7e907cSAndroid Build Coastguard Worker }
678*4d7e907cSAndroid Build Coastguard Worker int idType;
679*4d7e907cSAndroid Build Coastguard Worker if (!parseArgInt(idStrPair[0], &idType)) {
680*4d7e907cSAndroid Build Coastguard Worker return false;
681*4d7e907cSAndroid Build Coastguard Worker }
682*4d7e907cSAndroid Build Coastguard Worker long idVal;
683*4d7e907cSAndroid Build Coastguard Worker if (!parseArgLong(idStrPair[1], &idVal)) {
684*4d7e907cSAndroid Build Coastguard Worker return false;
685*4d7e907cSAndroid Build Coastguard Worker }
686*4d7e907cSAndroid Build Coastguard Worker ProgramIdentifier id = {getType(idType), idVal};
687*4d7e907cSAndroid Build Coastguard Worker out->push_back(id);
688*4d7e907cSAndroid Build Coastguard Worker }
689*4d7e907cSAndroid Build Coastguard Worker return true;
690*4d7e907cSAndroid Build Coastguard Worker }
691*4d7e907cSAndroid Build Coastguard Worker
692*4d7e907cSAndroid Build Coastguard Worker } // namespace utils
693*4d7e907cSAndroid Build Coastguard Worker
begin(const ProgramSelector & sel)694*4d7e907cSAndroid Build Coastguard Worker utils::IdentifierIterator begin(const ProgramSelector& sel) {
695*4d7e907cSAndroid Build Coastguard Worker return utils::IdentifierIterator(sel);
696*4d7e907cSAndroid Build Coastguard Worker }
697*4d7e907cSAndroid Build Coastguard Worker
end(const ProgramSelector & sel)698*4d7e907cSAndroid Build Coastguard Worker utils::IdentifierIterator end(const ProgramSelector& sel) {
699*4d7e907cSAndroid Build Coastguard Worker return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
700*4d7e907cSAndroid Build Coastguard Worker }
701*4d7e907cSAndroid Build Coastguard Worker
702*4d7e907cSAndroid Build Coastguard Worker } // namespace aidl::android::hardware::broadcastradio
703