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 
25 namespace android {
26 namespace server {
27 namespace BroadcastRadio {
28 namespace regions {
29 
30 namespace utils = hardware::broadcastradio::utils;
31 
32 using hardware::hidl_vec;
33 
34 using V1_0::Band;
35 using V1_0::BandConfig;
36 using V1_0::Deemphasis;
37 using V1_0::Rds;
38 
39 class RegionalBandDefinition {
40 public:
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 
54 static 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 
fitsInsideBand(const BandConfig & bandConfig) const144 bool 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 
withConfig(BandConfig config) const157 std::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 
mapRegions(const hidl_vec<BandConfig> & bands)175 std::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