]> git.kernelconcepts.de Git - rdstmc.git/blob - decoder/tmc.c
Add radio tuning test app
[rdstmc.git] / decoder / tmc.c
1 /*
2  * Copyright (C) 2009, 2010 by Nils Faerber <nils.faerber@kernelconcepts.de>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version
7  * 2 of the License, or (at your option) any later version.
8  *
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <limits.h>
19
20 #include <sqlite3.h>
21
22 #include "rds.h"
23 #include "bitstream.h"
24 #include "tmc.h"
25 #include "tmc_consts.h"
26
27 // #define DEBUG 1
28
29 static struct TMC_info tmc_info;
30 static struct TMC_msg cur_tmc_msg;
31 static char tmc_msg_str[4096];
32 static char *tmc_msg_ptr = tmc_msg_str;
33
34 static struct _TMC_Private {
35         void (*tmc_sid_cb)(char *sid_text, void *user_data);
36         void *tmc_sid_cb_data;
37         void (*tmc_msg_cb)(char *msg, void *user_data);
38         void *tmc_msg_cb_data;
39 } _tmc_private;
40
41 void tmc_init(void)
42 {
43         memset(&_tmc_private, 0, sizeof(struct _TMC_Private));
44 }
45
46 void tmc_set_sid_cb(void (*tmc_sid_cb)(char *sid_text, void *user_data), void *user_data)
47 {
48         _tmc_private.tmc_sid_cb = tmc_sid_cb;
49         _tmc_private.tmc_sid_cb_data = user_data;
50 }
51
52 static void reset_msg_buf(void)
53 {
54         tmc_msg_ptr = tmc_msg_str;
55         memset(tmc_msg_str, 0, 4096);
56 }
57
58 void tmc_set_msg_cb(void (*tmc_msg_cb)(char *msg, void *user_data), void *user_data)
59 {
60         reset_msg_buf();
61         _tmc_private.tmc_msg_cb = tmc_msg_cb;
62         _tmc_private.tmc_msg_cb_data = user_data;
63 }
64
65 void interpret_tmc(int event, int location, int extent, int CI, int direction)
66 {
67 char sql[256]="";
68 sqlite3_stmt *ppstmt;
69 int neg_off=0, pos_off=0, lin_ref=0;
70 char road_nr[256]="", fst_name[256]="";
71 char rdir1[256]="", rdir2[256]="";
72 char last_name[256]="";
73 char evt_str[256]="";
74 char type_str1[128]="";
75 char type_str2[128]="";
76 char typechr;
77 int typenr, subtype;
78
79         //fprintf(stderr, "mCI=%d CI=%d\n", cur_tmc_msg.CI, CI);
80         if (CI != cur_tmc_msg.CI || CI == -1) {
81 #ifdef DEBUG
82                 printf("GF evt=%d loc=%d ext=%d CI=%d dir=%d", event, location, extent, CI, direction);
83                 printf("ev=%d ", event);
84 #endif
85                 snprintf(sql, 256, "select ROADNUMBER,FIRST_NAME,NEGATIVE_OFFSET,POSITIVE_OFFSET,LINEAR_REFERENCE,TYPE,SUBTYPE from lcl where LOCATIONCODE=%d", location);
86                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
87                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
88 #ifdef DEBUG
89                         printf("lcl.db failed to get location %d event %d\n", location, event);
90 #endif
91                         // return; // we cannot do much without location
92                 } else {
93                         neg_off = sqlite3_column_int(ppstmt, 2);
94                         pos_off = sqlite3_column_int(ppstmt, 3);
95                         lin_ref = sqlite3_column_int(ppstmt, 4);
96                         strncpy(road_nr, (char *)sqlite3_column_text(ppstmt, 0), 255);
97                         strncpy(fst_name, (char *)sqlite3_column_text(ppstmt, 1), 255);
98                         strncpy(type_str1, (char *)sqlite3_column_text(ppstmt, 5), 128);
99                         subtype = sqlite3_column_int(ppstmt, 6);
100                         typechr = type_str1[0];
101                         typenr = atoi(&type_str1[1]);
102 #ifdef DEBUG
103                         printf(" type=%c %d stype=%d\n", typechr, typenr, subtype);
104 #endif
105                         snprintf(sql, 256, "select SNATDESC from lcl_supc where CLASS='%c' AND TCD=%d AND STCD=%d", typechr, typenr, subtype);
106                         sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
107                         if (sqlite3_step(ppstmt) != SQLITE_ROW) {
108 #ifdef DEBUG
109                                 printf("lcl.db failed to get suptype %c %d stype=%d\n", typechr, typenr, subtype);
110 #endif
111                         } else {
112                                 strncpy(type_str1, (char *)sqlite3_column_text(ppstmt, 0), 128);                        
113                         }
114                         if (lin_ref != 0) {
115                                 snprintf(sql, 256, "select FIRST_NAME,SECOND_NAME from lcl where LOCATIONCODE=%d", lin_ref);
116                                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
117                                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
118 #ifdef DEBUG
119                                         printf("lcl.db failed to get linear ref %d\n", lin_ref);
120 #endif
121                                 } else {
122                                         if (!direction) {
123                                                 strncpy(rdir1, (char *)sqlite3_column_text(ppstmt, 1), 255);
124                                                 strncpy(rdir2, (char *)sqlite3_column_text(ppstmt, 0), 255);
125                                         } else {
126                                                 strncpy(rdir1, (char *)sqlite3_column_text(ppstmt, 0), 255);
127                                                 strncpy(rdir2, (char *)sqlite3_column_text(ppstmt, 1), 255);
128                                         }
129                                 }
130                         }
131                         if (extent > 0) {
132                                 // printf("%s ab %s ", road_nr, fst_name);
133                                 if (direction) {
134                                         /* neg */
135                                         while (extent--) {
136                                                 snprintf(sql, 256, "select ROADNUMBER,FIRST_NAME,NEGATIVE_OFFSET,POSITIVE_OFFSET,TYPE,SUBTYPE from lcl where LOCATIONCODE=%d", neg_off);
137                                                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
138                                                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
139 #ifdef DEBUG
140                                                         printf("lcl.db failed to get location %d\n", location);
141 #endif
142                                                         break;
143                                                 } else
144                                                         neg_off = sqlite3_column_int(ppstmt, 2);
145                                         }
146                                         //printf("bis %s\n", (char *)sqlite3_column_text(ppstmt, 1));
147                                 } else {
148                                         /* pos */
149                                         while (extent--) {
150                                                 snprintf(sql, 256, "select ROADNUMBER,FIRST_NAME,NEGATIVE_OFFSET,POSITIVE_OFFSET,TYPE,SUBTYPE from lcl where LOCATIONCODE=%d", pos_off);
151                                                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
152                                                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
153 #ifdef DEBUG
154                                                         printf("lcl.db failed to get location %d\n", location);
155 #endif
156                                                         break;
157                                                 } else
158                                                         pos_off = sqlite3_column_int(ppstmt, 3);
159                                         }
160                                         //printf("bis %s\n", (char *)sqlite3_column_text(ppstmt, 1));
161                                 }
162                                 strncpy(last_name, (char *)sqlite3_column_text(ppstmt, 1), 255);
163                                 extent=1;
164                                 strncpy(type_str2, (char *)sqlite3_column_text(ppstmt, 4), 128);
165                                 subtype = sqlite3_column_int(ppstmt, 5);
166                                 typechr = type_str2[0];
167                                 typenr = atoi(&type_str2[1]);
168                                 // printf(" type=%c %d stype=%d\n", typechr, typenr, subtype);
169                                 snprintf(sql, 256, "select SNATDESC from lcl_supc where CLASS='%c' AND TCD=%d AND STCD=%d", typechr, typenr, subtype);
170                                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
171                                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
172 #ifdef DEBUG
173                                         printf("lcl.db failed to get suptype %c %d stype=%d\n", typechr, typenr, subtype);
174 #endif
175                                 } else {
176                                         strncpy(type_str2, (char *)sqlite3_column_text(ppstmt, 0), 128);
177                                 }
178                         }
179                 }
180                 snprintf(sql, 256, "select TEXT_DE_NOQUANT from evl where CODE=%d", event);
181                 sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
182                 if (sqlite3_step(ppstmt) != SQLITE_ROW) {
183 #ifdef DEBUG
184                         printf("lcl.db failed to get event %d\n", event);
185 #endif
186                 } else {
187                         strncpy(evt_str, (char *)sqlite3_column_text(ppstmt, 0), 255);
188                 }
189                 if (CI != -1)
190                         cur_tmc_msg.CI = CI;
191
192                 // here goes the message ;)
193                 if (lin_ref != 0)
194                         tmc_msg_ptr += sprintf(tmc_msg_ptr, "%s %s - %s,\n", road_nr, rdir1, rdir2);
195                 if (location == 64777) {
196                         tmc_msg_ptr += sprintf(tmc_msg_ptr, "%s\n", evt_str);
197                 } else {
198                         if (extent) {
199 #ifdef DEBUG
200                                 printf("dir=%d\n", direction);
201 #endif
202                                 if (direction)
203                                         tmc_msg_ptr += sprintf(tmc_msg_ptr, "zwischen %s %s und %s %s\n%s\n", type_str1, fst_name, type_str2, last_name, evt_str);
204                                 else
205                                         tmc_msg_ptr += sprintf(tmc_msg_ptr, "zwischen %s %s und %s %s\n%s\n", type_str2, last_name, type_str1, fst_name, evt_str);
206                         } else
207                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, "in Höhe %s %s\n%s\n", type_str1, fst_name, evt_str);
208                 }
209         }
210 }
211
212 void parse_tmc_single(unsigned short *rdsgroup)
213 {
214 unsigned short event = cur_tmc_msg.msgs[0][1] & 0x7FF;
215 unsigned short location = cur_tmc_msg.msgs[0][2];
216 unsigned char extent = (cur_tmc_msg.msgs[0][1] & ((0x07) << 11)) >> 11;
217 unsigned char dir = (cur_tmc_msg.msgs[0][1] & ((0x01) << 14)) >> 14;
218 static unsigned short oevent=0;
219 static unsigned short olocation=0;
220
221 #ifdef DEBUG
222         printf(" single group\n");
223 #endif
224         if (olocation != location && oevent != event) {
225                 interpret_tmc(event, location, extent, -1, dir);
226                 olocation = location;
227                 oevent = event;
228                 if (_tmc_private.tmc_msg_cb != NULL) {
229                         _tmc_private.tmc_msg_cb(tmc_msg_str, _tmc_private.tmc_msg_cb_data);
230                 }
231                 reset_msg_buf();
232         }
233 }
234
235 char *replace_str(char *str, char *orig, char *rep)
236 {
237 static char buffer[4096];
238 char *p;
239
240         if(!(p = strstr(str, orig)))  // Is 'orig' even in 'str'?
241                 return str;
242
243         strncpy(buffer, str, p-str); // Copy characters from 'str' start to 'orig' st$
244         buffer[p-str] = '\0';
245
246         sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
247
248 return buffer;
249 }
250
251 void interpret_tmc_multi(void)
252 {
253 int i;
254 unsigned short event = cur_tmc_msg.msgs[0][1] & 0x7FF;
255 unsigned short location = cur_tmc_msg.msgs[0][2];
256 unsigned char extent = (cur_tmc_msg.msgs[0][1] & (0x07 << 11)) >> 11;
257 unsigned char dir = (cur_tmc_msg.msgs[0][1] & (0x01 << 14)) >> 14;
258 unsigned char label;
259 unsigned short aevent;
260 char sql[256]="";
261 sqlite3_stmt *ppstmt;
262 char evt_str[256]="";
263 char lofrstr[16]="";
264 unsigned char ext_buf[256];
265
266 #ifdef DEBUG
267         printf("interpret_tmc_multi: sz=%d\n", cur_tmc_msg.msgsz);
268         for (i=0; i<cur_tmc_msg.msgsz; i++) {
269                 printf(" #%d 0x%04x 0x%04x 0x%04x\n", i, cur_tmc_msg.msgs[i][0], cur_tmc_msg.msgs[i][1], cur_tmc_msg.msgs[i][2]);
270         }
271
272         printf("TMC event=%d loc=%d ext=%d dir=%d\n", event, location, extent, dir);
273 #endif
274
275         interpret_tmc(event, location, extent, -1, dir);
276
277
278         for (i=0; i < cur_tmc_msg.msgsz; i++) {
279                 ext_buf[i*4] = (cur_tmc_msg.msgs[i+1][1] & 0xff00) >> 8;
280                 ext_buf[(i*4)+1] = cur_tmc_msg.msgs[i+1][1] & 0xff;
281                 ext_buf[(i*4)+2] = (cur_tmc_msg.msgs[i+1][2] & 0xff00) >> 8;
282                 ext_buf[(i*4)+3] = cur_tmc_msg.msgs[i+1][2] & 0xff;
283         };
284         bitstream_start(ext_buf, cur_tmc_msg.msgsz*4);
285
286         bitstream_get_next_bits(4);
287
288         while (bitstream_bits_remaining() > 0) {
289                 label = bitstream_get_next_bits(4);
290 #ifdef DEBUG
291                 if (OutputFlags & RDS_OUTPUT_TMC) {
292                         printf("o  '%s' %x\n", EVNT_LABEL[label], label);
293                 }
294 #endif
295                 if (label == 0) {
296                         unsigned char dur=0;
297
298                         dur = bitstream_get_next_bits(3);
299                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " dur=%d\n", dur);
300                 }
301                 if (label == 1) {
302                         unsigned char ctrlcd=0;
303
304                         ctrlcd = bitstream_get_next_bits(3);
305                         if (ctrlcd == 2)
306                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, "in beiden Richtungen\n");
307                         else
308                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " ctrlcd=%d\n", ctrlcd);
309                 }
310                 if (label == 2) {
311                         unsigned int lofr=0;
312
313                         lofr = bitstream_get_next_bits(5);
314                         if (lofr == 0) {
315                                 printf("shit - more than 100km\n");
316                                 strcpy(lofrstr, ">100 km");
317                         }
318                         if (lofr>0 && lofr<11) {
319                                 printf("lofr = %dkm\n", lofr);
320                                 sprintf(lofrstr, "%d km", lofr);
321                         }
322                         if (lofr>10 && lofr<16) {
323                                 printf("lofr = %dkm\n", 12 + ((lofr-11)*2));
324                                 sprintf(lofrstr, "%d km", 12 + ((lofr-11)*2));
325                         }
326                         if (lofr>15 && lofr<32)
327                                 printf("lofr = %dkm\n", 25 + ((lofr-16)*5));
328                                 sprintf(lofrstr, "%d km", 25 + ((lofr-16)*5));
329                 }
330                 if (label == 3) {
331                         unsigned int slim=0;
332
333                         slim = bitstream_get_next_bits(5);
334                         if (slim > 0)
335                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " slim = %d km/h\n", slim*5);
336                 }
337                 if (label == 4) {
338                         unsigned int quant5=0;
339
340                         quant5 = bitstream_get_next_bits(5);
341                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " quant5 = %d km\n", quant5);
342                 }
343                 if (label == 5) {
344                         unsigned int quant8=0;
345
346                         quant8 = bitstream_get_next_bits(8);
347                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " quant8 = %d km\n", quant8);
348                 }
349                 if (label == 6) {
350                         unsigned char supinfo=0;
351
352                         supinfo = bitstream_get_next_bits(8);
353 #ifdef DEBUG
354                         printf(" supinfo = %d\n", supinfo);
355 #endif
356                         snprintf(sql, 256, "select TEXT_DE from ev_sup where CODE=%d", supinfo);
357                         sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
358                         if (sqlite3_step(ppstmt) != SQLITE_ROW) {
359 #ifdef DEBUG
360                                 printf("lcl.db failed to get ev_sup %d\n", supinfo);
361 #endif
362                         } else {
363                                 strncpy(evt_str, (char *)sqlite3_column_text(ppstmt, 0), 255);
364                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, "%s\n", evt_str);
365                         }
366                 }
367                 if (label == 7) {
368                         unsigned int stime=0;
369
370                         stime = bitstream_get_next_bits(8);
371                         // printf(" stime = %d\n", stime);
372                         if (stime < 96) {
373                                 stime *= 15; // 15 min internval
374                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " ab %02d:%02d\n", (stime / 60), (stime % 60));
375                         } else if (stime < 201) {
376                                 stime -= 96;
377                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " ab %d Tage, %d:00 Uhr\n", (stime / 24), (stime % 24));
378                         } else if (stime < 232) {
379                                 stime -= 201;
380                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " ab dem %d.\n", stime+1);
381                         } else {
382                                 stime -= 232;
383                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " ab %s. %s\n", (stime % 2) ? "31":"15", monthname[stime / 2]);
384                         }
385                 }
386                 if (label == 8) {
387                         unsigned int etime=0;
388
389                         etime = bitstream_get_next_bits(8);
390                         // printf(" etime = %d\n", etime);
391                         if (etime < 96) {
392                                 etime *= 15; // 15 min internval
393                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " bis vor. %02d:%02d\n", (etime / 60), (etime % 60));
394                         } else if (etime < 201) {
395                                 etime -= 96;
396                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " bis %d Tage, %d:00 Uhr\n", (etime / 24), (etime % 24));
397                         } else if (etime < 232) {
398                                 etime -= 201;
399                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " bis zum %d.\n", etime+1);
400                         } else {
401                                 etime -= 232;
402                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, " bis etwa %s. %s\n", (etime % 2) ? "31":"15", monthname[etime / 2]);
403                         }
404                 }
405                 if (label == 9) {
406                         aevent = bitstream_get_next_bits(11);
407 #ifdef DEBUG
408                         printf(" aevent = %d ", aevent);
409 #endif
410                         snprintf(sql, 256, "select TEXT_DE_NOQUANT from evl where CODE=%d", aevent);
411                         sqlite3_prepare(lcl_db, sql, 256, &ppstmt, NULL);
412                         if (sqlite3_step(ppstmt) != SQLITE_ROW) {
413 #ifdef DEBUG
414                                 printf("-lcl.db failed to get event %d\n", aevent);
415 #endif
416                         } else {
417                                 strncpy(evt_str, (char *)sqlite3_column_text(ppstmt, 0), 255);
418                                 // printf("(L)='%s'\n", evt_str);
419                                 if (strlen(lofrstr) != 0 && strstr(evt_str,"(L)")!=NULL) {
420                                         replace_str(evt_str, "(L)", lofrstr);
421                                 }
422                                 tmc_msg_ptr += sprintf(tmc_msg_ptr, "%s\n", evt_str);
423                         }
424                 }
425                 if (label == 10) {
426                         unsigned char div;
427
428                         div = bitstream_get_next_bits(16);
429                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " div = %d\n", div);
430                 }
431                 if (label == 11) {
432                         unsigned char dest;
433
434                         dest = bitstream_get_next_bits(16);
435                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " dest = %d\n", dest);
436                 }
437                 if (label == 12) {
438                         unsigned char res;
439
440                         res = bitstream_get_next_bits(16);
441                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " res = %d\n", res);
442                 }
443                 if (label == 13) {
444                         unsigned char clink;
445
446                         clink = bitstream_get_next_bits(16);
447                         tmc_msg_ptr += sprintf(tmc_msg_ptr, " clink = %d\n", clink);
448                 }
449                 if (label == 14) {
450                         // tmc_msg_ptr += sprintf(tmc_msg_ptr, " seperator\n");
451                 }
452                 if (label == 15) {
453 #ifdef DEBUG
454                         printf(" res\n");
455 #endif
456                 }
457         }
458 #ifdef DEBUGx
459         if (cur_tmc_msg.msgsz > 2) {
460                 for (i=2; i<cur_tmc_msg.msgsz; i++) {
461                         printf(" #%d 0x%04x 0x%04x 0x%04x\n", i, cur_tmc_msg.msgs[i][0], cur_tmc_msg.msgs[i][1], cur_tmc_msg.msgs[i][2]);
462                 }
463         }
464 #endif
465         if (_tmc_private.tmc_msg_cb != NULL) {
466                 _tmc_private.tmc_msg_cb(tmc_msg_str, _tmc_private.tmc_msg_cb_data);
467         }
468         reset_msg_buf();
469 }
470
471 void parse_tmc_multi(unsigned short *rdsgroup)
472 {
473 unsigned char GSI = (rdsgroup[2] & 0x3000) >> 12;
474 static unsigned char oGSI = 0;
475 #ifdef DEBUG
476 unsigned char CI = rdsgroup[1] & 0x07;
477 #endif
478
479 #ifdef DEBUG
480         printf(" multi CI=%d ", CI);
481 #endif
482         if (rdsgroup[2] & 0x8000) {
483                 if (cur_tmc_msg.msgsz > 0) {
484                         interpret_tmc_multi();
485                         cur_tmc_msg.msgsz = 0;
486                 }
487 #ifdef DEBUG
488                 printf(" #1 GSI=%d\n", GSI);
489 #endif
490                 oGSI = 0;
491                 memset(&cur_tmc_msg.msgs, 0, 6*3*sizeof(short));
492                 cur_tmc_msg.msgs[0][0] = rdsgroup[1];
493                 cur_tmc_msg.msgs[0][1] = rdsgroup[2];
494                 cur_tmc_msg.msgs[0][2] = rdsgroup[3];
495                 //msgsz = 1;
496         } else {
497                 if (rdsgroup[2] & 0x4000) {
498                         // printf(" #2 GSI=%d\n", GSI);
499                         cur_tmc_msg.msgs[1][0] = rdsgroup[1];
500                         cur_tmc_msg.msgs[1][1] = rdsgroup[2];
501                         cur_tmc_msg.msgs[1][2] = rdsgroup[3];
502                         cur_tmc_msg.msgsz = 2;
503                 } else {
504                         if (oGSI == 0) {
505                                 oGSI = GSI;
506                         }
507                         // printf(" #%d GSI=%d (oGSI=%d)\n", 2+(oGSI-GSI), GSI, oGSI);
508                         cur_tmc_msg.msgs[2+(oGSI-GSI)][0] = rdsgroup[1];
509                         cur_tmc_msg.msgs[2+(oGSI-GSI)][1] = rdsgroup[2];
510                         cur_tmc_msg.msgs[2+(oGSI-GSI)][2] = rdsgroup[3];
511                         cur_tmc_msg.msgsz = 2+(oGSI-GSI);
512                 }
513         }
514         // printf("  0x%04x 0x%04x\n", rdsgroup[2], rdsgroup[3]);
515 }
516
517 // enum TMCtype { TMC_GROUP=0,  TMC_SINGLE,  TMC_SYSTEM,  TMC_TUNING };
518
519 void decode_tmc(unsigned short *rdsgroup)
520 {
521 unsigned char X4 = (rdsgroup[1] & 0x10) >> 4;
522 unsigned char X3 = (rdsgroup[1] & 0x08) >> 3;
523 unsigned char X0X2 = rdsgroup[1] & 0x07;
524 //static unsigned char tmc_provider[9] = "";
525
526         if (X4 == 0) { // User message
527                 if (X3 == 1) { // single group msg
528                         parse_tmc_single(rdsgroup);
529                 } else { // multi group msg
530                         if (X0X2 > 0) {
531                                 parse_tmc_multi(rdsgroup);
532                         }
533 #ifdef DEBUG
534                         else
535                                 printf("err... X0X2(CI) = %d\n", X0X2);
536 #endif
537                 }
538         } else {
539                 if (X3 == 1) {
540                         //printf(" tuning?\n");
541                 } else {
542                         // printf(" system ");
543                         if (X0X2 == 4) {
544                                 tmc_info.provider_str[0] = (rdsgroup[2] & 0xff00) >> 8;
545                                 tmc_info.provider_str[1] = rdsgroup[2] & 0xff;
546                                 tmc_info.provider_str[2] = (rdsgroup[3] & 0xff00) >> 8;
547                                 tmc_info.provider_str[3] = rdsgroup[3] & 0xff;
548                                 if (_tmc_private.tmc_sid_cb != NULL)
549                                         _tmc_private.tmc_sid_cb(tmc_info.provider_str, _tmc_private.tmc_sid_cb_data);
550                                 if (OutputFlags & RDS_OUTPUT_TMC)
551                                         printf("provider = '%s'\n", tmc_info.provider_str);
552                         } else if (X0X2 == 5) {
553                                 tmc_info.provider_str[4] = (rdsgroup[2] & 0xff00) >> 8;
554                                 tmc_info.provider_str[5] = rdsgroup[2] & 0xff;
555                                 tmc_info.provider_str[6] = (rdsgroup[3] & 0xff00) >> 8;
556                                 tmc_info.provider_str[7] = rdsgroup[3] & 0xff;
557                                 if (_tmc_private.tmc_sid_cb != NULL)
558                                         _tmc_private.tmc_sid_cb(tmc_info.provider_str, _tmc_private.tmc_sid_cb_data);
559                                 if (OutputFlags & RDS_OUTPUT_TMC)
560                                         printf("provider = '%s'\n", tmc_info.provider_str);
561                         }
562 #ifdef DEBUG
563                          else
564                                 printf("X0X2(CI)=%d \n", X0X2);
565 #endif
566                 }
567         }
568 }
569