source: svn/trunk/newcon3bcm2_21bu/nexus/app/nanotv/chan_mgr.c @ 2

Last change on this file since 2 was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 100.0 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2006, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile:  $
11 * $brcm_Revision:  $
12 * $brcm_Date: $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log:  $
19 *
20 ***************************************************************************/
21
22#include "chan_mgr.h"
23#include "bstd.h"
24#include "ts_psi.h"
25#include "ts_psi.h"
26#include "ts_pat.h"
27#include "ts_pmt.h"
28#include "bsettop_message.h"
29#include "bapp.h"
30#include "psip_ett.h"
31#include "bsmart.h"
32#include "bcrc32.h"
33#include "bsettop_smessage.h"
34
35BDBG_MODULE(chan_mgr);          /* Register software module with debug interface */
36
37
38/* PR32033 fix, for ETT 10.5- 10.10, need more buffer and timeout */
39
40#define CHM_MIN(x,y)        ((x < y) ? x : y)
41
42//#define DEBUG_RRT
43
44#ifdef BCM_DEBUG
45static const char *s_chm_cmd_name[] = { "eCHM_CANCEL","eCHM_SCAN","eCHM_TUNE","eCHM_INFO","eCHM_GUIDE","eCHM_STOP","eCHM_CHECK_SIGNAL"};
46static const char *s_chm_state[] = { "eCHM_GET_STT","eCHM_GET_VCT","eCHM_GET_MGT","eCHM_PROCESS_MGT","eCHM_PROG_IDLE","eCHM_GET_RRT"};
47#endif
48const char g_tz_map[] = { 0, 5, 6, 7, 8, 0};
49
50#define CHM_CHECK_SIGNAL_FREQ   1000
51
52
53#define PROG_INFO_TIMEOUT   (5 * g_ticks_per_second)
54
55#define CHM_INT_STK_SIZE        1024    /* in words */
56
57#define VCT_BUF_LEN         (1024 + 188)
58#define PAT_BUF_LEN         (1024 + 188)
59#define PMT_BUF_LEN         (1024 + 188)
60#define STT_BUF_LEN         (256 + 188)
61#define EIT_BUF_LEN         (4400 + 188)
62#define MGT_BUF_LEN         (4400 + 188)
63#define ETT_BUF_LEN                     (4400 + 188)
64#define CHM_IDLE_TIMEOUT        10
65
66#define VCT_TIMEOUT         1500
67#define PAT_TIMEOUT         800
68#define PMT_TIMEOUT         800
69#define MSC_TIMEOUT         800
70#define MGT_TIMEOUT         500
71#define STT_TIMEOUT         1200
72#define VCT_ETT_TIMEOUT     1200
73#define ETT_TIMEOUT         2000
74#define EIT_TIMEOUT         2000
75#define RRT_TIMEOUT         5000 /* in milliseconds */
76
77#define CHM_MUTEX_TIMEOUT   10
78#define MAX_TIME_SLOTS      4
79#define MGT_CYCLE_TIMEOUT   1           /* in seconds */
80#define RRT_CYCLE_TIME          (15)    /* in seconds */
81
82#define CHM_MIN(x,y)        ((x < y) ? x : y)
83
84typedef struct iso_lang_map_t
85{
86        char            iso_lang_code[3];
87        bapp_lang_t     lang;
88}iso_lang_map_t;
89
90typedef enum chm_err_t
91{
92        eCHM_ERR_OK         = 0,
93        eCHM_ERR_FAILED     = -1,
94        eCHM_ERR_TIMEOUT    = -2,
95        eCHM_ERR_CANCELED   = -3
96}chm_err_t;
97
98const static iso_lang_map_t s_iso_lang_map[] =
99{
100        { { 'e','n','g'},eLANG_ENGLISH},
101        { { 'f','r','a'},eLANG_FRENCH},
102        { { 'f','r','e'},eLANG_FRENCH},
103        { { 'e','s','l'},eLANG_SPANISH},
104        { { 's','p','a'},eLANG_SPANISH},
105};
106const static int s_iso_lang_map_num = sizeof(s_iso_lang_map)/sizeof(iso_lang_map_t);
107
108#ifdef BQAM_SCRIPT
109
110/* frequencies from the channel number  i.e. 2 - 69 in MHz*/
111const unsigned short s_ch_to_freq[133] =
112{
113        57,  63,  69,  79,                 /* 2 - 5 VHF-L 2 - 6 */
114        85, 177, 183, 189,                 /* 6 - 9 VHF-H 7 - 13*/
115        195, 201, 207, 213,                     /* 10 - 13 */
116        123, 129, 135, 141,
117        147, 153, 159, 165,
118
119        171, 219, 225, 231,
120        237, 243, 249, 255,
121        261, 267, 273, 279,
122        285, 291, 297, 303,
123        309, 315, 321, 327,
124
125        333, 339, 345, 351,
126        357, 363, 369, 375,
127        381, 387, 393, 399,
128        405, 411, 417, 423,
129        429, 435, 441, 447,
130
131        453, 459, 465, 471,
132        477, 483, 489, 495,
133        501, 507, 513, 519,
134        525, 531, 537, 543, 
135        547, 555, 561, 567, 
136
137        573, 579, 585, 591, 
138        597, 603, 609, 615, 
139        621, 627, 633, 639, 
140        645, 93,  99,  105, 
141        111, 117, 651, 657,
142
143        663, 669, 675, 681,
144        687, 693, 699, 705,
145        711, 717, 723, 729,
146        735, 741, 747, 753,
147        759, 765, 771, 777,
148
149        783, 789, 795, 801,
150        813, 819, 825, 831,
151        837, 843, 849, 855,
152        861
153};
154#else
155
156/* frequencies from the channel number  i.e. 2 - 69 in MHz*/
157const unsigned short s_ch_to_freq[68] =
158{
159        57,  63,  69,  79,                 /* 2 - 5 VHF-L 2 - 6 */
160        85, 177, 183, 189,                 /* 6 - 9 VHF-H 7 - 13*/
161        195, 201, 207, 213,                     /* 10 - 13 */
162        473, 479, 485, 491,                     /* 14 - 17, 14 -  Begin UHF */
163        497, 503, 509, 515,                     /* 18 - 21 */
164        521, 527, 533, 539,                     /* 22 - 25 */
165        545, 551, 557, 563,                     /* 26 - 29 */
166        569, 575, 581, 587,                     /* 30 to 33 */
167        593, 599, 605, 611,                     /* 34 to 37 */
168        617, 623, 629, 635,                     /* 38 to 41 */
169        641, 647, 653, 659,                     /* 42 to 45 */
170        665, 671, 677, 683,                     /* 46 to 49 */
171        689, 695, 701, 707,                     /* 50 to 53 */
172        713, 719, 725, 731,                     /* 54 to 57 */
173        737, 743, 749, 755,                     /* 58 to 61 */
174        761, 767, 773, 779,                     /* 62 to 65 */
175        785, 791, 797, 803,                     /* 66 to 69 */
176};
177#endif
178const unsigned int s_ch_num = (sizeof(s_ch_to_freq)/sizeof(s_ch_to_freq[0]));
179
180#define MAX_MAJOR_CH        s_ch_num
181
182static unsigned char s_freq_list[256];
183
184static int s_freq_cnt = 0;
185
186/* useful for byte swapping PID */
187typedef struct tsp_tmp_t
188{
189        unsigned int sync_byte                      : 8;
190        unsigned int PID                            : 16;
191        unsigned int other                          : 8;
192}tsp_tmp_t;
193#define SWAP_SHORT(x)   ((((unsigned short)x & 0xFF) << 8) | (((unsigned short)x & 0xFF00) >> 8))
194
195/* This if or Little Endian only and bitfield ordering can change in some compilers*/
196typedef struct tsp_t
197{
198        unsigned int sync_byte                      : 8;
199        unsigned int PID                            : 13;
200        unsigned int transport_priority             : 1;
201        unsigned int payload_unit_start_indicator   : 1;
202        unsigned int transport_error_indicator      : 1;
203        unsigned int continuity_counter             : 4;
204        unsigned int adaptation_field_control       : 2;
205        unsigned int transport_scrambling_control   : 2;
206}tsp_t;
207/* Local function prototypes */
208
209static void chm_scan(chm_mgr_t *p_chm);
210static int chm_get_prog(chm_mgr_t *p_chm,
211                                                bapp_ch_t *p_ch,
212                                                chm_info_t *p_info         /* info structure to populate */
213                                           );
214static int chm_get_prog_details(chm_mgr_t *p_chm);
215static int chm_post_app_event(chm_mgr_t *p_chm,         /* Channel manager reference */
216                                                          chm_event_t *p_event  /* Event to post to app queue */
217                                                         );
218static int chm_stop_decode(chm_mgr_t *p_chm);
219static int chm_tune_current_freq(chm_mgr_t *p_chm);
220
221
222#define DBG_DUMP
223#ifdef DBG_DUMP
224static void DBG_HEXDUMP(unsigned char* ptr, unsigned long len)
225{
226        unsigned long i;
227        for (i=0; i<len; i++ )
228        {
229                if ( i % 16 == 0 )
230                        printf ("\n");
231                printf ("0x%02x, ", ptr[i]);
232        }
233        printf("\n\n");
234}
235#else
236        #define DBG_HEXDUMP(ptr, len)
237#endif
238
239static inline bool TS_Filter_Compare(uint8_t *msg,              /* message buffer */
240                                                                         uint8_t *inclMask,       /* inclusion Mask */ 
241                                                                         uint8_t *exclMask,       /* exclution mask */
242                                                                         uint8_t *coef,           /* filter coeficients */
243                                                                         size_t filterSize        /* filter size in words */
244                                                                        )
245{
246        bool inclResult = true;
247        bool exclResult = true;
248        bool exclEnabled = false;
249        size_t i;
250
251        /* Assumes everything is aligned which is what should be the case */
252        for (i = 0; i < filterSize; i++)
253        {
254                if ( (inclMask[i] | coef[i]) != (inclMask[i] | msg[i]) )
255                {
256                        inclResult = false;
257                        break;
258                }
259
260                if ( exclEnabled == false && exclMask[i] != 0xFF )
261                {
262                        exclEnabled = true;
263                        exclResult = false;
264                }
265
266                if ( (~exclMask[i] & coef[i]) != (~exclMask[i] & msg[i]) )
267                {
268                        exclResult = true;
269                }
270        }
271        return inclResult && exclResult;
272}
273
274/*
275Summary:
276        Get the current utc time in seconds.
277        Return non-zero on failure.
278*/
279
280static int chm_get_utctime(chm_mgr_t *p_chm, unsigned int *time )
281{
282        struct timeval tv;
283
284        if (!p_chm->got_stt)
285                return eCHM_ERR_FAILED;
286
287        gettimeofday(&tv);
288
289        *time = p_chm->sys_time + (tv.tv_sec - p_chm->sys_offset);
290
291        return 0;
292}
293
294/*
295Summary:
296        Check for cancel, returns true if a cancel occured.
297*/
298#ifdef BCM_DEBUG
299static int chm_check_cancel_ex(chm_mgr_t *p_chm ,const char* func, int line)
300        #define chm_check_cancel(chm)   chm_check_cancel_ex(chm,__FUNCTION__,__LINE__)
301#else
302static int chm_check_cancel(chm_mgr_t *p_chm )
303#endif
304{
305        unsigned int cmd;
306
307        if (p_chm->cmd == eCHM_CANCEL)
308                return 1;
309
310        cmd = (unsigned int)bos_pend_event(p_chm->queue,0);
311
312        if (cmd == (eCHM_CANCEL + 1))
313        {
314                p_chm->cmd = (chm_cmd_t)(cmd - 1);
315                BDBG_WRN(("Command canceled(%s:%d)...\n",func,line));
316
317                /* Send message to app */
318                p_chm->chm_evt.type = eCHM_EVT_CANCEL;
319                p_chm->chm_evt.id = 0;
320                chm_post_app_event(p_chm,&p_chm->chm_evt);
321        } else if (cmd > 0)
322        {
323                BDBG_WRN(("Throwing away command %d(%s:%d)...\n", (cmd - 1),func,line));
324        }
325        return(p_chm->cmd == eCHM_CANCEL) ? 1 : 0;
326} 
327
328
329
330/*
331Summary:
332        Send current signal status.
333        Return non-zero on failure.
334*/
335
336static void chm_send_status(chm_mgr_t *p_chm,unsigned int freq, bool locked)
337{
338        btuner_ds_status ds_status;
339        chm_signal_event_t *p_sig = &(p_chm->signal_evt);
340        bapp_t *p_app = (bapp_t*)p_chm->p_app;
341        memset(&(p_chm->signal_evt),0,sizeof(chm_signal_event_t));
342        p_sig->type = eCHM_EVT_SIGNAL;
343
344        if (!locked)
345        {
346                p_sig->freq_hz = freq;
347        } else if (btuner_get_ds_status(p_app->tuner,&ds_status) == b_ok)
348        {
349                /* Send message to app */
350                p_sig->freq_hz = ds_status.freq;
351                p_sig->SNR = ds_status.snr;
352                p_sig->power = ds_status.power;
353                p_sig->qam_b_mode = ds_status.mode;
354                p_sig->lock = ds_status.lock;
355        }
356        chm_post_app_event(p_chm,(chm_event_t*)&(p_chm->signal_evt));
357}
358
359static void * chm_smessage_callback(void *context, size_t data_size)
360{
361    chm_mgr_t *p_chm = (chm_mgr_t *)context;
362    /* ignore return value */
363    bos_post_event(p_chm->gen_queue, (bapp_task_event_t*)data_size);
364        return NULL;
365}
366
367static void* chm_smessage_overflow(void * context, size_t data_size)
368{
369        return NULL;
370}
371
372static int chm_getmessage(chm_mgr_t *p_chm, /* Channel manager reference */
373                          void *buf, /* buffer to copy section into */
374                          unsigned int *len, /* [in] max size of buffer, [out] section size copied into buffer */
375                          unsigned int timeout /* timeout in milliseconds */
376    )
377{
378    bresult bres;
379    size_t msg_size;
380    int result = eCHM_ERR_FAILED;
381    bapp_t *p_app = (bapp_t*)p_chm->p_app;
382    smessage_stream_params_t params;
383
384    smessage_stream_params_init(&params, p_app->smsg);
385    params.band = p_app->msg_params.band;
386    params.pid = p_app->msg_params.pid;
387    params.filter = p_app->msg_params.filter;
388    params.buffer = buf;
389    params.buffer_size = *len;
390    params.crc_disabled = p_app->msg_params.psi_crc_disabled;
391    params.data_ready_callback = chm_smessage_callback;
392    params.overflow = chm_smessage_overflow;
393    params.callback_context = (void *)p_chm;
394    params.priv = (void *)4;
395    BDBG_MSG(("pid %x fil %x tim %u len %u", params.pid, params.filter.coef[0], timeout, *len));
396    bres = smessage_start(&params, p_app->smsg);
397    if(b_ok != bres){
398        BDBG_ERR(("%s:%d",__FILE__, __LINE__));
399        goto ExitFunc;
400    }
401    msg_size = (size_t) bos_pend_event(p_chm->gen_queue, timeout);
402    if (0 == msg_size){
403        result = eCHM_ERR_TIMEOUT;
404    }else{
405        *len = msg_size;
406        result = eCHM_ERR_OK;
407    }
408    bres = smessage_stop(p_app->smsg);
409    if(b_ok != bres){
410        BDBG_ERR(("%s:%d",__FILE__, __LINE__));
411        result = eCHM_ERR_FAILED;
412        goto ExitFunc;
413    }
414
415ExitFunc:
416    return result;
417}
418        #define CHM_SC_MASK 0xc0
419        #define CHM_SC_BUFFER_SIZE (188*10)
420static unsigned char chm_sc_buffer[CHM_SC_BUFFER_SIZE];
421
422static void * chm_sc_callback(void * c, size_t msg_size)
423{
424        unsigned int * pdata_ready = (unsigned int *)c;
425        *pdata_ready = msg_size;
426        return NULL;
427}
428
429bool chm_check_sc(chm_mgr_t *p_chm, bband_t band, unsigned short pid)
430{
431        smessage_stream_t ms;
432        smessage_stream_params_t params;
433        bresult bres;
434        bool result;
435        unsigned int count;
436        volatile unsigned int data_ready;
437        unsigned char * walker;
438
439        result = false;
440        ms = smessage_open(smessage_format_tsc);
441        if (NULL == ms)
442        {
443                BDBG_ERR(("%s : smessage_open", __PRETTY_FUNCTION__));
444                goto ExitFunc;
445        }
446        smessage_stream_params_init(&params, ms);
447        params.band = band;
448        params.pid = pid;
449        params.buffer_size = CHM_SC_BUFFER_SIZE;
450        params.buffer = chm_sc_buffer;
451        params.data_ready_callback = chm_sc_callback;
452        params.overflow = chm_sc_callback;
453        params.callback_context = (void *)&data_ready;
454        data_ready = 0;
455        bres = smessage_start(&params, ms);
456        if (b_ok != bres)
457        {
458                smessage_close(ms);
459                BDBG_ERR(("%s : smessage_start", __PRETTY_FUNCTION__));
460                goto ExitFunc;
461        }
462        /* Updating unsigned int is atomic operation on mips. We can just wait for
463           callback to update our flag when data is ready */
464        count = 3;
465        do
466        {
467                bos_sleep(50);
468                count--;
469        }while ((0 == data_ready)&&(0 != count));
470
471        bres = smessage_stop(ms);
472        if (b_ok != bres)
473        {
474                smessage_close(ms);
475                BDBG_ERR(("%s : smessage_stop", __PRETTY_FUNCTION__));
476                goto ExitFunc;
477        }
478        smessage_close(ms);
479        /* Figure out if we got data and if sc flags are set */
480        if (0 != data_ready)
481        {
482                /* We have data. Check few packets for sc bits */
483                walker = chm_sc_buffer;
484                for (count = 0; count < 5; count++)
485                {
486                        if (0 != (walker[3] & CHM_SC_MASK))
487                        {
488                                goto ExitFunc;
489                        }
490                        walker += 188;
491                }
492                result = true;
493        }
494        ExitFunc:
495        BDBG_ERR(("pid %d %s", pid, (result == true ? "clear" : "encr")));
496        return result;
497}
498
499/*
500Summary:
501        Add a chanell to the channel map.
502Description:
503        Add the channel to the channel map in sorted order.
504*/
505static void chm_add_channel(chm_mgr_t *p_chm,           /* Channel manager reference */
506                                                        bapp_ch_t *p_ch
507                                                   )
508{
509        int idx,idx2, found_slot;
510        bapp_t *p_app = (bapp_t*)p_chm->p_app;
511
512        found_slot = 0;
513        for (idx = 0; idx < p_app->settings.num_channels; idx++)
514        {
515                if ((p_ch->major < p_app->settings.ch[idx].major) ||
516                        ((p_ch->major == p_app->settings.ch[idx].major) && (p_ch->minor < p_app->settings.ch[idx].minor)))
517                {
518
519                        for (idx2 = p_app->settings.num_channels - 1; idx2 >= idx; idx2--)
520                        {
521                                BDBG_MSG(("move %d.%d from %d to %d\n",p_app->settings.ch[idx2].major,p_app->settings.ch[idx2].minor, idx2, idx2 + 1));
522                                memcpy(&p_app->settings.ch[idx2 + 1],&p_app->settings.ch[idx2], sizeof(bapp_ch_t));
523                        }
524
525                        memcpy(&p_app->settings.ch[idx ],p_ch, sizeof(bapp_ch_t));
526                        BDBG_MSG(("Add %d.%d at %d\n",p_ch->major,p_ch->minor, idx));
527                        p_app->settings.ch[idx].cmd = p_chm->ant_cmd;
528                        found_slot = 1;
529                        break;
530                }
531        }
532
533        if (!found_slot)
534        {
535                memcpy(&p_app->settings.ch[p_app->settings.num_channels],p_ch, sizeof(bapp_ch_t));
536                p_app->settings.ch[p_app->settings.num_channels].cmd = p_chm->ant_cmd;
537                BDBG_MSG(("Append %d.%d at %d\n",p_ch->major,p_ch->minor, p_app->settings.num_channels));
538        }
539        p_app->settings.num_channels++;
540}
541
542/*
543Summary:
544        Check for a valid language code for the current language settings.
545        Returns the bapp_lang_t number or < 0 if not a valid language.
546*/
547
548static int chm_valid_lang(chm_mgr_t *p_chm,                     /* Channel manager reference */
549                                                  char *p_code    /* Three byte iso 639-2 language code */
550                                                 )
551{
552        int idx;
553
554        for (idx = 0; idx < s_iso_lang_map_num; ++idx)
555        {
556                char *code = s_iso_lang_map[idx].iso_lang_code;
557                if ((p_code[0] == code[0]) && (p_code[1] == code[1]) && (p_code[2] ==code[2]))
558                {
559                        return s_iso_lang_map[idx].lang;
560                }
561        }
562        BDBG_MSG(("ISO 639-2 language not found %c%c%c\n",p_code[0],p_code[1],p_code[2]));
563        return eCHM_ERR_FAILED;
564}
565
566/*
567Summary:
568        Get the program info for the program.
569Description:
570        Get the PMT for the program.
571        Returns non-zero on failure.
572*/
573
574static int chm_get_program(chm_mgr_t *p_chm,            /* Channel manager reference */
575                                                   bband_t band, 
576                                                   unsigned short prog_number,
577                                                   bapp_ch_t *p_ch
578                                                  )
579{
580        unsigned int section_size, pmt_section_size;
581        TS_PMT_stream pmt;
582        TS_PAT_program pat;
583        int result = 0;
584        int idx,p_idx;
585        bapp_t *p_app = (bapp_t*)p_chm->p_app;
586
587        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
588        p_app->msg_params.band = band;
589        p_app->msg_params.pid = (unsigned short)0;      /* PAT */
590        section_size = PAT_BUF_LEN;
591
592        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
593        {
594                BDBG_WRN(("Error getting PAT 0x%04x = %d\n",prog_number, result));
595                return result;
596        }
597
598        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
599        {
600                BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",prog_number));
601                return eCHM_ERR_FAILED;
602        }
603
604        for (idx = 0; idx < TS_PAT_getNumPrograms(p_chm->pat_buf); idx++)
605        {
606                if (TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat ) != b_ok)
607                {
608                        BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",prog_number));
609                        return eCHM_ERR_FAILED;
610                }
611
612                if (pat.program_number != prog_number)
613                        continue;
614
615                bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
616                p_app->msg_params.band = band;
617                p_app->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
618                p_app->msg_params.filter.coef[0] = 0x2;
619                p_app->msg_params.filter.mask[0] = 0x00;
620                p_app->msg_params.filter.excl[0] = 0xff;
621                pmt_section_size = PMT_BUF_LEN;
622                if ((result = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT)) != 0)
623                {
624                        BDBG_ERR(("Error getting PAT 0x%04x\n",prog_number));
625                        return result;
626                }
627
628                p_ch->pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
629
630                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
631                {
632                        TS_PSI_descriptor psi_desc,lang_desc;
633                        int strm_idx;
634                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
635                        {
636                                BDBG_WRN(("Failure processing PMT %d\n",p_idx));
637                                return eCHM_ERR_FAILED;
638                        }
639
640                        strm_idx = 0;
641                        lang_desc = NULL;
642                        while ((psi_desc = TS_PMT_getStreamDescriptor(p_chm->pmt_buf,pmt_section_size, p_idx,strm_idx)) != NULL)
643                        {
644                                if (psi_desc[0] == TS_PSI_DT_ISO639Language) /* 0x0A ISO-639 Language descriptor */
645                                {
646                                        BDBG_WRN(("ISO-639 DESC\n" ));
647                                        lang_desc = psi_desc;
648                                        break;
649                                }
650                                strm_idx++;
651                                if (strm_idx > 0xFF)
652                                {
653                                        BDBG_ERR(("PMT Stream Desc limit exceeded %d\n",strm_idx));
654                                        break;
655                                }
656                                if (chm_check_cancel(p_chm))
657                                {
658                                        return eCHM_ERR_CANCELED;
659                                }
660                        }
661
662                        if (pmt.stream_type == 0x02) /* Video */
663                        {
664                                BDBG_WRN(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
665                                if (!p_ch->video_pid)
666                                {
667                                        p_ch->video_pid = pmt.elementary_PID;
668                                }
669#ifdef BQAM_SCRIPT
670                        } else if (pmt.stream_type == 0x80)     /* digicipher */
671                        {
672                                BDBG_WRN(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
673                                if (!p_ch->video_pid)
674                                {
675                                        p_ch->video_pid = pmt.elementary_PID;
676                                }
677#endif
678                        } else if (pmt.stream_type == 0x81)
679                        {
680                                BDBG_WRN(("Audio PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
681
682                                if (!p_ch->audio_pid[0])
683                                {
684                                        p_ch->audio_pid[0] = pmt.elementary_PID;
685                                }
686                        }
687                        else
688                        {
689                                /* We only support the above 3 types of stream */ 
690                                BDBG_WRN(("Unsupported stream type[0x%02x]\n", pmt.stream_type ));
691                                return eCHM_ERR_FAILED;
692                        }
693                }
694                break;
695        }
696        return result;
697}
698/*
699Summary:
700        Scan for channels using PSI.
701Description:
702        Scan for channels using PSI.
703        Returns number of channels added.
704*/
705
706static int chm_scan_psi(chm_mgr_t *p_chm,               /* Channel manager reference */
707                                                bband_t band, int freq_idx)
708{
709        unsigned int section_size, pmt_section_size;
710        TS_PMT_stream pmt;
711        TS_PAT_program pat;
712        int result = 0;
713        int idx,p_idx,tresult, desc_idx;
714        bapp_ch_t ch;
715        bapp_t *p_app = (bapp_t*)p_chm->p_app;
716        TS_PSI_descriptor psi_desc;
717        unsigned short ca_pid = 0;
718
719        /* Get the VCT */
720        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
721        p_app->msg_params.band = band;
722        p_app->msg_params.pid = (unsigned short)0;      /* PAT */
723        section_size = PAT_BUF_LEN;
724
725        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
726        {
727                BDBG_WRN(("Timeout getting PAT\n"));
728                return result;
729        }
730        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
731        {
732                BDBG_WRN(("TS_PAT_validate failed\n"));
733                return eCHM_ERR_FAILED;
734        }
735
736        for (idx = 0; idx < TS_PAT_getNumPrograms(p_chm->pat_buf); idx++)
737        {
738                if (chm_check_cancel(p_chm))
739                {
740                        return eCHM_ERR_CANCELED;
741                }
742
743                memset(&ch,0,sizeof(ch));
744                section_size = PAT_BUF_LEN;
745                if (TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat ) != b_ok)
746                {
747                        BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",pat.PID));
748                        return eCHM_ERR_FAILED;
749                }
750
751                bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
752                p_app->msg_params.band = band;
753                p_app->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
754                p_app->msg_params.filter.coef[0] = 0x2;
755                p_app->msg_params.filter.mask[0] = 0x00;
756                p_app->msg_params.filter.excl[0] = 0xff;
757                pmt_section_size = PMT_BUF_LEN;
758                if ((tresult = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT)) != 0)
759                {
760                        BDBG_WRN(("Failed getting PMT 0x%04x\n",pat.PID));
761                        continue;
762                }
763
764                ch.major = (freq_idx == 0x7F) ? 0 : freq_idx+2; //freq_idx is off by 2
765                ch.minor = idx + 1;
766                ch.freq_idx = freq_idx;
767                ch.pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
768                ca_pid = 0;
769#ifdef DTA_TEST
770                ch.program_number = pat.program_number;
771#endif
772                /* Get CA pid for cable */
773                desc_idx = 0;
774                while ((psi_desc = TS_PMT_getDescriptor(p_chm->pmt_buf, pmt_section_size,desc_idx++)) != NULL)
775                {
776                        if (desc_idx > 0xFF)
777                        {
778                                BDBG_ERR(("PMT Desc limit exceeded %d\n",desc_idx));
779                                break;
780                        }
781                        if (chm_check_cancel(p_chm))
782                        {
783                                return eCHM_ERR_CANCELED;
784                        }
785                        if (psi_desc[0] == 9)
786                        {
787                                ca_pid = (((unsigned short)(psi_desc[4] & 0x1F)) << 8) | (unsigned short)psi_desc[5];
788                                BDBG_WRN(("CA PID = 0x%04x\n",ca_pid));
789                                break;
790                        }
791                }
792                if (ca_pid != 0x0000)
793                {
794                        BDBG_WRN(("Program has CA PID 0x%02x so skip it\n",ca_pid));
795                        //continue;
796                }
797
798                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
799                {
800                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
801                        {
802                                BDBG_WRN(("Failure processing PMT %d\n",p_idx));
803                                return eCHM_ERR_FAILED;
804                        }
805                        if (pmt.stream_type == 0x02) /* Video */
806                        {
807                                BDBG_MSG(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
808                                if (!ch.video_pid)
809                                        ch.video_pid = pmt.elementary_PID;
810                        } else if (pmt.stream_type == 0x81)
811                        {
812                                BDBG_MSG(("Audio PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
813                                if (!ch.audio_pid[0])
814                                        ch.audio_pid[0] = pmt.elementary_PID;
815                        }
816#ifdef BQAM_SCRIPT
817                        else if ( pmt.stream_type == 0x80) //digicipher
818                        {
819                                BDBG_MSG(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
820                                if (!ch.video_pid)
821                                        ch.video_pid = pmt.elementary_PID;
822                        }
823                }
824
825                if ((ch.video_pid) || (ch.audio_pid[0]))
826                {
827                        bool clear;
828                        unsigned short pid;
829                        if (ch.video_pid)
830                                pid = (unsigned short)ch.video_pid;
831                        else
832                                pid     = (unsigned short)ch.audio_pid[0];
833
834                        clear = chm_check_sc(p_chm, band, pid);
835                        if (clear)
836                        {
837                                ch.psi = 1;
838                                chm_add_channel(p_chm,&ch);
839                                result += 1;
840                        }
841                }
842#else
843                ch.psi = 1;
844                chm_add_channel(p_chm,&ch);
845                result += 1;
846                }
847#endif
848        }
849
850        return result;
851}
852
853/*
854Summary:
855        Scan for channels using VCT.
856Description:
857        Scan for channels using VCT.
858        Returns number of channels added.
859*/
860
861static int chm_scan_vct(chm_mgr_t *p_chm,               /* Channel manager reference */
862                                                bband_t band, int freq_idx)
863{
864        unsigned int section_size;
865        int minor_idx;
866        bool got_vct;
867        unsigned char section_number;
868        int result = 0;
869        bapp_ch_t ch;
870        bapp_t *p_app = (bapp_t*)p_chm->p_app;
871        PSIP_VCT_channel    vct;
872        unsigned int timeout;
873        bool have_program;
874        char dst;
875        int local_offset;
876        timeout = bos_getticks() + MS_TO_TICKS(3 * VCT_TIMEOUT );
877
878        memset(&vct,0,sizeof(vct));
879
880        /* Get the VCT */
881        section_number = 0;
882        do
883        {
884                bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
885                p_app->msg_params.band = band;
886                p_app->msg_params.pid = 0x1ffb; /* VCT */
887
888                p_app->msg_params.filter.coef[0] = 0xc8;        /* Table ID for terrestrial */
889                p_app->msg_params.filter.mask[0] = 0x01;
890                p_app->msg_params.filter.excl[0] = 0xff;
891                p_app->msg_params.filter.coef[6] = section_number;      /* section number */
892                p_app->msg_params.filter.mask[6] = 0x00;
893                p_app->msg_params.filter.excl[6] = 0xff;
894                /* All PSIP tables have protocol_version which must be = 0 */
895                p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
896                p_app->msg_params.filter.mask[8] = 0x00;
897                p_app->msg_params.filter.excl[8] = 0xff;
898
899                got_vct = false;
900                do
901                {
902                        section_size = VCT_BUF_LEN;
903
904                        if (chm_getmessage(p_chm,p_chm->vct_buf,&section_size, VCT_TIMEOUT) != 0)
905                        {
906                                BDBG_WRN(("Timeout waiting for VCT!"));
907                                if (chm_check_cancel(p_chm))
908                                {
909                                        return eCHM_ERR_CANCELED;
910                                }
911                                return eCHM_ERR_TIMEOUT;
912                        }
913
914                        if (PSIP_VCT_getNumChannels(p_chm->vct_buf) == 0)
915                        {
916                                BDBG_WRN(("No VCT Found!"));
917                                break;
918                        }
919
920                        BDBG_MSG(("Adding PSIP_VCT_getNumChannels %d!",PSIP_VCT_getNumChannels(p_chm->vct_buf)));
921
922                        for (minor_idx = 0; minor_idx < PSIP_VCT_getNumChannels(p_chm->vct_buf); ++minor_idx)
923                        {
924                                int desc_idx;
925                                TS_PSI_descriptor psi_desc;
926                                got_vct = true;
927                                BDBG_MSG(("Get VCT[%d]\n",minor_idx));
928                                have_program = false;
929                                if (PSIP_VCT_getChannel( (const uint8_t *)p_chm->vct_buf, minor_idx, &vct ) == BERR_SUCCESS)
930                                {
931                                        if ((vct.hidden) || (vct.minor_channel_number == 0))
932                                        {
933                                                BDBG_WRN(("Channel hidden or analog channel %d, %d",vct.hidden,vct.minor_channel_number));
934                                                continue;
935                                        }
936
937                                        memset(&ch,0,sizeof(ch));
938                                        ch.freq_idx = freq_idx;
939                                        ch.minor = vct.minor_channel_number;
940                                        ch.major = vct.major_channel_number;
941                                        memcpy(ch.ch_name,vct.short_name,MAX_CH_NAME_CHARS * sizeof(unsigned short));
942
943                                        desc_idx = 0;
944                                        while ((psi_desc = PSIP_VCT_getChannelDescriptor(p_chm->vct_buf, minor_idx,desc_idx)) != NULL)
945                                        {
946                                                if (psi_desc[0] == 0xA1) /* Service location descriptor */
947                                                {
948                                                        PSIP_SLD_header sld_header;
949                                                        PSIP_SLD_element sld_elem;
950                                                        int sld_idx,lidx,num_aud;
951                                                        PSIP_SLD_getHeader(psi_desc,&sld_header);
952                                                        have_program = true;
953
954                                                        ch.pcr_pid = sld_header.PCR_PID;
955                                                        BDBG_MSG(("SLD number_elements = %d\n",sld_header.number_elements ));
956                                                        BDBG_MSG(("PCR PID = 0x%04x\n",ch.pcr_pid ));
957
958                                                        num_aud = 0;
959                                                        for (sld_idx = 0; sld_idx < sld_header.number_elements; ++sld_idx)
960                                                        {
961                                                                if (PSIP_SLD_getElement(psi_desc,sld_idx,&sld_elem) != BERR_SUCCESS)
962                                                                {
963                                                                        BDBG_WRN(("Error processing SLD Desc %d of %d",sld_idx,sld_header.number_elements));
964                                                                        break;
965                                                                }
966
967                                                                if (sld_elem.stream_type == 0x02) /* Video */
968                                                                {
969                                                                        BDBG_WRN(("Video PID[%d] = 0x%04x\n",sld_idx,sld_elem.elementary_PID ));
970                                                                        if (!ch.video_pid)
971                                                                        {
972                                                                                ch.video_pid = sld_elem.elementary_PID;
973                                                                        }
974#ifdef BQAM_SCRIPT
975                                                                } else if (sld_elem.stream_type == 0x80) /* digicipher */
976                                                                {
977                                                                        BDBG_WRN(("Video PID[%d] = 0x%04x\n",sld_idx,sld_elem.elementary_PID ));
978                                                                        if (!ch.video_pid)
979                                                                        {
980                                                                                ch.video_pid = sld_elem.elementary_PID;
981                                                                        }
982#endif
983                                                                } else if (sld_elem.stream_type == 0x81)
984                                                                {
985                                                                        BDBG_MSG(("Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
986                                                                                          sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
987                                                                        num_aud++;
988                                                                        if ((lidx = chm_valid_lang(p_chm,sld_elem.ISO_639_language_code)) >= 0 )
989                                                                        {
990                                                                                if (ch.audio_pid[lidx] != 0)
991                                                                                {
992                                                                                        BDBG_WRN(("Duplicate language Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
993                                                                                                          sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
994                                                                                } else
995                                                                                {
996                                                                                        ch.audio_pid[lidx] = sld_elem.elementary_PID;
997                                                                                        ch.has_lang |= 1 << lidx;
998                                                                                }
999                                                                        } else
1000                                                                        {
1001                                                                                BDBG_WRN(("Throwing out Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
1002                                                                                                  sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
1003                                                                        }
1004                                                                }
1005                                                        }
1006
1007                                                        /* Backup plan if there is no valid language code */
1008                                                        if ((ch.audio_pid[0] == 0) && (ch.audio_pid[1] == 0) && (ch.audio_pid[2] == 0) && num_aud)
1009                                                        {
1010                                                                BDBG_WRN(("No valid audio PID found for languages in audio %d descs...\n",num_aud));
1011                                                                num_aud = 0;
1012                                                                for (sld_idx = 0; sld_idx < sld_header.number_elements; ++sld_idx)
1013                                                                {
1014                                                                        if (PSIP_SLD_getElement(psi_desc,sld_idx,&sld_elem) != BERR_SUCCESS)
1015                                                                        {
1016                                                                                BDBG_WRN(("Error processing SLD Desc %d of %d",sld_idx,sld_header.number_elements));
1017                                                                                break;
1018                                                                        }
1019
1020                                                                        if (sld_elem.stream_type == 0x81)
1021                                                                        {
1022                                                                                BDBG_WRN(("Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
1023                                                                                                  sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
1024                                                                                ch.has_lang |= 1 << num_aud;
1025                                                                                ch.audio_pid[num_aud++] = sld_elem.elementary_PID;
1026                                                                        }
1027                                                                }
1028                                                        }
1029                                                }
1030                                                desc_idx++;
1031                                                if (desc_idx > 0xFF)
1032                                                {
1033                                                        BDBG_ERR(("VCT Channel Desc limit exceeded %d\n",desc_idx));
1034                                                        break;
1035                                                }
1036                                                if (chm_check_cancel(p_chm))
1037                                                {
1038                                                        return eCHM_ERR_CANCELED;
1039                                                }
1040                                        }
1041                                        if (!have_program)
1042                                        {
1043                                                if (chm_get_program(p_chm,band,vct.program_number,&ch) == 0)
1044                                                {
1045                                                        BDBG_MSG(("program V: 0x%04x, A: 0x%04x, PCR: 0x%04x\n",ch.video_pid,ch.audio_pid,ch.pcr_pid));
1046                                                        have_program = true;
1047                                                }
1048                                        }
1049
1050
1051                                        if (p_chm->local_time_source == eTS_NONE)
1052                                        {
1053                                                if (p_app->settings.time_zone != 0)
1054                                                {
1055                                                        p_chm->local_time_source = eTS_FIXED;
1056                                                        p_chm->local_offset = 0 - (int)g_tz_map[p_app->settings.time_zone];
1057                                                        p_app->chm.local_offset *= 3600;
1058                                                        p_chm->local_dst_obs = p_app->settings.dst;
1059                                                        BDBG_WRN(("### Local time %d Fixed ###\n",p_chm->local_offset));
1060                                                }
1061                                                /* set local time offset */
1062                                                else if ((tsid_to_utc_offset(vct.channel_TSID,&local_offset,&dst) == 0))
1063                                                {
1064                                                        p_chm->local_time_source = eTS_TSID;
1065                                                        p_chm->local_offset = local_offset;
1066                                                        p_chm->local_dst_obs = dst;
1067                                                        BDBG_WRN(("### Local time %d from TSID 0x%04x ###\n",local_offset,vct.channel_TSID));
1068                                                }
1069                                        }
1070
1071                                        if (have_program)
1072                                        {
1073                                                chm_add_channel(p_chm,&ch);
1074                                                result += 1;
1075                                        }
1076                                } else
1077                                {
1078                                        BDBG_WRN(("PSIP_VCT_getChannel %d failed",minor_idx));
1079                                }
1080                        }
1081                }while ((section_size != 0) && !got_vct);
1082
1083                if (chm_check_cancel(p_chm))
1084                {
1085                        return eCHM_ERR_CANCELED;
1086                }
1087     
1088     
1089                section_number++;
1090        }while ((section_number <= p_chm->vct_buf[7]) && (timeout < bos_getticks()));
1091
1092        return((result > 0) || (timeout < bos_getticks())) ? result : eCHM_ERR_TIMEOUT;
1093}
1094
1095
1096/*
1097Summary:
1098        Clear the current channel info.
1099*/
1100
1101static void chm_make_current(chm_mgr_t *p_chm, chm_info_t *p_info)
1102{
1103        /* Clear current info */
1104        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok)
1105        {
1106                memcpy(&p_chm->cur_info,p_info,sizeof(chm_info_t));
1107                bos_release_mutex(&p_chm->mutex);
1108        }
1109}
1110
1111/*
1112Summary:
1113        Clear the current channel info.
1114*/
1115
1116static int chm_clear_current(chm_mgr_t *p_chm)
1117{
1118        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1119        /* Clear current info */
1120        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok)
1121        {
1122                memset(&p_chm->cur_info,0,sizeof(chm_info_t));
1123                p_app->prog_rating_str[0] = 0;
1124                p_app->psip_rating_str[0] = 0;
1125                BDBG_MSG(("%s reset rating string @ %d\n",__FUNCTION__,__LINE__));
1126                p_app->tv_rating = 0;
1127
1128                p_chm->got_stt = false;
1129                bos_release_mutex(&p_chm->mutex);
1130        }
1131        return 0;
1132}
1133
1134/*
1135Summary:
1136        process the MMS string and associated tables.
1137        Returns non-zero on failure.
1138*/
1139
1140int chm_process_mss(chm_mgr_t *p_chm,                           /* Channel manager reference */
1141                                        PSIP_MSS_string p_mms,                  /* Pointer to MMS */
1142                                        unsigned char* mms_buf,                 /* string buffer */
1143                                        unsigned int mms_len                    /* string buffer length */
1144                                   )
1145{
1146        int str_idx,lsize;
1147        char *p_code;
1148        BERR_Code retcode;
1149        int num_str;
1150        bapp_t *p_app;
1151
1152        if (!p_mms)
1153                return eCHM_ERR_FAILED;
1154
1155        num_str = PSIP_MSS_getNumStrings(p_mms);
1156        p_app = (bapp_t*)p_chm->p_app;
1157        memset(mms_buf,0,mms_len);
1158
1159        for (str_idx = 0; str_idx < num_str; ++str_idx)
1160        {
1161                if ((retcode = PSIP_MSS_getCode(p_mms,str_idx, &p_code)) != BERR_SUCCESS)
1162                {
1163                        BDBG_WRN(("PSIP_MSS_getCode:%d failed %d\n",__LINE__,retcode));
1164                        memset(mms_buf,0,mms_len);
1165                        continue;
1166                }
1167
1168                lsize = mms_len;
1169                if (chm_valid_lang(p_chm,p_code) != p_app->lang)
1170                {
1171#ifdef BCM_DEBUG
1172                        if ((retcode = PSIP_MSS_getString(p_mms,str_idx,&lsize, mms_buf)) != BERR_SUCCESS)
1173                        {
1174                                BDBG_WRN(("PSIP_MSS_getCode:%d failed %d\n",__LINE__,retcode));
1175                        }
1176
1177                        if (lsize > 0)
1178                        {
1179                                BDBG_MSG(("Lang mismatch %c%c%c %s\n",p_code[0],p_code[1],p_code[2],mms_buf));
1180                        }
1181                        memset(mms_buf,0,mms_len);
1182#endif
1183                        continue;
1184                }
1185
1186
1187                if ((retcode = PSIP_MSS_getString(p_mms,str_idx,&lsize, mms_buf)) != BERR_SUCCESS)
1188                {
1189                        BDBG_ERR(("MSS invalid %d\n",retcode));
1190                        memset(mms_buf,0,mms_len);
1191                }
1192
1193                BDBG_MSG(("%s:%d idx = %d, %d/%d-%s\n",__FUNCTION__,__LINE__,str_idx,lsize,mms_len,mms_buf));
1194
1195                return 0;
1196        }
1197
1198        /* in case no valid language exists just use first string */
1199        if (num_str > 0)
1200        {
1201                lsize = mms_len;
1202                if ((retcode = PSIP_MSS_getString(p_mms,0,&lsize, mms_buf)) == BERR_SUCCESS)
1203                {
1204                        BDBG_WRN(("No language match using default\n"));
1205                        return eCHM_ERR_OK;
1206                } else
1207                {
1208                        BDBG_WRN(("PSIP_MSS_getString failed %d\n",retcode));
1209                }
1210
1211        }
1212        BDBG_WRN(("%s:%d no valid string found, num_str = %d\n",__FUNCTION__,__LINE__,num_str));
1213        return eCHM_ERR_FAILED;
1214}
1215
1216/*
1217Summary:
1218        process the VCT .
1219        Returns non-zero on failure.
1220*/
1221
1222static int chm_process_vct(chm_mgr_t *p_chm,            /* Channel manager reference */
1223                                                   unsigned char *msg_buf, /* Buffer containing the MGT table */
1224                                                   unsigned int msg_size,  /* PSI buffer size */
1225                                                   chm_info_t *p_info,     /* info structure to populate */
1226                                                   unsigned short minor    /* minor ch number */   
1227                                                  )
1228{
1229        int minor_idx,sld_idx,local_offset;
1230        TS_PSI_descriptor psi_desc;
1231        PSIP_VCT_channel    vct;
1232        char dst;
1233        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1234
1235        memset(&vct,0,sizeof(vct));
1236
1237        if (PSIP_VCT_getNumChannels(msg_buf) == 0)
1238                return eCHM_ERR_FAILED;
1239
1240        for (minor_idx = 0; minor_idx < PSIP_VCT_getNumChannels(msg_buf); ++minor_idx)
1241        {
1242                if (chm_check_cancel(p_chm))
1243                        return eCHM_ERR_CANCELED;
1244
1245                if (PSIP_VCT_getChannel( (const uint8_t *)msg_buf, minor_idx, &vct ) != BERR_SUCCESS)
1246                {
1247                        BDBG_WRN(("Failure processing VCT %d\n",minor_idx));
1248                        return eCHM_ERR_FAILED;
1249                }
1250                if (vct.minor_channel_number != minor)
1251                {
1252                        BDBG_WRN(("VCT for %d not %d\n",vct.minor_channel_number, minor));
1253                        memset(&vct,0,sizeof(vct));
1254                        continue;
1255                }
1256                p_info->major = vct.major_channel_number;
1257                p_info->minor = vct.minor_channel_number;
1258                p_info->source_id = vct.source_id;
1259                p_info->program_number = vct.program_number;
1260                memcpy(p_info->ch_name, vct.short_name,sizeof(uint16_t) * MAX_CH_NAME_CHARS),
1261                p_info->got_vct = true;
1262
1263                if (p_chm->local_time_source == eTS_NONE)
1264                {
1265                        if (p_app->settings.time_zone != 0)
1266                        {
1267                                p_chm->local_time_source = eTS_FIXED;
1268                                p_chm->local_offset = 0 - (int)g_tz_map[p_app->settings.time_zone];
1269                                p_app->chm.local_offset *= 3600;
1270                                p_chm->local_dst_obs = p_app->settings.dst;
1271                                BDBG_WRN(("### Local time %d Fixed ###\n",p_chm->local_offset));
1272                        }
1273                        /* set local time offset */
1274                        else if ((tsid_to_utc_offset(vct.channel_TSID,&local_offset,&dst) == 0))
1275                        {
1276                                p_chm->local_time_source = eTS_TSID;
1277                                p_chm->local_offset = local_offset;
1278                                p_chm->local_dst_obs = dst;
1279                                BDBG_WRN(("### Local time %d from TSID 0x%04x ###\n",local_offset,vct.channel_TSID));
1280                        }
1281                }
1282
1283                sld_idx = 0;
1284                while ((psi_desc = PSIP_VCT_getChannelDescriptor(msg_buf, minor_idx,sld_idx)) != NULL)
1285                {
1286                        if (psi_desc[0] == 0xA0) /* Extended channel name descriptor */
1287                        {
1288                                PSIP_MSS_string lstr = PSIP_ECND_getLongChannelName(psi_desc);
1289                                chm_process_mss(p_chm,lstr,p_info->ext_ch_name,MAX_LONG_NAME_CHARS);
1290                        }
1291                        sld_idx++;
1292                }
1293                return eCHM_ERR_OK;
1294        }
1295        return eCHM_ERR_FAILED; /* channel not found */
1296}
1297
1298/*
1299Summary:
1300        Get channel info details for tuning.
1301Description:
1302        Get channel info details for tuning.
1303        Returns non-zero on failure.
1304*/
1305
1306static int chm_get_prog(chm_mgr_t *p_chm,               /* Channel manager reference */
1307                                                bapp_ch_t *p_ch,
1308                                                chm_info_t *p_info         /* info structure to populate */
1309                                           )
1310{
1311        unsigned int section_size;
1312        int result = eCHM_ERR_FAILED;
1313        unsigned char section_number;
1314        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1315
1316        section_number = 0;
1317        do
1318        {
1319                /* Get the VCT */
1320                bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
1321                p_app->msg_params.band = p_app->band;
1322                p_app->msg_params.pid = 0x1ffb; /* VCT */
1323                section_size = VCT_BUF_LEN;
1324
1325                p_app->msg_params.filter.coef[0] = 0xc8;        /* Table ID for terrestrial */
1326                p_app->msg_params.filter.mask[0] = 0x01;
1327                p_app->msg_params.filter.excl[0] = 0xff;
1328                p_app->msg_params.filter.coef[6] = section_number;      /* section number */
1329                p_app->msg_params.filter.mask[6] = 0x00;
1330                p_app->msg_params.filter.excl[6] = 0xff;
1331                /* All PSIP tables have protocol_version which must be = 0 */
1332                p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
1333                p_app->msg_params.filter.mask[8] = 0x00;
1334                p_app->msg_params.filter.excl[8] = 0xff;
1335
1336                if (chm_getmessage(p_chm,p_chm->vct_buf,&section_size, VCT_TIMEOUT) != 0)
1337                {
1338                        BDBG_WRN(("%s timeout waiting for VCT (section # %d)\n",__FUNCTION__,section_number));
1339                        return result;
1340                }
1341
1342                if (chm_check_cancel(p_chm))
1343                        return eCHM_ERR_CANCELED;
1344
1345                result = chm_process_vct(p_chm,p_chm->vct_buf, section_size, 
1346                                                                 p_info,p_app->settings.ch[p_chm->cur_ch_num].minor);
1347                if (result != 0)
1348                {
1349                        BDBG_WRN(("VCT entry not found %d\n",section_number));
1350                        section_number++;
1351                        continue;
1352                }
1353
1354                if ((result = chm_get_program(p_chm,p_app->band,p_info->program_number,p_ch)) != 0)
1355                {
1356                        BDBG_WRN(("Failure processing PMT, %d\n",p_info->program_number ));
1357                        return result;
1358                }
1359
1360
1361                result = 0;
1362                break;
1363        }while (section_size != 0); 
1364
1365        return result;
1366}
1367/*
1368Summary:
1369        Generic tuner cancel callback.
1370*/
1371void chm_tune_cancel_callback(void *context)
1372{
1373        bapp_t    *p_app    =    (   bapp_t    *)context;
1374
1375        if (chm_check_cancel(&p_app->chm))
1376        {
1377                BDBG_WRN(("### CANCEL TUNE ###\n"));
1378                p_app->ds.cancel = true;
1379        }
1380}
1381
1382#if 1
1383
1384/*
1385 * Scan command history for best command value.
1386 */
1387
1388static int chm_check_hist(chm_mgr_t *p_chm, unsigned char *best)
1389{
1390        int idx,max,max_idx;
1391        max = 0;
1392        max_idx = -1;
1393        for (idx = 0; idx < MAX_CMD_HIST; ++idx)
1394        {
1395                if (!p_chm->cmd_hist[idx].locked)
1396                        continue;
1397
1398                if (p_chm->cmd_hist[idx].snr > max)
1399                {
1400                        max = p_chm->cmd_hist[idx].snr;
1401                        max_idx = idx;
1402                }
1403        }
1404
1405        if (max_idx >= 0)
1406        {
1407                *best =  p_chm->cmd_hist[max_idx].cmd;
1408                return 0;
1409        }
1410
1411        return -1;
1412}
1413
1414/*
1415Summary:
1416        Find the best smart antenna setting, assumes tuner is tuned. Return
1417        non-zero on failure to find a setting.
1418*/
1419        #define MAX_SMART_STATUS        8
1420static int chm_config_smart(chm_mgr_t *p_chm,           /* Channel manager reference */
1421                                                        int idx)
1422{
1423        uint8_t coarse_dir,dir,polarity,preamp_gain,cmd;
1424        uint8_t num_dir,num_coarse, num_polarity,num_preamp_gain;
1425        uint32_t freq = (unsigned int)s_ch_to_freq[0];
1426
1427        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1428        btuner_ds_status ds_status;
1429
1430        if ((p_app->ch_scan_type == eQUICK_SCAN) || (p_app->ch_scan_type == eQUICK_RESCAN))
1431        {
1432                num_dir = num_polarity = num_preamp_gain = 1;
1433                num_coarse = 5;
1434        } else
1435        {
1436                num_dir = 4; num_polarity = 1; num_preamp_gain = 4;
1437                num_coarse = 4;
1438        }
1439
1440        /* Reset history */
1441        memset(p_chm->cmd_hist,0,sizeof(cmd_hist_t) * MAX_CMD_HIST);
1442
1443        /* Do smart scan */
1444        for (coarse_dir = 0; coarse_dir < num_coarse; ++coarse_dir)
1445        {
1446                for (dir = 0; dir < num_dir; ++dir)
1447                {
1448                        for (polarity = 0; polarity < num_polarity; ++polarity)
1449                        {
1450                                for (preamp_gain = 0; preamp_gain < num_preamp_gain; ++preamp_gain)
1451                                {
1452                                        if (coarse_dir==4)
1453                                        {
1454                                                /* only gets here for eQUICK_SCAN only, for 5th face of smart antenna */
1455                                                cmd =  (0x2 << 5);
1456                                                cmd |= (0x2 << 3);
1457                                        } else
1458                                        {
1459                                                cmd = (coarse_dir << 5);
1460                                                cmd |= (dir << 3);
1461                                        }
1462                                        cmd |= (polarity << 2);
1463                                        cmd |= preamp_gain;
1464
1465                                        bant_send(cmd,idx + 2);
1466
1467                                        /* Check to see if scan was canceled */
1468                                        if (chm_check_cancel(p_chm))
1469                                                return -1;
1470
1471                                        bos_sleep(25);
1472
1473                                        freq = (unsigned int)s_ch_to_freq[idx];
1474                                        freq *= 1000000; /* convert to Hz */
1475                                        btuner_ds_params_init(&p_app->ds, p_app->tuner);
1476                                        p_app->ds.timeout = 16; /* 50ms * 16 = 800ms timeout */
1477                                        p_app->ds.cancel_callback = chm_tune_cancel_callback;
1478                                        p_app->ds.cancel_callback_context = p_app;
1479                                        p_app->ds.wait_for_lock = true;
1480#ifdef BQAM_SCRIPT
1481                                        p_app->ds.fecMode = eFEC_ANNEX_B;
1482                                        p_app->ds.qamMode = eQAM_Scan;
1483#endif
1484                                        if (btuner_tune_ds(p_app->tuner, freq, &p_app->ds) < 0)
1485                                        {
1486                                                continue;
1487                                        } else
1488                                        {
1489                                                btuner_get_ds_status(p_app->tuner, &ds_status);
1490                                                if (!ds_status.lock || (ds_status.snr > 40))
1491                                                {
1492                                                        int tidx;
1493                                                        BDBG_WRN(("strange SNR try again(%d,%d, cmd = 0x%02x,snr = %d)\n",idx,freq,cmd,ds_status.snr));
1494
1495                                                        for (tidx = 0; tidx < 50; ++tidx)
1496                                                        {
1497                                                                bos_sleep(20);
1498                                                                btuner_get_ds_status(p_app->tuner, &ds_status);
1499                                                                if (ds_status.lock && (ds_status.snr > 14) && (ds_status.snr < 40))
1500                                                                {
1501                                                                        break;
1502                                                                }
1503                                                                /* Check to see if scan was canceled */
1504                                                                if (chm_check_cancel(p_chm))
1505                                                                        return -1;
1506                                                        }
1507
1508                                                        if (!ds_status.lock || (ds_status.snr <= 14) || (ds_status.snr >= 40))
1509                                                        {
1510                                                                BDBG_WRN(("Could not re-lock(%d,%d, cmd = 0x%02x,snr = %d)\n",idx,freq,cmd,ds_status.snr));
1511                                                                continue;
1512                                                        }
1513                                                }
1514
1515                                                p_chm->cmd_hist[cmd].cmd = cmd;
1516                                                p_chm->cmd_hist[cmd].locked = ds_status.lock;
1517                                                p_chm->cmd_hist[cmd].snr = ds_status.snr;
1518                                                BDBG_WRN(("%s (%d,%d, cmd = 0x%02x,snr = %d)\n",__FUNCTION__,idx,freq,cmd,ds_status.snr));
1519                                                break;
1520                                        }
1521                                } /* preamp_gain */
1522                        } /* polarity */
1523                } /* dir */
1524        } /* course_dir */
1525
1526        /* find best command value based on SNR value */
1527        if (chm_check_hist(p_chm,&cmd) == 0)
1528        {
1529                BDBG_WRN(("%s best cmd(%d,%d, cmd = 0x%02x)\n",__FUNCTION__,idx,freq,cmd));
1530                p_chm->ant_cmd = cmd;
1531
1532                /* Check to see if scan was canceled */
1533                if (chm_check_cancel(p_chm))
1534                        return -1;
1535
1536                /* Send the command to put antenna in the best state */
1537                bant_send(cmd,idx + 2);
1538
1539                bos_sleep(25);
1540                return 0;
1541        } else
1542        {
1543                p_chm->ant_cmd = 0xFF;
1544                BDBG_WRN(("%s none(%d,%d, cmd = 0x%02x)\n",__FUNCTION__,idx,freq,p_chm->ant_cmd));
1545        }
1546        return -1;
1547}
1548/*
1549Summary:
1550        Scan for channels to create a channel map.
1551Description:
1552        Scan for all available channels.
1553*/
1554
1555static void chm_stream_close(chm_mgr_t *p_chm           /* Channel manager reference */
1556                                                        )
1557
1558{
1559        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1560        if (p_app->stream)
1561        {
1562                if (p_chm->stt_msg != NULL)
1563                {
1564                        if(b_ok != smessage_stop(p_chm->stt_msg)){
1565                            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
1566                        }
1567                        smessage_close(p_chm->stt_msg);
1568                        p_chm->stt_msg = NULL;
1569                }
1570                if (p_chm->rrt_msg != NULL)
1571                {
1572                        if(b_ok != smessage_stop(p_chm->rrt_msg)){
1573                            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
1574                        }
1575                        smessage_close(p_chm->rrt_msg);
1576                        p_chm->rrt_msg = NULL;
1577                }
1578                bstream_close(p_app->stream);
1579                p_app->stream = 0;
1580        }
1581}
1582
1583
1584/*
1585Summary:
1586        Is frequency in the list of channels.
1587*/
1588
1589static bool chm_find_freq_idx(chm_mgr_t *p_chm,         /* Channel manager reference */
1590                                        unsigned char freq_idx)
1591{
1592        int ch_idx;
1593        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1594
1595        for (ch_idx = 0; ch_idx < p_app->settings.num_channels; ch_idx++)
1596        {
1597                if (p_app->settings.ch[ch_idx].freq_idx == freq_idx)
1598                {
1599                        return true;
1600                }
1601        }
1602        return false;
1603}
1604/*
1605Summary:
1606        Find list of frequencies to scan.
1607*/
1608
1609static void chm_create_freq_list(chm_mgr_t *p_chm               /* Channel manager reference */
1610                                        )
1611{
1612        int freq_idx;
1613        s_freq_cnt = 0;
1614
1615        for (freq_idx = 0; freq_idx < MAX_MAJOR_CH;  freq_idx++)
1616        {
1617                if (!chm_find_freq_idx(p_chm,freq_idx))
1618                {
1619                        s_freq_list[s_freq_cnt++] = freq_idx;
1620                }
1621        }
1622}
1623
1624/*
1625Summary:
1626        Scan for channels to create a channel map.
1627Description:
1628        Scan for all available channels.
1629*/
1630
1631static void chm_scan(chm_mgr_t *p_chm           /* Channel manager reference */
1632                                        )
1633{
1634        unsigned int freq;
1635        int idx,num,list_idx;
1636        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1637
1638        chm_stop_decode(p_chm);
1639
1640        if (p_app->ch_scan_type < eFULL_RESCAN)
1641        {
1642                /* Completely reset and start over */
1643                p_app->settings.num_channels = 0;
1644        }
1645        memset(p_chm->p_info,0,p_chm->max_info_num * sizeof(chm_info_t));
1646        chm_create_freq_list(p_chm);
1647        p_chm->cur_ch_num = 0xFF;
1648
1649        chm_stream_close(p_chm);
1650
1651        /* Add streamer channel */
1652#ifdef BCM_DEBUG
1653#if (BCHP_CHIP != 3543)
1654        p_app->band = bstreamer_attach(0,bstream_mpeg_type_ts);
1655        BDBG_MSG(("chm_scan calling bstream_open for streamer input\n"));
1656        p_app->stream = bstream_open(p_app->band, &p_app->mpeg);
1657        if (p_app->stream)
1658        {
1659                BDBG_MSG(("STREAMER INPUT chm_scan_vct\n"));
1660                if ((num = chm_scan_vct(p_chm,p_app->band,0x7F)) <= 0)
1661                {
1662                        BDBG_MSG(("chm_scan_vct found no channels\n"));
1663                        BDBG_MSG(("STREAMER INPUT GET PSI\n"));
1664                        if ((num = chm_scan_psi(p_chm,p_app->band,0x7F)) <= 0)
1665                        {
1666                                BDBG_MSG(("chm_scan_psi found no channels\n"));
1667                        } else
1668                        {
1669                                BDBG_MSG(("STREAMER INPUT PSI channels %d \n", num));
1670                        }
1671                } else
1672                {
1673                        BDBG_MSG(("STREAMER INPUT VCT channels %d \n", num));
1674                }
1675
1676                chm_stream_close(p_chm);
1677        }
1678#endif
1679#endif
1680
1681        for (list_idx = 0; list_idx <  s_freq_cnt; list_idx++)
1682        {
1683                idx = s_freq_list[list_idx];
1684                freq = (unsigned int)s_ch_to_freq[idx];
1685                freq *= 1000000; /* convert to Hz */
1686                BDBG_WRN(("Scan[%d] freq = %d\n",idx,freq));
1687
1688                /* Check to see if scan was canceled */
1689                if (chm_check_cancel(p_chm))
1690                        break;
1691
1692                /* output progress event id will be % done */
1693                p_chm->chm_evt.type = eCHM_PROGRESS;
1694                p_chm->chm_evt.id = (idx * 100)/MAX_MAJOR_CH;
1695                chm_post_app_event(p_chm,&p_chm->chm_evt);
1696
1697                /* Try tuning */
1698                BDBG_WRN(("Start scan type = %d\n",p_app->ch_scan_type));
1699#ifndef BQAM_SCRIPT
1700                if (bant_detect())
1701                {
1702                        if (chm_config_smart(p_chm,idx) != 0)
1703                        {
1704                                continue;
1705                        }
1706                } else
1707                {
1708                        p_chm->ant_cmd = 0xFF;
1709                }
1710#endif
1711
1712                btuner_ds_params_init(&p_app->ds, p_app->tuner);
1713                p_app->ds.cancel_callback = chm_tune_cancel_callback;
1714                p_app->ds.cancel_callback_context = p_app;
1715                p_app->ds.wait_for_lock = true;
1716#ifdef BQAM_SCRIPT
1717                p_app->ds.fecMode = eFEC_ANNEX_B;
1718                p_app->ds.qamMode = eQAM_Scan;
1719#endif
1720                if (btuner_tune_ds(p_app->tuner, freq, &p_app->ds) < 0)
1721                {
1722                        BDBG_WRN(("DS[%d] freq = %d not locked, try next freq\n",idx,freq));
1723                        chm_send_status(p_chm,freq,false);
1724                        continue;
1725                } else
1726                {
1727                        BDBG_WRN(("btuner_tune_ds[%d] freq = %d, success\n",idx,freq));
1728                        chm_send_status(p_chm,freq,true);
1729                }
1730
1731                p_app->band = TUNER_BAND;
1732
1733                BDBG_MSG(("chm_scan calling bstream_open\n"));
1734                p_app->stream = bstream_open(p_app->band, &p_app->mpeg);
1735                if (!p_app->stream)
1736                {
1737                        BDBG_WRN(("bstream_open failed\n"));
1738                        continue;
1739                }
1740
1741#ifndef BQAM_SCRIPT
1742                if ((num = chm_scan_vct(p_chm,p_app->band,idx)) <= 0)
1743                {
1744                        BDBG_WRN(("chm_scan_vct found no channels\n"));
1745#endif
1746                        if ((num = chm_scan_psi(p_chm,p_app->band,idx)) <= 0)
1747                        {
1748                                BDBG_WRN(("chm_scan_psi found no channels\n"));
1749                        } else
1750                        {
1751                                BDBG_MSG(("PSI channels %d \n", num));
1752                        }
1753
1754                        continue;
1755#ifndef BQAM_SCRIPT
1756                } else
1757                {
1758                        BDBG_MSG(("VCT channels %d \n", num));
1759                }
1760#endif
1761        }
1762
1763        p_chm->rrt_size = 0;
1764        p_chm->chm_evt.type = eCHM_PROGRESS;
1765        p_chm->chm_evt.id = 100;
1766        chm_post_app_event(p_chm,&p_chm->chm_evt);
1767
1768        /* leave scan state */
1769        p_chm->cmd = eCHM_CANCEL;
1770        p_chm->cur_ch_num = p_app->cur_ch_num = 0;
1771
1772        WriteReg32(SCRATCH_CMD_BASE,eIR_CHMAP); /* Output channel map */
1773}
1774
1775#else
1776/*
1777Summary:
1778        Scan for channels to create a channel map.
1779Description:
1780        Scan for all available channels.
1781*/
1782
1783static void chm_scan(chm_mgr_t *p_chm           /* Channel manager reference */
1784                                        )
1785{
1786        unsigned int freq;
1787        int idx;
1788        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1789
1790        chm_stop_decode(p_chm);
1791
1792        /* Completely reset and start over */
1793        p_app->settings.num_channels = 0;
1794        memset(p_chm->p_info,0,p_chm->max_info_num * sizeof(chm_info_t));
1795
1796        p_chm->cur_ch_num = 0xFF;
1797
1798        chm_stream_close(p_chm);
1799
1800        /* Add streamer channel */
1801#ifdef BCM_DEBUG
1802        p_app->band = bstreamer_attach(0,bstream_mpeg_type_ts);
1803        BDBG_MSG(("chm_scan calling bstream_open for streamer input\n"));
1804        p_app->stream = bstream_open(p_app->band, &p_app->mpeg);
1805        if (p_app->stream)
1806        {
1807                int num;
1808                BDBG_MSG(("STREAMER INPUT chm_scan_vct\n"));
1809                if ((num = chm_scan_vct(p_chm,p_app->band,0x7F)) == 0)
1810                {
1811                        BDBG_MSG(("chm_scan_vct found no channels\n"));
1812                        BDBG_MSG(("STREAMER INPUT GET PSI\n"));
1813                        if ((num = chm_scan_psi(p_chm,p_app->band,0x7F)) == 0)
1814                        {
1815                                BDBG_MSG(("chm_scan_psi found no channels\n"));
1816                        } else
1817                        {
1818                                BDBG_MSG(("STREAMER INPUT PSI channels %d \n", num));
1819                        }
1820                } else
1821                {
1822                        BDBG_MSG(("STREAMER INPUT VCT channels %d \n", num));
1823                }
1824
1825
1826                chm_stream_close(p_chm);
1827        }
1828#endif
1829
1830        for (idx = 0; idx < MAX_MAJOR_CH; ++idx)
1831        {
1832                freq = (unsigned int)s_ch_to_freq[idx];
1833                freq *= 1000000; /* convert to Hz */
1834
1835                /* Check to see if scan was canceled */
1836                if (chm_check_cancel(p_chm))
1837                        break;
1838
1839                /* output progress event id will be % done */
1840                p_chm->chm_evt.type = eCHM_PROGRESS;
1841                p_chm->chm_evt.id = (idx * 100)/MAX_MAJOR_CH;
1842                chm_post_app_event(p_chm,&p_chm->chm_evt);
1843
1844                /* Try tuning */
1845                btuner_ds_params_init(&p_app->ds, p_app->tuner);
1846                p_app->ds.cancel_callback = chm_tune_cancel_callback;
1847                p_app->ds.cancel_callback_context = p_app;
1848                p_app->ds.wait_for_lock = true;
1849#ifdef BQAM_SCRIPT
1850                p_app->ds.fecMode = eFEC_ANNEX_B;
1851                p_app->ds.qamMode = eQAM_Scan;
1852#endif
1853                p_app->band = btuner_tune_ds(p_app->tuner, freq, &p_app->ds);
1854                if (p_app->band < 0)
1855                {
1856                        BDBG_WRN(("Tune failed (freq[%d] = %d)\n",idx, freq));
1857                        chm_send_status(p_chm,freq,false);
1858                        continue;
1859                }
1860                chm_send_status(p_chm,freq,true);
1861
1862                BDBG_MSG(("chm_scan calling bstream_open\n"));
1863                p_app->stream = bstream_open(p_app->band, &p_app->mpeg);
1864                if (!p_app->stream)
1865                {
1866                        BDBG_WRN(("bstream_open failed\n"));
1867                        continue;
1868                }
1869
1870                if (chm_scan_vct(p_chm,p_app->band,idx) == 0)
1871                {
1872                        BDBG_WRN(("chm_scan_vct found no channels\n"));
1873                        continue;
1874                }
1875        }
1876
1877        p_chm->chm_evt.type = eCHM_PROGRESS;
1878        p_chm->chm_evt.id = 100;
1879        chm_post_app_event(p_chm,&p_chm->chm_evt);
1880
1881        /* leave scan state */
1882        p_chm->cmd = eCHM_CANCEL;
1883}
1884#endif
1885/*
1886Summary:
1887        Post an event the app queue to provide status.
1888*/
1889
1890static int chm_post_app_event(chm_mgr_t *p_chm,         /* Channel manager reference */
1891                                                          chm_event_t *p_event  /* Event to post to app queue */
1892                                                         )
1893{
1894        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1895        bos_post_event(p_app->msg_queue,(bapp_task_event_t*)p_event);
1896
1897        return 0;
1898}
1899
1900/*
1901Summary:
1902        Output the current RRT text
1903*/
1904#ifdef DEBUG_RRT
1905static void chm_output_rrt(chm_mgr_t *p_chm)            /* Channel manager reference */
1906{
1907        PSIP_RRT_header header;
1908        PSIP_RRT_dimension dim;
1909        PSIP_RRT_value val;
1910        int dim_idx,val_idx;
1911        char tmp_str[64];
1912        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1913
1914        if (p_chm->rrt_size <= 0)
1915                return;
1916
1917        PSIP_RRT_getHeader(p_app->settings.rrt, &header);
1918        if (chm_process_mss(p_chm,header.p_rating_region_name_text,tmp_str,64) == 0)
1919        {
1920                BDBG_WRN(("RRT %8s\n",tmp_str));
1921        }
1922        for (dim_idx = 0; dim_idx < header.dimensions_defined; ++dim_idx)
1923        {
1924                if (PSIP_RRT_getDimension(p_app->settings.rrt,dim_idx,&dim) != BERR_SUCCESS)
1925                        continue;
1926
1927                if (chm_process_mss(p_chm,dim.p_dimension_name_text,tmp_str,sizeof(tmp_str)) == 0)
1928                {
1929                        BDBG_WRN(("  RRT[%d] %8s(%d)\n",dim_idx,tmp_str,dim.graduated_scale));
1930                }
1931
1932                for (val_idx = 0; val_idx < dim.values_defined; ++val_idx)
1933                {
1934                        if (PSIP_RRT_getValue(p_app->settings.rrt,dim_idx,val_idx,&val) != BERR_SUCCESS)
1935                                continue;
1936
1937                        if (chm_process_mss(p_chm,val.p_rating_value_text,tmp_str,sizeof(tmp_str)) == 0)
1938                        {
1939                                BDBG_WRN(("  RRT[%d,%d] %8s\n",dim_idx,val_idx,tmp_str));
1940                        }
1941
1942                        if (chm_process_mss(p_chm,val.p_abbrev_rating_value_text,tmp_str,sizeof(tmp_str)) == 0)
1943                        {
1944                                BDBG_WRN(("  RRT[%d,%d] %8s\n",dim_idx,val_idx,tmp_str));
1945                        }
1946                }
1947        }
1948}
1949#endif
1950#define CHM_RRT_BUF_SIZE 0x1000
1951static uint8_t chm_rrt_buffer[CHM_RRT_BUF_SIZE];
1952
1953static void *chm_smessage_rrt_callback(void * context, size_t data_size)
1954{
1955    static chm_event_t chm_evt;
1956    PSIP_RRT_header    header;
1957    int flags;
1958    chm_mgr_t *p_chm;
1959    bapp_t *p_app;
1960
1961    p_chm = (chm_mgr_t*)context;
1962    p_app = (bapp_t*)p_chm->p_app;
1963
1964    PSIP_RRT_getHeader(chm_rrt_buffer, &header);
1965    if ((header.rating_region == 1) || (memcmp(chm_rrt_buffer, p_app->settings.rrt, data_size) == 0)){
1966        BDBG_WRN(("RRTs region 1 or they match so don't update\n"));
1967        p_chm->last_rrt += 2 * 60;
1968                return(void*)(chm_rrt_buffer);
1969    }
1970    flags = bos_enter_critical();
1971    p_chm->last_rrt += 2 * 60;
1972    /* Make sure the app is not in ratings screen */
1973    if ((p_app->screen_id != eSCREEN_RATINGS_RRT_DIM) && 
1974        (p_app->screen_id != eSCREEN_RATINGS_RRT_VAL))
1975    {
1976        int i;
1977        memcpy(p_app->settings.rrt, chm_rrt_buffer, data_size);
1978        /* clear current user rrt restriction settings */
1979        for(i = 0; i < MAX_RRT_DIM; i++){
1980            p_app->settings.ratings_rrt[i] = 0;
1981        }
1982        p_app->settings_dirty = true;
1983    }
1984    bos_exit_critical(flags);
1985#ifdef DEBUG_RRT
1986    chm_output_rrt(p_chm); /* DEBUG ONLY */
1987#endif
1988    chm_evt.type = eCHM_EVT_RRT;
1989    chm_evt.id = ((((unsigned int)header.rating_region) << 8) |
1990                  (((unsigned int)header.version_number)));
1991    chm_evt.ticks = bos_getticks();
1992    bos_post_event(p_app->msg_queue,(bapp_task_event_t*)&chm_evt);
1993        return(void*)(chm_rrt_buffer);
1994}
1995/*
1996Summary:
1997        Get the RRT. return non-zero on failure
1998*/
1999
2000static int chm_get_rrt(chm_mgr_t *p_chm         /* Channel manager reference */
2001                                          )
2002{
2003
2004        int cerr;
2005        smessage_stream_params_t params;
2006        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2007
2008        cerr = eCHM_ERR_OK;
2009
2010        if (p_chm->rrt_msg != NULL)
2011        {
2012            if(b_ok != smessage_stop(p_chm->rrt_msg)){
2013                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2014                cerr = eCHM_ERR_FAILED;
2015                goto ExitFunc;
2016            }
2017            smessage_close(p_chm->rrt_msg);
2018            p_chm->rrt_msg = NULL;
2019        }
2020        p_chm->rrt_msg = smessage_open(bmessage_format_psi);
2021        if(NULL == p_chm->rrt_msg){
2022            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2023            cerr = eCHM_ERR_FAILED;
2024            goto ExitFunc;
2025        }
2026        smessage_stream_params_init(&params, p_chm->rrt_msg);
2027        params.band = p_app->band;
2028        params.pid = (uint16_t)0x1FFB;
2029        params.filter.coef[0] = 0xCA;
2030        params.filter.mask[0] = 0x00;
2031        params.filter.coef[8] = 0x00;
2032        params.filter.mask[8] = 0x00;
2033        params.buffer = chm_rrt_buffer;
2034        params.buffer_size = CHM_RRT_BUF_SIZE;
2035        params.data_ready_callback = chm_smessage_rrt_callback;
2036        params.overflow = chm_smessage_overflow;
2037        params.callback_context = (void *)p_chm;
2038        if(b_ok != smessage_start(&params, p_chm->rrt_msg)){
2039            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2040            cerr = eCHM_ERR_FAILED;
2041        }
2042ExitFunc:
2043        return cerr;
2044}
2045
2046#define BAPP_MPAA_RATING_STR_NUM        8
2047static const char *bapp_mpa_rating_str[] =
2048{
2049        "",     /* unrated */
2050        "G",
2051        "PG",
2052        "PG-13",
2053        "R",
2054        "NC-17",
2055        "X",
2056        "NR" /* Not Rated */
2057};
2058
2059#define BAPP_TV_RATING_STR_NUM  8
2060static const char *bapp_tv_rating_str[BAPP_TV_RATING_STR_NUM] =
2061{
2062        "",     /* unrated */
2063        "TV-Y",
2064        "TV-Y7",
2065        "TV-G",
2066        "TV-PG",
2067        "TV-14",
2068        "TV-MA",
2069        ""      /* unrated */
2070};
2071/*
2072Summary:
2073        Use dimension and value to make a ratings decision based on the
2074        static ratings configuration in the UI. 
2075
2076        This function assumes region matches currently received RRT or current
2077        region == 1 (USA).
2078*/
2079static int chm_psip_block(bapp_t *p_app, unsigned char region,unsigned char dim,unsigned char val, char *rating_str)
2080{
2081        int blocked = 0;
2082        int pos = 0;
2083
2084        BDBG_MSG(("%s - region:%d\n", __FUNCTION__, region));
2085
2086        /* handle RRT ratings */
2087        if ((p_app->settings.rrt_status == eRRT_AVAILABLE) && (region != 1))
2088        {
2089                if (p_app->settings.ratings_rrt[dim] & (1 << val))
2090                        blocked |= 1;
2091        }
2092        BDBG_WRN(("RRT psip rating check - rrt dim:%d rrt val:%d blocked:%d\n", dim, val, blocked));
2093
2094        if ((region == 1) && (!blocked))/* US ratings are fixed */
2095        {
2096                BDBG_WRN(("%s (movie:%x tv:%x) dim:%d val:%d\n",__FUNCTION__,p_app->settings.ratings_movies,p_app->settings.ratings_tv,dim,val));
2097
2098                if (val == 0)
2099                {
2100                        BDBG_WRN(("US PSIP rating value = 0 so assume unblocked!\n"));
2101                        return 0;
2102                }
2103
2104                if (dim == 7) /* check settings for MPAA ratings */
2105                {
2106                        pos = 0;
2107
2108                        /* map to xds values */
2109                        if (val > 0)
2110                                val--;
2111
2112                        p_app->movie_rating = val;
2113
2114                        pos = screen_ratings_movie_xds2pos(p_app->movie_rating);
2115
2116                        /* update rating string */
2117                        if (rating_str)
2118                        {
2119                                if (val < BAPP_MPAA_RATING_STR_NUM)
2120                                        strcpy(rating_str, bapp_mpa_rating_str[val]);
2121                        }
2122                        if (pos >= 0)
2123                                blocked |= ((p_app->settings.ratings_movies >> pos) & (0 | (0x1)));
2124                } else /* check settings for TV ratings */
2125                {
2126                        switch (dim)
2127                        {
2128                        case 0: /* entire audience */
2129                                {
2130                                        int pos = 0;
2131                                        /* map to xds values */
2132                                        if (val <= 1)
2133                                        {
2134                                                /* none (1) mapped to unrated */
2135                                                p_app->tv_rating = 0;
2136                                        } else
2137                                        {
2138                                                /* TV-G, TV-PG, TV-14, and TV-MA map to corresponding XDS TV ratings */
2139                                                p_app->tv_rating =  val + 1;
2140                                        }
2141
2142                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2143
2144                                        if (rating_str)
2145                                        {
2146                                                if (p_app->tv_rating < BAPP_TV_RATING_STR_NUM)
2147                                                        strcpy(rating_str, bapp_tv_rating_str[p_app->tv_rating]);
2148                                        }
2149
2150                                        if (pos >= 0)
2151                                                blocked |= ((p_app->settings.ratings_tv >> pos) & (0 | (0x1)));
2152                                }
2153                                break;
2154                        case 1: /* dialogue */
2155                                {
2156                                        if (val == 0)
2157                                                break;
2158                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2159                                        if (pos == ePOS_TV_14)
2160                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_14_D) & (0 | (0x1)));
2161                                        else
2162                                                if (pos == ePOS_TV_PG)
2163                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_PG_D) & (0 | (0x1)));
2164                                        if (rating_str)
2165                                        {
2166                                                strcpy(rating_str, "D");
2167                                        }
2168                                }
2169                                break;
2170                        case 2: /* language */
2171                                {
2172                                        if (val == 0)
2173                                                break;
2174                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2175                                        if (pos == ePOS_TV_MA)
2176                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_MA_L) & (0 | (0x1)));
2177                                        else
2178                                                if (pos == ePOS_TV_14)
2179                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_14_L) & (0 | (0x1)));
2180                                        else
2181                                                if (pos == ePOS_TV_PG)
2182                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_PG_L) & (0 | (0x1)));
2183
2184                                        if (rating_str)
2185                                        {
2186                                                strcpy(rating_str, "L");
2187                                        }
2188                                }
2189                                break;
2190                        case 3: /* sex */
2191                                {
2192                                        if (val == 0)
2193                                                break;
2194                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2195                                        if (pos == ePOS_TV_MA)
2196                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_MA_S) & (0 | (0x1)));
2197                                        else
2198                                                if (pos == ePOS_TV_14)
2199                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_14_S) & (0 | (0x1)));
2200                                        else
2201                                                if (pos == ePOS_TV_PG)
2202                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_PG_S) & (0 | (0x1)));
2203                                        if (rating_str)
2204                                        {
2205                                                strcpy(rating_str, "S");
2206                                        }
2207                                }
2208                                break;
2209                        case 4: /* violence */
2210                                {
2211                                        if (val == 0)
2212                                                break;
2213                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2214                                        if (pos == ePOS_TV_MA)
2215                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_MA_V) & (0 | (0x1)));
2216                                        else
2217                                                if (pos == ePOS_TV_14)
2218                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_14_V) & (0 | (0x1)));
2219                                        else
2220                                                if (pos == ePOS_TV_PG)
2221                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_PG_V) & (0 | (0x1)));
2222                                        if (rating_str)
2223                                        {
2224                                                strcpy(rating_str, "V");
2225                                        }
2226                                }
2227                                break;
2228                        case 5: /* children */
2229                                {
2230                                        if (val == 0)
2231                                                break;
2232                                        pos = 0;
2233
2234                                        /* TV-Y7 and TV-Y map to corresponding XDS TV ratings */
2235                                        p_app->tv_rating = val;
2236
2237                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2238
2239                                        if (rating_str)
2240                                        {
2241                                                if (p_app->tv_rating < BAPP_TV_RATING_STR_NUM)
2242                                                        strcpy(rating_str, bapp_tv_rating_str[p_app->tv_rating]);
2243                                        }
2244                                        if (pos >= 0)
2245                                                blocked |= ((p_app->settings.ratings_tv >> pos) & (0 | (0x1)));
2246                                }
2247                                break;
2248                        case 6: /* fantasy violence */
2249                                {
2250                                        if (val == 0)
2251                                                break;
2252                                        pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
2253                                        if (pos == ePOS_TV_Y7)
2254                                                blocked |= ((p_app->settings.ratings_tv >> ePOS_TV_Y7_FV) & (0 | (0x1)));
2255                                        if (rating_str)
2256                                        {
2257                                                strcpy(rating_str, "FV");
2258                                        }
2259                                }
2260                                break;
2261                        default:
2262                                break;
2263                        }
2264                }
2265        }
2266
2267        if (p_app->settings.ratings_lock == 0)
2268                blocked = 0;
2269
2270        return blocked;
2271}
2272/*
2273Summary:
2274        Process the EIT event descriptors and return > 0 if a change was made
2275        to the info structure, 0 if no changes are required and < 0
2276        if an error occured.
2277*/
2278
2279static int chm_process_eit_desc(chm_mgr_t *p_chm,               /* Channel manager reference */
2280                                                                unsigned char *msg_buf,         /* section buffer containing the EIT table */
2281                                                                int  eit_idx,                           /* EIT event index */
2282                                                                chm_eit_t *p_eit
2283                                                           )
2284{
2285        TS_PSI_descriptor eit_desc;
2286        int eit_desc_idx,result;
2287        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2288        char * rating_str;
2289
2290        result = 0;
2291        /* Process EIT entry descriptors */
2292        eit_desc_idx = 0;
2293        memset(p_eit->cc_service,0,MAX_CC_SERVICES * sizeof(PSIP_CSD_service));
2294        while ((eit_desc = PSIP_EIT_getEventDescriptor(p_chm->eit_buf,eit_idx,eit_desc_idx++)) != NULL)
2295        {
2296                switch (eit_desc[0])
2297                {
2298                case 0x87: /* Content advisory descriptor */
2299                        {
2300                                int rr_idx,rd_idx,psip_str_len;
2301                                PSIP_CAD_rating_region rr;
2302                                PSIP_CAD_rating_dimension rd;
2303                                static chm_event_t chm_evt;
2304                                PSIP_RRT_header rrt_header;
2305                                int blocked = 0;
2306                                if (p_app->settings.rrt_status == eRRT_AVAILABLE)
2307                                {
2308                                        PSIP_RRT_getHeader(p_app->settings.rrt, &rrt_header);
2309                                } else
2310                                {
2311                                        rrt_header.rating_region = 1;
2312                                }
2313
2314                                p_app->psip_rating_str[0] = 0;
2315                                for (rr_idx = 0; rr_idx < PSIP_CAD_getRatingRegionCount(eit_desc); ++rr_idx)
2316                                {
2317                                        if (PSIP_CAD_getRatingRegion(eit_desc,rr_idx,&rr) != BERR_SUCCESS)
2318                                                continue;
2319
2320                                        if ((rr.rating_region != 1) && (rr.rating_region != rrt_header.rating_region))
2321                                        {
2322                                                BDBG_WRN(("CAD skip %d of %d, rating_region = %d, current = %d\n",rr_idx,PSIP_CAD_getRatingRegionCount(eit_desc),rr.rating_region,rrt_header.rating_region));
2323                                                continue;
2324                                        }
2325
2326                                        if (rr_idx > 0)
2327                                        {
2328                                                if (strlen(p_app->psip_rating_str) + 4 < MAX_RATING_STR)
2329                                                {
2330                                                        psip_str_len = strlen(p_app->psip_rating_str);
2331                                                        p_app->psip_rating_str[psip_str_len] = ',';
2332                                                        p_app->psip_rating_str[psip_str_len + 1] = ' ';
2333                                                        p_app->psip_rating_str[psip_str_len + 2] = 0;
2334                                                }
2335                                        }
2336                                        psip_str_len = strlen(p_app->psip_rating_str);
2337                                        if (chm_process_mss(p_chm,rr.p_rating_description_text,&(p_app->psip_rating_str[psip_str_len]),MAX_RATING_STR - psip_str_len) == 0)
2338                                        {
2339                                                BDBG_WRN(("CAD[%d,%d] %s %d\n",rr_idx,rr.rating_region,p_app->psip_rating_str,rr.rated_dimensions));
2340                                                rating_str = NULL;
2341                                        } else
2342                                        {
2343                                                BDBG_MSG(("CAD[%d] chm_process_mss failed\n",rr_idx));
2344                                                rating_str = &(p_app->psip_rating_str[psip_str_len]);
2345                                        }
2346
2347                                        for (rd_idx = 0; rd_idx < rr.rated_dimensions; ++rd_idx)
2348                                        {
2349                                                if (PSIP_CAD_getRatingDimension(eit_desc,rr_idx,rd_idx,&rd) != BERR_SUCCESS)
2350                                                {
2351                                                        BDBG_WRN(("PSIP_CAD_getRatingDimension(%d,%d,%d) failed\n",rr.rating_region,rr_idx,rd_idx));
2352                                                        continue;
2353                                                }
2354
2355                                                if (rating_str != NULL)
2356                                                {
2357                                                        psip_str_len = strlen(p_app->psip_rating_str);
2358                                                        rating_str = &(p_app->psip_rating_str[psip_str_len]);
2359                                                }
2360                                                BDBG_WRN(("*** CAD_RD[%d,%d] region %d, %d-%d\n",rr_idx, rd_idx, rr.rating_region, rd.rating_dimension_j,rd.rating_value));
2361                                                blocked |= chm_psip_block(p_app, rr.rating_region, rd.rating_dimension_j, rd.rating_value,rating_str);
2362                                                BDBG_WRN(("--- dim:%d value:%d blocked:%d, %s\n", rd.rating_dimension_j, rd.rating_value, blocked,p_app->psip_rating_str));
2363                                        }
2364                                        if (chm_check_cancel(p_chm))
2365                                                return eCHM_ERR_CANCELED;
2366                                }
2367
2368                                chm_evt.type = eCHM_EVT_CAD;
2369                                chm_evt.id = (((unsigned int)blocked) << 24) |
2370                                                         (((unsigned int)rr.rating_region) << 16) |
2371                                                         (((unsigned int)rd.rating_dimension_j) << 8) |
2372                                                         ((unsigned int)rd.rating_value);
2373                                chm_evt.ticks = bos_getticks();
2374                                result++;
2375                                bos_post_event(p_app->msg_queue,(bapp_task_event_t*)&chm_evt);
2376                                bos_sleep(30); /* yield so other thread can update */
2377                        }
2378                        break;
2379                case 0x86: /* Caption Service descriptor */
2380                        {
2381                                int csd_idx;
2382                                PSIP_CSD_service tmpCSD;
2383                                for (csd_idx = 0; csd_idx < PSIP_CSD_getNumServices(eit_desc); ++csd_idx)
2384                                {
2385                                        if (PSIP_CSD_getService(eit_desc,csd_idx,&tmpCSD) != BERR_SUCCESS)
2386                                        {
2387                                                BDBG_WRN(("Error getting CSD %d\n", csd_idx));
2388                                                continue;
2389                                        }
2390                                        BDBG_MSG(("CSD-%d) %d, %d, %c%c%c\n", csd_idx,tmpCSD.cc_type,
2391                                                          tmpCSD.cc.caption_service_number,tmpCSD.language[0],tmpCSD.language[1],tmpCSD.language[2]));
2392                                        if (!tmpCSD.cc_type || 
2393                                                (tmpCSD.cc.caption_service_number == 0) ||
2394                                                (tmpCSD.cc.caption_service_number > MAX_CC_SERVICES))
2395                                                continue;
2396                                        memcpy(&(p_eit->cc_service[tmpCSD.cc.caption_service_number - 1]),&tmpCSD,sizeof(PSIP_CSD_service));
2397                                }
2398                        }
2399                        break;
2400                case 0x81: /* AC-3 Audio descriptor */
2401                case 0xAA: /* Redistribution control descriptor */
2402                case 0xB6: /* Content identifier descriptor */
2403                case 0xAB: /* Genre descriptor */
2404                default:
2405                        BDBG_MSG((" EIT_DESC[0x%02x]\n",eit_desc[0]));
2406                        break;
2407                }
2408        }
2409        return result;
2410}
2411
2412/*
2413Summary:
2414        Get the EIT section and return > 0 if a change was made
2415        to the info structure, 0 if no changes are required and < 0
2416        if an error occured.
2417*/
2418
2419static int chm_get_eit(chm_mgr_t *p_chm,                /* Channel manager reference */
2420                                           chm_info_t *p_info,     /* info structure to populate */
2421                                           unsigned short source_id, /* channel source ID from VCT channel */
2422                                           unsigned short pid      /* type type pid */
2423                                          )
2424{
2425        int eit_events,eit_idx,update,result;
2426        unsigned int eit_section_size,utc_time;
2427        PSIP_EIT_event eit;
2428        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2429        unsigned char *p_source_id = (unsigned char*)&source_id;
2430
2431        if ((result = chm_get_utctime(p_chm,&utc_time)) != 0)
2432                return result;
2433
2434        BDBG_MSG(("UTC TIME(%u)\n",utc_time));
2435
2436        update = eEIT_NONE;
2437        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
2438        p_app->msg_params.band = p_app->band;
2439        p_app->msg_params.pid = pid;    /* base pid */
2440
2441        /* Source ID for channel  (assumes little endian system!!! )*/
2442        p_app->msg_params.filter.coef[3] = p_source_id[1];
2443        p_app->msg_params.filter.mask[3] = 0x00;
2444        p_app->msg_params.filter.excl[3] = 0xff;
2445        p_app->msg_params.filter.coef[4] = p_source_id[0];
2446        p_app->msg_params.filter.mask[4] = 0x00;
2447        p_app->msg_params.filter.excl[4] = 0xff;
2448        /* All PSIP tables have protocol_version which must be = 0 */
2449        p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2450        p_app->msg_params.filter.mask[8] = 0x00;
2451        p_app->msg_params.filter.excl[8] = 0xff;
2452
2453        eit_section_size = EIT_BUF_LEN;
2454        if ((result = chm_getmessage(p_chm,p_chm->eit_buf,&eit_section_size, EIT_TIMEOUT)) != 0)
2455                return result;
2456        else
2457        {
2458                if (chm_check_cancel(p_chm))
2459                        return eCHM_ERR_CANCELED;
2460
2461                if ((result = chm_get_utctime(p_chm,&utc_time)) != 0)
2462                        return result;
2463
2464                utc_time += p_chm->stt.GPS_UTC_offset;
2465
2466                eit_events = PSIP_EIT_getNumEvents(p_chm->eit_buf);
2467                for (eit_idx = 0; eit_idx < eit_events; eit_idx++)
2468                {
2469                        if (PSIP_EIT_getEvent(p_chm->eit_buf,eit_idx,&eit) != BERR_SUCCESS)
2470                                continue;
2471#ifdef BCM_DEBUG
2472                        p_chm->eit_start_time = eit.start_time;
2473                        p_chm->eit_length = eit.length_in_seconds;
2474#endif
2475                        if ((utc_time >= eit.start_time) && ( utc_time < (eit.start_time + eit.length_in_seconds)))
2476                        {
2477                                chm_process_mss(p_chm,eit.p_title_text,
2478                                                                p_info->eit_info[EIT_CURRENT].prog_title,MAX_TITLE_CHARS);
2479
2480                                p_info->eit_info[EIT_CURRENT].event_id = eit.event_id;
2481                                p_info->eit_info[EIT_CURRENT].length = eit.length_in_seconds;
2482                                p_info->eit_info[EIT_CURRENT].start_time = eit.start_time;
2483                                BDBG_ERR(("EIT Add-%d = %s(%u,%u)\n",EIT_CURRENT,p_info->eit_info[EIT_CURRENT].prog_title,eit.start_time,eit.length_in_seconds));
2484
2485                                update |= eEIT_CURRENT;
2486                                chm_process_eit_desc(p_chm,p_chm->eit_buf,eit_idx,&(p_info->eit_info[EIT_CURRENT]));
2487                        } else if (((p_info->eit_info[EIT_CURRENT].start_time + p_info->eit_info[EIT_CURRENT].length) >= eit.start_time) && 
2488                                           ((p_info->eit_info[EIT_CURRENT].start_time + p_info->eit_info[EIT_CURRENT].length) < (eit.start_time + eit.length_in_seconds)))
2489                        {
2490                                chm_process_mss(p_chm,eit.p_title_text,
2491                                                                p_info->eit_info[EIT_NEXT].prog_title,MAX_TITLE_CHARS);
2492
2493                                p_info->eit_info[EIT_NEXT].event_id = eit.event_id;
2494                                p_info->eit_info[EIT_NEXT].length = eit.length_in_seconds;
2495                                p_info->eit_info[EIT_NEXT].start_time = eit.start_time;
2496                                BDBG_MSG(("EIT Add-%d = %s(%d,%u,%u)\n",EIT_NEXT,p_info->eit_info[EIT_NEXT].prog_title, p_info->eit_info[EIT_NEXT].event_id,eit.start_time,eit.length_in_seconds));
2497                                update |= eEIT_NEXT;
2498                        } else
2499                        {
2500#ifdef BCM_DEBUG
2501                                chm_process_mss(p_chm,eit.p_title_text,
2502                                                                p_chm->tmp_text,MAX_TITLE_CHARS);
2503                                BDBG_MSG(("EIT Ignore-%d = %s(%d,%u,%u, utc_time=%u)\n",eit_idx,p_chm->tmp_text, p_info->eit_info[EIT_NEXT].event_id,eit.start_time,eit.length_in_seconds,utc_time));
2504#endif
2505                        }
2506                        /* exit if both are found */
2507                        if (update == eEIT_BOTH)
2508                                break;
2509                }
2510        }
2511
2512        return update;
2513}
2514
2515
2516/*
2517Summary:
2518        Get the ETT section and return > 0 if a change was made
2519        to the info structure, 0 if no changes are required and < 0
2520        if an error occured.
2521*/
2522
2523static int chm_get_ett(chm_mgr_t *p_chm,                                /* Channel manager reference */
2524                                           chm_info_t *p_info,             /* info structure to populate */
2525                                           unsigned short source_id,   /* channel source ID from VCT channel */
2526                                           unsigned short pid              /* type type pid */
2527                                          )
2528{
2529        int update;
2530        unsigned int ett_section_size;
2531        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2532        unsigned char *p_source_id = (unsigned char*)&source_id;
2533        PSIP_ETT_header ett;
2534        int result;
2535
2536        update = eEIT_NONE;
2537
2538        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
2539        p_app->msg_params.band = p_app->band;
2540        p_app->msg_params.pid = pid;    /* base pid */
2541
2542        /* Source ID for channel  (assumes little endian system!!! )*/
2543        p_app->msg_params.filter.coef[9] = p_source_id[1];
2544        p_app->msg_params.filter.mask[9] = 0x00;
2545        p_app->msg_params.filter.excl[9] = 0xff;
2546        p_app->msg_params.filter.coef[10] = p_source_id[0];
2547        p_app->msg_params.filter.mask[10] = 0x00;
2548        p_app->msg_params.filter.excl[10] = 0xff;
2549        /* All PSIP tables have protocol_version which must be = 0 */
2550        p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2551        p_app->msg_params.filter.mask[8] = 0x00;
2552        p_app->msg_params.filter.excl[8] = 0xff;
2553        ett_section_size = ETT_BUF_LEN;
2554
2555        if ((result = chm_getmessage(p_chm,p_chm->eit_buf,&ett_section_size, ETT_TIMEOUT)) != 0)
2556                return result;
2557        else
2558        {
2559                PSIP_ETT_getHeader(p_chm->eit_buf,&ett);
2560
2561                if (ett.ETM_id.event_id == p_info->eit_info[EIT_CURRENT].event_id)
2562                {
2563                        chm_process_mss(p_chm,ett.p_extended_text_message,
2564                                                        p_info->eit_info[EIT_CURRENT].prog_desc,MAX_DESC_CHARS);
2565                        update |= eEIT_CURRENT;
2566                        BDBG_MSG(("ETT: 0x%04x(%d) %s\n",pid, EIT_CURRENT,p_info->eit_info[EIT_CURRENT].prog_desc));
2567                } else if (ett.ETM_id.event_id == p_info->eit_info[EIT_NEXT].event_id)
2568                {
2569                        chm_process_mss(p_chm,ett.p_extended_text_message,
2570                                                        p_info->eit_info[EIT_NEXT].prog_desc,MAX_DESC_CHARS);
2571
2572                        update |= eEIT_NEXT;
2573                        BDBG_MSG(("ETT: 0x%04x(%d) %s\n",pid, EIT_NEXT,p_info->eit_info[EIT_NEXT].prog_desc));
2574                } else
2575                {
2576#ifdef BCM_DEBUG
2577                        chm_process_mss(p_chm,ett.p_extended_text_message,
2578                                                        p_chm->tmp_text,MAX_TITLE_CHARS);
2579                        BDBG_MSG(("ETT: 0x%04x(%d != %d or %d) %s\n",pid,ett.ETM_id.event_id,
2580                                          p_info->eit_info[EIT_CURRENT].event_id,p_info->eit_info[EIT_NEXT].event_id ,p_chm->tmp_text));
2581                        BDBG_MSG(("RAW:  0x%02x%02x%02x%02x\n",p_chm->eit_buf[9],p_chm->eit_buf[10],p_chm->eit_buf[11],p_chm->eit_buf[12]));
2582#endif
2583
2584                }
2585        }
2586        return update;
2587}
2588
2589/*RLQ*/
2590#ifdef DEBUG_RRT
2591static void chm_debug_mgt(unsigned char *msg_buf)
2592{
2593        int tables_defined, i;
2594        PSIP_MGT_table table;
2595
2596        tables_defined = PSIP_MGT_getTablesDefined(msg_buf);
2597
2598        for (i = 0; i < tables_defined; i++)
2599        {
2600                if (PSIP_MGT_getTable( msg_buf, i, &table ) == b_ok)
2601                {
2602                        if ((table.table_type >= 0x0300) && (table.table_type <= 0x03FF))
2603                                BDBG_WRN(("RRT: idx%d: Table type=0x%x, pid=0x%x, ver=%d, num_bytes=%d", i, 
2604                                                  table.table_type, table.table_type_PID, 
2605                                                  table.table_type_version_number, table.number_bytes));
2606                        else if ((table.table_type >= 0x0100) && (table.table_type <= 0x017F))
2607                                BDBG_WRN(("EIT: 0x%04x(0x%04x)\n",table.table_type_PID,table.table_type));
2608                }
2609        }
2610}
2611#endif
2612
2613/*
2614Summary:
2615        process the MGT and associated tables.
2616        Returns non-zero on failure.
2617*/
2618
2619static int chm_process_mgt(chm_mgr_t *p_chm,            /* Channel manager reference */
2620                                                   unsigned char *msg_buf,      /* Buffer containing the MGT table */
2621                                                   unsigned int msg_size,       /* PSI buffer size */
2622                                                   chm_info_t *p_info,          /* info structure to populate */
2623                                                   bool ext_text,                       /* Get extended text */
2624                                                   bool redraw                          /* Send redraw event */
2625                                                  )
2626{
2627        PSIP_MGT_table table;
2628        int num_tables, update,result;
2629        unsigned short source_id;
2630        unsigned int utc_time;
2631        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2632
2633        source_id = p_info->source_id;
2634
2635        num_tables = PSIP_MGT_getTablesDefined(msg_buf);
2636
2637        update = eEIT_NONE;
2638        result = 0;
2639
2640        if ((result = chm_get_utctime(p_chm,&utc_time)) != 0)
2641                return result;
2642
2643        gettimeofday(&p_chm->mgt_tv);
2644
2645#ifdef DEBUG_RRT
2646
2647        /*RLQ*/
2648        chm_debug_mgt(msg_buf);         /* DEBUG ONLY */
2649#endif
2650
2651        switch (p_chm->mgt_state)
2652        {
2653        case eMGT_EIT:
2654                for (p_chm->mgt_idx = 0; p_chm->mgt_idx < num_tables; p_chm->mgt_idx++)
2655                {
2656                        if (chm_check_cancel(p_chm))
2657                                return eCHM_ERR_CANCELED;
2658
2659                        PSIP_MGT_getTable(msg_buf,p_chm->mgt_idx,&table);
2660                        if ((table.table_type >= 0x0100) && (table.table_type <= 0x017F))
2661                        {
2662                                BDBG_MSG(("EIT: 0x%04x(0x%04x)\n",table.table_type_PID,table.table_type));
2663                                result = chm_get_eit(p_chm,p_info,source_id,table.table_type_PID);
2664                                if (result < 0)
2665                                        return result;
2666
2667                                update |= result;
2668                                result = 0;
2669
2670                                if (update != 0)
2671                                {
2672                                        if (redraw)
2673                                        {
2674                                                chm_make_current(p_chm,p_info);
2675                                                p_chm->chm_evt.type = eCHM_EVT_REDRAW;
2676                                                p_chm->chm_evt.id = p_app->cur_ch_num;
2677                                                chm_post_app_event(p_chm,&p_chm->chm_evt);
2678                                        }
2679                                        if (update == eEIT_BOTH)
2680                                        {
2681                                                p_chm->mgt_state = eMGT_ETT;
2682                                                break;
2683                                        }
2684                                }
2685                        }
2686                }
2687                if (update != eEIT_CURRENT)
2688                {
2689                        result = -1;
2690                } else
2691                {
2692                        p_chm->mgt_state = eMGT_ETT;
2693                }
2694                break;
2695
2696        case eMGT_ETT:
2697                for (p_chm->mgt_idx = 0; p_chm->mgt_idx < num_tables; p_chm->mgt_idx++)
2698                {
2699                        if (chm_check_cancel(p_chm))
2700                                return eCHM_ERR_CANCELED;
2701
2702                        PSIP_MGT_getTable(msg_buf,p_chm->mgt_idx,&table);
2703                        if ((table.table_type >= 0x0200) && (table.table_type <= 0x027F))
2704                        {
2705                                BDBG_MSG(("ETT: 0x%04x(0x%04x)\n",table.table_type_PID,table.table_type));
2706                                result = chm_get_ett(p_chm,p_info,source_id,table.table_type_PID);
2707                                if (result < 0)
2708                                {
2709                                        BDBG_ERR(("chm_get_ett failed, ret=%d\n", result));
2710                                        p_chm->state = eCHM_PROG_IDLE;
2711                                        return result;
2712                                }
2713
2714                                update |= result;
2715                                result = 0;
2716
2717                                if (update == eEIT_CURRENT)
2718                                {
2719                                        if (redraw)
2720                                        {
2721                                                chm_make_current(p_chm,p_info);
2722                                                p_chm->chm_evt.type = eCHM_EVT_REDRAW;
2723                                                p_chm->chm_evt.id = p_app->cur_ch_num;
2724                                                chm_post_app_event(p_chm,&p_chm->chm_evt);
2725                                        }
2726                                        p_chm->state = eCHM_PROG_IDLE;
2727                                        BDBG_MSG(("MGT:  DONE\n"));
2728                                        break;
2729                                }
2730                        }
2731                }
2732                p_chm->state = eCHM_PROG_IDLE;
2733                break;
2734        }
2735
2736        if (p_chm->mgt_state == eMGT_ETT)
2737        {
2738                if (!ext_text)
2739                {
2740                        p_chm->state = eCHM_PROG_IDLE;
2741                        BDBG_MSG(("MGT:  DONE\n"));
2742                }
2743        }
2744
2745        return result;
2746}
2747/******************************************************************************
2748* INPUTS:      context
2749* OUTPUTS:     none.
2750* RETURNS:     none
2751* FUNCTION:    message_callback
2752* DESCRIPTION: Callback function normally called when a complete message has
2753*              been received and passed the filter criteria.
2754******************************************************************************/
2755#define CHM_STT_BUF_SIZE 0x200
2756static uint8_t chm_stt_buffer[CHM_STT_BUF_SIZE];
2757
2758static void *chm_smessage_stt_callback(void * context, size_t size)
2759{
2760    int flags;
2761    chm_mgr_t * p_chm;
2762    struct tm utc_time;
2763    struct timeval tv;
2764
2765    p_chm = (chm_mgr_t*)context;
2766
2767    flags = bos_enter_critical();
2768    PSIP_STT_getHeader(chm_stt_buffer, &p_chm->stt);
2769    /* current platform seconds when STT was received */
2770    gettimeofday(&tv);
2771    p_chm->sys_offset = tv.tv_sec;
2772    p_chm->sys_UTC_offset = p_chm->stt.GPS_UTC_offset;
2773
2774    /* Current UTC time according to STT */
2775    p_chm->sys_time = p_chm->stt.system_time - p_chm->stt.GPS_UTC_offset;
2776#if 0
2777    BDBG_ERR(("GPS-%u,GPS_UTC-%u)\n",p_chm->stt.system_time,p_chm->stt.GPS_UTC_offset));
2778#endif
2779    utctime(p_chm->sys_time,&utc_time);
2780
2781
2782    p_chm->got_stt = true;
2783    bos_exit_critical(flags);
2784#if 0
2785    BDBG_WRN(("STT UTC = %2d/%2d/%4d %2d:%2d:%2d-%s(%2d %2d)\n",
2786              utc_time.tm_mon + 1,utc_time.tm_mday,utc_time.tm_year + 1980, utc_time.tm_hour,utc_time.tm_min,utc_time.tm_sec,
2787              (p_chm->stt.daylight_savings.DS_status == 0) ? "STD" : "DST",
2788              p_chm->stt.daylight_savings.DS_day_of_month,p_chm->stt.daylight_savings.DS_hour ));
2789    BDBG_ERR(("STT UTC(%u,%u)\n",p_chm->sys_time,p_chm->sys_offset));
2790#endif
2791        return (void*)chm_stt_buffer;
2792}
2793
2794/*
2795Summary:
2796        Get the STT. return non-zero on failure
2797*/
2798
2799static int chm_get_stt(chm_mgr_t *p_chm         /* Channel manager reference */
2800                                          )
2801{
2802        int cerr;
2803        smessage_stream_params_t params;
2804        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2805
2806        cerr = eCHM_ERR_OK;
2807
2808        if (NULL != p_chm->stt_msg)
2809        {
2810            if(b_ok != smessage_stop(p_chm->stt_msg)){
2811                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2812                cerr = eCHM_ERR_FAILED;
2813                goto ExitFunc;
2814            }
2815            smessage_close(p_chm->stt_msg);
2816            p_chm->stt_msg = NULL;
2817        }
2818        p_chm->stt_msg = smessage_open(bmessage_format_psi);
2819        if(NULL == p_chm->stt_msg){
2820            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2821            cerr = eCHM_ERR_FAILED;
2822            goto ExitFunc;
2823        }
2824        smessage_stream_params_init(&params, p_chm->stt_msg);
2825        params.band = p_app->band;
2826        params.pid = (uint16_t)0x1FFB;
2827        params.filter.coef[0] = 0xCD;
2828        params.filter.mask[0] = 0x00;
2829        /* All PSIP tables have protocol_version which must be = 0 */
2830        params.filter.coef[8] = 0x00;   /* protocol_version */
2831        params.filter.mask[8] = 0x00;
2832        params.buffer = chm_stt_buffer;
2833        params.buffer_size = CHM_STT_BUF_SIZE;
2834        params.data_ready_callback = chm_smessage_stt_callback;
2835        params.overflow = chm_smessage_overflow;
2836        params.callback_context = (void *)p_chm;
2837        if(b_ok != smessage_start(&params, p_chm->stt_msg)){
2838            BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2839            cerr = eCHM_ERR_FAILED;
2840        }
2841        p_chm->state = eCHM_GET_VCT;
2842ExitFunc:
2843        return cerr;
2844}
2845/*
2846Summary:
2847        Get the STT. return non-zero on failure
2848*/
2849
2850static int chm_get_stt2(chm_mgr_t *p_chm                /* Channel manager reference */
2851                                           )
2852{
2853        struct tm utc_time;
2854        struct timeval tv;
2855        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2856        unsigned int section_size,result;
2857
2858        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
2859        p_app->msg_params.band = p_app->band;
2860        p_app->msg_params.pid = (unsigned short)0x1FFB; /* base pid */
2861        section_size = STT_BUF_LEN;
2862        p_app->msg_params.filter.coef[0] = 0xCD;
2863        p_app->msg_params.filter.mask[0] = 0x00;
2864        p_app->msg_params.filter.excl[0] = 0xff;
2865        /* All PSIP tables have protocol_version which must be = 0 */
2866        p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2867        p_app->msg_params.filter.mask[8] = 0x00;
2868        p_app->msg_params.filter.excl[8] = 0xff;
2869        result = 0;
2870
2871        if ((result = chm_getmessage(p_chm,p_chm->stt_buf,&section_size, STT_TIMEOUT)) != 0)
2872        {
2873                BDBG_WRN(("Error waiting for STT %d\n",result));
2874                return result;
2875        }
2876
2877        PSIP_STT_getHeader( p_chm->stt_buf, &p_chm->stt);
2878
2879        /* current platform seconds when STT was received */
2880        gettimeofday(&tv);
2881        p_chm->sys_offset = tv.tv_sec;
2882        p_chm->sys_UTC_offset = p_chm->stt.GPS_UTC_offset;
2883
2884        /* Current UTC time according to STT */
2885        p_chm->sys_time = p_chm->stt.system_time - p_chm->stt.GPS_UTC_offset;
2886
2887        utctime(p_chm->sys_time,&utc_time);
2888
2889        BDBG_WRN(("STT UTC = %2d/%2d/%4d %2d:%2d-%s(%2d %2d)\n",
2890                          utc_time.tm_mon + 1,utc_time.tm_mday,utc_time.tm_year + 1980, utc_time.tm_hour,utc_time.tm_min,
2891                          (p_chm->stt.daylight_savings.DS_status == 0) ? "STD" : "DST",
2892                          p_chm->stt.daylight_savings.DS_day_of_month,p_chm->stt.daylight_savings.DS_hour ));
2893
2894
2895
2896        p_chm->got_stt = true;
2897        return eCHM_ERR_OK;
2898}
2899/*
2900Summary:
2901        Get the VCT. return non-zero on failure
2902*/
2903
2904static int chm_get_vct(chm_mgr_t *p_chm,                /* Channel manager reference */
2905                                           chm_info_t *p_info           /* info structure to populate */
2906                                          )
2907{
2908        bapp_t *p_app= (bapp_t*)p_chm->p_app;
2909        unsigned int section_size,section_number;
2910        int result = eCHM_ERR_OK;
2911        if (p_info->got_vct)
2912        {
2913                p_chm->state = eCHM_GET_MGT;
2914                return result;
2915        }
2916
2917        section_number = 0;
2918        do
2919        {
2920                /* Get the VCT */
2921                bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
2922                p_app->msg_params.band = p_app->band;
2923                p_app->msg_params.pid = 0x1ffb; /* VCT */
2924                section_size = VCT_BUF_LEN;
2925
2926                p_app->msg_params.filter.coef[0] = 0xc8;        /* Table ID for terrestrial */
2927                p_app->msg_params.filter.mask[0] = 0x01;
2928                p_app->msg_params.filter.excl[0] = 0xff;
2929                p_app->msg_params.filter.coef[6] = section_number;      /* section number */
2930                p_app->msg_params.filter.mask[6] = 0x00;
2931                p_app->msg_params.filter.excl[6] = 0xff;
2932                /* All PSIP tables have protocol_version which must be = 0 */
2933                p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2934                p_app->msg_params.filter.mask[8] = 0x00;
2935                p_app->msg_params.filter.excl[8] = 0xff;
2936
2937                if ((result = chm_getmessage(p_chm,p_chm->vct_buf,&section_size, VCT_TIMEOUT)) != 0)
2938                {
2939                        BDBG_WRN(("%s Timeout waiting for VCT (section # %d)\n",__FUNCTION__,section_number));
2940                        return result;
2941                }
2942
2943                if (chm_check_cancel(p_chm))
2944                        return eCHM_ERR_CANCELED;
2945
2946                if (chm_process_vct(p_chm,p_chm->vct_buf, section_size, 
2947                                                        p_info,p_app->settings.ch[p_chm->cur_ch_num].minor) != 0)
2948                {
2949                        BDBG_WRN(("VCT entry not found %d\n",section_number));
2950                        section_number++;
2951                        continue;
2952                }
2953                break;
2954        }while (section_size != 0); 
2955
2956        p_chm->state = eCHM_GET_MGT;
2957
2958        return result;
2959}
2960
2961/*
2962Summary:
2963        Get the MGT. return non-zero on failure
2964*/
2965
2966static int chm_get_mgt(chm_mgr_t *p_chm         /* Channel manager reference */
2967                                          )
2968{
2969        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2970        int result;
2971
2972        bmessage_stream_params_init(&p_app->msg_params, p_app->msg);
2973        p_app->msg_params.band = p_app->band;
2974        p_app->msg_params.pid = (unsigned short)0x1FFB; /* base pid */
2975        p_chm->mgt_size = MGT_BUF_LEN;
2976        p_app->msg_params.filter.coef[0] = 0xC7;
2977        p_app->msg_params.filter.mask[0] = 0x00;
2978        p_app->msg_params.filter.excl[0] = 0xff;
2979        /* All PSIP tables have protocol_version which must be = 0 */
2980        p_app->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2981        p_app->msg_params.filter.mask[8] = 0x00;
2982        p_app->msg_params.filter.excl[8] = 0xff;
2983
2984        if ((result = chm_getmessage(p_chm,p_chm->mgt_buf,&p_chm->mgt_size, MGT_TIMEOUT)) != 0)
2985        {
2986                BDBG_WRN(("Timeout waiting for MGT\n"));
2987                return result;
2988        }
2989
2990        p_chm->mgt_state = eMGT_EIT;
2991        p_chm->state = eCHM_PROCESS_MGT;
2992
2993        return 0;
2994}
2995
2996/*
2997Summary:
2998        Get the current UTC time, local offset and dst flag.
2999        Returns non-zero when it is not possible to determine local time.
3000        Currently this function uses XDS local offset over one obtained from the TSIDs
3001       
3002*/
3003unsigned int g_xds_time_offset = 0;
3004bool g_xds_dst = false;
3005int chm_get_time_info(chm_mgr_t *p_chm, 
3006                                          unsigned int *utc_secs,                       /* Current UTC time in seconds */
3007                                          int *local_offset,                            /* Local time offset from UTC time in seconds */
3008                                          bool *dst                                                     /* Daylight savings flag */
3009                                         )
3010{
3011        int result;
3012
3013        if ((result = chm_get_utctime(p_chm,utc_secs)) != 0)
3014                return result;
3015
3016        /* Use XDS local time over time obtained from a TSID */
3017        if (g_xds_time_offset != 0)
3018        {
3019                p_chm->local_offset = 3600 * g_xds_time_offset;
3020                p_chm->local_time_source = eTS_XDS;
3021                p_chm->local_dst_obs = g_xds_dst;
3022        }
3023
3024        if (p_chm->local_time_source == eTS_NONE)
3025                return eCHM_ERR_FAILED;
3026
3027        *local_offset = p_chm->local_offset;
3028        *dst = ((p_chm->stt.daylight_savings.DS_status != 0) && p_chm->local_dst_obs) ? true : false;
3029
3030        BDBG_MSG(("STT system_time = %u\n",p_chm->stt.system_time));
3031        BDBG_MSG(("STT GPS_UTC_offset = %u\n",p_chm->stt.GPS_UTC_offset));
3032        BDBG_MSG(("STT DS_status = %d\n",p_chm->stt.daylight_savings.DS_status));
3033        BDBG_ERR(("Timesource %d, local_offset = %d, dst\n",p_chm->local_time_source,p_chm->local_offset,p_chm->local_dst_obs));
3034
3035        if (*dst)
3036        {
3037                *utc_secs += 3600;
3038        }
3039
3040        return 0;
3041}
3042
3043#ifdef VALIDATE_EIT
3044/*
3045Summary:
3046   Determine if the current channel info needs to be updated.
3047*/
3048static bool chm_needs_update(chm_mgr_t *p_chm)
3049{
3050        chm_info_t *p_info;
3051        unsigned int utc_time,local_offset;
3052        bool dst;
3053
3054        if (chm_get_time_info(p_chm,&utc_time,&local_offset,&dst) != 0)
3055        {
3056                BDBG_WRN(("### Invalid UTC time %d\n",utc_time));
3057                return true;
3058
3059        }
3060
3061        p_info = &p_chm->p_info[p_chm->cur_ch_num];
3062        if ((utc_time >= p_info->eit_info[EIT_CURRENT].start_time) && 
3063                ( utc_time < (p_info->eit_info[EIT_CURRENT].start_time + p_info->eit_info[EIT_CURRENT].length)))
3064        {
3065                return false;
3066        }
3067        BDBG_WRN(("### Entry %d invalid (%d, %d, %d)\n",p_chm->cur_ch_num, 
3068                          utc_time,p_info->eit_info[EIT_CURRENT].start_time, p_info->eit_info[EIT_CURRENT].length));
3069
3070        return true;
3071}
3072#endif
3073/*
3074Summary:
3075        Get program guide info.
3076Description:
3077        Get program guide info.
3078        Returns non-zero on failure.
3079*/
3080
3081static int chm_get_guide(chm_mgr_t *p_chm               /* Channel manager reference */
3082                                                )
3083{
3084        unsigned int utc_secs,cnt,local_offset,idx;
3085        bool dst;
3086        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3087        chm_info_t *p_info;
3088        static chm_event_t chm_evt;
3089        struct timeval tv;
3090
3091        chm_stop_decode(p_chm);
3092
3093        /* Check to see if scan was canceled */
3094        if (chm_check_cancel(p_chm))
3095                return eCHM_ERR_FAILED;
3096
3097        if ((chm_get_time_info(p_chm,&utc_secs,&local_offset,&dst) != 0) || (p_chm->local_time_source == eTS_NONE))
3098        {
3099                BDBG_WRN(("Need local time and UTC offset before guide can be displayed with time info.\n"));
3100        }
3101
3102        /* Completely reset and start over */
3103
3104        BDBG_MSG(("Get Guide (%d channels).\n",p_app->settings.num_channels));
3105        cnt = 0;
3106        p_chm->cur_ch_num = p_app->cur_ch_num; /* Start on current channel */
3107
3108        gettimeofday(&tv);
3109
3110        if (tv.tv_sec > (p_chm->guide_tv.tv_sec + (60 * 15)))
3111        {
3112                for (idx = 0; idx < p_app->settings.num_channels; ++idx)
3113                {
3114                        p_info = &p_chm->p_info[idx];
3115                        memset(p_info,0,sizeof(chm_info_t));
3116                        p_chm->chm_evt.type = eCHM_EVT_REDRAW;
3117                        p_chm->chm_evt.id = idx;
3118                        chm_post_app_event(p_chm,&p_chm->chm_evt);
3119                        bos_sleep(1);
3120                }
3121        }
3122
3123        gettimeofday(&p_chm->guide_tv);
3124
3125        while (p_chm->cmd == eCHM_GUIDE)
3126        {
3127                if (cnt >= p_app->settings.num_channels)
3128                {
3129                        cnt = 0;
3130                        p_chm->cur_ch_num = p_app->cur_ch_num; /* Start on current channel */
3131                }
3132                if (p_chm->cur_ch_num >= p_app->settings.num_channels)
3133                        p_chm->cur_ch_num = 0;
3134                BDBG_MSG(("Get program info for CH %d of %d\n",p_chm->cur_ch_num,p_app->settings.num_channels));
3135
3136                /* Check to see if scan was canceled */
3137                if (chm_check_cancel(p_chm))
3138                {
3139                        BDBG_WRN(("Get Guide canceled.\n",p_app->settings.num_channels));
3140                        break;
3141                }
3142
3143                p_info = &p_chm->p_info[p_chm->cur_ch_num];
3144                BDBG_MSG(("### Tune %d\n",p_chm->cur_ch_num));
3145                if (chm_tune_current_freq(p_chm) != 0)
3146                {
3147                        BDBG_WRN(("Tune to channel[%d] %d.%d failed\n",p_chm->cur_ch_num, 
3148                                          p_app->settings.ch[p_chm->cur_ch_num].major,p_app->settings.ch[p_chm->cur_ch_num].minor));
3149                        p_chm->cur_ch_num++;
3150                        cnt++;
3151                        continue;
3152                }
3153
3154                /* Some channels are sending STT correctly for DST and others do not. 
3155                   To work around this get STT for each channel */
3156                BDBG_MSG(("### Get STT %d\n",p_chm->cur_ch_num));
3157                if (chm_get_stt2(p_chm) != 0)
3158                {
3159                        BDBG_WRN(("Failed to get STT for guide.\n"));
3160                        p_chm->cur_ch_num++;
3161                        cnt++;
3162                        continue;
3163                } 
3164
3165                BDBG_MSG(("### Get VCT %d\n",p_chm->cur_ch_num));
3166                if (chm_get_vct(p_chm,p_info) != 0)
3167                {
3168                        BDBG_WRN(("Failed to get VCT for guide.\n"));
3169                        p_chm->cur_ch_num++;
3170                        cnt++;
3171                        continue;
3172                }
3173
3174                BDBG_MSG(("### Get MGT %d\n",p_chm->cur_ch_num));
3175                if (chm_get_mgt(p_chm) != 0)
3176                {
3177                        BDBG_WRN(("Failed to get MGT for guide.\n"));
3178                        p_chm->cur_ch_num++;
3179                        cnt++;
3180                        continue;
3181                }
3182
3183                p_chm->mgt_state = eMGT_EIT;
3184                do
3185                {
3186                        BDBG_MSG(("### Process MGT - %d\n",p_chm->mgt_idx));
3187                        if (chm_process_mgt(p_chm, p_chm->mgt_buf,p_chm->mgt_size,p_info,false,false) != 0)
3188                        {
3189                                BDBG_WRN(("Failed to process MGT for guide.\n"));
3190                                break;
3191                        }
3192                }while (p_chm->state == eCHM_PROCESS_MGT);
3193
3194                BDBG_MSG(("### Send redraw event - %d\n",p_chm->state));
3195                /* JPF Can probably get rid of this when progress is implemented. */
3196                p_chm->chm_evt.type = eCHM_EVT_REDRAW;
3197                p_chm->chm_evt.id = p_chm->cur_ch_num;
3198                chm_post_app_event(p_chm,&p_chm->chm_evt);
3199
3200                p_chm->cur_ch_num++;
3201                cnt++;
3202
3203                chm_evt.type = eCHM_PROGRESS;
3204                chm_evt.id = (100 * cnt) / p_app->settings.num_channels;
3205                chm_post_app_event(p_chm,&chm_evt);
3206        }
3207        BDBG_MSG(("Done processing guide current ch = %d.\n",p_chm->cur_ch_num));
3208
3209        p_chm->chm_evt.type = eCHM_PROGRESS;
3210        p_chm->chm_evt.id = 100;
3211        chm_post_app_event(p_chm,&p_chm->chm_evt);
3212
3213        /* leave guide state */
3214        p_chm->cmd = eCHM_CANCEL;
3215        return 0;
3216}
3217
3218/*
3219Summary:
3220        Initiate scan for new data
3221*/
3222
3223static int chm_prog_idle(chm_mgr_t *p_chm               /* Channel manager reference */
3224                                                )
3225{
3226        struct timeval tv;
3227        gettimeofday(&tv);
3228        static unsigned int last_signal_check = 0;
3229        if (last_signal_check < bos_getticks())
3230        {
3231                chm_send_status(p_chm,0,true);
3232                last_signal_check = bos_getticks() + MS_TO_TICKS(CHM_CHECK_SIGNAL_FREQ);
3233        }
3234
3235        if (tv.tv_sec > (p_chm->mgt_tv.tv_sec + MGT_CYCLE_TIMEOUT))
3236        {
3237                bapp_t *p_app = (bapp_t*)p_chm->p_app;
3238                if (p_app->chm.local_time_source == eTS_NONE)
3239                {
3240                        p_chm->state = eCHM_GET_VCT;
3241                        p_chm->p_info[p_chm->cur_ch_num].got_vct = false;
3242                }
3243                else
3244                        p_chm->state = eCHM_GET_MGT;
3245        } else
3246        {
3247        }
3248        return 0;
3249}
3250
3251/*
3252Summary:
3253        Get channel detailed program info.
3254Description:
3255        Get channel detailed program info.
3256        Returns non-zero on failure.
3257*/
3258
3259static int chm_get_prog_details(chm_mgr_t *p_chm                /* Channel manager reference */
3260                                                           )
3261{
3262        chm_state_t orig_state;
3263        int result = 0;
3264        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3265        //unsigned int timeout = bos_getticks() + PROG_INFO_TIMEOUT;
3266
3267        orig_state = p_chm->state;
3268
3269        if (chm_check_cancel(p_chm))
3270                return result;
3271
3272        switch (p_chm->state)
3273        {
3274#ifdef BQAM_SCRIPT
3275        case eCHM_GET_STT:
3276                result = chm_get_stt(p_chm);
3277                if (p_app->settings.ratings_lock == 2)
3278                        chm_get_rrt(p_chm);
3279                break;
3280
3281        case eCHM_GET_VCT:
3282                result = chm_get_vct(p_chm,&p_chm->p_info[p_chm->cur_ch_num]);
3283                break;
3284
3285        case eCHM_GET_MGT:
3286                result = chm_get_mgt(p_chm);
3287                break;
3288
3289        case eCHM_PROCESS_MGT:
3290                result = chm_process_mgt(p_chm, p_chm->mgt_buf,p_chm->mgt_size,&p_chm->p_info[p_chm->cur_ch_num],true,true);
3291                break;
3292#else
3293        case eCHM_GET_STT:
3294        case eCHM_GET_VCT:
3295        case eCHM_GET_MGT:
3296        case eCHM_PROCESS_MGT:
3297#endif
3298        case eCHM_PROG_IDLE:
3299                result = chm_prog_idle(p_chm);
3300                break;
3301
3302
3303        default:
3304                break;
3305        }
3306
3307        if (orig_state != p_chm->state)
3308        {
3309                BDBG_WRN(("CHM State changed from %s to %s\n",s_chm_state[orig_state],s_chm_state[p_chm->state]));
3310        }
3311        return result;
3312}
3313
3314/*
3315Summary:
3316   Tune to the current frequency.
3317*/
3318static int chm_tune_current_freq(chm_mgr_t *p_chm)
3319{
3320        unsigned int freq;
3321        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3322
3323        if (p_app->settings.ch[p_chm->cur_ch_num].freq_idx == 0x7F)
3324        {
3325                p_app->band = bstreamer_attach(0,bstream_mpeg_type_ts);
3326        } else
3327        {
3328                freq = s_ch_to_freq[p_app->settings.ch[p_chm->cur_ch_num].freq_idx] * 1000000;
3329                if (p_app->settings.ch[p_chm->cur_ch_num].cmd != 0xFF)
3330                {
3331                        bant_send(p_app->settings.ch[p_chm->cur_ch_num].cmd,p_app->settings.ch[p_chm->cur_ch_num].freq_idx + 2);
3332                        bos_sleep(25);
3333                }
3334
3335                BDBG_WRN(("Tune to frequency = %d\n",freq));
3336                btuner_ds_params_init(&p_app->ds, p_app->tuner);
3337                p_app->ds.cancel_callback = chm_tune_cancel_callback;
3338                p_app->ds.cancel_callback_context = p_app;
3339                p_app->ds.wait_for_lock = true;
3340#ifdef BQAM_SCRIPT
3341                p_app->ds.fecMode = eFEC_ANNEX_B;
3342                p_app->ds.qamMode = eQAM_Scan;
3343#endif
3344                p_app->band = btuner_tune_ds(p_app->tuner, freq, &p_app->ds);
3345                if (p_app->band < 0)
3346                {
3347                        BDBG_WRN(("Tune failed (freq = %d)\n",freq));
3348                        chm_send_status(p_chm,freq,false);
3349
3350                        return eCHM_ERR_FAILED;
3351                }
3352        }
3353        chm_send_status(p_chm,freq,true);
3354
3355        chm_stream_close(p_chm);
3356
3357        p_app->stream = bstream_open(p_app->band, &p_app->mpeg);
3358        if (!p_app->stream)
3359        {
3360                BDBG_WRN(("bstream_open failed\n"));
3361                return eCHM_ERR_FAILED;
3362        }
3363        return 0;
3364}
3365/*
3366Summary:
3367   Start audio and video decode.
3368Description:
3369        Handle tuning to the current channel. Returns non-zero on failure.
3370*/
3371#ifdef CONFIG_TEST_STATIC_KEY
3372        unsigned char VidEvenControlWord[] = { 0xbe, 0xf9, 0xb0, 0x67,0x13, 0xb8, 0xbc, 0x87}; 
3373        unsigned char VidOddControlWord[] = { 0xbc, 0xfb, 0xb2, 0x69,0x13, 0xba, 0xbe, 0x8b}; 
3374        unsigned char AudEvenControlWord[] = { 0xd3, 0x94, 0xdd, 0x44,0x13, 0xd5, 0xd1, 0xb9}; 
3375        unsigned char AudOddControlWord[] = { 0xd6, 0x91, 0xd8, 0x3f,0x13, 0xd0, 0xd4, 0xb7}; 
3376#endif
3377static int chm_start_decode(chm_mgr_t *p_chm)
3378{
3379        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3380
3381        if (chm_tune_current_freq(p_chm) != 0)
3382        {
3383                BDBG_WRN(("bapp_tune_current_freq failed\n"));
3384                return eCHM_ERR_FAILED;
3385        }
3386#ifdef CONFIG_HAS_VIDEO
3387        if (bdecode_start(p_app->decode, p_app->stream, p_app->window))
3388        {
3389                BDBG_WRN(("bdecode_start failed\n"));
3390                return eCHM_ERR_FAILED;
3391        }
3392#endif
3393#ifdef CONFIG_HAS_AUDIO
3394        if (baudio_decode_start(p_app->audio, (void *)1, p_app->stream))
3395        {
3396                BDBG_WRN(("baudio_decode_start failed\n"));
3397                return eCHM_ERR_FAILED;
3398        }
3399#endif
3400#ifdef CONFIG_TEST_STATIC_KEY
3401        {
3402                bstream_config config;
3403                config.mode = 0;
3404                config.key_id = BSETTOP_VIDEO_KEYS;
3405                config.feed_key = true;
3406                memcpy(config.even_key,VidEvenControlWord,8); 
3407                memcpy(config.odd_key,VidOddControlWord,8); 
3408                bstream_set_config(&config);
3409                config.key_id = BSETTOP_AUDIO_KEYS;
3410                config.feed_key = true;
3411                memcpy(config.even_key,AudEvenControlWord,8); 
3412                memcpy(config.odd_key,AudOddControlWord,8); 
3413                bstream_set_config(&config);
3414        }
3415#endif
3416        return 0;
3417}
3418/*
3419Summary:
3420   Stop audio and video decode.
3421*/
3422static int chm_stop_decode(chm_mgr_t *p_chm)
3423{
3424        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3425
3426        p_chm->got_stt = false;
3427        p_chm->cur_ch_num = 0xFF;
3428#ifdef CONFIG_HAS_VIDEO
3429        if (p_app->decode)
3430                bdecode_stop(p_app->decode);
3431#endif
3432#ifdef CONFIG_HAS_AUDIO
3433        if (p_app->audio)
3434                baudio_decode_stop(p_app->audio);
3435#endif
3436
3437        return 0;
3438}
3439/*
3440Summary:
3441   Tune to the current frequency and get the VCT.
3442Description:
3443        Tune to the current frequency and get the VCT. Returns non-zero on failure.
3444*/
3445static void chm_config_mpeg(bapp_ch_t *p_ch,bstream_mpeg *p_mpeg, 
3446                                                        bapp_lang_t pref_lang)
3447{
3448        p_mpeg->pcr_pid = p_ch->pcr_pid;
3449        p_mpeg->video[0].pid = p_ch->video_pid;
3450
3451        if (p_ch->audio_pid[pref_lang] != 0)
3452        {
3453                p_mpeg->audio[0].pid = p_ch->audio_pid[pref_lang];
3454        } else
3455        {
3456                bapp_lang_t lang;
3457                for (lang = eLANG_ENGLISH; lang < eLANG_MAX; ++lang)
3458                {
3459                        if (p_ch->audio_pid[lang] != 0)
3460                        {
3461                                /* choose first non-zero PID */
3462                                p_mpeg->audio[0].pid = p_ch->audio_pid[lang];
3463                                break;
3464                        }
3465                }
3466        }
3467
3468        if (p_mpeg->audio[0].pid == 0)
3469        {
3470                BDBG_WRN(("### All audio PIDs are 0x0000 ###\n"));
3471        }
3472}
3473/*
3474Summary:
3475   Tune to the current frequency and get the VCT.
3476Description:
3477        Tune to the current frequency and get the VCT. Returns non-zero on failure.
3478*/
3479int chm_tune(chm_mgr_t *p_chm)
3480{
3481        int result = eCHM_ERR_FAILED;
3482
3483        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3484
3485        chm_clear_current(p_chm);
3486
3487        if (chm_check_cancel(p_chm))
3488                return result;
3489
3490        if (!p_app->settings.num_channels)
3491                return result;
3492
3493        chm_stop_decode(p_chm);
3494
3495        BDBG_WRN(("CH Index = %d\n",p_app->cur_ch_num));
3496        p_chm->cur_ch_num = p_app->cur_ch_num;
3497
3498        if (p_app->settings.ch[p_chm->cur_ch_num].pcr_pid != 0)
3499        {
3500                BDBG_WRN(("Start decode on ch %d.%d (0x%04x,0x%04x)...\n",
3501                                  p_app->settings.ch[p_chm->cur_ch_num].major,
3502                                  p_app->settings.ch[p_chm->cur_ch_num].minor,
3503                                  p_app->settings.ch[p_chm->cur_ch_num].video_pid,
3504                                  p_app->settings.ch[p_chm->cur_ch_num].audio_pid[p_app->lang]));
3505
3506                /* start decode success so now transition to info acquire state */
3507                chm_config_mpeg(&p_app->settings.ch[p_chm->cur_ch_num], &p_app->mpeg, p_app->lang);
3508                if ((result = chm_start_decode(p_chm)) != 0)
3509                {
3510                        BDBG_WRN(("chm_start_decode failed %d\n",result));
3511
3512                }
3513        }
3514
3515        if (chm_check_cancel(p_chm))
3516                return result;
3517
3518        /* If the pids are not set or the start decode fails try to get program info */
3519        if ((p_app->settings.ch[p_chm->cur_ch_num].pcr_pid == 0) || (result != 0))
3520        {
3521                BDBG_WRN(("Reaquire program info failed 0x%04x, %d\n",p_app->settings.ch[p_chm->cur_ch_num].pcr_pid, result));
3522
3523                if (chm_tune_current_freq(p_chm) != 0)
3524                {
3525                        BDBG_WRN(("bapp_tune_current_freq failed\n"));
3526                        return result;
3527                }
3528
3529                if (chm_check_cancel(p_chm))
3530                        return result;
3531
3532
3533                if ((result = chm_get_prog(p_chm,&p_app->settings.ch[p_chm->cur_ch_num], &p_chm->p_info[p_chm->cur_ch_num])) != 0)
3534                {
3535                        BDBG_WRN(("chanmgr_get_prog failed\n"));
3536                        return result;
3537                }
3538
3539                if (chm_check_cancel(p_chm))
3540                        return result;
3541
3542                chm_config_mpeg(&p_app->settings.ch[p_chm->cur_ch_num], &p_app->mpeg, p_app->lang);
3543
3544                if ((result = chm_start_decode(p_chm)) != 0)
3545                {
3546                        BDBG_WRN(("chm_start_decode failed\n"));
3547                        return result;
3548                }
3549        }
3550
3551        if (chm_check_cancel(p_chm))
3552                return result;
3553
3554        if (result == 0)
3555        {
3556
3557                chm_make_current(p_chm,&p_chm->p_info[p_chm->cur_ch_num]);
3558
3559                /* start decode success so transition to info acquire state */
3560                p_chm->cmd = eCHM_INFO;
3561        }
3562
3563        return result;
3564}
3565
3566/*
3567Summary:
3568   Do a tune for the purpose of checking the signal strength.
3569*/
3570int chm_check_signal(chm_mgr_t *p_chm)
3571{
3572        int result = eCHM_ERR_FAILED;
3573        btuner_ds_status ds_status;
3574        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3575
3576        if (chm_check_cancel(p_chm))
3577                return 0;
3578
3579        p_chm->cur_ch_num = p_app->cur_ch_num;
3580
3581        if (chm_tune_current_freq(p_chm) != 0)
3582        {
3583                p_chm->chm_evt.type = eCHM_PROGRESS;
3584                p_chm->chm_evt.id = 0;
3585                chm_post_app_event(p_chm,&p_chm->chm_evt);
3586                BDBG_WRN(("bapp_tune_current_freq failed\n"));
3587                return result;
3588        }
3589
3590        while (!chm_check_cancel(p_chm))
3591        {
3592                if (btuner_get_ds_status(p_app->tuner,&ds_status) == b_ok)
3593                {
3594                        p_chm->chm_evt.type = eCHM_PROGRESS;
3595                        p_chm->chm_evt.id = ds_status.signal_strength;
3596                        chm_post_app_event(p_chm,&p_chm->chm_evt);
3597
3598                }
3599                bos_sleep(50);
3600        }
3601
3602        return result;
3603}
3604
3605/*
3606Summary:
3607        Channel Manager Task.
3608*/
3609static void chm_handler(void *data)
3610{
3611        unsigned int cmd;
3612        chm_cmd_t orig_cmd;
3613        chm_mgr_t *p_chm = (chm_mgr_t *)data;
3614
3615        while (1)
3616        {
3617                orig_cmd = p_chm->cmd;
3618                switch (p_chm->cmd)
3619                {
3620                case eCHM_CANCEL:
3621                        if (p_chm->state > eCHM_GET_STT)
3622                                p_chm->state = eCHM_GET_STT;
3623                        cmd = (unsigned int)bos_pend_event(p_chm->queue,-1);
3624                        if (cmd == 0)
3625                                break;
3626
3627                        p_chm->cmd = (chm_cmd_t)(cmd - 1);
3628                        break;
3629                case eCHM_STOP:
3630                        chm_stop_decode(p_chm);
3631                        p_chm->cmd = eCHM_CANCEL;
3632                        break;
3633
3634                case eCHM_TUNE:
3635                        chm_tune(p_chm); 
3636                        break;
3637                case eCHM_SCAN:
3638                        chm_scan(p_chm); 
3639                        break;
3640                case eCHM_INFO:
3641                        chm_get_prog_details(p_chm); 
3642                        break;
3643                case eCHM_GUIDE:
3644                        chm_get_guide(p_chm);
3645                        break;
3646                case eCHM_CHECK_SIGNAL:
3647                        chm_check_signal(p_chm);
3648                        break;
3649                }
3650
3651                if (orig_cmd != p_chm->cmd)
3652                {
3653                        BDBG_WRN(("CHM CMD changed from %s to %s\n", s_chm_cmd_name[orig_cmd],s_chm_cmd_name[p_chm->cmd]));
3654                }
3655
3656                /* Yield a little */
3657                bos_sleep(10);
3658        }
3659}
3660
3661/*
3662Summary:
3663        Initialize the channel manager.
3664*/
3665
3666void chm_init(chm_mgr_t *p_chm, void *p_app)
3667{
3668        b_task_params   params;
3669        bresult rc;
3670        memset(p_chm,0,sizeof(chm_mgr_t));
3671        p_chm->p_app = p_app;
3672        p_chm->cur_ch_num = 0xFF;
3673        rc = bos_create_queue(&p_chm->queue,p_chm->event,MAX_CHM_EVENT);
3674        BDBG_ASSERT(rc == b_ok);
3675        rc = bos_create_queue(&p_chm->gen_queue,p_chm->gen_event,MAX_MSG_EVENTS);
3676        BDBG_ASSERT(rc == b_ok);
3677        rc = bos_create_mutex(&p_chm->mutex);
3678        BDBG_ASSERT(rc == b_ok);
3679
3680        p_chm->stack = malloc(CHM_INT_STK_SIZE * 4);
3681        BDBG_ASSERT(p_chm->stack);
3682
3683        /* round to nearest chm_info_t size */
3684        p_chm->max_info_num = MAX_CHANNELS;
3685        p_chm->p_info = (chm_info_t*)malloc(p_chm->max_info_num * sizeof(chm_info_t));
3686
3687        BDBG_ASSERT(p_chm->p_info);
3688        memset(p_chm->p_info,0,p_chm->max_info_num * sizeof(chm_info_t));
3689
3690        BDBG_MSG(("Maximum guide entries = %d.\n",p_chm->max_info_num));
3691
3692        params.priority = CHM_INT_PRIORITY;
3693        params.stack = p_chm->stack;
3694        params.name = "chan_mgr";
3695        params.stack_size = CHM_INT_STK_SIZE;
3696
3697        p_chm->vct_buf = malloc(VCT_BUF_LEN);
3698        p_chm->pat_buf = malloc(PAT_BUF_LEN);
3699        p_chm->pmt_buf = malloc(PMT_BUF_LEN);
3700        p_chm->stt_buf = malloc(STT_BUF_LEN);
3701        p_chm->eit_buf = malloc(EIT_BUF_LEN);
3702        p_chm->ett_buf = malloc(ETT_BUF_LEN);
3703        p_chm->mgt_buf = malloc(MGT_BUF_LEN);
3704        p_chm->new_rrt_buf = malloc(RRT_BUF_LEN);
3705        BDBG_ASSERT(p_chm->vct_buf && p_chm->pat_buf && p_chm->pmt_buf && p_chm->stt_buf && p_chm->eit_buf && p_chm->mgt_buf && p_chm->new_rrt_buf);
3706
3707        bos_start_task(&p_chm->task,&params,chm_handler,p_chm);
3708
3709        BDBG_SetModuleLevel("chan_mgr",BDBG_eMsg);
3710        SW_TRACE_SET(SW_TRACE_CHM_INIT);
3711}
3712
3713/*
3714Summary:
3715        Function to pass a command to the channel manager.
3716        Any results and notification is handled by passing events to the app via
3717        the msg_queue.
3718       
3719*/
3720void chm_cmd(chm_mgr_t *p_chm, chm_cmd_t cmd)
3721{
3722        if ((cmd != eCHM_CANCEL) && (p_chm->cmd != eCHM_CANCEL))
3723        {
3724#if 0
3725                if ((cmd == eCHM_TUNE) && (p_chm->cur_ch_num == p_app->cur_ch_num))
3726                {
3727                        BDBG_WRN(("Abort %s for %s because current channel (%d) is alread set.\n", s_chm_cmd_name[p_chm->cmd],s_chm_cmd_name[cmd],p_chm->cur_ch_num));
3728                        return;
3729                }
3730#endif
3731                BDBG_WRN(("Canceling pervious command %s for %s\n", s_chm_cmd_name[p_chm->cmd],s_chm_cmd_name[cmd]));
3732                bos_post_event(p_chm->queue,(bapp_task_event_t*)(eCHM_CANCEL + 1));
3733                bos_sleep(40); /* yield so thread can process event right away */
3734        }
3735        chm_clear_current(p_chm);
3736
3737        bos_post_event(p_chm->queue,(bapp_task_event_t*)(cmd + 1));
3738        bos_sleep(10); /* yield so thread can process event right away */
3739}
3740
3741
3742/*
3743Summary:
3744        Get a copy of the current channel manager info structure.
3745       
3746*/
3747void chm_get_cur_ch_info(chm_mgr_t *p_chm,
3748                                                 chm_info_t *p_info,
3749                                                 bstream_mpeg *p_mpeg)
3750{
3751        memset(p_info,0,sizeof(chm_info_t));
3752        memset(p_mpeg,0,sizeof(bstream_mpeg));
3753        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok)
3754        {
3755                *p_mpeg = p_chm->mpeg;
3756
3757                *p_info = p_chm->cur_info;
3758
3759                bos_release_mutex(&p_chm->mutex);
3760        } else
3761        {
3762                BDBG_WRN(("%s:%d mutex timeout\n", __FUNCTION__,__LINE__));
3763        }
3764}
3765
3766
Note: See TracBrowser for help on using the repository browser.