summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'broadcastradio/common/utils/Utils.cpp')
-rw-r--r--broadcastradio/common/utils/Utils.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/broadcastradio/common/utils/Utils.cpp b/broadcastradio/common/utils/Utils.cpp
new file mode 100644
index 00000000..bdaf8e8c
--- /dev/null
+++ b/broadcastradio/common/utils/Utils.cpp
@@ -0,0 +1,236 @@
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 "BroadcastRadioDefault.utils"
17//#define LOG_NDEBUG 0
18
19#include <broadcastradio-utils/Utils.h>
20
21#include <log/log.h>
22
23namespace android {
24namespace hardware {
25namespace broadcastradio {
26namespace utils {
27
28using V1_0::Band;
29using V1_1::IdentifierType;
30using V1_1::ProgramIdentifier;
31using V1_1::ProgramSelector;
32using V1_1::ProgramType;
33
34static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
35 auto a = static_cast<ProgramType>(ia);
36 auto b = static_cast<ProgramType>(ib);
37
38 if (a == b) return true;
39 if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
40 if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
41 if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
42 if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
43 return false;
44}
45
46static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
47 const IdentifierType type) {
48 return hasId(a, type) && hasId(b, type);
49}
50
51static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
52 const IdentifierType type) {
53 return hasId(a, type) || hasId(b, type);
54}
55
56static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
57 const IdentifierType type) {
58 if (!bothHaveId(a, b, type)) return false;
59 /* We should check all Ids of a given type (ie. other AF),
60 * but it doesn't matter for default implementation.
61 */
62 auto aId = getId(a, type);
63 auto bId = getId(b, type);
64 return aId == bId;
65}
66
67bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
68 if (!isCompatibleProgramType(a.programType, b.programType)) return false;
69
70 auto type = getType(a);
71
72 switch (type) {
73 case ProgramType::AM:
74 case ProgramType::AM_HD:
75 case ProgramType::FM:
76 case ProgramType::FM_HD:
77 if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
78
79 // if HD Radio subchannel is specified, it must match
80 if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
81 // missing subchannel (analog) is an equivalent of first subchannel (MPS)
82 auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
83 auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
84 if (aCh != bCh) return false;
85 }
86
87 if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
88
89 return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
90 case ProgramType::DAB:
91 return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
92 case ProgramType::DRMO:
93 return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
94 case ProgramType::SXM:
95 if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
96 return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
97 }
98 return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
99 default: // includes all vendor types
100 ALOGW("Unsupported program type: %s", toString(type).c_str());
101 return false;
102 }
103}
104
105ProgramType getType(const ProgramSelector& sel) {
106 return static_cast<ProgramType>(sel.programType);
107}
108
109bool isAmFm(const ProgramType type) {
110 switch (type) {
111 case ProgramType::AM:
112 case ProgramType::FM:
113 case ProgramType::AM_HD:
114 case ProgramType::FM_HD:
115 return true;
116 default:
117 return false;
118 }
119}
120
121bool isAm(const Band band) {
122 return band == Band::AM || band == Band::AM_HD;
123}
124
125bool isFm(const Band band) {
126 return band == Band::FM || band == Band::FM_HD;
127}
128
129bool hasId(const ProgramSelector& sel, const IdentifierType type) {
130 auto itype = static_cast<uint32_t>(type);
131 if (sel.primaryId.type == itype) return true;
132 // not optimal, but we don't care in default impl
133 for (auto&& id : sel.secondaryIds) {
134 if (id.type == itype) return true;
135 }
136 return false;
137}
138
139uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
140 auto itype = static_cast<uint32_t>(type);
141 if (sel.primaryId.type == itype) return sel.primaryId.value;
142 // not optimal, but we don't care in default impl
143 for (auto&& id : sel.secondaryIds) {
144 if (id.type == itype) return id.value;
145 }
146 ALOGW("Identifier %s not found", toString(type).c_str());
147 return 0;
148}
149
150uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
151 if (!hasId(sel, type)) return defval;
152 return getId(sel, type);
153}
154
155ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
156 ProgramSelector sel = {};
157
158 ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
159 "got subChannel for non-HD AM/FM");
160
161 // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
162 ProgramType type;
163 if (isAm(band)) {
164 type = ProgramType::AM;
165 } else if (isFm(band)) {
166 type = ProgramType::FM;
167 } else {
168 LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
169 }
170
171 sel.programType = static_cast<uint32_t>(type);
172 sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
173 sel.primaryId.value = channel;
174 if (subChannel > 0) {
175 /* stating sub channel for AM/FM channel does not give any guarantees,
176 * but we can't do much more without HD station ID
177 *
178 * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
179 */
180 sel.secondaryIds = hidl_vec<ProgramIdentifier>{
181 {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1},
182 };
183 }
184
185 return sel;
186}
187
188bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) {
189 if (channelOut) *channelOut = 0;
190 if (subChannelOut) *subChannelOut = 0;
191 if (isAmFm(getType(sel))) {
192 if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
193 if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) {
194 // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
195 *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1;
196 }
197 return true;
198 }
199 return false;
200}
201
202bool isDigital(const ProgramSelector& sel) {
203 switch (getType(sel)) {
204 case ProgramType::AM:
205 case ProgramType::FM:
206 return false;
207 default:
208 // VENDOR might not be digital, but it doesn't matter for default impl.
209 return true;
210 }
211}
212
213} // namespace utils
214
215namespace V1_0 {
216
217bool operator==(const BandConfig& l, const BandConfig& r) {
218 if (l.type != r.type) return false;
219 if (l.antennaConnected != r.antennaConnected) return false;
220 if (l.lowerLimit != r.lowerLimit) return false;
221 if (l.upperLimit != r.upperLimit) return false;
222 if (l.spacings != r.spacings) return false;
223 if (utils::isAm(l.type)) {
224 return l.ext.am == r.ext.am;
225 } else if (utils::isFm(l.type)) {
226 return l.ext.fm == r.ext.fm;
227 } else {
228 ALOGW("Unsupported band config type: %s", toString(l.type).c_str());
229 return false;
230 }
231}
232
233} // namespace V1_0
234} // namespace broadcastradio
235} // namespace hardware
236} // namespace android