Skip to content

Commit f0bd17f

Browse files
fix north americal RDS callsign decoding
1 parent a8ed213 commit f0bd17f

File tree

2 files changed

+143
-7
lines changed

2 files changed

+143
-7
lines changed

decoder_modules/radio/src/rds.cpp

Lines changed: 141 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,98 @@ namespace rds {
2222
{ BLOCK_TYPE_D, 0b0110110100 }
2323
};
2424

25+
std::map<uint16_t, const char*> THREE_LETTER_CALLS = {
26+
{ 0x99A5, "KBW" },
27+
{ 0x99A6, "KCY" },
28+
{ 0x9990, "KDB" },
29+
{ 0x99A7, "KDF" },
30+
{ 0x9950, "KEX" },
31+
{ 0x9951, "KFH" },
32+
{ 0x9952, "KFI" },
33+
{ 0x9953, "KGA" },
34+
{ 0x9991, "KGB" },
35+
{ 0x9954, "KGO" },
36+
{ 0x9955, "KGU" },
37+
{ 0x9956, "KGW" },
38+
{ 0x9957, "KGY" },
39+
{ 0x99AA, "KHQ" },
40+
{ 0x9958, "KID" },
41+
{ 0x9959, "KIT" },
42+
{ 0x995A, "KJR" },
43+
{ 0x995B, "KLO" },
44+
{ 0x995C, "KLZ" },
45+
{ 0x995D, "KMA" },
46+
{ 0x995E, "KMJ" },
47+
{ 0x995F, "KNX" },
48+
{ 0x9960, "KOA" },
49+
{ 0x99AB, "KOB" },
50+
{ 0x9992, "KOY" },
51+
{ 0x9993, "KPQ" },
52+
{ 0x9964, "KQV" },
53+
{ 0x9994, "KSD" },
54+
{ 0x9965, "KSL" },
55+
{ 0x9966, "KUJ" },
56+
{ 0x9995, "KUT" },
57+
{ 0x9967, "KVI" },
58+
{ 0x9968, "KWG" },
59+
{ 0x9996, "KXL" },
60+
{ 0x9997, "KXO" },
61+
{ 0x996B, "KYW" },
62+
{ 0x9999, "WBT" },
63+
{ 0x996D, "WBZ" },
64+
{ 0x996E, "WDZ" },
65+
{ 0x996F, "WEW" },
66+
{ 0x999A, "WGH" },
67+
{ 0x9971, "WGL" },
68+
{ 0x9972, "WGN" },
69+
{ 0x9973, "WGR" },
70+
{ 0x999B, "WGY" },
71+
{ 0x9975, "WHA" },
72+
{ 0x9976, "WHB" },
73+
{ 0x9977, "WHK" },
74+
{ 0x9978, "WHO" },
75+
{ 0x999C, "WHP" },
76+
{ 0x999D, "WIL" },
77+
{ 0x997A, "WIP" },
78+
{ 0x99B3, "WIS" },
79+
{ 0x997B, "WJR" },
80+
{ 0x99B4, "WJW" },
81+
{ 0x99B5, "WJZ" },
82+
{ 0x997C, "WKY" },
83+
{ 0x997D, "WLS" },
84+
{ 0x997E, "WLW" },
85+
{ 0x999E, "WMC" },
86+
{ 0x999F, "WMT" },
87+
{ 0x9981, "WOC" },
88+
{ 0x99A0, "WOI" },
89+
{ 0x9983, "WOL" },
90+
{ 0x9984, "WOR" },
91+
{ 0x99A1, "WOW" },
92+
{ 0x99B9, "WRC" },
93+
{ 0x99A2, "WRR" },
94+
{ 0x99A3, "WSB" },
95+
{ 0x99A4, "WSM" },
96+
{ 0x9988, "WWJ" },
97+
{ 0x9989, "WWL" }
98+
};
99+
100+
std::map<uint16_t, const char*> NAT_LOC_LINKED_STATIONS = {
101+
{ 0xB01, "NPR-1" },
102+
{ 0xB02, "CBC - Radio One" },
103+
{ 0xB03, "CBC - Radio Two" },
104+
{ 0xB04, "Radio-Canada - Première Chaîne" },
105+
{ 0xB05, "Radio-Canada - Espace Musique" },
106+
{ 0xB06, "CBC" },
107+
{ 0xB07, "CBC" },
108+
{ 0xB08, "CBC" },
109+
{ 0xB09, "CBC" },
110+
{ 0xB0A, "NPR-2" },
111+
{ 0xB0B, "NPR-3" },
112+
{ 0xB0C, "NPR-4" },
113+
{ 0xB0D, "NPR-5" },
114+
{ 0xB0E, "NPR-6" }
115+
};
116+
25117
// 9876543210
26118
const uint16_t LFSR_POLY = 0b0110111001;
27119
const uint16_t IN_POLY = 0b1100011011;
@@ -146,7 +238,7 @@ namespace rds {
146238
countryCode = (blocks[BLOCK_TYPE_A] >> 22) & 0xF;
147239
programCoverage = (AreaCoverage)((blocks[BLOCK_TYPE_A] >> 18) & 0xF);
148240
programRefNumber = (blocks[BLOCK_TYPE_A] >> 10) & 0xFF;
149-
decodeCallsign();
241+
callsign = decodeCallsign(piCode);
150242

151243
// Update timeout
152244
blockALastUpdate = std::chrono::high_resolution_clock::now();;
@@ -287,7 +379,7 @@ namespace rds {
287379
// Decode block B
288380
decodeBlockB();
289381

290-
//flog::debug("RDS Group {}{}", groupType, (groupVer == GROUP_VER_A) ? 'A':'B');
382+
flog::debug("RDS Group {}{}", groupType, (groupVer == GROUP_VER_A) ? 'A':'B');
291383

292384
// Decode depending on group type
293385
switch (groupType) {
@@ -305,14 +397,14 @@ namespace rds {
305397
}
306398
}
307399

308-
void Decoder::decodeCallsign() {
400+
std::string Decoder::base26ToCall(uint16_t pi) {
309401
// Determin first better based on offset
310-
bool w = (piCode >= 21672);
311-
callsign = w ? 'W' : 'K';
402+
bool w = (pi >= 21672);
403+
std::string callsign(w ? "W" : "K");
312404

313405
// Base25 decode the rest
314406
std::string restStr;
315-
int rest = piCode - (w ? 21672 : 4096);
407+
int rest = pi - (w ? 21672 : 4096);
316408
while (rest) {
317409
restStr += 'A' + (rest % 26);
318410
rest /= 26;
@@ -322,6 +414,49 @@ namespace rds {
322414
for (int i = restStr.size() - 1; i >= 0; i--) {
323415
callsign += restStr[i];
324416
}
417+
418+
return callsign;
419+
}
420+
421+
std::string Decoder::decodeCallsign(uint16_t pi) {
422+
if ((pi >> 8) == 0xAF) {
423+
// AFXY -> XY00
424+
return base26ToCall((pi & 0xFF) << 8);
425+
}
426+
else if ((pi >> 12) == 0xA) {
427+
// AXYZ -> X0YZ
428+
return base26ToCall((((pi >> 8) & 0xF) << 12) | (pi & 0xFF));
429+
}
430+
else if (pi >= 0x9950 && pi <= 0x9EFF) {
431+
// 3 letter callsigns
432+
if (THREE_LETTER_CALLS.find(pi) != THREE_LETTER_CALLS.end()) {
433+
return THREE_LETTER_CALLS[pi];
434+
}
435+
else {
436+
return "Not Assigned";
437+
}
438+
}
439+
else if (pi >= 0x1000 && pi <= 0x994F) {
440+
// Normal encoding
441+
if ((pi & 0xFF) == 0 || ((pi >> 8) & 0xF) == 0) {
442+
return "Not Assigned";
443+
}
444+
else {
445+
return base26ToCall(pi);
446+
}
447+
}
448+
else if (pi >= 0xB000 && pi <= 0xEFFF) {
449+
uint16_t _pi = ((pi >> 12) << 8) | (pi & 0xFF);
450+
if (NAT_LOC_LINKED_STATIONS.find(_pi) != NAT_LOC_LINKED_STATIONS.end()) {
451+
return NAT_LOC_LINKED_STATIONS[_pi];
452+
}
453+
else {
454+
return "Not Assigned";
455+
}
456+
}
457+
else {
458+
return "Not Assigned";
459+
}
325460
}
326461

327462
bool Decoder::blockAValid() {

decoder_modules/radio/src/rds.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ namespace rds {
246246
void decodeGroup10();
247247
void decodeGroup();
248248

249-
void decodeCallsign();
249+
static std::string base26ToCall(uint16_t pi);
250+
static std::string decodeCallsign(uint16_t pi);
250251

251252
bool blockAValid();
252253
bool blockBValid();

0 commit comments

Comments
 (0)