blob: 3c9fba774a477418f07fe3f6091541da98a16419 [file] [log] [blame]
Tomasz Wasilczyk06100b32017-12-04 09:53:32 -08001/*
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 <log/log.h>
22
23namespace android {
24namespace hardware {
25namespace broadcastradio {
26namespace utils {
27
28using V2_0::IdentifierType;
29using V2_0::Metadata;
30using V2_0::MetadataKey;
31using V2_0::ProgramIdentifier;
32using V2_0::ProgramSelector;
33
34using std::string;
35
36IdentifierType getType(const ProgramIdentifier& id) {
37 return static_cast<IdentifierType>(id.type);
38}
39
40static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
41 const IdentifierType type) {
42 return hasId(a, type) && hasId(b, type);
43}
44
45static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
46 const IdentifierType type) {
47 if (!bothHaveId(a, b, type)) return false;
48 /* We should check all Ids of a given type (ie. other AF),
49 * but it doesn't matter for default implementation.
50 */
51 return getId(a, type) == getId(b, type);
52}
53
54static int getHdSubchannel(const ProgramSelector& sel) {
55 auto hdsidext = getId(sel, IdentifierType::HD_STATION_ID_EXT, 0);
56 hdsidext >>= 32; // Station ID number
57 return hdsidext & 0xF; // HD Radio subchannel
58}
59
60bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
61 auto type = getType(b.primaryId);
62
63 switch (type) {
64 case IdentifierType::HD_STATION_ID_EXT:
65 case IdentifierType::RDS_PI:
66 case IdentifierType::AMFM_FREQUENCY:
67 if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
68 if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
69 return getHdSubchannel(b) == 0 && haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
70 case IdentifierType::DAB_SID_EXT:
71 return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
72 case IdentifierType::DRMO_SERVICE_ID:
73 return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
74 case IdentifierType::SXM_SERVICE_ID:
75 return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
76 default: // includes all vendor types
77 ALOGW("Unsupported program type: %s", toString(type).c_str());
78 return false;
79 }
80}
81
82static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
83 auto itype = static_cast<uint32_t>(type);
84
85 if (sel.primaryId.type == itype) {
86 if (val) *val = sel.primaryId.value;
87 return true;
88 }
89
90 // not optimal, but we don't care in default impl
91 for (auto&& id : sel.secondaryIds) {
92 if (id.type == itype) {
93 if (val) *val = id.value;
94 return true;
95 }
96 }
97
98 return false;
99}
100
101bool hasId(const ProgramSelector& sel, const IdentifierType type) {
102 return maybeGetId(sel, type, nullptr);
103}
104
105uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
106 uint64_t val;
107
108 if (maybeGetId(sel, type, &val)) {
109 return val;
110 }
111
112 ALOGW("Identifier %s not found", toString(type).c_str());
113 return 0;
114}
115
116uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
117 if (!hasId(sel, type)) return defval;
118 return getId(sel, type);
119}
120
121bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel) {
122 // Not optimal, but it doesn't matter for default impl nor VTS tests.
123 for (auto&& idTypeI : prop.supportedIdentifierTypes) {
124 auto idType = static_cast<IdentifierType>(idTypeI);
125 if (hasId(sel, idType)) return true;
126 }
127 return false;
128}
129
130static bool isValid(const ProgramIdentifier& id) {
131 auto val = id.value;
132 bool valid = true;
133
134 auto expect = [&valid](bool condition, std::string message) {
135 if (!condition) {
136 valid = false;
137 ALOGE("Identifier not valid, expected %s", message.c_str());
138 }
139 };
140
141 switch (static_cast<IdentifierType>(id.type)) {
142 case IdentifierType::AMFM_FREQUENCY:
143 case IdentifierType::DAB_FREQUENCY:
144 case IdentifierType::DRMO_FREQUENCY:
145 expect(val > 100u, "f > 100kHz");
146 expect(val < 10000000u, "f < 10GHz");
147 break;
148 case IdentifierType::RDS_PI:
149 expect(val != 0u, "RDS PI != 0");
150 expect(val <= 0xFFFFu, "16bit id");
151 break;
152 case IdentifierType::HD_STATION_ID_EXT: {
153 auto stationId = val & 0xFFFFFFFF; // 32bit
154 val >>= 32;
155 auto subchannel = val & 0xF; // 4bit
156 val >>= 4;
157 auto freq = val & 0x3FFFF; // 18bit
158 expect(stationId != 0u, "HD station id != 0");
159 expect(subchannel < 8u, "HD subch < 8");
160 expect(freq > 100u, "f > 100kHz");
161 expect(freq < 10000000u, "f < 10GHz");
162 break;
163 }
164 case IdentifierType::DAB_SID_EXT: {
165 auto sid = val & 0xFFFF; // 16bit
166 val >>= 16;
167 auto ecc = val & 0xFF; // 8bit
168 expect(sid != 0u, "DAB SId != 0");
169 expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
170 break;
171 }
172 case IdentifierType::DAB_ENSEMBLE:
173 expect(val != 0u, "DAB ensemble != 0");
174 expect(val <= 0xFFFFu, "16bit id");
175 break;
176 case IdentifierType::DAB_SCID:
177 expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
178 expect(val <= 0xFFFu, "12bit id");
179 break;
180 case IdentifierType::DRMO_SERVICE_ID:
181 expect(val != 0u, "DRM SId != 0");
182 expect(val <= 0xFFFFFFu, "24bit id");
183 break;
184 case IdentifierType::SXM_SERVICE_ID:
185 expect(val != 0u, "SXM SId != 0");
186 expect(val <= 0xFFFFFFFFu, "32bit id");
187 break;
188 case IdentifierType::SXM_CHANNEL:
189 expect(val < 1000u, "SXM channel < 1000");
190 break;
191 case IdentifierType::VENDOR_START:
192 case IdentifierType::VENDOR_END:
193 // skip
194 break;
195 }
196
197 return valid;
198}
199
200bool isValid(const V2_0::ProgramSelector& sel) {
201 if (!isValid(sel.primaryId)) return false;
202 for (auto&& id : sel.secondaryIds) {
203 if (!isValid(id)) return false;
204 }
205 return true;
206}
207
208ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) {
209 return {static_cast<uint32_t>(type), value};
210}
211
212ProgramSelector make_selector_amfm(uint32_t frequency) {
213 ProgramSelector sel = {};
214 sel.primaryId = make_identifier(IdentifierType::AMFM_FREQUENCY, frequency);
215 return sel;
216}
217
218Metadata make_metadata(MetadataKey key, int64_t value) {
219 Metadata meta = {};
220 meta.key = static_cast<uint32_t>(key);
221 meta.intValue = value;
222 return meta;
223}
224
225Metadata make_metadata(MetadataKey key, string value) {
226 Metadata meta = {};
227 meta.key = static_cast<uint32_t>(key);
228 meta.stringValue = value;
229 return meta;
230}
231
232} // namespace utils
233} // namespace broadcastradio
234} // namespace hardware
235} // namespace android