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