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