diff options
author | Tomasz Wasilczyk <twasilczyk@google.com> | 2017-12-21 11:51:29 -0800 |
---|---|---|
committer | Tomasz Wasilczyk <twasilczyk@google.com> | 2018-01-02 11:51:59 -0800 |
commit | 8b70ee43b071df7d942ff695d6b87a1de7e3cf29 (patch) | |
tree | 6dd15cfebc5d2c8f094f0b2799304c948fa7810b /broadcastradio | |
parent | c0af94ad84e470828c6ad2300353a314bcd7392f (diff) | |
download | android_hardware_interfaces-8b70ee43b071df7d942ff695d6b87a1de7e3cf29.tar.gz android_hardware_interfaces-8b70ee43b071df7d942ff695d6b87a1de7e3cf29.tar.bz2 android_hardware_interfaces-8b70ee43b071df7d942ff695d6b87a1de7e3cf29.zip |
Implement regional configuration fetching.
Bug: 69958423
Test: VTS
Change-Id: I7c184191b4f4999bd03b06bd3b2283e028694918
Diffstat (limited to 'broadcastradio')
-rw-r--r-- | broadcastradio/2.0/Android.bp | 5 | ||||
-rw-r--r-- | broadcastradio/2.0/IBroadcastRadio.hal | 22 | ||||
-rw-r--r-- | broadcastradio/2.0/default/Android.bp | 3 | ||||
-rw-r--r-- | broadcastradio/2.0/default/BroadcastRadio.cpp | 52 | ||||
-rw-r--r-- | broadcastradio/2.0/default/BroadcastRadio.h | 7 | ||||
-rw-r--r-- | broadcastradio/2.0/default/TunerSession.cpp | 40 | ||||
-rw-r--r-- | broadcastradio/2.0/default/TunerSession.h | 5 | ||||
-rw-r--r-- | broadcastradio/2.0/types.hal | 103 | ||||
-rw-r--r-- | broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp | 140 | ||||
-rw-r--r-- | broadcastradio/common/utils2x/Utils.cpp | 18 | ||||
-rw-r--r-- | broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h | 19 |
11 files changed, 396 insertions, 18 deletions
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp index 1d7861e45..f4894ad70 100644 --- a/broadcastradio/2.0/Android.bp +++ b/broadcastradio/2.0/Android.bp @@ -16,8 +16,12 @@ hidl_interface { "android.hidl.base@1.0", ], types: [ + "AmFmBandRange", + "AmFmRegionConfig", "ConfigFlag", "Constants", + "DabTableEntry", + "Deemphasis", "IdentifierType", "Metadata", "MetadataKey", @@ -28,6 +32,7 @@ hidl_interface { "ProgramListChunk", "ProgramSelector", "Properties", + "Rds", "Result", "VendorKeyValue", ], diff --git a/broadcastradio/2.0/IBroadcastRadio.hal b/broadcastradio/2.0/IBroadcastRadio.hal index 3ab1cc21d..3b19e6123 100644 --- a/broadcastradio/2.0/IBroadcastRadio.hal +++ b/broadcastradio/2.0/IBroadcastRadio.hal @@ -33,6 +33,28 @@ interface IBroadcastRadio { getProperties() generates (Properties properties); /** + * Fetches current or possible AM/FM region configuration. + * + * @param full If true, returns full hardware capabilities. + * If false, returns current regional configuration. + * @return result OK in case of success. + * NOT_SUPPORTED if the tuner doesn't support AM/FM. + * @return config Hardware capabilities (full=true) or + * current configuration (full=false). + */ + getAmFmRegionConfig(bool full) + generates (Result result, AmFmRegionConfig config); + + /** + * Fetches current DAB region configuration. + * + * @return result OK in case of success. + * NOT_SUPPORTED if the tuner doesn't support DAB. + * @return config Current configuration. + */ + getDabRegionConfig() generates (Result result, vec<DabTableEntry> config); + + /** * Opens a new tuner session. * * There may be only one session active at a time. If the new session was diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp index 6d4effb9f..900454e78 100644 --- a/broadcastradio/2.0/default/Android.bp +++ b/broadcastradio/2.0/default/Android.bp @@ -24,6 +24,9 @@ cc_binary { "-Wextra", "-Werror", ], + cppflags: [ + "-std=c++1z", + ], srcs: [ "BroadcastRadio.cpp", "TunerSession.cpp", diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp index 5ab517d17..5dde8a7be 100644 --- a/broadcastradio/2.0/default/BroadcastRadio.cpp +++ b/broadcastradio/2.0/default/BroadcastRadio.cpp @@ -33,6 +33,16 @@ using std::map; using std::mutex; using std::vector; +static const AmFmRegionConfig gDefaultAmFmConfig = { // + { + {87500, 108000, 100, 100}, // FM + {153, 282, 3, 9}, // AM LW + {531, 1620, 9, 9}, // AM MW + {1600, 30000, 1, 5}, // AM SW + }, + static_cast<uint32_t>(Deemphasis::D50), + static_cast<uint32_t>(Rds::RDS)}; + static Properties initProperties(const VirtualRadio& virtualRadio) { Properties prop = {}; @@ -51,7 +61,9 @@ static Properties initProperties(const VirtualRadio& virtualRadio) { } BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio) - : mVirtualRadio(virtualRadio), mProperties(initProperties(virtualRadio)) {} + : mVirtualRadio(virtualRadio), + mProperties(initProperties(virtualRadio)), + mAmFmConfig(gDefaultAmFmConfig) {} Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) { ALOGV("%s", __func__); @@ -59,6 +71,44 @@ Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) { return {}; } +AmFmRegionConfig BroadcastRadio::getAmFmConfig() const { + lock_guard<mutex> lk(mMut); + return mAmFmConfig; +} + +Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) { + ALOGV("%s(%d)", __func__, full); + + if (full) { + AmFmRegionConfig config = {}; + config.ranges = hidl_vec<AmFmBandRange>({ + {65000, 108000, 10, 0}, // FM + {150, 30000, 1, 0}, // AM + }); + config.fmDeemphasis = Deemphasis::D50 | Deemphasis::D75; + config.fmRds = Rds::RDS | Rds::RBDS; + _hidl_cb(Result::OK, config); + return {}; + } else { + _hidl_cb(Result::OK, getAmFmConfig()); + return {}; + } +} + +Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) { + ALOGV("%s", __func__); + + hidl_vec<DabTableEntry> config = { + {"5A", 174928}, {"7D", 194064}, {"8A", 195936}, {"8B", 197648}, {"9A", 202928}, + {"9B", 204640}, {"9C", 206352}, {"10B", 211648}, {"10C", 213360}, {"10D", 215072}, + {"11A", 216928}, {"11B", 218640}, {"11C", 220352}, {"11D", 222064}, {"12A", 223936}, + {"12B", 225648}, {"12C", 227360}, {"12D", 229072}, + }; + + _hidl_cb(Result::OK, config); + return {}; +} + Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) { ALOGV("%s", __func__); diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h index fcf06155e..733cadf8a 100644 --- a/broadcastradio/2.0/default/BroadcastRadio.h +++ b/broadcastradio/2.0/default/BroadcastRadio.h @@ -32,14 +32,19 @@ struct BroadcastRadio : public IBroadcastRadio { // V2_0::IBroadcastRadio methods Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb); + Return<void> getDabRegionConfig(getDabRegionConfig_cb _hidl_cb); Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override; Return<void> getImage(uint32_t id, getImage_cb _hidl_cb); std::reference_wrapper<const VirtualRadio> mVirtualRadio; Properties mProperties; + AmFmRegionConfig getAmFmConfig() const; + private: - std::mutex mMut; + mutable std::mutex mMut; + AmFmRegionConfig mAmFmConfig; wp<TunerSession> mSession; }; diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp index 244544a00..3166d8619 100644 --- a/broadcastradio/2.0/default/TunerSession.cpp +++ b/broadcastradio/2.0/default/TunerSession.cpp @@ -77,8 +77,12 @@ void TunerSession::tuneInternalLocked(const ProgramSelector& sel) { mCallback->onCurrentProgramInfoChanged(programInfo); } +const BroadcastRadio& TunerSession::module() const { + return mModule.get(); +} + const VirtualRadio& TunerSession::virtualRadio() const { - return mModule.get().mVirtualRadio; + return module().mVirtualRadio; } Return<Result> TunerSession::tune(const ProgramSelector& sel) { @@ -86,7 +90,7 @@ Return<Result> TunerSession::tune(const ProgramSelector& sel) { lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; - if (!utils::isSupported(mModule.get().mProperties, sel)) { + if (!utils::isSupported(module().mProperties, sel)) { ALOGW("Selector not supported"); return Result::NOT_SUPPORTED; } @@ -170,23 +174,19 @@ Return<Result> TunerSession::step(bool directionUp) { mIsTuneCompleted = false; auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY); -#if 0 - // TODO(b/69958423): handle regions - if (directionUp) { - stepTo += mAmfmConfig.spacings[0]; - } else { - stepTo -= mAmfmConfig.spacings[0]; + auto range = getAmFmRangeLocked(); + if (!range) { + ALOGE("Can't find current band"); + return Result::INTERNAL_ERROR; } - if (stepTo > mAmfmConfig.upperLimit) stepTo = mAmfmConfig.lowerLimit; - if (stepTo < mAmfmConfig.lowerLimit) stepTo = mAmfmConfig.upperLimit; -#else if (directionUp) { - stepTo += 100; + stepTo += range->spacing; } else { - stepTo -= 100; + stepTo -= range->spacing; } -#endif + if (stepTo > range->upperBound) stepTo = range->lowerBound; + if (stepTo < range->lowerBound) stepTo = range->upperBound; auto task = [this, stepTo]() { ALOGI("Performing step to %s", std::to_string(stepTo).c_str()); @@ -280,6 +280,18 @@ Return<void> TunerSession::close() { return {}; } +std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const { + if (!mIsTuneCompleted) return {}; + if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {}; + + auto freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY); + for (auto&& range : module().getAmFmConfig().ranges) { + if (range.lowerBound <= freq && range.upperBound >= freq) return range; + } + + return {}; +} + } // namespace implementation } // namespace V2_0 } // namespace broadcastradio diff --git a/broadcastradio/2.0/default/TunerSession.h b/broadcastradio/2.0/default/TunerSession.h index a58aa1952..5d27b1e6d 100644 --- a/broadcastradio/2.0/default/TunerSession.h +++ b/broadcastradio/2.0/default/TunerSession.h @@ -22,6 +22,8 @@ #include <android/hardware/broadcastradio/2.0/ITunerSession.h> #include <broadcastradio-utils/WorkerThread.h> +#include <optional> + namespace android { namespace hardware { namespace broadcastradio { @@ -48,6 +50,8 @@ struct TunerSession : public ITunerSession { getParameters_cb _hidl_cb) override; virtual Return<void> close() override; + std::optional<AmFmBandRange> getAmFmRangeLocked() const; + private: std::mutex mMut; WorkerThread mThread; @@ -61,6 +65,7 @@ struct TunerSession : public ITunerSession { void tuneInternalLocked(const ProgramSelector& sel); const VirtualRadio& virtualRadio() const; + const BroadcastRadio& module() const; }; } // namespace implementation diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal index b5264f47a..38a5709a2 100644 --- a/broadcastradio/2.0/types.hal +++ b/broadcastradio/2.0/types.hal @@ -32,6 +32,7 @@ enum Constants : int32_t { enum Result : int32_t { OK, UNKNOWN_ERROR, + INTERNAL_ERROR, INVALID_ARGUMENTS, INVALID_STATE, NOT_SUPPORTED, @@ -120,6 +121,108 @@ struct VendorKeyValue { }; /** + * A supported or configured RDS variant. + * + * Both might be set for hardware capabilities check (with full=true when + * calling getAmFmRegionConfig), but only one (or none) for specific + * region settings. + */ +enum Rds : uint8_t { + /** Standard variant, used everywhere except North America. */ + RDS = 1 << 0, + + /** Variant used in North America. */ + RBDS = 1 << 1, +}; + +/** + * FM de-emphasis filter supported or configured. + * + * Both might be set for hardware capabilities check (with full=true when + * calling getAmFmRegionConfig), but exactly one for specific region settings. + */ +enum Deemphasis : uint8_t { + D50 = 1 << 0, + D75 = 1 << 1, +}; + +/** + * Regional configuration for AM/FM. + * + * For hardware capabilities check (with full=true when calling + * getAmFmRegionConfig), HAL implementation fills entire supported range of + * frequencies and features. + * + * When checking current configuration, at most one bit in each bitfield + * can be set. + */ +struct AmFmRegionConfig { + /** + * All supported or configured AM/FM bands. + * + * AM/FM bands are identified by frequency value + * (see IdentifierType::AMFM_FREQUENCY). + * + * With typical configuration, it's expected to have two frequency ranges + * for capabilities check (AM and FM) and four ranges for specific region + * configuration (AM LW, AM MW, AM SW, FM). + */ + vec<AmFmBandRange> ranges; + + /** De-emphasis filter supported/configured. */ + bitfield<Deemphasis> fmDeemphasis; + + /** RDS/RBDS variant supported/configured. */ + bitfield<Rds> fmRds; +}; + +/** + * AM/FM band range for region configuration. + * + * Defines channel grid: each possible channel is set at + * lowerBound + channelNumber * spacing, up to upperBound. + */ +struct AmFmBandRange { + /** The frequency of the first channel within the range. */ + uint32_t lowerBound; + + /** The frequency of the last channel within the range. */ + uint32_t upperBound; + + /** Channel grid resolution, how far apart are the channels. */ + uint32_t spacing; + + /** + * Spacing used when scanning for channels. It's a multiply of spacing and + * allows to skip some channels when scanning to make it faster. + * + * Tuner may first quickly check every n-th channel and if it detects echo + * from a station, it fine-tunes to find the exact frequency. + * + * It's ignored for capabilities check (with full=true when calling + * getAmFmRegionConfig). + */ + uint32_t scanSpacing; +}; + +/** + * An entry in regional configuration for DAB. + * + * Defines a frequency table row for ensembles. + */ +struct DabTableEntry { + /** + * Channel name, i.e. 5A, 7B. + * + * It must match the following regular expression: /^[A-Z0-9]{2,5}$/. + */ + string label; + + /** Frequency, in kHz. */ + uint32_t frequency; +}; + +/** * Properties of a given broadcast radio module. */ struct Properties { diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp index cbe628840..87ac93415 100644 --- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp +++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp @@ -26,9 +26,11 @@ #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> +#include <cutils/bitops.h> #include <gmock/gmock.h> #include <chrono> +#include <regex> namespace android { namespace hardware { @@ -93,6 +95,7 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase { virtual void TearDown() override; bool openSession(); + bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config); sp<IBroadcastRadio> mModule; Properties mProperties; @@ -159,6 +162,22 @@ bool BroadcastRadioHalTest::openSession() { return nullptr != mSession.get(); } +bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) { + auto halResult = Result::UNKNOWN_ERROR; + auto cb = [&](Result result, AmFmRegionConfig configCb) { + halResult = result; + if (config) *config = configCb; + }; + + auto hidlResult = mModule->getAmFmRegionConfig(full, cb); + EXPECT_TRUE(hidlResult.isOk()); + + if (halResult == Result::NOT_SUPPORTED) return false; + + EXPECT_EQ(Result::OK, halResult); + return halResult == Result::OK; +} + /** * Test session opening. * @@ -181,6 +200,127 @@ TEST_F(BroadcastRadioHalTest, OpenSession) { ASSERT_TRUE(openSession()); } +static bool isValidAmFmFreq(uint64_t freq) { + auto id = utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq); + return utils::isValid(id); +} + +static void validateRange(const AmFmBandRange& range) { + EXPECT_TRUE(isValidAmFmFreq(range.lowerBound)); + EXPECT_TRUE(isValidAmFmFreq(range.upperBound)); + EXPECT_LT(range.lowerBound, range.upperBound); + EXPECT_GT(range.spacing, 0u); + EXPECT_EQ(0u, (range.upperBound - range.lowerBound) % range.spacing); +} + +static bool supportsFM(const AmFmRegionConfig& config) { + for (auto&& range : config.ranges) { + if (utils::getBand(range.lowerBound) == utils::FrequencyBand::FM) return true; + } + return false; +} + +/** + * Test fetching AM/FM regional configuration. + * + * Verifies that: + * - AM/FM regional configuration is either set at startup or not supported at all by the hardware; + * - there is at least one AM/FM band configured; + * - FM Deemphasis and RDS are correctly configured for FM-capable radio; + * - all channel grids (frequency ranges and spacings) are valid; + * - scan spacing is a multiply of manual spacing value. + */ +TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) { + AmFmRegionConfig config; + bool supported = getAmFmRegionConfig(false, &config); + if (!supported) { + printSkipped("AM/FM not supported"); + return; + } + + EXPECT_GT(config.ranges.size(), 0u); + EXPECT_LE(popcountll(config.fmDeemphasis), 1); + EXPECT_LE(popcountll(config.fmRds), 1); + + for (auto&& range : config.ranges) { + validateRange(range); + EXPECT_EQ(0u, range.scanSpacing % range.spacing); + EXPECT_GE(range.scanSpacing, range.spacing); + } + + if (supportsFM(config)) { + EXPECT_EQ(popcountll(config.fmDeemphasis), 1); + } +} + +/** + * Test fetching AM/FM regional capabilities. + * + * Verifies that: + * - AM/FM regional capabilities are either available or not supported at all by the hardware; + * - there is at least one AM/FM range supported; + * - there is at least one de-emphasis filter mode supported for FM-capable radio; + * - all channel grids (frequency ranges and spacings) are valid; + * - scan spacing is not set. + */ +TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) { + AmFmRegionConfig config; + bool supported = getAmFmRegionConfig(true, &config); + if (!supported) { + printSkipped("AM/FM not supported"); + return; + } + + EXPECT_GT(config.ranges.size(), 0u); + + for (auto&& range : config.ranges) { + validateRange(range); + EXPECT_EQ(0u, range.scanSpacing); + } + + if (supportsFM(config)) { + EXPECT_GE(popcountll(config.fmDeemphasis), 1); + } +} + +/** + * Test fetching DAB regional configuration. + * + * Verifies that: + * - DAB regional configuration is either set at startup or not supported at all by the hardware; + * - all channel labels match correct format; + * - all channel frequencies are in correct range. + */ +TEST_F(BroadcastRadioHalTest, GetDabRegionConfig) { + Result halResult; + hidl_vec<DabTableEntry> config; + auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) { + halResult = result; + config = configCb; + }; + auto hidlResult = mModule->getDabRegionConfig(cb); + ASSERT_TRUE(hidlResult.isOk()); + + if (halResult == Result::NOT_SUPPORTED) { + printSkipped("DAB not supported"); + return; + } + ASSERT_EQ(Result::OK, halResult); + + std::regex re("^[A-Z0-9]{2,5}$"); + // double-check correctness of the test + ASSERT_TRUE(std::regex_match("5A", re)); + ASSERT_FALSE(std::regex_match("5a", re)); + ASSERT_FALSE(std::regex_match("123ABC", re)); + + for (auto&& entry : config) { + EXPECT_TRUE(std::regex_match(std::string(entry.label), re)); + + auto id = utils::make_identifier(IdentifierType::DAB_FREQUENCY, entry.frequency); + EXPECT_TRUE(utils::isValid(id)); + } +} + /** * Test tuning with FM selector. * diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp index e0337b41a..d825a7a00 100644 --- a/broadcastradio/common/utils2x/Utils.cpp +++ b/broadcastradio/common/utils2x/Utils.cpp @@ -89,6 +89,18 @@ IdentifierIterator end(const V2_0::ProgramSelector& sel) { return IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size(); } +FrequencyBand getBand(uint64_t freq) { + // keep in sync with + // frameworks/base/services/core/java/com/android/server/broadcastradio/hal2/Utils.java + if (freq < 30) return FrequencyBand::UNKNOWN; + if (freq < 500) return FrequencyBand::AM_LW; + if (freq < 1705) return FrequencyBand::AM_MW; + if (freq < 30000) return FrequencyBand::AM_SW; + if (freq < 60000) return FrequencyBand::UNKNOWN; + if (freq < 110000) return FrequencyBand::FM; + return FrequencyBand::UNKNOWN; +} + static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType type) { return hasId(a, type) && hasId(b, type); @@ -194,7 +206,7 @@ bool isSupported(const Properties& prop, const ProgramSelector& sel) { return false; } -static bool isValid(const ProgramIdentifier& id) { +bool isValid(const ProgramIdentifier& id) { auto val = id.value; bool valid = true; @@ -209,8 +221,10 @@ static bool isValid(const ProgramIdentifier& id) { case IdentifierType::INVALID: expect(false, "IdentifierType::INVALID"); break; - case IdentifierType::AMFM_FREQUENCY: case IdentifierType::DAB_FREQUENCY: + expect(val > 100000u, "f > 100MHz"); + // fallthrough + case IdentifierType::AMFM_FREQUENCY: case IdentifierType::DRMO_FREQUENCY: expect(val > 100u, "f > 100kHz"); expect(val < 10000000u, "f < 10GHz"); diff --git a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h index bac11fd02..e3134f7b8 100644 --- a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h +++ b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h @@ -27,6 +27,14 @@ namespace hardware { namespace broadcastradio { namespace utils { +enum class FrequencyBand { + UNKNOWN, + FM, + AM_LW, + AM_MW, + AM_SW, +}; + V2_0::IdentifierType getType(uint32_t typeAsInt); V2_0::IdentifierType getType(const V2_0::ProgramIdentifier& id); @@ -64,6 +72,16 @@ IdentifierIterator begin(const V2_0::ProgramSelector& sel); IdentifierIterator end(const V2_0::ProgramSelector& sel); /** + * Guesses band from the frequency value. + * + * The band bounds are not exact to cover multiple regions. + * The function is biased towards success, i.e. it never returns + * FrequencyBand::UNKNOWN for correct frequency, but a result for + * incorrect one is undefined (it doesn't have to return UNKNOWN). + */ +FrequencyBand getBand(uint64_t frequency); + +/** * Checks, if {@code pointer} tunes to {@channel}. * * For example, having a channel {AMFM_FREQUENCY = 103.3}: @@ -105,6 +123,7 @@ std::vector<uint64_t> getAllIds(const V2_0::ProgramSelector& sel, const V2_0::Id */ bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel); +bool isValid(const V2_0::ProgramIdentifier& id); bool isValid(const V2_0::ProgramSelector& sel); V2_0::ProgramIdentifier make_identifier(V2_0::IdentifierType type, uint64_t value); |