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 //#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