Skip to content

Commit c4f4e2b

Browse files
author
pyrog
committed
Add a charset option for POCSAG demodulators
fix EliasOenal#69
1 parent 46c3b0a commit c4f4e2b

File tree

2 files changed

+238
-86
lines changed

2 files changed

+238
-86
lines changed

pocsag.c

Lines changed: 228 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -125,94 +125,237 @@ static unsigned int pocsag_syndrome(uint32_t data)
125125
}
126126

127127
/* ---------------------------------------------------------------------- */
128+
// ISO 646 national variant: US / IRV (1991)
129+
char *trtab[128] = {
130+
"<NUL>", // 0x0
131+
"<SOH>", // 0x1
132+
"<STX>", // 0x2
133+
"<ETX>", // 0x3
134+
"<EOT>", // 0x4
135+
"<ENQ>", // 0x5
136+
"<ACK>", // 0x6
137+
"<BEL>", // 0x7
138+
"<BS>", // 0x8
139+
"<HT>", // 0x9
140+
"<LF>", // 0xa
141+
"<VT>", // 0xb
142+
"<FF>", // 0xc
143+
"<CR>", // 0xd
144+
"<SO>", // 0xe
145+
"<SI>", // 0xf
146+
"<DLE>", // 0x10
147+
"<DC1>", // 0x11
148+
"<DC2>", // 0x12
149+
"<DC3>", // 0x13
150+
"<DC4>", // 0x14
151+
"<NAK>", // 0x15
152+
"<SYN>", // 0x16
153+
"<ETB>", // 0x17
154+
"<CAN>", // 0x18
155+
"<EM>", // 0x19
156+
"<SUB>", // 0x1a
157+
"<ESC>", // 0x1b
158+
"<FS>", // 0x1c
159+
"<GS>", // 0x1d
160+
"<RS>", // 0x1e
161+
"<US>", // 0x1f
162+
" ", // 0x20
163+
"!", // 0x21
164+
"\"", // 0x22
165+
166+
// national variant
167+
"#", // 0x23
168+
"$", // 0x24
169+
170+
"%", // 0x25
171+
"&", // 0x26
172+
"'", // 0x27
173+
"(", // 0x28
174+
")", // 0x29
175+
"*", // 0x2a
176+
"+", // 0x2b
177+
",", // 0x2c
178+
"-", // 0x2d
179+
".", // 0x2e
180+
"/", // 0x2f
181+
"0", // 0x30
182+
"1", // 0x31
183+
"2", // 0x32
184+
"3", // 0x33
185+
"4", // 0x34
186+
"5", // 0x35
187+
"6", // 0x36
188+
"7", // 0x37
189+
"8", // 0x38
190+
"9", // 0x39
191+
":", // 0x3a
192+
";", // 0x3b
193+
"<", // 0x3c
194+
"=", // 0x3d
195+
">", // 0x3e
196+
"?", // 0x3f
197+
"@", // 0x40
198+
"A", // 0x41
199+
"B", // 0x42
200+
"C", // 0x43
201+
"D", // 0x44
202+
"E", // 0x45
203+
"F", // 0x46
204+
"G", // 0x47
205+
"H", // 0x48
206+
"I", // 0x49
207+
"J", // 0x4a
208+
"K", // 0x4b
209+
"L", // 0x4c
210+
"M", // 0x4d
211+
"N", // 0x4e
212+
"O", // 0x4f
213+
"P", // 0x50
214+
"Q", // 0x51
215+
"R", // 0x52
216+
"S", // 0x53
217+
"T", // 0x54
218+
"U", // 0x55
219+
"V", // 0x56
220+
"W", // 0x57
221+
"X", // 0x58
222+
"Y", // 0x59
223+
"Z", // 0x5a
224+
225+
// national variant
226+
"[", // 0x5b
227+
"\\", // 0x5c
228+
"]", // 0x5d
229+
"^", // 0x5e
230+
231+
"_", // 0x5f
232+
233+
// national variant
234+
"`", // 0x60
235+
236+
"a", // 0x61
237+
"b", // 0x62
238+
"c", // 0x63
239+
"d", // 0x64
240+
"e", // 0x65
241+
"f", // 0x66
242+
"g", // 0x67
243+
"h", // 0x68
244+
"i", // 0x69
245+
"j", // 0x6a
246+
"k", // 0x6b
247+
"l", // 0x6c
248+
"m", // 0x6d
249+
"n", // 0x6e
250+
"o", // 0x6f
251+
"p", // 0x70
252+
"q", // 0x71
253+
"r", // 0x72
254+
"s", // 0x73
255+
"t", // 0x74
256+
"u", // 0x75
257+
"v", // 0x76
258+
"w", // 0x77
259+
"x", // 0x78
260+
"y", // 0x79
261+
"z", // 0x7a
262+
263+
// national variant
264+
"{", // 0x7b
265+
"|", // 0x7c
266+
"}", // 0x7d
267+
"~", // 0x7e
268+
269+
"<DEL>" // 0x7f
270+
};
271+
272+
273+
/*
274+
// national variant
275+
"#", // 0x23
276+
"$", // 0x24
277+
278+
"[", // 0x5b
279+
"\\", // 0x5c
280+
"]", // 0x5d
281+
"^", // 0x5e
282+
283+
"`", // 0x60
284+
285+
"{", // 0x7b
286+
"|", // 0x7c
287+
"}", // 0x7d
288+
"~", // 0x7e
289+
*/
290+
291+
bool pocsag_init_charset(char *charset)
292+
{
293+
if(strcmp(charset,"DE")==0) // German charset
294+
{
295+
#ifdef CHARSET_UTF8
296+
trtab[0x5b] = "Ä";
297+
trtab[0x5c] = "Ö";
298+
trtab[0x5d] = "Ü";
299+
300+
trtab[0x7b] = "ä";
301+
trtab[0x7c] = "ö";
302+
trtab[0x7d] = "ü";
303+
trtab[0x7e] = "ß";
304+
#elif defined CHARSET_LATIN1
305+
trtab[0x5b] = "\304";
306+
trtab[0x5c] = "\326";
307+
trtab[0x5d] = "\334";
308+
309+
trtab[0x7b] = "\344";
310+
trtab[0x7c] = "\366";
311+
trtab[0x7d] = "\374";
312+
trtab[0x7e] = "\337";
313+
#else
314+
trtab[0x5b] = "AE";
315+
trtab[0x5c] = "OE";
316+
trtab[0x5d] = "UE";
317+
318+
trtab[0x7b] = "ae";
319+
trtab[0x7c] = "oe";
320+
trtab[0x7d] = "ue";
321+
trtab[0x7e] = "ss";
322+
#endif
323+
}
324+
else if (strcmp(charset,"FR")==0) // French charset
325+
{
326+
trtab[0x24] = "£";
327+
328+
trtab[0x40] = "à";
329+
330+
trtab[0x5b] = "°";
331+
trtab[0x5c] = "ç";
332+
trtab[0x5d] = "§";
333+
trtab[0x5e] = "^";
334+
trtab[0x5f] = "_";
335+
trtab[0x60] = "µ";
336+
337+
trtab[0x7b] = "é";
338+
trtab[0x7c] = "ù";
339+
trtab[0x7d] = "è";
340+
trtab[0x7e] = "¨";
341+
}
342+
else if (strcmp(charset,"US")==0) // US charset
343+
{
344+
// default
345+
}
346+
else
347+
{
348+
fprintf(stderr, "Error: invalid POCSAG charset %s\n", charset);
349+
fprintf(stderr, "Use: US,FR,DE\n");
350+
charset = "US";
351+
return false;
352+
}
353+
return true;
354+
}
128355

129356
static char *translate_alpha(unsigned char chr)
130357
{
131-
static const struct trtab {
132-
unsigned char code;
133-
char *str;
134-
} trtab[] = {{ 0, "<NUL>" },
135-
{ 1, "<SOH>" },
136-
{ 2, "<STX>" },
137-
{ 3, "<ETX>" },
138-
{ 4, "<EOT>" },
139-
{ 5, "<ENQ>" },
140-
{ 6, "<ACK>" },
141-
{ 7, "<BEL>" },
142-
{ 8, "<BS>" },
143-
{ 9, "<HT>" },
144-
{ 10, "<LF>" },
145-
{ 11, "<VT>" },
146-
{ 12, "<FF>" },
147-
{ 13, "<CR>" },
148-
{ 14, "<SO>" },
149-
{ 15, "<SI>" },
150-
{ 16, "<DLE>" },
151-
{ 17, "<DC1>" },
152-
{ 18, "<DC2>" },
153-
{ 19, "<DC3>" },
154-
{ 20, "<DC4>" },
155-
{ 21, "<NAK>" },
156-
{ 22, "<SYN>" },
157-
{ 23, "<ETB>" },
158-
{ 24, "<CAN>" },
159-
{ 25, "<EM>" },
160-
{ 26, "<SUB>" },
161-
{ 27, "<ESC>" },
162-
{ 28, "<FS>" },
163-
{ 29, "<GS>" },
164-
{ 30, "<RS>" },
165-
{ 31, "<US>" },
166-
#ifdef CHARSET_LATIN1
167-
{ 0x5b, "\304" }, /* upper case A dieresis */
168-
{ 0x5c, "\326" }, /* upper case O dieresis */
169-
{ 0x5d, "\334" }, /* upper case U dieresis */
170-
{ 0x7b, "\344" }, /* lower case a dieresis */
171-
{ 0x7c, "\366" }, /* lower case o dieresis */
172-
{ 0x7d, "\374" }, /* lower case u dieresis */
173-
{ 0x7e, "\337" }, /* sharp s */
174-
#elif defined CHARSET_UTF8
175-
{ 0x5b, "Ä" }, /* upper case A dieresis */
176-
{ 0x5c, "Ö" }, /* upper case O dieresis */
177-
{ 0x5d, "Ü" }, /* upper case U dieresis */
178-
{ 0x7b, "ä" }, /* lower case a dieresis */
179-
{ 0x7c, "ö" }, /* lower case o dieresis */
180-
{ 0x7d, "ü" }, /* lower case u dieresis */
181-
{ 0x7e, "ß" }, /* sharp s */
182-
#else
183-
{ 0x5b, "AE" }, /* upper case A dieresis */
184-
{ 0x5c, "OE" }, /* upper case O dieresis */
185-
{ 0x5d, "UE" }, /* upper case U dieresis */
186-
{ 0x7b, "ae" }, /* lower case a dieresis */
187-
{ 0x7c, "oe" }, /* lower case o dieresis */
188-
{ 0x7d, "ue" }, /* lower case u dieresis */
189-
{ 0x7e, "ss" }, /* sharp s */
190-
#endif
191-
{ 127, "<DEL>" }};
192-
193-
int min = 0, max = (sizeof(trtab) / sizeof(trtab[0])) - 1;
194-
195-
/*
196-
* binary search, list must be ordered!
197-
*/
198-
for (;;) {
199-
int mid = (min+max) >> 1;
200-
const struct trtab *tb = trtab + mid;
201-
int cmp = ((int) tb->code) - ((int) chr);
202-
203-
if (!cmp)
204-
return tb->str;
205-
if (cmp < 0) {
206-
min = mid+1;
207-
if (min > max)
208-
return NULL;
209-
}
210-
if (cmp > 0) {
211-
max = mid-1;
212-
if (max < min)
213-
return NULL;
214-
}
215-
}
358+
return trtab[chr & 0x7f];
216359
}
217360

218361
/* ---------------------------------------------------------------------- */

unixinput.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ extern int pocsag_error_correction;
9797
extern int pocsag_show_partial_decodes;
9898
extern int pocsag_heuristic_pruning;
9999
extern int pocsag_prune_empty;
100+
extern bool pocsag_init_charset(char *charset);
100101

101102
extern int aprs_mode;
102103
extern int cw_dit_length;
@@ -580,6 +581,7 @@ static const char usage_str[] = "\n"
580581
" (<mode> can be 'numeric', 'alpha' and 'skyper')\n"
581582
" -b <level> : POCSAG: BCH bit error correction level. Set 0 to disable, default is 2.\n"
582583
" Lower levels increase performance and lower false positives.\n"
584+
" -C <cs> : POCSAG: Set Charset.\n"
583585
" -o : CW: Set threshold for dit detection (default: 500)\n"
584586
" -d : CW: Dit length in ms (default: 50)\n"
585587
" -g : CW: Gap length in ms (default: 50)\n"
@@ -607,10 +609,11 @@ int main(int argc, char *argv[])
607609
{
608610
{"timestamp", no_argument, &timestamp, 1},
609611
{"label", required_argument, NULL, 'l'},
612+
{"charset", required_argument, NULL, 'C'},
610613
{0, 0, 0, 0}
611614
};
612615

613-
while ((c = getopt_long(argc, argv, "t:a:s:v:b:f:g:d:o:cqhAmrxynipeu", long_options, NULL)) != EOF) {
616+
while ((c = getopt_long(argc, argv, "t:a:s:v:b:f:g:d:o:cqhAmrxynipeuC:", long_options, NULL)) != EOF) {
614617
switch (c) {
615618
case 'h':
616619
case '?':
@@ -730,6 +733,11 @@ int main(int argc, char *argv[])
730733
}else fprintf(stderr, "a POCSAG mode has already been selected!\n");
731734
break;
732735

736+
case 'C':
737+
if (!pocsag_init_charset(optarg))
738+
errflg++;
739+
break;
740+
733741
case 'n':
734742
dont_flush = true;
735743
break;
@@ -769,6 +777,7 @@ int main(int argc, char *argv[])
769777
case 'y':
770778
cw_disable_auto_timing = true;
771779
break;
780+
772781
case 'l':
773782
label = optarg;
774783
break;

0 commit comments

Comments
 (0)