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 42 IdentifierType getType(uint32_t typeAsInt) { 43 return static_cast<IdentifierType>(typeAsInt); 44 } 45 46 IdentifierType getType(const ProgramIdentifier& id) { 47 return getType(id.type); 48 } 49 50 IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel) 51 : IdentifierIterator(sel, 0) {} 52 53 IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel, size_t pos) 54 : mSel(sel), mPos(pos) {} 55 56 IdentifierIterator IdentifierIterator::operator++(int) { 57 auto i = *this; 58 mPos++; 59 return i; 60 } 61 62 IdentifierIterator& IdentifierIterator::operator++() { 63 ++mPos; 64 return *this; 65 } 66 67 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 75 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 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 96 static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, 97 const IdentifierType type) { 98 return hasId(a, type) && hasId(b, type); 99 } 100 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 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 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 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 158 bool hasId(const ProgramSelector& sel, const IdentifierType type) { 159 return maybeGetId(sel, type, nullptr); 160 } 161 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 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 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 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 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 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 294 ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) { 295 return {static_cast<uint32_t>(type), value}; 296 } 297 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 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 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 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 341 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 353 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 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 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 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 409 utils::IdentifierIterator begin(const ProgramSelector& sel) { 410 return utils::IdentifierIterator(sel); 411 } 412 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