Home | History | Annotate | Download | only in utils2x
      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