• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #define LOG_TAG "BcRadioDef.utils"
17 //#define LOG_NDEBUG 0
18 
19 #include <broadcastradio-utils-2x/Utils.h>
20 
21 #include <android-base/logging.h>
22 #include <log/log.h>
23 
24 namespace android {
25 namespace hardware {
26 namespace broadcastradio {
27 namespace utils {
28 
29 using V2_0::IdentifierType;
30 using V2_0::Metadata;
31 using V2_0::MetadataKey;
32 using V2_0::ProgramFilter;
33 using V2_0::ProgramIdentifier;
34 using V2_0::ProgramInfo;
35 using V2_0::ProgramListChunk;
36 using V2_0::ProgramSelector;
37 using V2_0::Properties;
38 
39 using std::string;
40 using std::vector;
41 
getType(uint32_t typeAsInt)42 IdentifierType getType(uint32_t typeAsInt) {
43     return static_cast<IdentifierType>(typeAsInt);
44 }
45 
getType(const ProgramIdentifier & id)46 IdentifierType getType(const ProgramIdentifier& id) {
47     return getType(id.type);
48 }
49 
IdentifierIterator(const V2_0::ProgramSelector & sel)50 IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel)
51     : IdentifierIterator(sel, 0) {}
52 
IdentifierIterator(const V2_0::ProgramSelector & sel,size_t pos)53 IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel, size_t pos)
54     : mSel(sel), mPos(pos) {}
55 
operator ++(int)56 IdentifierIterator IdentifierIterator::operator++(int) {
57     auto i = *this;
58     mPos++;
59     return i;
60 }
61 
operator ++()62 IdentifierIterator& IdentifierIterator::operator++() {
63     ++mPos;
64     return *this;
65 }
66 
operator *() const67 IdentifierIterator::ref_type IdentifierIterator::operator*() const {
68     if (mPos == 0) return sel().primaryId;
69 
70     // mPos is 1-based for secondary identifiers
71     DCHECK(mPos <= sel().secondaryIds.size());
72     return sel().secondaryIds[mPos - 1];
73 }
74 
operator ==(const IdentifierIterator & rhs) const75 bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
76     // Check, if both iterators points at the same selector.
77     if (reinterpret_cast<uintptr_t>(&sel()) != reinterpret_cast<uintptr_t>(&rhs.sel())) {
78         return false;
79     }
80 
81     return mPos == rhs.mPos;
82 }
83 
getBand(uint64_t freq)84 FrequencyBand getBand(uint64_t freq) {
85     // keep in sync with
86     // frameworks/base/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
87     if (freq < 30) return FrequencyBand::UNKNOWN;
88     if (freq < 500) return FrequencyBand::AM_LW;
89     if (freq < 1705) return FrequencyBand::AM_MW;
90     if (freq < 30000) return FrequencyBand::AM_SW;
91     if (freq < 60000) return FrequencyBand::UNKNOWN;
92     if (freq < 110000) return FrequencyBand::FM;
93     return FrequencyBand::UNKNOWN;
94 }
95 
bothHaveId(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType type)96 static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
97                        const IdentifierType type) {
98     return hasId(a, type) && hasId(b, type);
99 }
100 
haveEqualIds(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType type)101 static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
102                          const IdentifierType type) {
103     if (!bothHaveId(a, b, type)) return false;
104     /* We should check all Ids of a given type (ie. other AF),
105      * but it doesn't matter for default implementation.
106      */
107     return getId(a, type) == getId(b, type);
108 }
109 
getHdSubchannel(const ProgramSelector & sel)110 static int getHdSubchannel(const ProgramSelector& sel) {
111     auto hdsidext = getId(sel, IdentifierType::HD_STATION_ID_EXT, 0);
112     hdsidext >>= 32;        // Station ID number
113     return hdsidext & 0xF;  // HD Radio subchannel
114 }
115 
tunesTo(const ProgramSelector & a,const ProgramSelector & b)116 bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
117     auto type = getType(b.primaryId);
118 
119     switch (type) {
120         case IdentifierType::HD_STATION_ID_EXT:
121         case IdentifierType::RDS_PI:
122         case IdentifierType::AMFM_FREQUENCY:
123             if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
124             if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
125             return getHdSubchannel(b) == 0 && haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
126         case IdentifierType::DAB_SID_EXT:
127             return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
128         case IdentifierType::DRMO_SERVICE_ID:
129             return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
130         case IdentifierType::SXM_SERVICE_ID:
131             return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
132         default:  // includes all vendor types
133             ALOGW("Unsupported program type: %s", toString(type).c_str());
134             return false;
135     }
136 }
137 
maybeGetId(const ProgramSelector & sel,const IdentifierType type,uint64_t * val)138 static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
139     auto itype = static_cast<uint32_t>(type);
140 
141     if (sel.primaryId.type == itype) {
142         if (val) *val = sel.primaryId.value;
143         return true;
144     }
145 
146     // TODO(twasilczyk): use IdentifierIterator
147     // not optimal, but we don't care in default impl
148     for (auto&& id : sel.secondaryIds) {
149         if (id.type == itype) {
150             if (val) *val = id.value;
151             return true;
152         }
153     }
154 
155     return false;
156 }
157 
hasId(const ProgramSelector & sel,const IdentifierType type)158 bool hasId(const ProgramSelector& sel, const IdentifierType type) {
159     return maybeGetId(sel, type, nullptr);
160 }
161 
getId(const ProgramSelector & sel,const IdentifierType type)162 uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
163     uint64_t val;
164 
165     if (maybeGetId(sel, type, &val)) {
166         return val;
167     }
168 
169     ALOGW("Identifier %s not found", toString(type).c_str());
170     return 0;
171 }
172 
getId(const ProgramSelector & sel,const IdentifierType type,uint64_t defval)173 uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
174     if (!hasId(sel, type)) return defval;
175     return getId(sel, type);
176 }
177 
getAllIds(const ProgramSelector & sel,const IdentifierType type)178 vector<uint64_t> getAllIds(const ProgramSelector& sel, const IdentifierType type) {
179     vector<uint64_t> ret;
180     auto itype = static_cast<uint32_t>(type);
181 
182     if (sel.primaryId.type == itype) ret.push_back(sel.primaryId.value);
183 
184     // TODO(twasilczyk): use IdentifierIterator
185     for (auto&& id : sel.secondaryIds) {
186         if (id.type == itype) ret.push_back(id.value);
187     }
188 
189     return ret;
190 }
191 
isSupported(const Properties & prop,const ProgramSelector & sel)192 bool isSupported(const Properties& prop, const ProgramSelector& sel) {
193     // TODO(twasilczyk): use IdentifierIterator
194     // Not optimal, but it doesn't matter for default impl nor VTS tests.
195     for (auto&& idType : prop.supportedIdentifierTypes) {
196         if (hasId(sel, getType(idType))) return true;
197     }
198     return false;
199 }
200 
isValid(const ProgramIdentifier & id)201 bool isValid(const ProgramIdentifier& id) {
202     auto val = id.value;
203     bool valid = true;
204 
205     auto expect = [&valid](bool condition, std::string message) {
206         if (!condition) {
207             valid = false;
208             ALOGE("Identifier not valid, expected %s", message.c_str());
209         }
210     };
211 
212     switch (getType(id)) {
213         case IdentifierType::INVALID:
214             expect(false, "IdentifierType::INVALID");
215             break;
216         case IdentifierType::DAB_FREQUENCY:
217             expect(val > 100000u, "f > 100MHz");
218         // fallthrough
219         case IdentifierType::AMFM_FREQUENCY:
220         case IdentifierType::DRMO_FREQUENCY:
221             expect(val > 100u, "f > 100kHz");
222             expect(val < 10000000u, "f < 10GHz");
223             break;
224         case IdentifierType::RDS_PI:
225             expect(val != 0u, "RDS PI != 0");
226             expect(val <= 0xFFFFu, "16bit id");
227             break;
228         case IdentifierType::HD_STATION_ID_EXT: {
229             auto stationId = val & 0xFFFFFFFF;  // 32bit
230             val >>= 32;
231             auto subchannel = val & 0xF;  // 4bit
232             val >>= 4;
233             auto freq = val & 0x3FFFF;  // 18bit
234             expect(stationId != 0u, "HD station id != 0");
235             expect(subchannel < 8u, "HD subch < 8");
236             expect(freq > 100u, "f > 100kHz");
237             expect(freq < 10000000u, "f < 10GHz");
238             break;
239         }
240         case IdentifierType::HD_STATION_NAME: {
241             while (val > 0) {
242                 auto ch = static_cast<char>(val & 0xFF);
243                 val >>= 8;
244                 expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
245                        "HD_STATION_NAME does not match [A-Z0-9]+");
246             }
247             break;
248         }
249         case IdentifierType::DAB_SID_EXT: {
250             auto sid = val & 0xFFFF;  // 16bit
251             val >>= 16;
252             auto ecc = val & 0xFF;  // 8bit
253             expect(sid != 0u, "DAB SId != 0");
254             expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
255             break;
256         }
257         case IdentifierType::DAB_ENSEMBLE:
258             expect(val != 0u, "DAB ensemble != 0");
259             expect(val <= 0xFFFFu, "16bit id");
260             break;
261         case IdentifierType::DAB_SCID:
262             expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
263             expect(val <= 0xFFFu, "12bit id");
264             break;
265         case IdentifierType::DRMO_SERVICE_ID:
266             expect(val != 0u, "DRM SId != 0");
267             expect(val <= 0xFFFFFFu, "24bit id");
268             break;
269         case IdentifierType::SXM_SERVICE_ID:
270             expect(val != 0u, "SXM SId != 0");
271             expect(val <= 0xFFFFFFFFu, "32bit id");
272             break;
273         case IdentifierType::SXM_CHANNEL:
274             expect(val < 1000u, "SXM channel < 1000");
275             break;
276         case IdentifierType::VENDOR_START:
277         case IdentifierType::VENDOR_END:
278             // skip
279             break;
280     }
281 
282     return valid;
283 }
284 
isValid(const ProgramSelector & sel)285 bool isValid(const ProgramSelector& sel) {
286     if (!isValid(sel.primaryId)) return false;
287     // TODO(twasilczyk): use IdentifierIterator
288     for (auto&& id : sel.secondaryIds) {
289         if (!isValid(id)) return false;
290     }
291     return true;
292 }
293 
make_identifier(IdentifierType type,uint64_t value)294 ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) {
295     return {static_cast<uint32_t>(type), value};
296 }
297 
make_selector_amfm(uint32_t frequency)298 ProgramSelector make_selector_amfm(uint32_t frequency) {
299     ProgramSelector sel = {};
300     sel.primaryId = make_identifier(IdentifierType::AMFM_FREQUENCY, frequency);
301     return sel;
302 }
303 
make_metadata(MetadataKey key,int64_t value)304 Metadata make_metadata(MetadataKey key, int64_t value) {
305     Metadata meta = {};
306     meta.key = static_cast<uint32_t>(key);
307     meta.intValue = value;
308     return meta;
309 }
310 
make_metadata(MetadataKey key,string value)311 Metadata make_metadata(MetadataKey key, string value) {
312     Metadata meta = {};
313     meta.key = static_cast<uint32_t>(key);
314     meta.stringValue = value;
315     return meta;
316 }
317 
satisfies(const ProgramFilter & filter,const ProgramSelector & sel)318 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
319     if (filter.identifierTypes.size() > 0) {
320         auto typeEquals = [](const V2_0::ProgramIdentifier& id, uint32_t type) {
321             return id.type == type;
322         };
323         auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
324                                      filter.identifierTypes.end(), typeEquals);
325         if (it == end(sel)) return false;
326     }
327 
328     if (filter.identifiers.size() > 0) {
329         auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
330                                      filter.identifiers.end());
331         if (it == end(sel)) return false;
332     }
333 
334     if (!filter.includeCategories) {
335         if (getType(sel.primaryId) == IdentifierType::DAB_ENSEMBLE) return false;
336     }
337 
338     return true;
339 }
340 
operator ()(const ProgramInfo & info) const341 size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
342     auto& id = info.selector.primaryId;
343 
344     /* This is not the best hash implementation, but good enough for default HAL
345      * implementation and tests. */
346     auto h = std::hash<uint32_t>{}(id.type);
347     h += 0x9e3779b9;
348     h ^= std::hash<uint64_t>{}(id.value);
349 
350     return h;
351 }
352 
operator ()(const ProgramInfo & info1,const ProgramInfo & info2) const353 bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
354     auto& id1 = info1.selector.primaryId;
355     auto& id2 = info2.selector.primaryId;
356     return id1.type == id2.type && id1.value == id2.value;
357 }
358 
updateProgramList(ProgramInfoSet & list,const ProgramListChunk & chunk)359 void updateProgramList(ProgramInfoSet& list, const ProgramListChunk& chunk) {
360     if (chunk.purge) list.clear();
361 
362     list.insert(chunk.modified.begin(), chunk.modified.end());
363 
364     for (auto&& id : chunk.removed) {
365         ProgramInfo info = {};
366         info.selector.primaryId = id;
367         list.erase(info);
368     }
369 }
370 
getMetadataString(const V2_0::ProgramInfo & info,const V2_0::MetadataKey key)371 std::optional<std::string> getMetadataString(const V2_0::ProgramInfo& info,
372                                              const V2_0::MetadataKey key) {
373     auto isKey = [key](const V2_0::Metadata& item) {
374         return static_cast<V2_0::MetadataKey>(item.key) == key;
375     };
376 
377     auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isKey);
378     if (it == info.metadata.end()) return std::nullopt;
379 
380     return it->stringValue;
381 }
382 
make_hdradio_station_name(const std::string & name)383 V2_0::ProgramIdentifier make_hdradio_station_name(const std::string& name) {
384     constexpr size_t maxlen = 8;
385 
386     std::string shortName;
387     shortName.reserve(maxlen);
388 
389     auto&& loc = std::locale::classic();
390     for (char ch : name) {
391         if (!std::isalnum(ch, loc)) continue;
392         shortName.push_back(std::toupper(ch, loc));
393         if (shortName.length() >= maxlen) break;
394     }
395 
396     uint64_t val = 0;
397     for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
398         val <<= 8;
399         val |= static_cast<uint8_t>(*rit);
400     }
401 
402     return make_identifier(IdentifierType::HD_STATION_NAME, val);
403 }
404 
405 }  // namespace utils
406 
407 namespace V2_0 {
408 
begin(const ProgramSelector & sel)409 utils::IdentifierIterator begin(const ProgramSelector& sel) {
410     return utils::IdentifierIterator(sel);
411 }
412 
end(const ProgramSelector & sel)413 utils::IdentifierIterator end(const ProgramSelector& sel) {
414     return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
415 }
416 
417 }  // namespace V2_0
418 }  // namespace broadcastradio
419 }  // namespace hardware
420 }  // namespace android
421