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
17#define LOG_TAG "BroadcastRadioService.regions.jni"
18#define LOG_NDEBUG 0
19
20#include "regions.h"
21
22#include <broadcastradio-utils-1x/Utils.h>
23#include <utils/Log.h>
24
25namespace android {
26namespace server {
27namespace BroadcastRadio {
28namespace regions {
29
30namespace utils = hardware::broadcastradio::utils;
31
32using hardware::hidl_vec;
33
34using V1_0::Band;
35using V1_0::BandConfig;
36using V1_0::Deemphasis;
37using V1_0::Rds;
38
39class RegionalBandDefinition {
40public:
41    std::vector<Region> mRegions;
42    std::vector<Band> mTypes;
43    uint32_t mLowerLimit;
44    uint32_t mUpperLimit;
45    uint32_t mSpacing;
46
47    Deemphasis mFmDeemphasis = {};
48    Rds mFmRds = Rds::NONE;
49
50    bool fitsInsideBand(const BandConfig &bandConfig) const;
51    std::vector<RegionalBandConfig> withConfig(BandConfig bandConfig) const;
52};
53
54static const RegionalBandDefinition kKnownRegionConfigs[] = {
55    {
56        { Region::ITU_1 },
57        { Band::FM },
58        87500,
59        108000,
60        100,
61        Deemphasis::D50,
62        Rds::WORLD,
63    },
64    {
65        { Region::ITU_2 },
66        { Band::FM, Band::FM_HD },
67        87700,
68        107900,
69        200,
70        Deemphasis::D75,
71        Rds::US,
72    },
73    {
74        { Region::OIRT },
75        { Band::FM },
76        65800,
77        74000,
78        10,
79        Deemphasis::D50,
80        Rds::WORLD,
81    },
82    {
83        { Region::JAPAN },
84        { Band::FM },
85        76000,
86        90000,
87        100,
88        Deemphasis::D50,
89        Rds::WORLD,
90    },
91    {
92        { Region::KOREA },
93        { Band::FM },
94        87500,
95        108000,
96        100,
97        Deemphasis::D75,
98        Rds::WORLD,
99    },
100    {  // AM LW
101        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
102        { Band::AM },
103        153,
104        282,
105        9,
106    },
107    {  // AM MW
108        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
109        { Band::AM },
110        531,
111        1620,
112        9,
113    },
114    {  // AM SW
115        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
116        { Band::AM },
117        2300,
118        26100,
119        5,
120    },
121    {  // AM LW ITU2
122        { Region::ITU_2 },
123        { Band::AM, Band::AM_HD },
124        153,
125        279,
126        9,
127    },
128    {  // AM MW ITU2
129        { Region::ITU_2 },
130        { Band::AM, Band::AM_HD },
131        530,
132        1700,
133        10,
134    },
135    {  // AM SW ITU2
136        { Region::ITU_2 },
137        { Band::AM, Band::AM_HD },
138        2300,
139        26100,
140        5,
141    },
142};
143
144bool RegionalBandDefinition::fitsInsideBand(const BandConfig &bandConfig) const {
145    if (std::find(mTypes.begin(), mTypes.end(), bandConfig.type) == mTypes.end()) return false;
146    if (mLowerLimit < bandConfig.lowerLimit) return false;
147    if (mUpperLimit > bandConfig.upperLimit) return false;
148    auto&& spacings = bandConfig.spacings;
149    if (std::find(spacings.begin(), spacings.end(), mSpacing) == spacings.end()) return false;
150    if (utils::isFm(bandConfig.type)) {
151        if (0 == (mFmDeemphasis & bandConfig.ext.fm.deemphasis)) return false;
152    }
153
154    return true;
155}
156
157std::vector<RegionalBandConfig> RegionalBandDefinition::withConfig(BandConfig config) const {
158    config.lowerLimit = mLowerLimit;
159    config.upperLimit = mUpperLimit;
160    config.spacings = hidl_vec<uint32_t>({ mSpacing });
161    if (utils::isFm(config.type)) {
162        auto&& fm = config.ext.fm;
163        fm.deemphasis = mFmDeemphasis;
164        fm.rds = static_cast<Rds>(mFmRds & fm.rds);
165    }
166
167    std::vector<RegionalBandConfig> configs;
168    for (auto region : mRegions) {
169        configs.push_back({region, config});
170    }
171
172    return configs;
173}
174
175std::vector<RegionalBandConfig> mapRegions(const hidl_vec<BandConfig>& bands) {
176    ALOGV("%s", __func__);
177
178    std::vector<RegionalBandConfig> out;
179
180    for (auto&& regionalBand : kKnownRegionConfigs) {
181        for (auto&& tunerBand : bands) {
182            if (regionalBand.fitsInsideBand(tunerBand)) {
183                auto mapped = regionalBand.withConfig(tunerBand);
184                out.insert(out.end(), mapped.begin(), mapped.end());
185            }
186        }
187    }
188
189    ALOGI("Mapped %zu tuner bands to %zu regional bands", bands.size(), out.size());
190    return out;
191}
192
193} // namespace regions
194} // namespace BroadcastRadio
195} // namespace server
196} // namespace android
197