source: svn/newcon3bcm2_21bu/dta/src/app/ntia/chan_mgr.c @ 43

Last change on this file since 43 was 43, checked in by megakiss, 11 years ago

광주방송 OTC 주파수 369Mhz로 변경

  • Property svn:executable set to *
File size: 154.3 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2013, 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 "bavc.h"
25#include "ts_psi.h"
26#include "ts_pat.h"
27#include "ts_pmt.h"
28#include "ts_scte_18.h"
29#include "bapp.h"
30#include "psip_ett.h"
31#include "si.h"
32#include "psip_rrt.h"
33#include "bsettop_smessage.h"
34#include "image_recv.h"
35#include "ca_parser.h"
36#include "bos_task_priorities.h"
37#include "bapp_util.h"
38#include "ch_map.h"
39#include "bsettop_tuner.h"
40
41/* defined in tsid_to_utc_off.c */
42extern int tsid_to_utc_offset(unsigned short tsid, int *p_offset, char *p_dst);
43/* defined in bscreen_dolby.c */
44extern void bapp_user_freq_table_get(bapp_t *p_app, unsigned int *freq_table[], unsigned int *num_freq);
45
46#define CHECK_PROGRAM
47#ifdef CHECK_PROGRAM
48int chm_check_program(chm_mgr_t *p_chm);
49#endif
50
51#ifndef TS_PSI_DT_ISO639Language
52#define TS_PSI_DT_ISO639Language          0x0A
53#endif
54
55#ifndef isalpha
56#define isalpha(c)  (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
57#define isdigit(c)  ((c) >= '0' && (c) <= '9')
58#endif
59
60#ifdef  FOR_DOLBY_CERTIFICATION
61        #include "bchp_hifidac_ctrl0.h"
62        #include "projinc.h"
63#endif
64
65#include "ram_header.h"
66
67BDBG_MODULE(chan_mgr);          /* Register software module with debug interface */
68
69#ifdef BCM_DEBUG
70static const char *s_chm_cmd_name[] = { 
71        "eCHM_CANCEL",
72        "eCHM_TUNE",
73        "eCHM_INFO",
74        "eCHM_STOP",
75        "eCHM_CHECK_SIGNAL",
76        "eCHM_HUNT",
77        "eCHM_GUIDE",
78        "eCHM_SAP"
79};
80
81static const char *s_chm_state[] = { 
82        "eCHM_GET_STT",
83        "eCHM_GET_VCT",
84        "eCHM_GET_MGT",
85        "eCHM_PROCESS_MGT",
86        "eCHM_PROG_IDLE"
87};
88
89#endif
90
91#define CURR_CH                                 0
92#define NEXT_CH                                 1
93#define PREV_CH                                 2
94
95#define CHM_INT_STK_SIZE        1024    /* in words */
96
97#define CHM_CHECK_SIGNAL_FREQ   1000
98#define CHM_CHECK_CHMAP_FREQ    5000
99#define CHM_CHECK_PROG_FREQ             1000
100
101#define VCT_BUF_LEN             (1024 + 188)
102#define EIT_BUF_LEN             (4400 + 188)
103#define ETT_BUF_LEN             (4400 + 188)
104#define MGT_BUF_LEN             (4400 + 188)
105
106#define VCT_TIMEOUT             1200    /* current 1200, should be 400 ms */
107#define MSC_TIMEOUT             800
108#define MGT_TIMEOUT             500
109#define VCT_ETT_TIMEOUT         1200
110#define ETT_TIMEOUT             1500
111#define EIT_TIMEOUT             2000
112#define CHM_CHECK_SNR_INTERVAL  500
113
114#define RRT_TIMEOUT             5000    /* in milliseconds */
115#define CHM_MUTEX_TIMEOUT       10
116#define MAX_TIME_SLOTS          4
117#define MGT_CYCLE_TIMEOUT       1               /* in seconds */
118#define RRT_CYCLE_TIME                  (20)    /* in seconds */
119
120#define CHM_MIN(x,y)            ((x < y) ? x : y)
121
122#define PAT_BUF_LEN             (1024 + 188)
123#define CAT_BUF_LEN             (1024 + 188)
124#define PMT_BUF_LEN             (1024 + 188)
125#define STT_BUF_LEN             (256 + 188)
126#define EAS_BUF_LEN                     (1024 + 188)
127#define EMM_BUF_LEN                     (1024 + 188)
128#define CVT_BUF_LEN                             (1024 + 188)
129
130#define CHM_IDLE_TIMEOUT                30
131
132#define CAT_TIMEOUT             3000
133#define PAT_TIMEOUT             800
134#define PMT_TIMEOUT             800
135#define STT_TIMEOUT             1200
136#define EAS_TIMEOUT             1200
137
138#define SCTE_18_ALERT_PRIORITY  0       /* all priority */
139#define EAS_INFINITY            157680000       /* About 5 years in seconds, which is "infinity" for EAS purposes */
140
141/* frequency vector is encoded in 0.25MHz increments */
142#define CHM_VECTOR_MULTIPLIER   (25 * 10000)
143
144#ifndef toupper
145#define toupper(x) (x&0xDF)
146#endif
147
148typedef struct iso_lang_map_t
149{
150        char            iso_lang_code[3];
151        bapp_lang_t     lang;
152}iso_lang_map_t;
153
154typedef enum chm_err_t
155{
156        eCHM_ERR_OK         = 0,
157        eCHM_ERR_FAILED     = -1,
158        eCHM_ERR_TIMEOUT    = -2,
159        eCHM_ERR_CANCELED   = -3,
160        eCHM_ERR_NO_PAT     = -4,
161        eCHM_ERR_PARAMS     = -5
162}chm_err_t;
163
164#ifndef ACB612
165const char g_tz_map[] = { 0, 5, 6, 7, 8, 0};
166#else
167/* note that now we don't support auto zone for Mexico NTIA platform */
168const char g_tz_map[] = { 6, 7, 8, 0 };
169#endif
170
171const static iso_lang_map_t s_iso_lang_map[] =
172{
173        { { 'e','n','g'},eLANG_ENGLISH},
174#ifndef ACB612
175        { { 'f','r','a'},eLANG_FRENCH},
176        { { 'f','r','e'},eLANG_FRENCH},
177#endif
178        { { 'e','s','l'},eLANG_SPANISH},
179        { { 's','p','a'},eLANG_SPANISH},
180};
181const static int s_iso_lang_map_num = sizeof(s_iso_lang_map)/sizeof(iso_lang_map_t);
182
183/* These files are in flash_install_<platform>.c and are assumed to be RAM only and
184 * are therefore not access through dispatch table.
185 */
186extern void flash_install(uint32_t base, uint32_t offset, uint8_t * data, size_t len);
187extern void chip_reset(void);
188
189static int chm_post_app_event(chm_mgr_t *p_chm,         /* Channel manager reference */
190                                                          chm_event_t *p_event  /* Event to post to app queue */
191                                                         );
192static int chm_stop_decode(chm_mgr_t *p_chm);
193static int chm_tune_freq(chm_mgr_t *p_chm, unsigned int freq_hz);
194static int chm_rotate_audio(chm_mgr_t *p_chm);
195static int chm_stt_start(chm_mgr_t *p_chm, unsigned short network_pid);
196static void chm_stt_stop(chm_mgr_t *p_chm);
197static int chm_rrt_start(chm_mgr_t *p_chm, unsigned short network_pid);
198static void chm_rrt_stop(chm_mgr_t *p_chm);
199static int chm_prog_idle(chm_mgr_t *p_chm);
200static void chm_post_progress(chm_mgr_t *p_chm, int cnt);
201
202bresult chm_write_software(struct image_t * image);
203
204static bool chm_check_sc(chm_mgr_t *p_chm, bband_t band, unsigned short pid);
205static void chm_stop_stream(chm_mgr_t *p_chm, chm_stream_t *p_stream);
206
207#ifndef NO_VCHIP
208static int chm_psip_block(bapp_t *p_app, unsigned char region,unsigned char dim,unsigned char val, char *rating_str);
209#endif
210static int chm_get_utctime(chm_mgr_t *p_chm, unsigned int *time);
211
212static int chm_get_guide(chm_mgr_t *p_chm);
213
214#ifdef ACB612
215
216#if 0
217#define FACTORY_CHN_NUMBER 3
218unsigned int F_chaSet[FACTORY_CHN_NUMBER] = {2,13,51};
219#else
220#define FACTORY_CHN_NUMBER 2
221unsigned int F_chaSet[FACTORY_CHN_NUMBER] = {4,48};
222#endif
223bool isScanStatusFinish = false;
224#endif
225
226/* we should add this function in either ministd.c or include the libc.c which has the function */
227char *strchr(const char *s, int c)
228{
229        int len = strlen(s), i;
230        char *p = (char *)s;
231       
232        for (i = 0; i < len; i++, p++) {
233                if (c == *p)
234                        return p;
235        }
236        return NULL;
237}
238/*
239Summary:
240        go through all the dimensions to find out if the given rating from CAD is existed in thre downloadable
241        RRT table or not
242
243Returnes:
244        true if existed
245        false if not
246*/
247bool is_rating_supported(unsigned char *prrt, unsigned char *p, int size)
248{
249        PSIP_RRT_header header;
250        PSIP_RRT_dimension dimension;
251        PSIP_RRT_value value;
252        int i, j, k;
253        /*RLQ, TODO we may need to increase the stack size for chm task */
254        char string[2048];
255        int stringSize = sizeof(string);
256
257        PSIP_RRT_getHeader(prrt, &header);
258        for(i=0; PSIP_RRT_getDimension(prrt, i, &dimension)==BERR_SUCCESS; i++)
259        {
260                if (dimension.values_defined)
261                {
262                        for(j=0; PSIP_RRT_getValue(prrt, i, j, &value)==BERR_SUCCESS; j++)
263                        {
264                                //if (value.abbrev_rating_value_text_len > 8) {
265                                        for(k=0; PSIP_MSS_getString(value.p_abbrev_rating_value_text, k, &stringSize, string)==BERR_SUCCESS; stringSize = sizeof(string), k++ )
266                                        {
267                                                if (stringSize == size && 0 == memcmp(p, string, size))
268                                                        return true;
269                                        }
270                                //}
271                        }
272                }
273        }
274
275        return false;
276}
277
278/*
279Summary:
280find each rating value from given CAD rating and check them against current downloadable RRT
281to see if they are in the table or no
282
283a ponter with rating string that are supported (after filtering out unsupported ones)
284and the *size will contains the length of the string returend
285NULL if not
286*/
287unsigned char *cad_rating_filter(unsigned char *prrt, unsigned char *rating_str, int *size)
288{
289        static char buf[64];
290        char *p;
291        int i = 0, j, valid = 0;
292
293        if (rating_str) {
294                memset(&buf, 0, sizeof(buf));
295                p = rating_str;
296                while (*size) {
297                        j = 0;
298                        /* skip white space if any */
299                        while (0x20 == (*(p + j)) && (j < *size)) {
300                                p++;
301                                *size -= 1;
302                        }
303                        /* check letter */
304                        while (isalpha(*(p + j)) && (j < *size)) {
305                                j++;
306                        }
307                        /* check number */
308                        while (isdigit(*(p + j)) && (j < *size)) {
309                                j++;
310                        }
311                        if (is_rating_supported(prrt, p, j)) {
312                                for (i = 0; i < j; i++) {
313                                        buf[valid++] = *p++;
314                                }
315                        }
316                        else {
317                                p += j;
318                        }
319                        *size -= j;
320                }
321        }
322
323        if (valid) {
324                *size = valid;
325                return buf;
326        }
327        else
328                return NULL;
329}
330
331//#define DBG_DUMP
332#ifdef DBG_DUMP
333static void DBG_HEXDUMP(unsigned char* ptr, unsigned long len)
334{
335        unsigned long i;
336        for (i=0; i<len; i++ )
337        {
338                if ( i % 16 == 0 )
339                        printf ("\n");
340                printf ("0x%02x, ", ptr[i]);
341        }
342        printf("\n\n");
343}
344#else
345#define DBG_HEXDUMP(ptr, len)
346#endif
347
348
349/*
350Summary:
351        check given major, minor and source_id for matching
352*/
353static int chm_find_match_channel(chm_mgr_t *p_chm, uint16_t major, uint16_t minor, uint16_t source_id)
354{
355        bapp_t *p_app = (bapp_t*)p_chm->p_app;
356        bapp_ch_t       *pch;   
357        int i;
358
359        for (i = 0; i < p_app->settings.num_channels; i++) {
360                pch = &p_app->settings.ch[i];
361                if ((pch->major == major) && (pch->minor == minor) && (pch->source_id == source_id))
362                        return i;
363        }
364        return -1;
365}
366
367/*
368Summary:
369        check audio pid
370*/
371uint16_t chm_check_audio(chm_mgr_t *p_chm, bapp_ch_t *pch)
372{
373        uint16_t apid, i;
374
375        apid = pch->audio_pid[pch->cur_audio];
376
377        if (0 == apid && pch->num_audio) {
378                for (i = 0; i < MAX_AUDIO_PIDS; i++) {
379                        pch->cur_audio++;
380                        pch->cur_audio %= MAX_AUDIO_PIDS;
381                        apid = pch->audio_pid[pch->cur_audio];
382                        if (apid)
383                                break;
384                }
385        }
386        return apid;
387}
388
389/*
390Summary:
391        Set next channel information.
392*/
393bool chm_ch_set_next(chm_mgr_t *p_chm, bapp_ch_t **pch)
394{
395        bapp_t *p_app = (bapp_t*)p_chm->p_app;
396        int idx = 0;
397
398        idx = p_app->cur_ch_num + 1;
399        if ((idx % p_app->settings.num_channels) != p_app->cur_ch_num) {
400                *pch = &p_app->settings.ch[idx];
401                return true;
402        }
403        else 
404                *pch = &p_app->settings.ch[p_app->cur_ch_num];
405
406        return false;
407}
408
409/*
410Summary:
411        Set next channel information.
412*/
413bool chm_ch_set_prev(chm_mgr_t *p_chm, bapp_ch_t **pch)
414{
415        bapp_t *p_app = (bapp_t*)p_chm->p_app;
416        int idx = 0;
417
418        idx = p_app->cur_ch_num - 1;
419        if (idx < 0) {
420                idx = p_app->settings.num_channels - 1;
421        }
422        if (idx != p_app->cur_ch_num) {
423                *pch = &p_app->settings.ch[idx];
424                return true;
425        }
426        else 
427                *pch = &p_app->settings.ch[p_app->cur_ch_num];
428        return false;
429}
430
431/*
432Summary:
433Get section crc.
434*/
435static inline unsigned int chm_section_crc(unsigned char *buf,size_t length)
436{
437        unsigned int crc32;
438        memcpy(&crc32, &(buf[length-4]),4);
439        return crc32;
440}
441
442/*
443Summary:
444        Clear the current channel info.
445 */
446static void chm_make_current(chm_mgr_t *p_chm, chm_info_t *p_info)
447{
448        /* Clear current info */
449        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok) {
450                memcpy(&p_chm->cur_info,p_info,sizeof(chm_info_t));
451                bos_release_mutex(&p_chm->mutex);
452        }
453}
454
455/*
456Summary:
457        Clear the current channel info.
458 */
459int chm_clear_current(chm_mgr_t *p_chm)
460{
461        bapp_t *p_app = (bapp_t*)p_chm->p_app;
462
463        /* Clear current info */
464        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok) {
465                memset(&p_chm->cur_info,0,sizeof(chm_info_t));
466                p_app->prog_rating_str[0] = 0;
467                p_app->psip_rating_str[0] = 0;
468                BDBG_WRN(("%s reset rating string @ %d\n",__func__,__LINE__));
469                p_app->tv_rating = 0;
470                /* do we need to clear STT? */
471                //p_chm->got_stt = false;
472                bos_release_mutex(&p_chm->mutex);
473        }
474        return 0;
475}
476
477/*
478Summary:
479Add a chanell to the channel map.
480Description:
481Add the channel to the channel map in sorted order.
482*/
483static void chm_add_vsb_channel(
484                chm_mgr_t *p_chm,               /* Channel manager reference */
485                bapp_ch_t *p_ch
486                )
487{
488        bapp_t *p_app = (bapp_t*)p_chm->p_app;
489        int idx,idx2;
490        bool found_slot = false;
491
492        if (p_app->settings.num_channels >= (MAX_CHANNELS - 1)) {
493                BDBG_ERR(("%s: maximum channel allowed %d reached, can't add more", __func__, MAX_CHANNELS));
494                return;
495        }
496
497        for (idx = 0; idx < p_app->settings.num_channels; idx++)
498        {
499                if ((p_ch->major < p_app->settings.ch[idx].major) ||
500                                ((p_ch->major == p_app->settings.ch[idx].major) && (p_ch->minor < p_app->settings.ch[idx].minor)))
501                {
502#if 0
503                        if ((p_ch->major == p_app->settings.ch[idx].major) &&
504                                (p_ch->minor < p_app->settings.ch[idx].minor)) {
505                                if (p_ch->minor == p_app->settings.ch[idx].minor) {
506                                        /* found duplicate, drop it */ 
507                                        BDBG_WRN(("Found duplicate channel, drop it (%d.%d)", p_ch->major, p_ch->minor));
508                                        return;
509                                }
510                        }
511#endif
512                        for (idx2 = p_app->settings.num_channels - 1; idx2 >= idx; idx2--)
513                        {
514                                memcpy(&p_app->settings.ch[idx2 + 1],&p_app->settings.ch[idx2], sizeof(bapp_ch_t));
515                        }
516                        memcpy(&p_app->settings.ch[idx],p_ch, sizeof(bapp_ch_t));
517                        found_slot = 1;
518                        break;
519                }
520        }
521
522        if (!found_slot)
523        {
524                memcpy(&p_app->settings.ch[p_app->settings.num_channels],p_ch, sizeof(bapp_ch_t));
525        }
526        p_app->settings.num_channels++;
527}
528
529/*
530Summary:
531Get the current utc time in seconds.
532Return non-zero on failure.
533*/
534
535static void chm_send_status(chm_mgr_t *p_chm,unsigned int freq, bool locked)
536{
537        bapp_t *p_app = (bapp_t*)p_chm->p_app;
538        chm_signal_event_t *p_sig = &(p_chm->signal_evt);
539        memset(&(p_chm->signal_evt),0,sizeof(chm_signal_event_t));
540        p_sig->type = eCHM_EVT_SIGNAL;
541        if (locked) {
542                if (btuner_get_status(p_chm->tuner,&p_app->tuner_status) == b_ok)
543                {
544                        /* Send message to app */
545                        p_sig->freq_hz = p_app->tuner_status.freq;
546                        p_sig->SNR = p_app->tuner_status.snr;
547                        p_sig->power = p_app->tuner_status.power;
548                        p_sig->lock = p_app->tuner_status.lock;
549                        p_sig->signal_quality = p_app->tuner_status.PreRS;
550                }
551        }
552        chm_post_app_event(p_chm,(chm_event_t*)&(p_chm->signal_evt));
553}
554
555/*
556Summary:
557Check for a valid language code for the current language settings.
558Returns the bapp_lang_t number or < 0 if not a valid language.
559*/
560
561static int chm_valid_lang(chm_mgr_t *p_chm,                     /* Channel manager reference */
562                char *p_code      /* Three byte iso 639-2 language code */
563                )
564{
565        bapp_lang_t lang = iso_639_to_lang(p_code);
566
567        if (eLANG_MAX != lang)
568                BDBG_MSG(("ISO 639-2 language supported %c%c%c\n",p_code[0],p_code[1],p_code[2]));
569        else
570                BDBG_MSG(("ISO 639-2 language not found %c%c%c\n",p_code[0],p_code[1],p_code[2]));
571        return (lang == eLANG_MAX) ? eCHM_ERR_FAILED : (int)lang;
572}
573
574/*
575Summary:
576Check for cancel, returns true if a cancel occured.
577*/
578#ifdef BCM_DEBUG
579static int chm_check_cancel_ex(chm_mgr_t *p_chm ,const char* func, int line)
580#define chm_check_cancel(chm)   chm_check_cancel_ex(chm,__func__,__LINE__)
581#else
582static int chm_check_cancel(chm_mgr_t *p_chm )
583#endif
584{
585        chm_cmd_event_t *p_cmd;
586
587        if (p_chm->cmd == eCHM_CANCEL)
588                return 1;
589
590        p_cmd = (chm_cmd_event_t*)bos_pend_event(p_chm->queue,0);
591
592        if (!p_cmd)
593                return 0;
594
595        if (p_cmd->cmd_id == eCHM_CANCEL)
596        {
597                p_chm->cmd = eCHM_CANCEL;
598                BDBG_WRN(("Command canceled(%s:%d)...\n",func,line));
599                //RLQ, do we need this?
600#if 0 
601                /* Send message to app */
602                p_chm->chm_evt.type = eCHM_EVT_CANCEL;
603                p_chm->chm_evt.id = 0;
604                chm_post_app_event(p_chm,&p_chm->chm_evt);
605#endif
606        } else
607        {
608                if (p_cmd->cmd_id == eCHM_SAP)
609                {
610                        chm_rotate_audio(p_chm);
611                } 
612                else
613                {
614                        BDBG_WRN(("Throwing away command %d(%s:%d)...\n", p_chm->cmd ,func,line));
615                }
616        }
617
618        return(p_chm->cmd == eCHM_CANCEL) ? 1 : 0;
619} 
620
621
622static void * chm_smessage_callback(void *context, size_t data_size)
623{
624        chm_mgr_t *p_chm = (chm_mgr_t *)context;
625        /* ignore return value */
626        bos_post_event(p_chm->gen_queue, (b_event_t*)data_size);
627        return NULL;
628}
629
630static int chm_getmessage(chm_mgr_t *p_chm,     /* Channel manager reference */
631                void *buf, /* buffer to copy section into */
632                unsigned int *len, /* [in] max size of buffer, [out] section size copied into buffer */
633                unsigned int timeout /* timeout in milliseconds */
634                )
635{
636        bresult bres;
637        size_t msg_size;
638        int result = eCHM_ERR_FAILED;
639        smessage_stream_params_t params;
640
641        smessage_stream_params_init(&params, NULL);
642        params.band = p_chm->msg_params.band;
643        params.pid = p_chm->msg_params.pid;
644        params.filter = p_chm->msg_params.filter;
645        params.buffer = buf;
646        params.buffer_size = *len;
647        params.crc_disabled = p_chm->msg_params.crc_disabled;
648        params.data_ready_callback = chm_smessage_callback;
649        params.overflow = NULL;
650        params.callback_context = (void *)p_chm;
651        params.priv = (void *)4;
652        BDBG_MSG(("pid %x fil %x tim %u len %u", params.pid, params.filter.coef[0], timeout, *len));
653        bres = smessage_start(&params, p_chm->smsg);
654        if (b_ok != bres)
655        {
656                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
657                goto ExitFunc;
658        }
659        msg_size = (size_t) bos_pend_event(p_chm->gen_queue, timeout);
660        if (0 == msg_size)
661        {
662                result = eCHM_ERR_TIMEOUT;
663        } else
664        {
665                result = eCHM_ERR_OK;
666        }
667        bres = smessage_stop(p_chm->smsg);
668        if (b_ok != bres)
669        {
670                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
671                result = eCHM_ERR_FAILED;
672                goto ExitFunc;
673        }
674
675ExitFunc:
676        return result;
677}
678
679/*
680Summary:
681Stop EAS monitoring..
682*/
683static void chm_eas_stop(chm_mgr_t *p_chm)
684{
685        if (NULL != p_chm->eas_msg)
686        {
687                if (b_ok != smessage_stop(p_chm->eas_msg))
688                {
689                        BDBG_ERR(("%s:%d",__FILE__, __LINE__));
690                        return;
691                }
692                smessage_close(p_chm->eas_msg);
693                p_chm->eas_msg = NULL;
694                p_chm->eas_timer_started = false;
695        }
696}
697
698#ifdef CHECK_PROGRAM
699/*
700Summary:
701        Get current program PID information from PAT and PMT
702Description:
703        Get the PAT/PMT for the program
704Returns:
705non-zero on failure.
706*/
707static int chm_get_program(
708                chm_mgr_t *p_chm,
709                bapp_ch_t *pch)
710{
711        unsigned int section_size, pmt_section_size;
712        TS_PMT_stream pmt;
713        TS_PAT_program pat;
714        int result = 0;
715        int idx,p_idx,num_prog, i;
716        unsigned int prog_ticks, crc;
717        bsettop_av_stream_type_t *stream_type;
718
719        prog_ticks = bos_getticks();
720
721        smessage_stream_params_init(&p_chm->msg_params, NULL);
722        p_chm->msg_params.band = p_chm->band;
723        p_chm->msg_params.pid = (unsigned short)0;      /* PAT */
724        section_size = PAT_BUF_LEN;
725
726        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
727        {
728                BDBG_WRN(("%s Error getting PAT (err=%d)",__func__, result));
729                return result;
730        }
731
732        p_chm->pat_cnt++;
733        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
734        {
735                BDBG_MSG(("TS_PAT_validate failed\n"));
736                return eCHM_ERR_FAILED;
737        }
738
739        num_prog = TS_PAT_getNumPrograms(p_chm->pat_buf);
740        if (num_prog == 0)
741        {
742                BDBG_WRN(("%s No program?", __func__));
743                return eCHM_ERR_FAILED;
744        }
745
746        /* check to make sure the user doesn't cancel during the PAT/PMT checking process */
747        if (chm_check_cancel(p_chm))
748        {
749                return eCHM_ERR_CANCELED;
750        }
751
752        /* move it to caller function with mutex protection of program num to avoid possible race condition */
753        //memset(pch, 0, sizeof(bapp_ch_t));
754
755        /* remember PAT CRC for later comparison for changes */
756        crc = chm_section_crc(p_chm->pat_buf,section_size);
757        if (crc == p_chm->pat_crc) {
758                /* PAT doesn't change, simply return */
759                return eCHM_ERR_OK;
760        }
761        p_chm->pat_crc = crc;
762
763        BDBG_MSG(("TS_PAT_getNumPrograms %d", num_prog));
764
765        for (idx = 0; idx < num_prog; idx++)
766        {
767                if (TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat ) != b_ok)
768                {
769                        BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",idx));
770                        p_chm->pat_crc = 0;             /* invalide it */
771                        return eCHM_ERR_FAILED;
772                }
773
774                BDBG_MSG(("TS_PAT_getProgram(%d,0x%04x)\n", pat.program_number,pat.PID));
775
776                /* Check for new network PID */
777                if (pat.program_number == 0)
778                {
779                        /* we don't use network PID */
780                        continue;
781                }
782
783                if (pch->program_num != pat.program_number)
784                        continue;
785
786                smessage_stream_params_init(&p_chm->msg_params, NULL);
787                p_chm->msg_params.band = p_chm->band;
788                p_chm->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
789                p_chm->msg_params.filter.coef[0] = 0x2;
790                p_chm->msg_params.filter.mask[0] = 0x0;
791                p_chm->msg_params.filter.coef[3] = pch->program_num >> 8;
792                p_chm->msg_params.filter.mask[3] = 0x0;
793                p_chm->msg_params.filter.coef[4] = pch->program_num & 0xff;
794                p_chm->msg_params.filter.mask[4] = 0x0;
795                pmt_section_size = PMT_BUF_LEN;
796                if ((result = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT)) != 0)
797                {
798                        BDBG_ERR(("%s Error getting PMT 0x%04x = %d",__func__,pch->program_num, result));
799                        return result;
800                }
801                p_chm->pmt_cnt++;
802                crc = chm_section_crc(p_chm->pmt_buf,pmt_section_size);
803                if (crc == p_chm->pmt_crc) {
804                        /* PMT doesn't change, simply return */
805                        return eCHM_ERR_OK;
806                }
807                p_chm->pmt_crc = crc;
808
809                pch->pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
810
811                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
812                {
813                        TS_PSI_descriptor psi_desc,lang_desc;
814                        int strm_idx;
815                        int num_aud, aidx;
816
817                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
818                        {
819                                BDBG_WRN(("Failure processing PMT %d",p_idx));
820                                return eCHM_ERR_FAILED;
821                        }
822
823                        strm_idx = 0;
824                        lang_desc = NULL;
825                        /* remember how many audio channels from VCT */
826                        num_aud = pch->num_audio;
827                        while ((psi_desc = TS_PMT_getStreamDescriptor(p_chm->pmt_buf,pmt_section_size, p_idx,strm_idx)) != NULL)
828                        {
829                                if (psi_desc[0] == TS_PSI_DT_ISO_639_Language) /* 0x0A ISO-639 Language descriptor */
830                                {
831                                        BDBG_MSG(("ISO-639 DESC\n" ));
832                                        lang_desc = psi_desc;
833                                        break;
834                                }
835                                strm_idx++;
836                                if (strm_idx > 0xFF)
837                                {
838                                        BDBG_ERR(("PMT Stream Desc limit exceeded %d\n",strm_idx));
839                                        break;
840                                }
841                                if (chm_check_cancel(p_chm))
842                                {
843                                        return eCHM_ERR_CANCELED;
844                                }
845                        }
846
847                        if ((stream_type = bdecode_supported_video(pmt.stream_type)) != NULL)
848                        {
849                                BDBG_MSG(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
850                                if (!pch->video_pid || (pch->video_pid != pmt.elementary_PID))
851                                {
852                                        pch->video_pid = pmt.elementary_PID;
853                                        pch->video_type = stream_type->codec_id;
854                                }
855                        }
856                        else if ((stream_type = bdecode_supported_audio(pmt.stream_type)) != NULL)
857                        {
858                                BDBG_MSG(("Audio PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
859                                if (lang_desc) {
860                                        /* MSS format, so point to right offset */
861                                        aidx = chm_valid_lang(p_chm, (char *)&lang_desc[2]);
862                                        if ((aidx >= 0) && (aidx < MAX_AUDIO_PIDS))
863                                {
864                                                /* will audio PID changed in the PMT other than missing? */
865                                                /* for now just check missing one */
866                                                if (!pch->audio_pid[aidx])
867                                        {
868                                                        pch->has_lang |= 1 << aidx;
869                                                        pch->audio_pid[aidx] = pmt.elementary_PID;
870                                                        pch->audio_type[aidx] = stream_type->codec_id;
871                                                        /* initialize audio selection if match */
872#ifdef  USE_LANGUAGE
873                                                        if (aidx == p_app->settings.language)
874                                                                pch->cur_audio = aidx;
875#else
876                                                        /* assume that first audio PID always has audio */
877                                                        if (0 == pch->num_audio)
878                                                                pch->cur_audio = aidx;
879#endif
880                                                        pch->num_audio++;
881                                                        memcpy(&pch->audio_lang[aidx][0],(char *)&lang_desc[2], 3);
882                                                }
883                                                else {
884                                                        /* handle duplicate case which should be pretty common in Mexico broadcast */
885                                                        num_aud = aidx;
886                                                        i = aidx;
887                                                        do {
888                                                                i++;
889                                                                i %= MAX_AUDIO_PIDS;
890                                                                if (0 == pch->audio_pid[i]) {
891                                                                        pch->has_lang |= 1 << i;
892                                                                        pch->audio_pid[i] = pmt.elementary_PID;
893                                                                        pch->audio_type[i] = stream_type->codec_id;
894                                                                        pch->num_audio++;
895                                                                        memcpy(&pch->audio_lang[i][0],(char *)&lang_desc[2], 3);
896                                                                        break;
897                                                                }
898                                                        } while (i != num_aud);
899                                                }
900                                        }
901                                        else {
902                                                /* drop audio? */
903                                                BDBG_WRN(("Audio PID[%d] = 0x%04x dropped due to language not supported", aidx, pmt.elementary_PID ));
904                                        }
905                                }
906                                else {
907                                        /* no language descriptor, just put them in the order in PMT table */
908                                        if (num_aud < MAX_AUDIO_PIDS) {
909                                                i = num_aud;
910                                                do {
911                                                        if (!pch->audio_pid[i]) {
912                                                                pch->has_lang |= 1 << i;
913                                                                pch->audio_pid[i] = pmt.elementary_PID;
914                                                                pch->audio_type[i] = stream_type->codec_id;
915                                                                if (0 == pch->num_audio)
916                                                                        pch->cur_audio = i;
917                                                                pch->num_audio++;
918                                                                break;
919                                                        }
920                                                        i++;
921                                                        i %= MAX_AUDIO_PIDS;
922                                                } while (i != num_aud);
923                                        }
924                                }
925                        }
926                        else
927                        {
928                                BDBG_MSG(("Unsupported stream type[0x%02x]\n", pmt.stream_type));
929                        }
930                }
931                /* we should find the match program */
932                break;
933        }
934       
935        /* final check to make sure the user doesn't cancel during the PAT/PMT checking process */
936        if (chm_check_cancel(p_chm))
937        {
938                return eCHM_ERR_CANCELED;
939        }
940
941        prog_ticks = bos_getticks() - prog_ticks;
942        p_chm->status_evt.type = eCHM_EVT_STATUS;
943        p_chm->status_evt.id = eCHM_STATUS_SI_MS;
944        p_chm->status_evt.ticks = TICKS_TO_MS(prog_ticks);
945        chm_post_app_event(p_chm,&p_chm->status_evt);
946
947        /* one more check */
948        if (0 == pch->video_pid && 0 == pch->pcr_pid && 0 == pch->audio_pid[0])
949                result = eCHM_ERR_FAILED;
950
951        return result;
952}
953#endif
954
955/*
956Summary:
957Get the program info for a given program number.
958Description:
959Get the PAT/PMT for the program.
960Returns non-zero on failure.
961*/
962static int chm_get_program_info(chm_mgr_t *p_chm,               /* Channel manager reference */
963                bband_t band, 
964                unsigned short prog_number,
965                bapp_ch_t *p_ch
966                )
967{
968        unsigned int section_size, pmt_section_size;
969        TS_PMT_stream pmt;
970        TS_PAT_program pat;
971        int result = 0;
972        int idx,p_idx;
973        unsigned short audio_pid[MAX_AUDIO_PIDS];
974        unsigned short audio_type[MAX_AUDIO_PIDS];
975        int num_aud = 0, num_aud_tmp = 0;
976
977        smessage_stream_params_init(&p_chm->msg_params, NULL);
978        p_chm->msg_params.band = band;
979        p_chm->msg_params.pid = (unsigned short)0;      /* PAT */
980        /* All PSIP tables have protocol_version which must be = 0 */
981        //p_chm->msg_params.filter.coef[8] = 0x00;      /* protocol_version */
982        //p_chm->msg_params.filter.mask[8] = 0x00;
983        section_size = PAT_BUF_LEN;
984
985        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
986        {
987                BDBG_WRN(("Error getting PAT 0x%04x = %d\n",prog_number, result));
988                return result;
989        }
990
991        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
992        {
993                BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",prog_number));
994                return eCHM_ERR_FAILED;
995        }
996
997        for (idx = 0; idx < TS_PAT_getNumPrograms(p_chm->pat_buf); idx++)
998        {
999                if (TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat ) != b_ok)
1000                {
1001                        BDBG_WRN(("TS_PAT_validate failed 0x%04x\n",prog_number));
1002                        return eCHM_ERR_FAILED;
1003                }
1004
1005                /* network, skip it */
1006                if (pat.program_number != prog_number)
1007                        continue;
1008
1009                smessage_stream_params_init(&p_chm->msg_params, NULL);
1010                p_chm->msg_params.band = band;
1011                p_chm->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
1012                p_chm->msg_params.filter.coef[0] = 0x2;
1013                p_chm->msg_params.filter.mask[0] = 0x00;
1014                //p_chm->msg_params.filter.excl[0] = 0xff;
1015                /* All PSIP tables have protocol_version which must be = 0 */
1016                //p_chm->msg_params.filter.coef[8] = 0x00;      /* protocol_version */
1017                //p_chm->msg_params.filter.mask[8] = 0x00;
1018                pmt_section_size = PMT_BUF_LEN;
1019                if ((result = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT)) != 0)
1020                {
1021                        BDBG_ERR(("Error getting PAT 0x%04x\n",prog_number));
1022                        return result;
1023                }
1024
1025                p_ch->pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
1026
1027                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
1028                {
1029                        TS_PSI_descriptor psi_desc,lang_desc;
1030                        bsettop_av_stream_type_t *stream_type;
1031                        int strm_idx, aidx = 0;
1032                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
1033                        {
1034                                BDBG_WRN(("Failure processing PMT %d\n",p_idx));
1035                                return eCHM_ERR_FAILED;
1036                        }
1037
1038                        strm_idx = 0;
1039                        lang_desc = NULL;
1040                        num_aud = 0;
1041                        num_aud_tmp = 0;
1042                        p_ch->has_lang = 0;
1043                        while ((psi_desc = TS_PMT_getStreamDescriptor(p_chm->pmt_buf,pmt_section_size, p_idx,strm_idx)) != NULL)
1044                        {
1045                                if (psi_desc[0] == TS_PSI_DT_ISO639Language) /* 0x0A ISO-639 Language descriptor */
1046                                {
1047                                        BDBG_WRN(("ISO-639 DESC\n" ));
1048                                        lang_desc = psi_desc;
1049                                        break;
1050                                }
1051                                strm_idx++;
1052                                if (strm_idx > 0xFF)
1053                                {
1054                                        BDBG_ERR(("PMT Stream Desc limit exceeded %d\n",strm_idx));
1055                                        break;
1056                                }
1057                                if (chm_check_cancel(p_chm))
1058                                {
1059                                        return eCHM_ERR_CANCELED;
1060                                }
1061                        }
1062
1063                        if ((stream_type = bdecode_supported_video(pmt.stream_type)) != NULL)
1064                        {
1065                                BDBG_WRN(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
1066                                if (!p_ch->video_pid)
1067                                {
1068                                        p_ch->video_pid = pmt.elementary_PID;
1069                                        p_ch->video_type = stream_type->codec_id;
1070                                }
1071                        } else if ((stream_type = bdecode_supported_audio(pmt.stream_type)) != NULL)
1072                        {
1073                                BDBG_MSG(("Audio PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
1074                                if (lang_desc) {
1075                                        aidx = chm_valid_lang(p_chm, (char *)&lang_desc[2]);
1076                                        if ((aidx >= 0) && (aidx < MAX_AUDIO_PIDS))
1077                                        {
1078                                                if (!p_ch->audio_pid[aidx])
1079                                                {
1080                                                        p_ch->has_lang |= 1 < aidx;
1081                                                        p_ch->audio_pid[aidx] = pmt.elementary_PID;
1082                                                        p_ch->audio_type[aidx] = stream_type->codec_id;
1083#ifdef  USE_LANGUAGE
1084                                                        if (aidx == p_app->settings.language)
1085                                                                pch->cur_audio = aidx;
1086#else
1087                                                        /* assume that first audio PID always has audio */
1088                                                        if (0 == num_aud)
1089                                                                p_ch->cur_audio = aidx;
1090#endif
1091                                                        num_aud++;
1092                                                }
1093                                        }
1094                                        else {
1095                                                /* remember it first */
1096                                                if ((num_aud_tmp < MAX_AUDIO_PIDS) && !audio_pid[num_aud_tmp]) {
1097                                                        audio_pid[num_aud_tmp] = pmt.elementary_PID;
1098                                                        audio_type[num_aud_tmp] = stream_type->codec_id;
1099                                                        num_aud_tmp++;
1100                                                }
1101                                        }
1102                                }
1103                                else {
1104                                        if ((num_aud < MAX_AUDIO_PIDS) && !p_ch->audio_pid[num_aud]) {
1105                                                p_ch->audio_pid[num_aud] = pmt.elementary_PID;
1106                                                p_ch->audio_type[num_aud] = pmt.stream_type;
1107                                                if (0 == p_ch->num_audio)
1108                                                        p_ch->cur_audio = aidx;
1109                                                num_aud++;
1110                                        }
1111                                }
1112                        }
1113                }
1114                if (0 == num_aud && num_aud_tmp) {
1115                        for (idx = 0; idx < num_aud_tmp; idx++) {
1116                                p_ch->has_lang |= 1 < idx;
1117                                p_ch->audio_pid[idx] = audio_pid[idx];
1118                                p_ch->audio_type[idx] = audio_type[idx];
1119                        }
1120                        p_ch->num_audio = num_aud_tmp;
1121                        p_ch->cur_audio = 0;
1122                }
1123                break;
1124        }
1125        return result;
1126}
1127
1128/*
1129Summary:
1130Scan for channels using VCT for given time, and if no VCT, then will using PSI scan instead
1131Description:
1132Scan for channels using VCT.
1133Returns:
1134number of channels added.
1135*/
1136static int chm_scan_vct(
1137                chm_mgr_t *p_chm,               /* Channel manager reference */
1138                bband_t band, 
1139                int freq_idx)
1140{
1141        unsigned int section_size;
1142        int minor_idx, channels;
1143        bool got_vct;
1144        unsigned char section_number;
1145        int result = 0;                 /* we just track 3 audio channels currently */
1146        bapp_ch_t ch;
1147        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1148        PSIP_VCT_channel    vct;
1149        unsigned int timeout;
1150        bool have_program;
1151
1152        timeout = bos_getticks() + MS_TO_TICKS(15 * VCT_TIMEOUT);
1153        memset(&vct,0,sizeof(vct));
1154
1155        /* Get the VCT */
1156        section_number = 0;
1157        do
1158        {       
1159                smessage_stream_params_init(&p_chm->msg_params, NULL);
1160                p_chm->msg_params.band = band;
1161                p_chm->msg_params.pid = 0x1ffb; /* VCT */
1162
1163                p_chm->msg_params.filter.coef[0] = 0xc8;        /* Table ID for terrestrial */
1164                p_chm->msg_params.filter.mask[0] = 0x00;
1165                p_chm->msg_params.filter.coef[6] = section_number;      /* section number */
1166                p_chm->msg_params.filter.mask[6] = 0x00;
1167                /* All PSIP tables have protocol_version which must be = 0 */
1168                p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
1169                p_chm->msg_params.filter.mask[8] = 0x00;
1170
1171                got_vct = false;
1172                memset(&p_chm->prev_vct, 0, sizeof(p_chm->prev_vct));
1173                do
1174                {
1175                        section_size = VCT_BUF_LEN;
1176                        if (chm_getmessage(p_chm,p_chm->vct_buf,&section_size, VCT_TIMEOUT) != 0)
1177                        {
1178                                /* timeout, clear section size in case there is no vct in the stream at all */
1179                                p_chm->vct_buf[7] = 0;
1180                                BDBG_WRN(("Timeout waiting for VCT, section_number=%d", section_number));
1181                                if (!p_chm->not_check_cancel && chm_check_cancel(p_chm))
1182                                {
1183                                        return eCHM_ERR_CANCELED;
1184                                }
1185                                if (timeout > bos_getticks()) {
1186                                        p_chm->msg_params.crc_disabled = true;
1187                                        continue;
1188                                }
1189                                else {
1190                                        break;
1191                                }
1192                        }
1193
1194                        channels = PSIP_VCT_getNumChannels(p_chm->vct_buf);
1195                        if (0 == channels)
1196                        {
1197                                BDBG_WRN(("No VCT Found!"));
1198                                break;
1199                        }
1200
1201                        BDBG_MSG(("PSIP_VCT_getNumChannels %d fount!", channels));
1202
1203                        for (minor_idx = 0; minor_idx < channels; ++minor_idx)
1204                        {
1205                                int desc_idx;
1206                                TS_PSI_descriptor psi_desc;
1207                                have_program = false;
1208                                bsettop_av_stream_type_t *stream_type;
1209
1210                                if (PSIP_VCT_getChannel( (const uint8_t *)p_chm->vct_buf, minor_idx, &vct ) == BERR_SUCCESS)
1211                                {
1212                                        /* if hidden or analog, skip it */
1213                                        if ((vct.hidden) || (vct.minor_channel_number == 0) || (vct.service_type!=2 && vct.service_type!=3))
1214                                        {
1215                                                /* RLQ, TODO, we can set hidden in ch stucture instead of skip it */
1216                                                BDBG_MSG(("Channel hidden or analog channel %d, %d",vct.hidden,vct.minor_channel_number));
1217                                                /* got vct, but hidden or analog, need to skip do loop if reach end of VCT */
1218                                                if ((minor_idx + 1) >= channels) {
1219                                                        got_vct = true;
1220                                                        break;
1221                                                }
1222                                                else
1223                                                        continue;
1224                                        }
1225                                        /* note the vct can't duplicate in same station, but can if it is different station with different frequency */
1226                                        if (0 == memcmp((void *)&vct, (void *)&p_chm->prev_vct, sizeof(vct))){
1227                                                BDBG_WRN(("Duplicate VCT entry (%d.%d), discard",vct.major_channel_number, vct.minor_channel_number));
1228                                                continue;
1229                                        }
1230                                        /* remember it for next comparison */
1231                                        p_chm->prev_vct = vct;
1232
1233                                        got_vct = true;
1234                                        memset(&ch,0,sizeof(ch));
1235                                        ch.freq_idx = freq_idx;
1236                                        /* remember the frequency to use it directly instead using the frequency index */
1237                                        ch.major = vct.major_channel_number;
1238                                        ch.minor = vct.minor_channel_number;
1239                                        ch.psi = false;
1240                                        ch.source_id = vct.source_id;
1241                                        memcpy(ch.ch_name, vct.short_name, sizeof(ch.ch_name));
1242                                        /* need to remember program number so that we can check the program number for PAT/PMT checking */
1243                                        ch.program_num = vct.program_number;
1244
1245                                        desc_idx = 0;
1246                                        while ((psi_desc = PSIP_VCT_getChannelDescriptor(p_chm->vct_buf, minor_idx,desc_idx)) != NULL)
1247                                        {
1248                                                if (psi_desc[0] == 0xA1) /* Service location descriptor */
1249                                                {
1250                                                        PSIP_SLD_header sld_header;
1251                                                        PSIP_SLD_element sld_elem;
1252                                                        int sld_idx,lidx;
1253
1254                                                        PSIP_SLD_getHeader(psi_desc,&sld_header);
1255                                                        have_program = true;
1256
1257                                                        ch.pcr_pid = sld_header.PCR_PID;
1258                                                        ch.has_lang = 0;
1259                                                        ch.num_audio = 0;
1260                                                        BDBG_MSG(("SLD number_elements = %d\n",sld_header.number_elements ));
1261
1262                                                        for (sld_idx = 0; sld_idx < sld_header.number_elements; ++sld_idx)
1263                                                        {
1264                                                                if (PSIP_SLD_getElement(psi_desc,sld_idx,&sld_elem) != BERR_SUCCESS)
1265                                                                {
1266                                                                        BDBG_WRN(("Error processing SLD Desc %d of %d",sld_idx,sld_header.number_elements));
1267                                                                        break;
1268                                                                }
1269                                                                if ((stream_type = bdecode_supported_video(sld_elem.stream_type)) != NULL)
1270                                                                {
1271                                                                        BDBG_WRN(("Video PID[%d] = 0x%04x\n",sld_idx,sld_elem.elementary_PID ));
1272                                                                        if (!ch.video_pid)
1273                                                                        {
1274                                                                                ch.video_pid = sld_elem.elementary_PID;
1275                                                                                ch.video_type = stream_type->codec_id;
1276                                                                        }
1277                                                                } else 
1278                                                                {
1279                                                                        if ((stream_type = bdecode_supported_audio(sld_elem.stream_type)) != NULL)
1280                                                                        {
1281                                                                                BDBG_MSG(("Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
1282                                                                                                        sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
1283                                                                                if ((lidx = chm_valid_lang(p_chm,sld_elem.ISO_639_language_code)) >= 0 )
1284                                                                                {
1285
1286                                                                                        if ((lidx >= 0) && (lidx < MAX_AUDIO_PIDS) && (ch.num_audio < MAX_AUDIO_PIDS)) { 
1287                                                                                                if (ch.audio_pid[lidx] != 0)
1288                                                                                                {
1289                                                                                                        int i = lidx, j = lidx;
1290                                                                                                        BDBG_WRN(("Duplicate language Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
1291                                                                                                                                sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
1292                                                                                                        /* we need to handle it as it happens often in Mexico broadcast */
1293                                                                                                        do {
1294                                                                                                                i++;
1295                                                                                                                i %= MAX_AUDIO_PIDS;
1296                                                                                                                if (0 == ch.audio_pid[i]) {
1297                                                                                                                        ch.audio_pid[i] = sld_elem.elementary_PID;
1298                                                                                                                        ch.audio_type[i] = stream_type->codec_id;
1299                                                                                                                        ch.has_lang |= 1 << i;
1300                                                                                                                        if (0 == ch.num_audio)
1301                                                                                                                                ch.cur_audio = i;
1302                                                                                                                        ch.num_audio++;
1303                                                                                                                        ch.audio_lang[i][0] = toupper(sld_elem.ISO_639_language_code[0]);
1304                                                                                                                        ch.audio_lang[i][1] = toupper(sld_elem.ISO_639_language_code[1]);
1305                                                                                                                        ch.audio_lang[i][2] = toupper(sld_elem.ISO_639_language_code[2]);
1306                                                                                                                        break;
1307                                                                                                                }
1308                                                                                                        } while (i != j);
1309                                                                                                } else
1310                                                                                                {
1311                                                                                                        ch.audio_pid[lidx] = sld_elem.elementary_PID;
1312                                                                                                        ch.audio_type[lidx] = stream_type->codec_id;
1313                                                                                                        ch.has_lang |= 1 << lidx;
1314#ifdef  USE_LANGUAGE
1315                                                                                                        /* initialize audio selection if match in scan time */
1316                                                                                                        if (lidx == p_app->settings.language)
1317                                                                                                                ch.cur_audio = lidx;
1318#else
1319                                                                                                        /* assume that first audio PID always has audio */
1320                                                                                                        if (0 == ch.num_audio)
1321                                                                                                                ch.cur_audio = lidx;
1322#endif
1323                                                                                                        ch.num_audio++;
1324                                                                                                }
1325                                                                                        }
1326                                                                                } else
1327                                                                                {
1328                                                                                        BDBG_WRN(("Throwing out Audio PID[%d] = 0x%04x, lang => %c%c%c\n",sld_idx,sld_elem.elementary_PID,
1329                                                                                                                sld_elem.ISO_639_language_code[0],sld_elem.ISO_639_language_code[1],sld_elem.ISO_639_language_code[2] ));
1330                                                                                }
1331                                                                        }
1332                                                                }
1333                                                        }
1334
1335                                                        /* Backup plan if there is no valid language code */
1336                                                        if (0 == ch.num_audio)
1337                                                        {
1338                                                                BDBG_WRN(("No valid audio PID found for languages in audio descs...\n"));
1339                                                                for (sld_idx = 0; sld_idx < sld_header.number_elements && (ch.num_audio < MAX_AUDIO_PIDS); ++sld_idx)
1340                                                                {
1341                                                                        if (PSIP_SLD_getElement(psi_desc,sld_idx,&sld_elem) != BERR_SUCCESS)
1342                                                                        {
1343                                                                                BDBG_WRN(("Error processing SLD Desc %d of %d",sld_idx,sld_header.number_elements));
1344                                                                                break;
1345                                                                        }
1346                                                                        if ((stream_type = bdecode_supported_audio(sld_elem.stream_type)) != NULL)
1347                                                                        {
1348                                                                                if (ch.num_audio < MAX_AUDIO_PIDS) {
1349                                                                                        BDBG_WRN(("Audio PID[%d] = 0x%04x\n",sld_idx,sld_elem.elementary_PID));
1350                                                                                        ch.audio_pid[ch.num_audio] = sld_elem.elementary_PID; 
1351                                                                                        ch.audio_type[ch.num_audio] = stream_type->codec_id;
1352                                                                                        if (0 == ch.num_audio)
1353                                                                                                ch.cur_audio = 0;
1354                                                                                        ch.num_audio++;
1355                                                                                }
1356                                                                        }
1357                                                                }
1358                                                        }
1359                                                }
1360                                                desc_idx++;
1361                                                if (desc_idx > 0xFF)
1362                                                {
1363                                                        BDBG_ERR(("VCT Channel Desc limit exceeded %d\n",desc_idx));
1364                                                        break;
1365                                                }
1366                                                if (!p_chm->not_check_cancel && chm_check_cancel(p_chm))
1367                                                {
1368                                                        return eCHM_ERR_CANCELED;
1369                                                }
1370                                        }
1371                                        if (!have_program)
1372                                        {
1373                                                BDBG_WRN(("Don't have program, look for PAT/PMT instead "));
1374                                                if (chm_get_program_info(p_chm,band,vct.program_number,&ch) == 0)
1375                                                {
1376                                                        if ((0 == ch.video_pid) && (0 == ch.num_audio)) {
1377                                                                /* data program, skip it */
1378                                                        }
1379                                                        else {
1380                                                                BDBG_MSG(("program video 0x%04x, audio 0x%04x, PCR 0x%04x",ch.video_pid,ch.audio_pid,ch.pcr_pid));
1381                                                                have_program = true;
1382                                                        }
1383                                                }
1384                                        }
1385
1386                                        if (p_chm->local_time_source == eTS_NONE)
1387                                        {
1388                                                p_chm->local_time_source = eTS_FIXED;
1389                                                p_chm->local_offset = 0 - (int)g_tz_map[p_app->settings.time_zone];
1390                                                p_chm->local_offset *= 3600;
1391                                                p_chm->local_dst_obs = p_app->settings.dst;
1392                                                BDBG_WRN(("### Local time %d Fixed ###\n",p_chm->local_offset));
1393                                        }
1394
1395                                        if (have_program)
1396                                        {
1397                                                ch.frequency_khz = p_chm->freq_table[p_chm->select_idx];
1398                                                chm_add_vsb_channel(p_chm,&ch);
1399                                                result += 1;
1400
1401                                                p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
1402                                                p_chm->chm_pat_evt.id = eCHM_STATUS_PAT;
1403                                                p_chm->chm_pat_evt.ticks = (unsigned int)(((p_chm->select_idx)*100)/p_chm->num_freq);
1404                                                chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
1405
1406                                                if (p_app->screen_id == eSCREEN_CH_SCAN_PROGRESS) {
1407                                                        //bos_sleep(100);
1408                                                        bos_sleep(50);
1409                                                }
1410
1411                                        }
1412                                } else
1413                                {
1414                                        if ((0 == ch.video_pid) && (0 == ch.num_audio)) {
1415                                                BDBG_WRN(("Skip data program %d.%d",ch.major, ch.minor));
1416                                        }
1417                                        else
1418                                                BDBG_WRN(("PSIP_VCT_getChannel %d failed",minor_idx));
1419                                }
1420                        }
1421                        if (p_chm->not_check_cancel)
1422                                break;
1423                } while ((section_size > 0) && !got_vct);
1424
1425                if (!p_chm->not_check_cancel && chm_check_cancel(p_chm))
1426                {
1427                        return eCHM_ERR_CANCELED;
1428                }
1429                section_number++;
1430#if 1 //LAST_SECTION_BUG_FIX
1431                if (section_number <= p_chm->vct_buf[7])
1432#else
1433                if (section_number < p_chm->vct_buf[7])
1434#endif
1435                        timeout = bos_getticks() + MS_TO_TICKS(15 * VCT_TIMEOUT);
1436  }
1437#if 1 //LAST_SECTION_BUG_FIX
1438        while (section_number <= p_chm->vct_buf[7]); // hschang_130613 should also include last section
1439#else
1440        //while ((section_number < p_chm->vct_buf[7]) && (timeout < bos_getticks()));
1441        while (section_number < p_chm->vct_buf[7]);
1442#endif
1443
1444        return((result > 0) || (timeout < bos_getticks())) ? result : eCHM_ERR_TIMEOUT;
1445}
1446
1447/*
1448Summary:
1449Scan for channels using PSI for given frequency index
1450Description:
1451Scan for channels using PSI.
1452Returns:
1453Number of channels added
1454Or error code if < 0
1455*/
1456static int chm_scan_psi(
1457                chm_mgr_t *p_chm,               /* Channel manager reference */
1458                bband_t band, 
1459                int freq_idx)
1460{
1461        unsigned int section_size, pmt_section_size;
1462        TS_PMT_stream pmt;
1463        TS_PAT_program pat;
1464        int result = 0;
1465        int idx,p_idx,tresult, desc_idx = 0, programs;
1466        TS_PSI_descriptor psi_desc;
1467        unsigned short ca_pid = 0, minor = 1;
1468        bapp_ch_t ch;
1469
1470        /* Get the PAT */
1471        smessage_stream_params_init(&p_chm->msg_params, NULL);
1472        p_chm->msg_params.band = band;
1473        p_chm->msg_params.pid = (unsigned short)0;      /* PAT */
1474        /* All PSIP tables have protocol_version which must be = 0 */
1475        //p_chm->msg_params.filter.coef[8] = 0x00;      /* protocol_version */
1476        //p_chm->msg_params.filter.mask[8] = 0x00;
1477        section_size = PAT_BUF_LEN;
1478
1479        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
1480        {
1481                BDBG_WRN(("%s Timeout getting PAT\n",__func__));
1482                return result;
1483        }
1484
1485        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
1486        {
1487                BDBG_WRN(("TS_PAT_validate failed\n"));
1488                return eCHM_ERR_FAILED;
1489        }
1490
1491        programs = TS_PAT_getNumPrograms(p_chm->pat_buf);
1492        BDBG_MSG(("Programs %d in PAT", programs));
1493
1494        if (0 == programs)
1495        {
1496                BDBG_WRN(("%s TS_PAT_getNumPrograms = 0,section_size = %d\n",__func__,section_size));
1497                return eCHM_ERR_FAILED;
1498        }
1499        p_chm->pat_crc = chm_section_crc(p_chm->pat_buf,section_size);
1500
1501        for (idx = 0; idx < programs; idx++)
1502        {
1503                if (chm_check_cancel(p_chm))
1504                {
1505                        return eCHM_ERR_CANCELED;
1506                }
1507
1508                section_size = PAT_BUF_LEN;
1509                if ((tresult = TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat )) != b_ok)
1510                {
1511                        BDBG_WRN(("TS_PAT_getProgram failed 0x%x", tresult));
1512                        return eCHM_ERR_FAILED;
1513                }
1514
1515                smessage_stream_params_init(&p_chm->msg_params, NULL);
1516                p_chm->msg_params.band = band;
1517                p_chm->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
1518                /*RLQ*/
1519                p_chm->msg_params.filter.coef[0] = 0x2;
1520                p_chm->msg_params.filter.mask[0] = 0x00;
1521                pmt_section_size = PMT_BUF_LEN;
1522                if ((tresult = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT)) != 0)
1523                {
1524                        BDBG_WRN(("Failed getting PMT 0x%04x\n",pat.PID));
1525                        continue;
1526                }
1527                p_chm->pmt_crc = chm_section_crc(p_chm->pmt_buf,pmt_section_size);
1528
1529                memset(&ch,0,sizeof(ch));
1530                ch.major = (freq_idx == 0x7F) ? 0 : freq_idx + 2;       /* freq_idx is off by 2 */
1531                ch.minor = minor++;
1532                ch.freq_idx = freq_idx;
1533                ch.pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
1534                ch.program_num = pat.program_number;
1535                ch.psi = true;          /* we got this entry using PSI scan vs VCT */
1536                /* Get CA pid if */
1537                while ((psi_desc = TS_PMT_getDescriptor(p_chm->pmt_buf, pmt_section_size,desc_idx++)) != NULL)
1538                {
1539                        if (desc_idx > 0xFF)
1540                        {
1541                                BDBG_ERR(("PMT Desc limit exceeded %d\n",desc_idx));
1542                                break;
1543                        }
1544                        if (chm_check_cancel(p_chm))
1545                        {
1546                                return eCHM_ERR_CANCELED;
1547                        }
1548                        if (psi_desc[0] == 9)
1549                        {
1550                                ca_pid = (((unsigned short)(psi_desc[4] & 0x1F)) << 8) | (unsigned short)psi_desc[5];
1551                                BDBG_MSG(("CA PID = 0x%04x\n",ca_pid));
1552                                break;
1553                        }
1554                }
1555                if (ca_pid != 0x0000)
1556                {
1557                        BDBG_MSG(("Program has CA PID 0x%02x check for scrambling control bit.\n",ca_pid));
1558                }
1559
1560                BDBG_MSG(("Streams = %d\n",TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size)));
1561                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
1562                {
1563                        bsettop_av_stream_type_t *stream_type;
1564
1565                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
1566                        {
1567                                BDBG_WRN(("Failure processing PMT %d\n",p_idx));
1568                                return eCHM_ERR_FAILED;
1569                        }
1570                        if ((stream_type = bdecode_supported_video(pmt.stream_type)) != NULL)
1571                        {
1572                                BDBG_MSG(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
1573                                if (!ch.video_pid)
1574                                {
1575                                        ch.video_pid = pmt.elementary_PID;
1576                                        ch.video_type = stream_type->codec_id;
1577                                }
1578                        }
1579                        else if ((stream_type = bdecode_supported_audio(pmt.stream_type)) != NULL)
1580                        {
1581                                BDBG_MSG(("Audio PID[%d] = 0x%04x\n",ch.num_audio,pmt.elementary_PID ));
1582                                if (!ch.audio_pid[ch.num_audio] && (ch.num_audio < MAX_AUDIO_PIDS))
1583                                {
1584                                        ch.audio_pid[ch.num_audio] = pmt.elementary_PID;
1585                                        ch.audio_type[ch.num_audio] = stream_type->codec_id;
1586                                        if (0 == ch.num_audio)
1587                                                ch.cur_audio = 0;
1588                                        ch.num_audio++;
1589                                }
1590                        }
1591                }
1592
1593                if (ch.video_pid || ch.audio_pid[0])
1594                {
1595                        bool clear = true;
1596                        unsigned short pid;
1597
1598                        /* if has video, use video first */
1599                        if (ch.video_pid)
1600                                pid = ch.video_pid;
1601                        else
1602                                pid     = ch.audio_pid[0];
1603                        /* correct pid in case video pid carries too few frames */
1604                        if(ch.pcr_pid == ch.audio_pid[0])
1605                                pid = ch.audio_pid[0];
1606
1607                        if (ca_pid != 0x0000)
1608                                clear = chm_check_sc(p_chm, band, pid);
1609
1610                        if (clear)
1611                        {
1612                                bapp_t *p_app = (bapp_t *)p_chm->p_app;
1613
1614                                p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
1615                                p_chm->chm_pat_evt.id = eCHM_STATUS_PAT;
1616                                p_chm->chm_pat_evt.ticks = (unsigned int)(((p_chm->select_idx)*100)/p_chm->num_freq);
1617                                chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
1618                                ch.frequency_khz = p_chm->freq_table[p_chm->select_idx];
1619                                chm_add_vsb_channel(p_chm,&ch);
1620                                result += 1;
1621
1622                                /* in the chm_scan_psi, it will post STATUS_PAT. but sometimes the event is missed.. don't know why.. */ 
1623                                if (p_app->screen_id == eSCREEN_CH_SCAN_PROGRESS) {
1624                                        bos_sleep(100);
1625                                }
1626                        }
1627                }
1628        }
1629
1630        return result;
1631}
1632
1633/*
1634Summary:
1635Process the EIT event descriptors and return > 0 if a change was made
1636to the info structure, 0 if no changes are required and < 0
1637if an error occured.
1638*/
1639static int chm_process_eit_desc(
1640                chm_mgr_t *p_chm,                       /* Channel manager reference */
1641                unsigned char *msg_buf,         /* section buffer containing the EIT table */
1642                int  eit_idx,                           /* EIT event index */
1643                chm_eit_t *p_eit
1644                )
1645{
1646        TS_PSI_descriptor eit_desc;
1647        int eit_desc_idx,result = 0;
1648        bapp_t *p_app = (bapp_t*)p_chm->p_app;
1649        char * rating_str;
1650
1651        /* Process EIT entry descriptors */
1652        eit_desc_idx = 0;
1653        memset(p_eit->cc_service,0,MAX_CC_SERVICES * sizeof(PSIP_CSD_service));
1654        while ((eit_desc = PSIP_EIT_getEventDescriptor(p_chm->eit_buf,eit_idx,eit_desc_idx++)) != NULL)
1655        {
1656                switch (eit_desc[0])
1657                {
1658                        case 0x87: /* Content advisory descriptor */
1659                                {
1660                                        int rr_idx,rd_idx,psip_str_len;
1661                                        PSIP_CAD_rating_region rr;
1662                                        PSIP_CAD_rating_dimension rd;
1663                                        static chm_event_t chm_evt;
1664                                        PSIP_RRT_header rrt_header;
1665                                        int blocked = 0;
1666                                        if (p_app->settings.rrt_settings.rrt_status == eRRT_AVAILABLE)
1667                                        {
1668                                                PSIP_RRT_getHeader(p_app->settings.rrt_settings.rrt, &rrt_header);
1669                                        } else
1670                                        {
1671                                                rrt_header.rating_region = 1;
1672                                        }
1673
1674                                        p_app->psip_rating_str[0] = 0;
1675                                        for (rr_idx = 0; rr_idx < PSIP_CAD_getRatingRegionCount(eit_desc); ++rr_idx)
1676                                        {
1677                                                if (PSIP_CAD_getRatingRegion(eit_desc,rr_idx,&rr) != BERR_SUCCESS)
1678                                                        continue;
1679
1680                                                if ((rr.rating_region != 1) && (rr.rating_region != rrt_header.rating_region))
1681                                                {
1682                                                        BDBG_WRN(("CAD skip %d of %d, rating_region = %d, current = %d\n",
1683                                                                                rr_idx,PSIP_CAD_getRatingRegionCount(eit_desc),rr.rating_region,rrt_header.rating_region));
1684                                                        continue;
1685                                                }
1686
1687                                                if (rr_idx > 0)
1688                                                {
1689                                                        if (strlen(p_app->psip_rating_str) + 4 < MAX_RATING_STR_CHARS)
1690                                                        {
1691                                                                psip_str_len = strlen(p_app->psip_rating_str);
1692                                                                p_app->psip_rating_str[psip_str_len] = ',';
1693                                                                p_app->psip_rating_str[psip_str_len + 1] = ' ';
1694                                                                p_app->psip_rating_str[psip_str_len + 2] = 0;
1695                                                        }
1696                                                }
1697                                                psip_str_len = strlen(p_app->psip_rating_str);
1698                                                if (chm_process_mss(p_chm,rr.p_rating_description_text,&(p_app->psip_rating_str[psip_str_len]),
1699                                                                        MAX_RATING_STR_CHARS - psip_str_len) == 0)
1700                                                {
1701                                                        BDBG_MSG(("CAD[%d,%d] %s %d\n",rr_idx,rr.rating_region,p_app->psip_rating_str,rr.rated_dimensions));
1702                                                        if (p_app->settings.rrt_settings.rrt_status == eRRT_AVAILABLE && (1 != rr.rating_region)) {
1703                                                                unsigned char *p = strchr(p_app->psip_rating_str, (int)','), *p1;
1704                                                                if (p) {
1705                                                                        int size;
1706
1707                                                                        /* remember current point at ',' */
1708                                                                        p1 = p;
1709                                                                        p++;    /* skip ',' */
1710                                                                        if (0x20 == *p) /* skip ' ' */
1711                                                                                p++;                                           
1712
1713                                                                        if (!isdigit(*p)) {
1714                                                                                psip_str_len = strlen(p_app->psip_rating_str);
1715                                                                                size = psip_str_len - (int)(p - p_app->psip_rating_str);
1716                                                                                p = cad_rating_filter(p_app->settings.rrt_settings.rrt, p, &size);
1717                                                                                if (p) {
1718                                                                                        p1++;
1719                                                                                        strcpy(p1, p);
1720                                                                                }
1721                                                                                else {
1722                                                                                        /* NULL, remove ',' as well */
1723                                                                                        *p1 = '\0';
1724                                                                                }       
1725                                                                                psip_str_len = strlen(p_app->psip_rating_str);
1726                                                                        }
1727                                                                }
1728                                                        }
1729                                                        rating_str = NULL;
1730                                                } else
1731                                                {
1732                                                        BDBG_MSG(("CAD[%d] chm_process_mss failed\n",rr_idx));
1733                                                        rating_str = &(p_app->psip_rating_str[psip_str_len]);
1734                                                }
1735
1736                                                for (rd_idx = 0; rd_idx < rr.rated_dimensions; ++rd_idx)
1737                                                {
1738                                                        if (PSIP_CAD_getRatingDimension(eit_desc,rr_idx,rd_idx,&rd) != BERR_SUCCESS)
1739                                                        {
1740                                                                BDBG_WRN(("PSIP_CAD_getRatingDimension(%d,%d,%d) failed\n",rr.rating_region,rr_idx,rd_idx));
1741                                                                continue;
1742                                                        }
1743
1744                                                        if (rating_str != NULL)
1745                                                        {
1746                                                                psip_str_len = strlen(p_app->psip_rating_str);
1747                                                                rating_str = &(p_app->psip_rating_str[psip_str_len]);
1748                                                        }
1749#ifndef NO_VCHIP
1750                                                        BDBG_MSG(("*** CAD_RD[%d,%d] region %d, %d-%d\n",rr_idx, rd_idx, rr.rating_region, rd.rating_dimension_j,rd.rating_value));
1751                                                        blocked |= chm_psip_block(p_app, rr.rating_region, rd.rating_dimension_j, rd.rating_value,rating_str);
1752                                                        BDBG_MSG(("--- dim:%d value:%d blocked:%d, %s\n", rd.rating_dimension_j, rd.rating_value, blocked,p_app->psip_rating_str));
1753#endif
1754                                                }
1755                                                if (chm_check_cancel(p_chm))
1756                                                        return eCHM_ERR_CANCELED;
1757                                        }
1758
1759                                        chm_evt.type = eCHM_EVT_CAD;
1760                                        chm_evt.id = (((unsigned int)blocked) << 24) |
1761                                                (((unsigned int)rr.rating_region) << 16) |
1762                                                (((unsigned int)rd.rating_dimension_j) << 8) |
1763                                                ((unsigned int)rd.rating_value);
1764                                        chm_evt.ticks = bos_getticks();
1765                                        result++;
1766                                        bos_post_event(p_app->msg_queue,(b_event_t*)&chm_evt);
1767                                        bos_sleep(30); /* yield so other thread can update */
1768                                }
1769                                break;
1770                        case 0x86: /* Caption Service descriptor */
1771                                {
1772                                        int csd_idx;
1773                                        PSIP_CSD_service tmpCSD;
1774                                        for (csd_idx = 0; csd_idx < PSIP_CSD_getNumServices(eit_desc); ++csd_idx)
1775                                        {
1776                                                if (PSIP_CSD_getService(eit_desc,csd_idx,&tmpCSD) != BERR_SUCCESS)
1777                                                {
1778                                                        BDBG_WRN(("Error getting CSD %d\n", csd_idx));
1779                                                        continue;
1780                                                }
1781                                                BDBG_MSG(("CSD-%d) %d, %d, %c%c%c\n", csd_idx,tmpCSD.cc_type,
1782                                                                        tmpCSD.cc.caption_service_number,tmpCSD.language[0],tmpCSD.language[1],tmpCSD.language[2]));
1783                                                if (!tmpCSD.cc_type || 
1784                                                                (tmpCSD.cc.caption_service_number == 0) ||
1785                                                                (tmpCSD.cc.caption_service_number > MAX_CC_SERVICES))
1786                                                        continue;
1787                                                memcpy(&(p_eit->cc_service[tmpCSD.cc.caption_service_number - 1]),&tmpCSD,sizeof(PSIP_CSD_service));
1788                                        }
1789                                }
1790                                break;
1791                        case 0x81: /* AC-3 Audio descriptor */
1792                        case 0xAA: /* Redistribution control descriptor */
1793                        case 0xB6: /* Content identifier descriptor */
1794                        case 0xAB: /* Genre descriptor */
1795                        default:
1796                                BDBG_MSG((" EIT_DESC[0x%02x]\n",eit_desc[0]));
1797                                break;
1798                }
1799        }
1800        return result;
1801}
1802
1803/*
1804Summary:
1805Get the EIT section and return > 0 if a change was made
1806to the info structure, 0 if no changes are required and < 0
1807if an error occured.
1808*/
1809static int chm_get_eit(
1810                chm_mgr_t *p_chm,                       /* Channel manager reference */
1811                chm_info_t *p_info,                     /* info structure to populate */
1812                unsigned short source_id,       /* channel source ID from VCT channel */
1813                unsigned short pid                      /* table type pid */
1814                )
1815{
1816        int eit_events,eit_idx,update,result;
1817        unsigned int eit_section_size,utc_time;
1818        PSIP_EIT_event eit;
1819        unsigned char *p_source_id = (unsigned char*)&source_id;
1820
1821        if (chm_check_cancel(p_chm))
1822                return eCHM_ERR_CANCELED;
1823
1824        if ((result = chm_get_utctime(p_chm,&utc_time)) != 0)
1825                return result;
1826
1827        BDBG_MSG(("UTC TIME(%u), source_id=0x%x\n",utc_time, source_id));
1828
1829        update = eEIT_NONE;
1830        smessage_stream_params_init(&p_chm->msg_params, NULL);
1831        p_chm->msg_params.band = p_chm->band;
1832        p_chm->msg_params.pid = pid;    /* base pid */
1833
1834        /* Source ID for channel  (assumes little endian system!!! )*/
1835        p_chm->msg_params.filter.coef[0] = 0xCB;
1836        p_chm->msg_params.filter.mask[0] = 0x00;
1837        p_chm->msg_params.filter.coef[3] = p_source_id[1];
1838        p_chm->msg_params.filter.mask[3] = 0x00;
1839        p_chm->msg_params.filter.coef[4] = p_source_id[0];
1840        p_chm->msg_params.filter.mask[4] = 0x00;
1841        /* All PSIP tables have protocol_version which must be = 0 */
1842        p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
1843        p_chm->msg_params.filter.mask[8] = 0x00;
1844        eit_section_size = EIT_BUF_LEN;
1845
1846        if ((result = chm_getmessage(p_chm,p_chm->eit_buf,&eit_section_size, EIT_TIMEOUT)) != 0) {
1847                BDBG_MSG(("%s failed, result=0x%x", __func__, result));
1848                return result;
1849        }
1850        else
1851        {
1852                int eit_cnt = 2;                /* track eit entry index */
1853
1854                chm_get_utctime(p_chm,&utc_time);
1855                utc_time += p_chm->stt.GPS_UTC_offset;
1856
1857                eit_events = PSIP_EIT_getNumEvents(p_chm->eit_buf);
1858                for (eit_idx = 0; eit_idx < eit_events; eit_idx++)
1859                {
1860                        if (chm_check_cancel(p_chm))
1861                                return eCHM_ERR_CANCELED;
1862
1863                        if (PSIP_EIT_getEvent(p_chm->eit_buf,eit_idx,&eit) != BERR_SUCCESS)
1864                                continue;
1865
1866                        if ((utc_time >= eit.start_time) && (utc_time < (eit.start_time + eit.length_in_seconds)))
1867                        {
1868                                chm_process_mss(p_chm,eit.p_title_text,
1869                                                p_info->eit_info[EIT_CURRENT].prog_title,MAX_TITLE_CHARS);
1870
1871                                p_info->eit_info[EIT_CURRENT].event_id = eit.event_id;
1872                                p_info->eit_info[EIT_CURRENT].length = eit.length_in_seconds;
1873                                p_info->eit_info[EIT_CURRENT].start_time = eit.start_time;
1874                                BDBG_MSG(("EIT cur=%s(%d,%u,%u)\n",p_info->eit_info[EIT_CURRENT].prog_title,eit.event_id,eit.start_time,eit.length_in_seconds));
1875
1876                                update |= eEIT_CURRENT;
1877                                chm_process_eit_desc(p_chm,p_chm->eit_buf,eit_idx,&(p_info->eit_info[EIT_CURRENT]));
1878                                /* got current event */
1879                                p_chm->got_eit = true;
1880                        } else if (((p_info->eit_info[EIT_CURRENT].start_time + p_info->eit_info[EIT_CURRENT].length) >= eit.start_time) && 
1881                                        ((p_info->eit_info[EIT_CURRENT].start_time + p_info->eit_info[EIT_CURRENT].length) < (eit.start_time + eit.length_in_seconds)))
1882                        {
1883                                chm_process_mss(p_chm,eit.p_title_text,
1884                                                p_info->eit_info[EIT_NEXT].prog_title,MAX_TITLE_CHARS);
1885
1886                                p_info->eit_info[EIT_NEXT].event_id = eit.event_id;
1887                                p_info->eit_info[EIT_NEXT].length = eit.length_in_seconds;
1888                                p_info->eit_info[EIT_NEXT].start_time = eit.start_time;
1889                                BDBG_MSG(("EIT next=%s(%d,%u,%u)\n",p_info->eit_info[EIT_NEXT].prog_title, p_info->eit_info[EIT_NEXT].event_id,eit.start_time,eit.length_in_seconds));
1890                                update |= eEIT_NEXT;
1891                        } else
1892                        {
1893                                /* update other entries */
1894                                if ((eit_idx < MAX_EIT_NUM) && (eit_cnt < MAX_EIT_NUM)) {
1895                                        /* same batch of EIT data after NEXT */
1896                                        if (update & eEIT_NEXT) {
1897                                                chm_process_mss(p_chm,eit.p_title_text, p_info->eit_info[eit_cnt].prog_title,MAX_TITLE_CHARS);
1898                                                p_info->eit_info[eit_cnt].event_id = eit.event_id;
1899                                                p_info->eit_info[eit_cnt].length = eit.length_in_seconds;
1900                                                p_info->eit_info[eit_cnt].start_time = eit.start_time;
1901                                                BDBG_WRN(("EIT entry %d = %s(%d,%u,%u, utc_time=%u)\n",eit_idx,p_info->eit_info[eit_cnt].prog_title, p_info->eit_info[eit_cnt].event_id,eit.start_time,eit.length_in_seconds,utc_time));
1902                                                eit_cnt++;
1903                                                update |= eEIT_CONT;    /* beyond current and next entries */
1904                                        }
1905                                }
1906                        }
1907                        /* exit if both are found */
1908                        //if (update == eEIT_BOTH)      /* don't quit since we need to get more EPG */
1909                        //      break;
1910                }
1911        }
1912
1913        return update;
1914}
1915
1916
1917/*
1918Summary:
1919Get the ETT section and return > 0 if a change was made
1920to the info structure, 0 if no changes are required and < 0
1921if an error occured.
1922*/
1923
1924static int chm_get_ett(
1925                chm_mgr_t *p_chm,                       /* Channel manager reference */
1926                chm_info_t *p_info,                     /* info structure to populate */
1927                unsigned short source_id,   /* channel source ID from VCT channel */
1928                unsigned short pid                      /* type type pid */
1929                )
1930{
1931        int update;
1932        unsigned int ett_section_size;
1933        unsigned char *p_source_id = (unsigned char*)&source_id;
1934        PSIP_ETT_header ett;
1935        int result;
1936        unsigned short event_id;
1937
1938        update = eEIT_NONE;
1939
1940        smessage_stream_params_init(&p_chm->msg_params, NULL);
1941        p_chm->msg_params.band = p_chm->band;
1942        p_chm->msg_params.pid = pid;    /* base pid */
1943
1944        /* All PSIP tables have protocol_version which must be = 0 */
1945        p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
1946        p_chm->msg_params.filter.mask[8] = 0x00;
1947        /* Source ID for channel  (assumes little endian system!!! )*/
1948        p_chm->msg_params.filter.coef[9] = p_source_id[1];
1949        p_chm->msg_params.filter.mask[9] = 0x00;
1950        p_chm->msg_params.filter.coef[10] = p_source_id[0];
1951        p_chm->msg_params.filter.mask[10] = 0x00;
1952        /* just check current one */
1953        event_id = (p_info->eit_info[EIT_CURRENT].event_id << 2) | 0x2;
1954        p_chm->msg_params.filter.coef[11] = (event_id >> 8);
1955        p_chm->msg_params.filter.mask[11] = 0x00;
1956        p_chm->msg_params.filter.coef[12] = event_id & 0xff;
1957        p_chm->msg_params.filter.mask[12] = 0x03;
1958        ett_section_size = ETT_BUF_LEN;
1959
1960        if ((result = chm_getmessage(p_chm,p_chm->ett_buf,&ett_section_size, ETT_TIMEOUT)) != 0)
1961                return result;
1962        else
1963        {
1964                p_chm->ett_cnt++;
1965                PSIP_ETT_getHeader(p_chm->ett_buf,&ett);
1966
1967                if (ett.ETM_id.event_id == p_info->eit_info[EIT_CURRENT].event_id)
1968                {
1969                        chm_process_mss(p_chm,ett.p_extended_text_message,
1970                                        p_info->eit_info[EIT_CURRENT].prog_desc,MAX_DESC_CHARS);
1971                        update |= eEIT_CURRENT;
1972                        BDBG_MSG(("ETT: 0x%04x(%d) %s\n",pid, EIT_CURRENT,p_info->eit_info[EIT_CURRENT].prog_desc));
1973                        p_chm->got_ett = true;
1974                } else if (ett.ETM_id.event_id == p_info->eit_info[EIT_NEXT].event_id)
1975                {
1976                        chm_process_mss(p_chm,ett.p_extended_text_message,
1977                                        p_info->eit_info[EIT_NEXT].prog_desc,MAX_DESC_CHARS);
1978
1979                        update |= eEIT_NEXT;
1980                        BDBG_MSG(("ETT: 0x%04x(%d) %s\n",pid, EIT_NEXT,p_info->eit_info[EIT_NEXT].prog_desc));
1981                } else
1982                {
1983#ifdef BCM_DEBUG
1984                        chm_process_mss(p_chm,ett.p_extended_text_message, p_chm->tmp_text,MAX_TITLE_CHARS);
1985                        BDBG_MSG(("ETT: 0x%04x(%d != %d or %d) %s\n",pid,ett.ETM_id.event_id,
1986                                                p_info->eit_info[EIT_CURRENT].event_id,p_info->eit_info[EIT_NEXT].event_id ,p_chm->tmp_text));
1987#endif
1988                }
1989        }
1990        return update;
1991}
1992
1993/*
1994Summary:
1995Process the MMS string and associated tables.
1996Returns
1997non-zero on failure.
1998*/
1999int chm_process_mss(
2000                chm_mgr_t *p_chm,                               /* Channel manager reference */
2001                PSIP_MSS_string p_mms,                  /* Pointer to MMS */
2002                unsigned char* mms_buf,                 /* string buffer */
2003                unsigned int mms_len                    /* string buffer length */
2004                )
2005{
2006        int str_idx,lsize;
2007        char *p_code;
2008        BERR_Code retcode;
2009        int num_str;
2010        bapp_t *p_app;
2011
2012        if (!p_mms)
2013                return eCHM_ERR_FAILED;
2014
2015        num_str = PSIP_MSS_getNumStrings(p_mms);
2016        p_app = (bapp_t*)p_chm->p_app;
2017        memset(mms_buf,0,mms_len);
2018
2019        for (str_idx = 0; str_idx < num_str; ++str_idx) {
2020                if ((retcode = PSIP_MSS_getCode(p_mms,str_idx, &p_code)) != BERR_SUCCESS) {
2021                        BDBG_MSG(("PSIP_MSS_getCode:%d failed %d\n",__LINE__,retcode));
2022                        continue;
2023                }
2024                if (chm_valid_lang(p_chm,p_code) != p_app->lang) {
2025                        continue;
2026                }
2027
2028                lsize = mms_len;
2029                if ((retcode = PSIP_MSS_getString(p_mms,str_idx,&lsize, mms_buf)) == BERR_SUCCESS) {
2030                        /* got one matched to current language */
2031                        return 0;
2032                }
2033        }
2034
2035        /* in case no valid language exists just use first string */
2036        if (num_str > 0) {
2037                lsize = mms_len;
2038                if ((retcode = PSIP_MSS_getString(p_mms,0,&lsize, mms_buf)) == BERR_SUCCESS) {
2039                        BDBG_WRN(("No language match using first language in the MMS list\n"));
2040                        return eCHM_ERR_OK;
2041                } else {
2042                        BDBG_WRN(("PSIP_MSS_getString failed %d\n",retcode));
2043                }
2044        }
2045        BDBG_WRN(("%s: no valid string found, num_str = %d\n",__func__,num_str));
2046        return eCHM_ERR_FAILED;
2047}
2048
2049/*
2050Summary:
2051Pocess the VCT in background manner?
2052Returns
2053non-zero on failure.
2054*/
2055static int chm_process_vct(
2056                chm_mgr_t *p_chm,               /* Channel manager reference */
2057                unsigned char *msg_buf, /* Buffer containing the MGT table */
2058                unsigned int msg_size,  /* PSI buffer size */
2059                chm_info_t *p_info,             /* info structure to populate */
2060                unsigned short minor    /* minor ch number */   
2061                )
2062{
2063        int minor_idx,sld_idx,total;
2064        TS_PSI_descriptor psi_desc;
2065        PSIP_VCT_channel    vct;
2066        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2067
2068        total = PSIP_VCT_getNumChannels(msg_buf);
2069        if (total < 1)
2070                return eCHM_ERR_FAILED;
2071
2072        for (minor_idx = 0; minor_idx < total; ++minor_idx)
2073        {
2074                /* if user cancel is recevied */
2075                if (chm_check_cancel(p_chm))
2076                        return eCHM_ERR_CANCELED;
2077
2078                memset(&vct,0,sizeof(vct));
2079                if (PSIP_VCT_getChannel( (const uint8_t *)msg_buf, minor_idx, &vct ) != BERR_SUCCESS)
2080                {
2081                        BDBG_WRN(("Failure processing VCT %d\n",minor_idx));
2082                        return eCHM_ERR_FAILED;
2083                }
2084                /* for digital, start from 1 */
2085                if (vct.minor_channel_number != minor)
2086                {
2087                        BDBG_MSG(("VCT minor number %d not match to %d\n",vct.minor_channel_number, minor));
2088                        continue;
2089                }
2090                p_info->major = vct.major_channel_number;
2091                p_info->minor = vct.minor_channel_number;
2092                p_info->source_id = vct.source_id;
2093                p_info->program_number = vct.program_number;
2094                memcpy(p_info->ch_name, vct.short_name,sizeof(uint16_t) * MAX_CH_NAME_CHARS);
2095                p_info->got_vct = true;
2096
2097                if (p_chm->local_time_source == eTS_NONE)
2098                {
2099                        p_chm->local_time_source = eTS_FIXED;
2100                        p_chm->local_offset = 0 - (int)g_tz_map[p_app->settings.time_zone];
2101                        p_chm->local_offset *= 3600;
2102                        p_chm->local_dst_obs = p_app->settings.dst;
2103                        BDBG_MSG(("### Local time %d Fixed ###\n",p_chm->local_offset));
2104                }
2105
2106                sld_idx = 0;
2107                while ((psi_desc = PSIP_VCT_getChannelDescriptor(msg_buf, minor_idx,sld_idx)) != NULL)
2108                {
2109                        if (psi_desc[0] == 0xA0) /* Extended channel name descriptor */
2110                        {
2111                                PSIP_MSS_string lstr = PSIP_ECND_getLongChannelName(psi_desc);
2112                                chm_process_mss(p_chm,lstr,p_info->ext_ch_name,MAX_LONG_NAME_CHARS);
2113                        }
2114                        sld_idx++;
2115                }
2116                return eCHM_ERR_OK;
2117        }
2118        return eCHM_ERR_FAILED; /* channel not found */
2119}
2120
2121/*
2122Summary:
2123Process the MGT and associated tables.
2124Returns
2125non-zero on failure.
2126*/
2127static int chm_process_mgt(
2128                chm_mgr_t *p_chm,               /* Channel manager reference */
2129                unsigned char *msg_buf, /* Buffer containing the MGT table */
2130                unsigned int msg_size,  /* PSI buffer size */
2131                chm_info_t *p_info,             /* info structure to populate */
2132                bool ext_text,                  /* Get extended text */
2133                bool redraw                             /* Send redraw event */
2134                )
2135{
2136        PSIP_MGT_table table;
2137        int num_tables, update = eEIT_NONE,result = 0;
2138        unsigned short source_id;
2139        unsigned int utc_time;
2140        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2141
2142        if ((result = chm_get_utctime(p_chm,&utc_time)) != 0)
2143                return result;
2144
2145        gettimeofday(&p_chm->mgt_tv);
2146
2147        source_id = p_info->source_id;
2148        num_tables = PSIP_MGT_getTablesDefined(msg_buf);
2149        switch (p_chm->mgt_state)
2150        {
2151                case eMGT_EIT:
2152                        /* try to get either EIT or ETT */
2153                        for (p_chm->mgt_idx = 0; p_chm->mgt_idx < num_tables; p_chm->mgt_idx++)
2154                        {
2155                                if (chm_check_cancel(p_chm))
2156                                        return eCHM_ERR_CANCELED;
2157
2158                                PSIP_MGT_getTable(msg_buf,p_chm->mgt_idx,&table);
2159                                /* currently we only care current and next program instead of 128 eits (0x017F) */
2160                                //if ((table.table_type >= 0x0100) && (table.table_type < (0x0100 + MAX_EIT_NUM)) && (eEIT_BOTH != update))
2161                                if ((table.table_type >= 0x0100) && (table.table_type < (0x0100 + MAX_EIT_NUM)))
2162                                {
2163                                        BDBG_MSG(("EIT: PID=0x%04x, type=0x%04x",table.table_type_PID,table.table_type));
2164
2165                                        result = chm_get_eit(p_chm,p_info,source_id,table.table_type_PID);
2166                                        if (result < 0) {
2167                                                BDBG_MSG(("chm_get_eit failed, ret=%d", result));
2168                                                if (update)
2169                                                        result = 0;
2170                                                break;
2171                                        }
2172#ifndef NO_VCHIP
2173                                        if (p_app->psip_rating_str[0] && !(0 == result || eEIT_CONT == result)) {
2174                                                memcpy(&p_info->psip_rating_str, p_app->psip_rating_str, strlen(p_info->psip_rating_str));
2175                                                p_info->psip_rating_str[strlen(p_info->psip_rating_str)] = 0;
2176                                        }
2177#endif
2178                                        if (eEIT_NONE == result) {
2179                                                /* continue check until find the EIT entry corresponding to current */
2180                                                /* current should be EIT-0 but some station encode it in different order */
2181                                                /* since now we have a new eEIT_CONT, so if it is not, then don't need to continue */
2182                                                if (update)
2183                                                        break;
2184                                        }
2185
2186                                        /* clear CONT flag if any */
2187                                        result &= ~eEIT_CONT;
2188
2189                                        update |= result;
2190                                        result = 0;
2191
2192                                        if (update != 0)
2193                                        {
2194                                                if (redraw)
2195                                                {
2196                                                        chm_make_current(p_chm,p_info);
2197                                                        p_chm->redraw_evt.type = eCHM_EVT_REDRAW;
2198                                                        p_chm->redraw_evt.id = p_app->cur_ch_num;
2199                                                        p_chm->redraw_evt.ticks = 1;                    /* force to redraw if in banner screen */
2200                                                        chm_post_app_event(p_chm,&p_chm->redraw_evt);
2201                                                        //bos_sleep(50);
2202                                                }
2203                                        }
2204                                        //if (update == eEIT_BOTH)
2205                                        //      break;
2206                                }
2207#if 1
2208                                if (((table.table_type >= 0x0200) && (table.table_type < 0x0201)) && !p_chm->got_ett && (update & eEIT_CURRENT))
2209                                {
2210                                        BDBG_MSG(("ETT: PID=0x%04x, type=0x%04x",table.table_type_PID,table.table_type));
2211                                        chm_get_ett(p_chm,p_info,source_id,table.table_type_PID);
2212                                        /* update UI if in case BIG banner screen is shown */
2213                    if ((update & eEIT_CURRENT) && p_chm->got_ett)
2214                    {
2215                        if (redraw)
2216                        {
2217                            chm_make_current(p_chm,p_info);
2218                            p_chm->redraw_evt.type = eCHM_EVT_REDRAW;
2219                            p_chm->redraw_evt.id = p_app->cur_ch_num;
2220                            p_chm->redraw_evt.ticks = 1;            /* force to redraw if in banner screen */
2221                            chm_post_app_event(p_chm,&p_chm->redraw_evt);
2222                            //bos_sleep(50);
2223                        }
2224                    }
2225                                }
2226#endif
2227                        }                       
2228                        if (update & eEIT_CURRENT) {
2229                                /* have current event, so clear previous ETT if any to get ETT again */
2230                                if (!p_chm->got_ett) {
2231                                        p_info->eit_info[EIT_CURRENT].prog_desc[0] = 0;
2232                                        p_chm->mgt_state = eMGT_ETT;
2233                                        result = 0;
2234                                }
2235                                else {
2236                                        p_chm->state = eCHM_PROG_IDLE;
2237                                }
2238                        }
2239                        break;
2240
2241                case eMGT_ETT:
2242                        if (!ext_text)
2243                        {
2244                                p_chm->state = eCHM_PROG_IDLE;
2245                                break;
2246                        }
2247                        for (p_chm->mgt_idx = 0; p_chm->mgt_idx < num_tables; p_chm->mgt_idx++)
2248                        {
2249                                if (chm_check_cancel(p_chm))
2250                                        return eCHM_ERR_CANCELED;
2251
2252                                PSIP_MGT_getTable(msg_buf,p_chm->mgt_idx,&table);
2253
2254                                /* currently we only care current and next program instead of 128 eits (0x027F) */
2255                                //if ((table.table_type >= 0x0200) && (table.table_type < (0x0200 + MAX_EIT_NUM)))
2256                                if ((table.table_type >= 0x0200) && (table.table_type < (0x0201)))
2257                                {
2258                                        BDBG_MSG(("ETT: PID=0x%04x, type=0x%04x",table.table_type_PID,table.table_type));
2259
2260                                        result = chm_get_ett(p_chm,p_info,source_id,table.table_type_PID);
2261                                        if (result < 0)
2262                                        {
2263                                                BDBG_WRN(("chm_get_ett failed, ret=%d", result));
2264                                                continue;
2265                                        }
2266
2267                                        update |= result;
2268                                        result = 0;
2269
2270                                        if (update & eEIT_CURRENT)
2271                                        {
2272                                                if (redraw)
2273                                                {
2274                                                        chm_make_current(p_chm,p_info);
2275                                                        p_chm->redraw_evt.type = eCHM_EVT_REDRAW;
2276                                                        p_chm->redraw_evt.id = p_app->cur_ch_num;
2277                                                        p_chm->redraw_evt.ticks = 1;                    /* force to redraw if in banner screen */
2278                                                        chm_post_app_event(p_chm,&p_chm->redraw_evt);
2279                                                        //bos_sleep(50);
2280                                                }
2281                                                p_chm->state = eCHM_PROG_IDLE;
2282                                                break;
2283                                        }
2284                                }
2285                        }
2286                        break;
2287        }
2288
2289        return result;
2290}
2291
2292/*
2293Summary:
2294Get the VCT callback, and process it
2295*/
2296void * chm_smessage_vct_callback(void * context, size_t size)
2297{
2298        chm_mgr_t * p_chm;
2299        bapp_t *p_app;
2300        int total;
2301
2302        p_chm = (chm_mgr_t*)context;
2303        p_app = (bapp_t*)p_chm->p_app;
2304
2305        if (chm_check_cancel(p_chm))
2306                return(void*)NULL;
2307
2308        total = PSIP_VCT_getNumChannels(p_chm->vct_buf);
2309        if (total >= p_app->settings.ch[p_chm->cur_ch_num].minor) {
2310                /*TODO need add one more state to process VCT instead process it in callback */
2311                /* VERIFY slow channel change */
2312#if 0
2313                if (eCHM_ERR_OK == chm_process_vct(p_chm,p_chm->vct_buf, size, &p_chm->p_info[p_chm->cur_ch_num], p_app->settings.ch[p_chm->cur_ch_num].minor)) {
2314                        p_chm->got_vct = true;
2315                }
2316#endif
2317        }
2318
2319        //return(void*)p_chm->vct_buf;
2320        return (p_chm->got_vct ? (void *)NULL : (void*)p_chm->vct_buf);
2321}
2322
2323/*
2324Summary:
2325Get the VCT. return non-zero on failure
2326*/
2327static int chm_get_vct(
2328                chm_mgr_t *p_chm,               /* Channel manager reference */
2329                chm_info_t *p_info              /* info structure to populate */
2330                )
2331{
2332        bapp_t *p_app= (bapp_t*)p_chm->p_app;
2333        unsigned int section_size,section_number;
2334        int result = eCHM_ERR_OK;
2335
2336        if (p_info->got_vct)
2337        {
2338                p_chm->state = eCHM_GET_MGT;
2339                return result;
2340        }
2341
2342        section_number = 0;
2343        do
2344        {
2345                if (chm_check_cancel(p_chm))
2346                        return eCHM_ERR_CANCELED;
2347
2348                /* Get the VCT */
2349                smessage_stream_params_init(&p_chm->msg_params, NULL);
2350                p_chm->msg_params.band = p_chm->band;
2351                p_chm->msg_params.pid = 0x1ffb; /* VCT */
2352                section_size = VCT_BUF_LEN;
2353
2354                p_chm->msg_params.filter.coef[0] = 0xc8;        /* Table ID for terrestrial */
2355                p_chm->msg_params.filter.mask[0] = 0x00;
2356                p_chm->msg_params.filter.coef[6] = section_number;      /* section number */
2357                p_chm->msg_params.filter.mask[6] = 0x00;
2358                /* All PSIP tables have protocol_version which must be = 0 */
2359                p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2360                p_chm->msg_params.filter.mask[8] = 0x00;
2361
2362                if ((result = chm_getmessage(p_chm,p_chm->vct_buf, &section_size, VCT_TIMEOUT)) != 0)
2363                {
2364                        BDBG_WRN(("%s Timeout waiting for VCT (section # %d)\n",__func__,section_number));
2365                        return result;
2366                }
2367
2368                if (chm_check_cancel(p_chm))
2369                        return eCHM_ERR_CANCELED;
2370
2371                if (chm_process_vct(p_chm,p_chm->vct_buf, section_size, 
2372                                        p_info,p_app->settings.ch[p_chm->cur_ch_num].minor) != 0)
2373                {
2374                        BDBG_WRN(("VCT entry not found %d\n",section_number));
2375                        section_number++;
2376                        continue;
2377                }
2378                break;
2379        } while (section_size != 0);
2380
2381        p_chm->state = eCHM_GET_MGT;
2382
2383        return result;
2384}
2385
2386/*
2387 * Summary:
2388 *      Stop the VCT message filter.
2389 */
2390static void chm_mgt_stop(chm_mgr_t *p_chm)
2391{
2392        if (NULL != p_chm->mgt_msg)
2393        {
2394                if (b_ok != smessage_stop(p_chm->mgt_msg))
2395                {
2396                        BDBG_ERR(("%s:%d",__func__, __LINE__));
2397                        return;
2398                }
2399                smessage_close(p_chm->mgt_msg);
2400                p_chm->mgt_msg = NULL;
2401        }
2402}
2403
2404/*
2405 * Summary:
2406 *      MGT callback, and process it
2407 */
2408void *chm_smessage_mgt_callback(void * context, size_t size)
2409{
2410        chm_mgr_t * p_chm;
2411        bapp_t *p_app;
2412        int total;
2413        uint32_t crc;
2414
2415        p_chm = (chm_mgr_t*)context;
2416        p_app = (bapp_t*)p_chm->p_app;
2417
2418        if (chm_check_cancel(p_chm))
2419                return(void*)NULL;
2420
2421        total = PSIP_MGT_getTablesDefined(p_chm->mgt_buf);
2422        if (total > 0) {
2423                /* new MGT? */
2424                crc = chm_section_crc(p_chm->mgt_buf, size);
2425                if (p_chm->mgt_crc != crc) {
2426                        p_chm->mgt_crc = crc;
2427                        p_chm->mgt_size = size;
2428                        p_chm->got_mgt = true;
2429                        p_chm->mgt_state = eMGT_EIT;
2430                        p_chm->state = eCHM_PROCESS_MGT;
2431                }
2432        }
2433
2434        return(void*)p_chm->mgt_buf;
2435}
2436
2437static int chm_mgt_start(
2438                chm_mgr_t *p_chm,
2439                unsigned short network_pid
2440                )
2441{
2442        int cerr = eCHM_ERR_OK;
2443
2444        chm_mgt_stop(p_chm);
2445
2446        p_chm->mgt_msg = smessage_open(smessage_format_psi);
2447        if (NULL == p_chm->mgt_msg)
2448        {
2449                BDBG_ERR(("%s failed",__func__));
2450                cerr = eCHM_ERR_FAILED;
2451                goto ExitFunc;
2452        }
2453        smessage_stream_params_init(&p_chm->msg_params, NULL);
2454        p_chm->msg_params.band = p_chm->band;
2455        p_chm->msg_params.pid = (uint16_t)network_pid;      /* 0x1ffb */
2456
2457        p_chm->msg_params.filter.coef[0] = 0xC7;
2458        p_chm->msg_params.filter.mask[0] = 0x00;
2459        /* All PSIP tables have protocol_version which must be = 0 */
2460        p_chm->msg_params.filter.coef[8] = 0x00;    /* protocol_version */
2461        p_chm->msg_params.filter.mask[8] = 0x00;
2462        p_chm->msg_params.buffer = p_chm->mgt_buf;
2463        p_chm->msg_params.buffer_size = MGT_BUF_LEN;
2464        /* processing is done in callback */
2465        p_chm->msg_params.data_ready_callback = chm_smessage_mgt_callback;
2466        p_chm->msg_params.overflow = NULL;
2467        p_chm->msg_params.callback_context = (void *)p_chm;
2468        if (b_ok != smessage_start(&p_chm->msg_params, p_chm->mgt_msg))
2469        {
2470                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
2471                cerr = eCHM_ERR_FAILED;
2472        }
2473
2474ExitFunc:
2475        return cerr;
2476}
2477
2478/*
2479Summary:
2480Get the MGT. return non-zero on failure
2481*/
2482static int chm_get_mgt(chm_mgr_t *p_chm)
2483{
2484        int result;
2485
2486        smessage_stream_params_init(&p_chm->msg_params, NULL);
2487        p_chm->msg_params.band = p_chm->band;
2488        p_chm->msg_params.pid = (unsigned short)0x1FFB; /* base pid */
2489        p_chm->mgt_size = MGT_BUF_LEN;
2490        p_chm->msg_params.filter.coef[0] = 0xC7;
2491        p_chm->msg_params.filter.mask[0] = 0x00;
2492        /* All PSIP tables have protocol_version which must be = 0 */
2493        p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
2494        p_chm->msg_params.filter.mask[8] = 0x00;
2495
2496        if ((result = chm_getmessage(p_chm,p_chm->mgt_buf,&p_chm->mgt_size, MGT_TIMEOUT)) != 0)
2497        {
2498                BDBG_WRN(("Timeout waiting for MGT\n"));
2499                return result;
2500        }
2501
2502        p_chm->got_mgt = true;
2503        p_chm->mgt_state = eMGT_EIT;
2504        p_chm->state = eCHM_PROCESS_MGT;
2505        p_chm->mgt_cnt++;
2506
2507        return eCHM_ERR_OK;
2508}
2509
2510/*
2511Summary:
2512Generic tuner cancel callback.
2513*/
2514void chm_tune_cancel_callback(void *context)
2515{
2516        chm_mgr_t *p_chm = (chm_mgr_t *)context;
2517
2518        if (chm_check_cancel(p_chm))
2519        {
2520                BDBG_WRN(("### CANCEL TUNE ###\n"));
2521                p_chm->tuner_params.cancel = true;
2522        }
2523}
2524
2525/*
2526Summary:
2527Return the hunt mode progress in percent so that the UI can be updated accordingly.
2528*/
2529
2530int chm_get_hunt_progress(chm_mgr_t *p_chm)
2531{
2532        bapp_t *p_app = (bapp_t *)p_chm->p_app;
2533
2534        if (0 == p_app->settings.num_channels)
2535        {
2536                if (eFREQ_TABLE_USER_DEFINED == p_chm->fe_type)
2537                        bapp_user_freq_table_get(p_app, &p_chm->freq_table, &p_chm->num_freq);
2538                else
2539                        bapp_freq_table_get(p_chm->fe_type,(const unsigned int **)&(p_chm->freq_table),&(p_chm->num_freq));
2540        }
2541
2542        if (p_chm->num_freq == 0)
2543        {
2544                BDBG_WRN(("%s p_chm->num_freq = %d",__func__,p_chm->num_freq));
2545                return 0;
2546        }
2547        return (p_chm->select_idx * 100)/p_chm->num_freq;
2548}
2549
2550#ifdef ACB612
2551bool chm_GetScanStatusFinish(void)
2552{
2553        return isScanStatusFinish;
2554}
2555#endif
2556/*
2557Summary:
2558Reset the channel and do a scan for channels to create a new channel map.
2559Description:
2560Scan for all available channels.
2561 */
2562
2563static void chm_scan(chm_mgr_t *p_chm)
2564{
2565        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2566        unsigned int freq;
2567        int num;
2568#ifdef ACB612
2569        int nFCnt = 0;
2570        isScanStatusFinish = false;
2571#endif
2572        bband_t rc;
2573
2574        if (eFREQ_TABLE_USER_DEFINED == p_chm->fe_type)
2575                bapp_user_freq_table_get(p_app, &p_chm->freq_table, &p_chm->num_freq);
2576        else
2577                bapp_freq_table_get(p_chm->fe_type,(const unsigned int **)&(p_chm->freq_table),&(p_chm->num_freq));
2578
2579        /* current we do a full scan always, so clear channel map information */
2580        p_app->settings.num_channels = 0;
2581        p_app->cur_ch_num = 0;
2582        p_chm->cur_ch_num = 0;
2583        memset(p_chm->p_info,0,p_chm->num_freq * sizeof(chm_info_t));
2584
2585        p_chm->band = TUNER_BAND;
2586#ifdef ACB612
2587        if(p_app->factory_test)
2588                nFCnt = 0;
2589#endif
2590        for (p_chm->select_idx = 0; p_chm->select_idx < p_chm->num_freq; p_chm->select_idx++)
2591        {
2592#ifdef ACB612
2593                if(p_app->factory_test)
2594                {
2595                        if(nFCnt >= FACTORY_CHN_NUMBER)
2596                                break;
2597                        p_chm->select_idx = (F_chaSet[nFCnt] - 2);
2598                        nFCnt++;
2599                }
2600#endif
2601                freq = (unsigned int)(p_chm->freq_table[p_chm->select_idx]);
2602                freq *= 1000; /* convert to Hz */
2603                /* need to show frequency in scanning on UI */
2604                p_chm->last_freq_hz = freq;
2605                BDBG_WRN(("Scan[%d] freq = %d\n",p_chm->select_idx,freq));
2606
2607                /* Check to see if scan was canceled */
2608                if (chm_check_cancel(p_chm))
2609                        break;
2610
2611                if (eFREQ_TABLE_USER_DEFINED != p_chm->fe_type) {
2612                        /* output progress event id will be % done */
2613                        p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
2614                        p_chm->chm_pat_evt.id = eCHM_STATUS_NOPAT;
2615                        p_chm->chm_pat_evt.ticks = (unsigned int)(((p_chm->select_idx)*100)/p_chm->num_freq);
2616                        chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
2617                }
2618
2619                /* Try tuning */
2620                btuner_params_init(&p_chm->tuner_params, p_chm->tuner);
2621                p_chm->tuner_params.cancel_callback = chm_tune_cancel_callback;
2622                p_chm->tuner_params.cancel_callback_context = p_chm;
2623                p_chm->tuner_params.wait_for_lock = true;
2624
2625                rc = btuner_tune(p_chm->tuner, freq, &p_chm->tuner_params);
2626                if ( rc< 0)
2627                {
2628                        BDBG_MSG(("FREQ[%d] freq = %d not locked, try next freq",p_chm->select_idx,freq));
2629                        chm_send_status(p_chm,freq,false);
2630                        continue;
2631                } else
2632                {
2633                        //printf("%15s@%5d:%10s ===> FREQ [%3d] freq = %4dMhz locked\n",        strrchr(__FILE__,'/')? strrchr(__FILE__,'/')+1 : __FILE__,__LINE__,__FUNCTION__,p_chm->select_idx,freq/1000000);
2634                        chm_send_status(p_chm,freq,true);
2635                }
2636
2637                if ((num = chm_scan_vct(p_chm,p_chm->band,p_chm->select_idx)) <= 0)
2638                {
2639                        BDBG_WRN(("no VCT found, perform PSI scan instead"));
2640                        if ((num = chm_scan_psi(p_chm,p_chm->band,p_chm->select_idx)) <= 0)
2641                        {
2642                                BDBG_WRN(("chm_scan_psi found no channels\n"));
2643                        } else
2644                        {
2645                                BDBG_MSG(("PSI channels %d \n", num));
2646                        }
2647                }
2648        }
2649        /* clear it after scanning */
2650        p_chm->last_freq_hz = 0;
2651
2652        if (eFREQ_TABLE_USER_DEFINED != p_chm->fe_type) {
2653                p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
2654                p_chm->chm_pat_evt.id = eCHM_STATUS_PAT;
2655                p_chm->chm_pat_evt.ticks = 100;
2656                /* update only meet following condition */
2657                if (false == p_app->scan_in_progress && 0 == p_app->settings.num_channels) {
2658                        /* user cancel the scan before getting any channel yet, bail out */
2659                }
2660                else {
2661                        chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
2662                        //if (p_app->screen_id == eSCREEN_CH_SCAN_PROGRESS) {
2663                        bos_sleep(200);
2664                        //}
2665                }
2666        }
2667
2668        if (eRRT_AVAILABLE != p_app->settings.rrt_settings.rrt_status) 
2669                p_chm->rrt_size = 0;
2670
2671        p_chm->cmd = eCHM_CANCEL;
2672        p_app->cur_ch_num = 0;
2673
2674        /* update p_info */
2675        if (p_app->settings.num_channels > 0) {
2676                bapp_ch_t *pch;
2677                chm_info_t      *p_info;
2678
2679                for (num = 0; num < p_app->settings.num_channels; num++) {
2680                        pch = &p_app->settings.ch[num];
2681                        p_info = &p_chm->p_info[num];
2682
2683                        p_info->source_id = pch->source_id;
2684                        p_info->major = pch->major;
2685                        p_info->minor = pch->minor;
2686                        p_info->program_number = pch->program_num;
2687                        memcpy(p_info->ch_name, p_info->ch_name, sizeof(pch->ch_name));
2688                        p_info->got_vct = !pch->psi;
2689                }
2690        }
2691
2692#ifdef ACB612
2693        isScanStatusFinish = true;
2694#endif
2695}
2696
2697/*
2698Summary:
2699Initial or rescan of VSB channels
2700Description:
2701Scan for all available VSB channels.
2702 */
2703
2704static void chm_hunt(chm_mgr_t *p_chm)
2705{
2706        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2707
2708        chm_stop_decode(p_chm);
2709
2710        /* stop all streams */
2711        chm_stop_stream(p_chm,&(p_chm->chm_stream[CURR_CH]));
2712        chm_stop_stream(p_chm,&(p_chm->chm_stream[PREV_CH]));
2713        chm_stop_stream(p_chm,&(p_chm->chm_stream[NEXT_CH]));
2714
2715        p_app->scan_in_progress = true;
2716        chm_scan(p_chm);
2717
2718        /* channel scan done, all the channel map are added during scan time, so to update the channel map */
2719        p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
2720        p_chm->chm_pat_evt.id = eCHM_STATUS_CHMAP;
2721        /* to update channel map if changed */
2722        p_chm->chm_pat_evt.ticks = p_app->settings.num_channels ? 2 : 0;
2723        if (0 == p_app->settings.num_channels && false == p_app->scan_in_progress) {
2724                /* if no channel scanned and scan_in_progress is false, it should be cancelled by the user */
2725                /* bail out */
2726        }
2727        else 
2728                chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
2729        p_app->scan_in_progress = false;
2730
2731        p_chm->cmd = eCHM_CANCEL;
2732        bos_sleep(200);
2733
2734        p_chm->hunt_cnt++;
2735}
2736
2737/*
2738Summary:
2739Post an event the app queue to provide status.
2740 */
2741
2742static int chm_post_app_event_cb(chm_mgr_t *p_chm,              /* Channel manager reference */
2743                chm_event_t *p_event     /* Event to post to app queue */
2744                )
2745{
2746        bapp_t *p_app = (bapp_t*)p_chm->p_app;
2747        bos_post_event(p_app->msg_queue,(b_event_t*)p_event);
2748        bos_sleep(10);
2749
2750        return 0;
2751}
2752
2753/*
2754Summary:
2755Post an event the app queue to provide status.
2756 */
2757
2758static int chm_post_app_event(chm_mgr_t *p_chm,         /* Channel manager reference */
2759                chm_event_t *p_event      /* Event to post to app queue */
2760                )
2761{
2762        int result = chm_post_app_event_cb(p_chm,p_event);
2763
2764        return result;
2765}
2766
2767/******************************************************************************
2768 * INPUTS:      context
2769 * OUTPUTS:     none.
2770 * RETURNS:     none
2771 * FUNCTION:    message_callback
2772 * DESCRIPTION: Callback function normally called when a complete message has
2773 *              been received and passed the filter criteria.
2774 ******************************************************************************/
2775void * chm_smessage_eas_callback(void * context, size_t size)
2776{
2777        chm_mgr_t * p_chm = (chm_mgr_t*)context;
2778        bapp_t *p_app;
2779        TS_SCTE_18_header header;               /* header structure */
2780        unsigned int timegpssec, event_end_time;
2781        unsigned short source_id;
2782        b_timeval cur;
2783        bool found_sourceid = false;
2784        size_t ex_size,i, j;
2785        uint8_t *pOffset;
2786        p_app = (bapp_t*)p_chm->p_app;
2787        int eas_ch_num = -1;
2788
2789        BDBG_WRN(("#### EAS Event %d ####", p_chm->eas_cnt));
2790        p_chm->eas_cnt++;
2791
2792        if (!p_app->power)
2793        {
2794                BDBG_WRN(("####EAS Event: Box in standby state: ignore. #### \n"));
2795                goto ExitFunc;
2796        }
2797
2798        if (TS_SCTE_18_getSectionHeader(p_chm->eas_buf, size, &header) != 0)
2799        {
2800                BDBG_ERR(("#### TS_SCTE_18_getSectionHeader failed ####\n"));
2801                goto ExitFunc;
2802        }
2803
2804        if (0 == header.alert_priority)
2805        {
2806                BDBG_MSG(("#### reset EAS sequence %d ####\n",header.sequence_number));
2807                /* establish a new sequence number */
2808                p_chm->sequence_number = header.sequence_number;
2809                /* eas reset, so don't check once get other alert priority */
2810                p_chm->eas_reset = true;
2811                goto ExitFunc;
2812        }
2813
2814        if (p_chm->sequence_number == header.sequence_number)
2815        {
2816                if (!p_chm->eas_reset) {
2817                        BDBG_WRN(("#### EAS Event %d duplicate ####\n",header.sequence_number));
2818                        /* the test stream also uses same sequence number all the time */
2819                        goto ExitFunc;
2820                }
2821        }
2822
2823        if ((int8_t)header.alert_priority < SCTE_18_ALERT_PRIORITY)
2824        {
2825                BDBG_WRN(("#### EAS Event alert priority %d < %d, ignore.#### \n", header.alert_priority, SCTE_18_ALERT_PRIORITY));
2826                goto ExitFunc;
2827        }
2828
2829        if ((int8_t)header.alert_message_time_remaining < 0 || header.alert_message_time_remaining > 120)
2830        {
2831                BDBG_WRN(("#### EAS Event alert_message_time_remaining %d out of range ####\n",header.alert_message_time_remaining));
2832                goto ExitFunc;
2833        }
2834        p_chm->sequence_number = header.sequence_number;
2835
2836        if (p_chm->EAS_event_ID == header.EAS_event_ID)
2837        {
2838                if (!p_chm->eas_reset) {
2839                        /* same EAS message, but only time remaining changed */
2840                        GETTIMEOFDAY(&cur);
2841                        if (header.alert_message_time_remaining)
2842                                p_app->eas_timeout = cur.tv_sec + header.alert_message_time_remaining;
2843                        else
2844                                p_app->eas_timeout = 0;
2845
2846                        BDBG_MSG(("#### EAS Event %d already processed ####\n",header.EAS_event_ID));
2847                        goto ExitFunc;
2848                }
2849        }
2850        /* new EAS message is distributed */
2851        p_chm->EAS_event_ID = header.EAS_event_ID;
2852        /* it is the point that we will do sanity check after here */
2853        p_chm->eas_reset = false;
2854
2855        if (0 == header.event_duration) {
2856                BDBG_WRN(("#### EAS Event event_duration set to infinity ####"));
2857                /*RLQ, need to check what to do with infinity value as it may cause problem */
2858                header.event_duration = (uint16_t)(EAS_INFINITY / 60);
2859        }
2860        if (header.event_start_time && header.event_duration)
2861        {
2862                /* 15 mins to 100 hours */
2863                if (header.event_duration < 15 || header.event_duration > 6000 )
2864                {
2865                        if ((uint16_t)(EAS_INFINITY / 60) != header.event_duration) {
2866                                BDBG_WRN(("#### EAS Event event_duration %d out of range ####\n",header.event_duration));
2867                                goto ExitFunc;
2868                        }
2869                }
2870                GETTIMEOFDAY(&cur);
2871                timegpssec = p_app->system_time + cur.tv_sec;
2872                event_end_time = header.event_start_time+(header.event_duration * 60);
2873
2874                if (event_end_time < timegpssec)
2875                {
2876                        BDBG_WRN(("#### EAS Event has expired %d < %d, ignore.#### \n", event_end_time, timegpssec));
2877                        goto ExitFunc;
2878                }
2879        }
2880
2881        /* if exception list existed, check to see if current channel is in exception list */
2882        if (header.exception_count)
2883        {
2884                BDBG_WRN(("#### EAS exception count = %d\n",header.exception_count));
2885                pOffset = TS_SCTE_18_getExpectionOffset((const char *)p_chm->eas_buf, &ex_size);
2886                if (pOffset)
2887                {
2888                        chm_info_t      *p_info;
2889                        TS_SCTE_18_exception s;
2890
2891                        for (i = 0; i < header.exception_count; i++)
2892                        {
2893                                if (TS_SCTE_18_getException(pOffset, i, &s))
2894                                {
2895                                        BDBG_WRN(("#### EAS exception (%d,0x%04x,0x%04x)\n",s.in_band_reference,s.major_channel_number,s.minor_channel_number));
2896                                        for (j = 0; j < p_app->settings.num_channels; j++) {
2897                                                p_info = &p_chm->p_info[j];
2898
2899                                                if ((unsigned char)s.major_channel_number == p_info[j].major && 
2900                                                                (unsigned short)s.minor_channel_number == p_info[j].minor) {
2901                                                        if (s.in_band_reference) {
2902                                                                BDBG_WRN(("#### 0x%04x.0x%04x in exception list, discard\n", s.major_channel_number, s.minor_channel_number));
2903                                                                goto ExitFunc;
2904                                                        } else
2905                                                        {
2906                                                                /* do we support OOB in ATSC? or do further check for source id within given major and minor? */
2907                                                                BDBG_WRN(("#### OOB 0x%04x.0x%04x in exception list, discard\n",s.major_channel_number,s.minor_channel_number));
2908                                                                goto ExitFunc;
2909                                                        }
2910                                                }
2911                                        }
2912                                }
2913                                else {
2914                                        BDBG_WRN(("#### EAS TS_SCTE_18_getException %d failed\n",i));
2915                                        goto ExitFunc;
2916                                }
2917                        }
2918                }
2919        }
2920
2921#if 0
2922        /* try details OOB source ID first */
2923        if (header.details_OOB_source_ID)
2924        {
2925                BDBG_WRN(("#### EAS Attempt to set details source ID = 0x%04x.#### \n", header.details_OOB_source_ID));
2926                source_id = header.details_OOB_source_ID;
2927                found_sourceid = ch_map_set(bapp_cur_ch_map(p_app),source_id);
2928        }
2929#endif
2930        /* check if the EAS channel is in the channel map? */
2931        if (header.details_major_channel_number && header.details_minor_channel_number)
2932        {
2933                BDBG_WRN(("#### EAS Attempt to set major.minor [0x%04x.0x%04x] #### \n", header.details_major_channel_number, header.details_minor_channel_number));
2934                eas_ch_num = chm_find_match_channel(p_chm, header.details_major_channel_number, 
2935                                header.details_minor_channel_number, header.details_OOB_source_ID);
2936                if (eas_ch_num < 0)
2937                {
2938                        /* try audio only */
2939                        if (15 == header.alert_priority && header.audio_OOB_source_ID)
2940                        {
2941                                BDBG_WRN(("#### EAS Attempt to set audio source ID = 0x%04x.#### \n", header.audio_OOB_source_ID));
2942                                if ((eas_ch_num = chm_find_match_channel(p_chm, header.details_major_channel_number, header.details_minor_channel_number, header.audio_OOB_source_ID)) < 0) {
2943                                        BDBG_WRN(("#### EAS Attempt to set audio source ID = 0x%04x failed.#### \n", header.audio_OOB_source_ID));
2944                                        /*RLQ, if the channel is not in the channel map, just scroll EAS text if any */
2945                                        if (header.alert_text_length) 
2946                                                goto SCROLL_ONLY;
2947                                        goto ExitFunc;
2948                                }
2949                        } else
2950                        {
2951                                BDBG_WRN(("#### EAS no details source ID available\n"));
2952                                /*RLQ*/
2953                                if (header.alert_text_length)
2954                                        goto SCROLL_ONLY;
2955                                goto ExitFunc;
2956                        }
2957                }
2958                found_sourceid = true;
2959        }
2960
2961        /* TODO until find a way to map the RF_channel and program_number to major/minor/source_id, then we can enable this part */
2962#if 0
2963        /* Check for Channel Descriptor */
2964        if (!found_sourceid)
2965        {
2966                /* try channel description */
2967                TS_SCTE_18_in_band_channel_descriptor ib_channel_desc;
2968                pOffset = TS_SCTE_18_getDescriptorOffset((const char *)p_chm->eas_buf, &ex_size);
2969
2970                if (pOffset == NULL)
2971                {
2972                        BDBG_WRN(("#### EAS Channel Descriptor not found #### \n"));
2973                        goto ExitFunc;
2974                }
2975
2976                if (!TS_SCTE_18_getInBandChannelDescriptor(pOffset, &ib_channel_desc,ex_size))
2977                {
2978                        BDBG_WRN(("#### EAS Channel Desc not found #### \n"));
2979                        goto ExitFunc;
2980                }
2981                if (!ch_map_find_soure_id(bapp_cur_ch_map(p_app),
2982                                        (unsigned char)ib_channel_desc.exception_RF_channel,
2983                                        (unsigned short)ib_channel_desc.exception_program_number,
2984                                        &source_id))
2985                {
2986                        BDBG_WRN(("#### EAS sourceID not found for ib channel desc [0x%04x.0x%04x] #### \n", ib_channel_desc.exception_RF_channel, ib_channel_desc.exception_program_number));
2987                        goto ExitFunc;
2988                }
2989        }
2990#endif
2991
2992        if ( ((header.location_code_count) < 1) || ((header.location_code_count) > 31) )
2993        {
2994                BDBG_WRN(("#### EAS location code count invalid %d #### \n",header.location_code_count));
2995                //goto ExitFunc;
2996        } else
2997        {
2998                pOffset = TS_SCTE_18_getLocationOffset((const char *)p_chm->eas_buf, &size);
2999                if (pOffset)
3000                {
3001                        TS_SCTE_18_location_code s;
3002                        for (i = 0; i < header.location_code_count; i++)
3003                        {
3004                                if (TS_SCTE_18_getLocationCode(pOffset, i, &s))
3005                                {
3006                                        if ( (((int8_t)s.state_code) < 0) || ((s.state_code) > 99) || 
3007                                                        (((int8_t)s.county_subdivision) < 0) || ((s.county_subdivision) > 9) ||
3008                                                        (((int8_t)s.county_code) < 0) || ((s.county_code) > 999) )
3009                                        {
3010                                                BDBG_WRN(("#### EAS state code %d or subdivision %d country_code %d invalid#### \n",s.state_code, s.county_subdivision, s.county_code));
3011                                                goto ExitFunc;
3012                                        }
3013                                } else
3014                                {
3015                                        goto ExitFunc;
3016                                }
3017                        }
3018                } else
3019                {
3020                        goto ExitFunc;
3021                }
3022        }
3023
3024        /* if we are here, then it is good to switch to EAS channel */
3025SCROLL_ONLY:
3026        if ((eas_ch_num >= 0) || header.alert_text_length) 
3027        {
3028                BDBG_WRN(("#### EAS source ID = 0x%04x found (timeout %d secs).#### \n", source_id,header.alert_message_time_remaining));
3029                p_chm->chm_eas_evt.type = eCHM_EVT_EAS;
3030                p_chm->chm_eas_evt.ticks = (0 == header.alert_message_time_remaining) ? EAS_INFINITY : header.alert_message_time_remaining;
3031                p_chm->chm_eas_evt.id = eas_ch_num;
3032                p_chm->chm_eas_evt.data[0] = (eas_ch_num >= 0)? true : false;
3033                p_chm->eas_timer_started = true;
3034                memcpy(p_app->eas_buf, p_chm->eas_buf, size);
3035                p_app->eas_buf_size = size;
3036
3037                chm_post_app_event_cb(p_chm,&p_chm->chm_eas_evt);
3038        } else
3039        {
3040                BDBG_WRN(("#### EAS source ID = 0x%04x not found.#### \n", source_id));
3041        }
3042ExitFunc:
3043        return(void*)p_chm->eas_buf;
3044}
3045
3046/*
3047Summary:
3048Stop the STT. return non-zero on failure
3049 */
3050static void chm_stt_stop(chm_mgr_t *p_chm)
3051{
3052        if (NULL != p_chm->stt_msg)
3053        {
3054                if (b_ok != smessage_stop(p_chm->stt_msg))
3055                {
3056                        BDBG_ERR(("%s:%d",__func__, __LINE__));
3057                        return;
3058                }
3059                smessage_close(p_chm->stt_msg);
3060                p_chm->stt_msg = NULL;
3061        }
3062}
3063
3064/******************************************************************************
3065 * INPUTS:      context
3066 * OUTPUTS:     none.
3067 * RETURNS:     none
3068 * FUNCTION:    message_callback
3069 * DESCRIPTION: Callback function normally called when a complete message has
3070 *              been received and passed the filter criteria.
3071 ******************************************************************************/
3072
3073void * chm_smessage_stt_callback(void * context, size_t size)
3074{
3075        chm_mgr_t * p_chm;
3076        b_tm utc_time;
3077        b_timeval tv;
3078
3079        p_chm = (chm_mgr_t*)context;
3080
3081        p_chm->stt_cnt++;
3082
3083        PSIP_STT_getHeader(p_chm->stt_buf, &p_chm->stt);
3084        /* current time in seconds when STT was received */
3085        GETTIMEOFDAY(&tv);
3086        p_chm->sys_offset = tv.tv_sec;
3087        p_chm->sys_UTC_offset = p_chm->stt.GPS_UTC_offset;
3088
3089        /* Current UTC time according to STT */
3090        p_chm->sys_time = p_chm->stt.system_time - p_chm->stt.GPS_UTC_offset;
3091
3092        utctime(p_chm->sys_time,&utc_time);
3093
3094        /* Current UTC time according to STT */
3095        p_chm->time_evt.type = eCHM_EVT_TIME;
3096        p_chm->time_evt.system_time = p_chm->sys_time;
3097        p_chm->time_evt.system_offset = tv.tv_sec;
3098        p_chm->time_evt.utc_offset = p_chm->sys_UTC_offset;
3099        /* will see if we need to post the STT? */
3100        chm_post_app_event(p_chm,(chm_event_t*)&p_chm->time_evt);
3101
3102        utctime(p_chm->time_evt.system_time,&utc_time);
3103        BDBG_MSG(("STT UTC = %2d/%2d/%4d %2d:%2d:%2d\n",
3104                                utc_time.tm_mon + 1,utc_time.tm_mday,utc_time.tm_year + 1980, 
3105                                utc_time.tm_hour,utc_time.tm_min,utc_time.tm_sec));
3106
3107        p_chm->got_stt = true;
3108
3109        return(void*)p_chm->stt_buf;
3110}
3111
3112/*
3113Summary:
3114Get the STT. return non-zero on failure
3115 */
3116
3117static int chm_get_stt(chm_mgr_t *p_chm)
3118{
3119        int result = eCHM_ERR_FAILED, stt_size;
3120        b_tm utc_time;
3121        b_timeval tv;
3122
3123        smessage_stream_params_init(&p_chm->msg_params, NULL);
3124        p_chm->msg_params.band = p_chm->band;
3125        p_chm->msg_params.pid = (unsigned short)p_chm->network_pid;
3126        p_chm->msg_params.buffer_size = STT_BUF_LEN;
3127        stt_size = STT_BUF_LEN;
3128        p_chm->msg_params.filter.coef[0] = 0xCD;
3129        p_chm->msg_params.filter.mask[0] = 0x00;
3130        /* All PSIP tables have protocol_version which must be = 0 */
3131        p_chm->msg_params.filter.coef[8] = 0x00;    /* protocol_version */
3132        p_chm->msg_params.filter.mask[8] = 0x00;
3133        if ((result = chm_getmessage(p_chm,p_chm->stt_buf,&stt_size, STT_TIMEOUT)) != 0)
3134        {
3135                BDBG_MSG(("Timeout waiting for STT\n"));
3136                return result;
3137        }
3138
3139        p_chm->stt_cnt++;
3140
3141        PSIP_STT_getHeader(p_chm->stt_buf, &p_chm->stt);
3142
3143        /* current time in seconds when STT was received */
3144        GETTIMEOFDAY(&tv);
3145        p_chm->sys_offset = tv.tv_sec;
3146        p_chm->sys_UTC_offset = p_chm->stt.GPS_UTC_offset;
3147
3148        /* Current UTC time according to STT */
3149        p_chm->sys_time = p_chm->stt.system_time - p_chm->stt.GPS_UTC_offset;
3150
3151        utctime(p_chm->sys_time,&utc_time);
3152
3153        /* Current UTC time according to STT */
3154        p_chm->time_evt.type = eCHM_EVT_TIME;
3155        p_chm->time_evt.system_time = p_chm->sys_time;
3156        p_chm->time_evt.system_offset = tv.tv_sec;
3157        p_chm->time_evt.utc_offset = p_chm->sys_UTC_offset;
3158        /* will see if we need to post the STT? */
3159        chm_post_app_event(p_chm,(chm_event_t*)&p_chm->time_evt);
3160
3161        utctime(p_chm->time_evt.system_time,&utc_time);
3162        BDBG_MSG(("STT UTC = %2d/%2d/%4d %2d:%2d:%2d\n",
3163                                utc_time.tm_mon + 1,utc_time.tm_mday,utc_time.tm_year + 1980,
3164                                utc_time.tm_hour,utc_time.tm_min,utc_time.tm_sec));
3165
3166        p_chm->got_stt = true;
3167
3168        return result;
3169}
3170
3171/*
3172Summary:
3173Start the STT message filtering. return non-zero on failure
3174 */
3175
3176static int chm_stt_start(
3177                chm_mgr_t *p_chm,               /* Channel manager reference */
3178                unsigned short network_pid)
3179{
3180        int cerr;
3181
3182        cerr = eCHM_ERR_OK;
3183        BDBG_MSG(("%s:%d (0x%04x)",__func__, __LINE__,network_pid));
3184
3185        chm_stt_stop(p_chm);
3186
3187        p_chm->stt_msg = smessage_open(smessage_format_psi);
3188        if (NULL == p_chm->stt_msg)
3189        {
3190                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
3191                cerr = eCHM_ERR_FAILED;
3192                goto ExitFunc;
3193        }
3194
3195        smessage_stream_params_init(&p_chm->msg_params, NULL);
3196        p_chm->msg_params.band = p_chm->band;
3197        p_chm->msg_params.pid = (uint16_t)network_pid;
3198        p_chm->msg_params.filter.coef[0] = 0xCD;
3199        p_chm->msg_params.filter.mask[0] = 0x00;
3200        /* All PSIP tables have protocol_version which must be = 0 */
3201        p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
3202        p_chm->msg_params.filter.mask[8] = 0x00;
3203        p_chm->msg_params.buffer = p_chm->stt_buf;
3204        p_chm->msg_params.buffer_size = STT_BUF_LEN;
3205        /* processing is done in callback */
3206        p_chm->msg_params.data_ready_callback = chm_smessage_stt_callback;
3207        p_chm->msg_params.overflow = NULL;
3208        p_chm->msg_params.callback_context = (void *)p_chm;
3209
3210        if (b_ok != smessage_start(&p_chm->msg_params, p_chm->stt_msg))
3211        {
3212                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
3213                cerr = eCHM_ERR_FAILED;
3214        }
3215ExitFunc:
3216        return cerr;
3217}
3218
3219#ifdef DEBUG_RRT
3220static void chm_output_rrt(chm_mgr_t *p_chm)
3221{
3222        PSIP_RRT_header header;
3223        PSIP_RRT_dimension dim;
3224        PSIP_RRT_value val;
3225        int dim_idx,val_idx;
3226        char tmp_str[64];
3227
3228        if (p_chm->rrt_cnt <= 0)
3229                return;
3230
3231        PSIP_RRT_getHeader(p_chm->rrt_buf, &header);
3232        if (chm_process_mss(p_chm,header.p_rating_region_name_text,tmp_str,64) == 0)
3233        {
3234                BDBG_WRN(("RRT %8s",tmp_str));
3235        }
3236
3237        for (dim_idx = 0; dim_idx < header.dimensions_defined; ++dim_idx)
3238        {
3239                if (PSIP_RRT_getDimension(p_chm->rrt_buf,dim_idx,&dim) != BERR_SUCCESS)
3240                        continue;
3241
3242                if (chm_process_mss(p_chm,dim.p_dimension_name_text,tmp_str,sizeof(tmp_str)) == 0)
3243                {
3244                        BDBG_WRN(("  RRT[%d] %8s(%d)",dim_idx,tmp_str,dim.graduated_scale));
3245                }
3246
3247                for (val_idx = 0; val_idx < dim.values_defined; ++val_idx)
3248                {
3249                        if (PSIP_RRT_getValue(p_chm->rrt_buf,dim_idx,val_idx,&val) != BERR_SUCCESS)
3250                                continue;
3251
3252                        if (chm_process_mss(p_chm,val.p_rating_value_text,tmp_str,sizeof(tmp_str)) == 0)
3253                        {
3254                                BDBG_WRN(("  RRT[%d,%d] %8s",dim_idx,val_idx,tmp_str));
3255                        }
3256
3257                        if (chm_process_mss(p_chm,val.p_abbrev_rating_value_text,tmp_str,sizeof(tmp_str)) == 0)
3258                        {
3259                                BDBG_WRN(("  RRT[%d,%d] %8s",dim_idx,val_idx,tmp_str));
3260                        }
3261                }
3262        }
3263}
3264#endif
3265
3266/*
3267 * Summary:
3268 *      Callback function normally called when a complete message has
3269 *      been received and passed the filter criteria.
3270 */
3271static void * chm_smessage_rrt_callback(void * context, size_t size)
3272{
3273        chm_mgr_t * p_chm = (chm_mgr_t*)context;
3274        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3275        uint32_t crc;
3276
3277        PSIP_RRT_header header;
3278        b_timeval tv;
3279
3280        p_chm->rrt_cnt++;
3281
3282        GETTIMEOFDAY(&tv);
3283        p_chm->last_rrt = tv.tv_sec;
3284
3285        PSIP_RRT_getHeader(p_chm->rrt_buf, &header);
3286        crc = chm_section_crc(p_chm->rrt_buf, size);
3287
3288        //if ((header.rating_region == 1) || ((size == p_app->settings.rrt_settings.rrt_size) && (memcmp(p_chm->rrt_buf,p_app->settings.rrt_settings.rrt, size) == 0)))
3289        if ((header.rating_region == 1) || ((size == p_app->settings.rrt_settings.rrt_size) && (crc == p_chm->rrt_crc)))
3290        {
3291                BDBG_WRN(("RRTs region 1 or they match so don't update\n"));
3292                p_chm->last_rrt += (2 * 60);
3293                return(void*)p_chm->rrt_buf;
3294        }
3295        p_chm->rrt_crc = crc;
3296
3297#ifdef DEBUG_RRT
3298        chm_output_rrt(p_chm); /* DEBUG ONLY */
3299#endif
3300        p_chm->rrt_evt.type = eCHM_EVT_RRT;
3301        p_chm->rrt_evt.size = size;
3302        memcpy(p_chm->rrt_evt.rrt,p_chm->rrt_buf,size);
3303
3304        chm_post_app_event_cb(p_chm,(chm_event_t*)&p_chm->rrt_evt);
3305
3306        return(void*)p_chm->rrt_buf;
3307}
3308
3309/*
3310Summary:
3311Stop the RRT. return non-zero on failure
3312 */
3313static void chm_rrt_stop(chm_mgr_t *p_chm)
3314{
3315        if (NULL != p_chm->rrt_msg)
3316        {
3317                if (b_ok != smessage_stop(p_chm->rrt_msg))
3318                {
3319                        BDBG_ERR(("%s:%d",__FUNCTION__, __LINE__));
3320                        return;
3321                }
3322                smessage_close(p_chm->rrt_msg);
3323                p_chm->rrt_msg = NULL;
3324        }
3325}
3326
3327/*
3328Summary:
3329Get the RRT. return non-zero on failure
3330 */
3331static int chm_rrt_start(chm_mgr_t *p_chm, unsigned short network_pid)
3332{
3333        int cerr;
3334
3335        cerr = eCHM_ERR_OK;
3336        BDBG_MSG(("%s: (0x%04x)",__FUNCTION__, network_pid));
3337
3338        chm_rrt_stop(p_chm);
3339
3340        p_chm->rrt_msg = smessage_open(smessage_format_psi);
3341        if (NULL == p_chm->rrt_msg)
3342        {
3343                BDBG_ERR(("%s: get RRT failed",__func__));
3344                cerr = eCHM_ERR_FAILED;
3345                goto ExitFunc;
3346        }
3347        smessage_stream_params_init(&p_chm->msg_params, NULL);
3348        p_chm->msg_params.band = p_chm->band;
3349        p_chm->msg_params.pid = (uint16_t)network_pid;
3350        p_chm->msg_params.filter.coef[0] = 0xCA;
3351        p_chm->msg_params.filter.mask[0] = 0x00;
3352        p_chm->msg_params.buffer = p_chm->rrt_buf;
3353        p_chm->msg_params.buffer_size = RRT_BUF_LEN;
3354        /* processing is done in callback */
3355        p_chm->msg_params.data_ready_callback = chm_smessage_rrt_callback;
3356        p_chm->msg_params.overflow = NULL;
3357        p_chm->msg_params.callback_context = (void *)p_chm;
3358        if (b_ok != smessage_start(&p_chm->msg_params, p_chm->rrt_msg))
3359        {
3360                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
3361                cerr = eCHM_ERR_FAILED;
3362        }
3363
3364ExitFunc:
3365        return cerr;
3366}
3367
3368/*
3369Summary:
3370Tune to the given frequency.
3371 */
3372static int chm_tune_freq(chm_mgr_t *p_chm,unsigned int freq_hz)
3373{
3374        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3375        unsigned int tune_ticks;
3376
3377        BDBG_MSG(("%s frequency=%d, last_freq_hz=%d\n",__func__, freq_hz, p_chm->last_freq_hz));
3378
3379        if (p_chm->force_tune)
3380        {
3381                p_chm->last_freq_hz = 0;
3382                p_chm->force_tune = false;
3383        }
3384
3385        if (p_chm->last_freq_hz != freq_hz)
3386        {
3387                btuner_params_init(&p_chm->tuner_params, p_chm->tuner);
3388                p_chm->tuner_params.cancel_callback = chm_tune_cancel_callback;
3389                p_chm->tuner_params.cancel_callback_context = p_chm;
3390                p_chm->tuner_params.wait_for_lock = true;
3391
3392                BDBG_MSG(("Tune to frequency = %d",freq_hz));
3393
3394                timing_profile_start(p_app->ptp_tune);
3395                tune_ticks = bos_getticks();
3396                p_chm->band = btuner_tune(p_chm->tuner, freq_hz, &p_chm->tuner_params);
3397                tune_ticks = bos_getticks() - tune_ticks;
3398                timing_profile_stop(p_app->ptp_tune);
3399
3400                p_chm->status_evt.type = eCHM_EVT_STATUS;
3401                p_chm->status_evt.id = eCHM_STATUS_TUNE_MS;
3402                p_chm->status_evt.ticks = TICKS_TO_MS(tune_ticks);
3403                chm_post_app_event(p_chm,(chm_event_t*)&p_chm->status_evt);
3404
3405                if (p_chm->band < 0)
3406                {
3407                        BDBG_MSG(("Tune failed (freq = %d)", freq_hz));
3408                        p_chm->last_freq_hz = 0;
3409                        /* Send message to app */
3410                        chm_send_status(p_chm,freq_hz,false);
3411
3412                        return eCHM_ERR_FAILED;
3413                }
3414                p_chm->last_freq_hz = freq_hz;
3415        } else
3416        {
3417                BDBG_MSG(("Already tuned to frequency = %d",freq_hz));
3418        }
3419        //RLQ, do it after calling start decode function since we don't want to switch task before channel change
3420        //chm_send_status(p_chm,freq_hz,true);
3421
3422        return eCHM_ERR_OK;
3423}
3424
3425/*
3426Summary:
3427Rotate audio pids.
3428 */
3429
3430static int chm_rotate_audio(chm_mgr_t *p_chm)
3431{
3432        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3433        bapp_ch_t *pch;
3434
3435        if (!p_chm->curr_stream || !p_chm->curr_stream->stream)
3436                return eCHM_ERR_FAILED;
3437
3438        pch = &p_app->settings.ch[p_app->cur_ch_num];
3439
3440        BDBG_MSG(("%s from 0x%04x to 0x%04x\n",__func__,p_chm->mpeg[CURR_CH].audio[0].pid, pch->audio_pid[pch->cur_audio]));
3441
3442        if (p_app->audio && (p_chm->mpeg[CURR_CH].audio[0].pid != 0))
3443        {
3444                BDBG_WRN(("baudio_decode_stop  0x%04x\n",p_chm->mpeg[CURR_CH].audio[0].pid));
3445                baudio_decode_stop(p_app->audio);
3446        }
3447
3448        p_chm->mpeg[CURR_CH].audio[0].pid = pch->audio_pid[pch->cur_audio];
3449        if (p_app->audio)
3450        {
3451                if (p_chm->mpeg[CURR_CH].audio[0].pid != 0)
3452                {
3453                        BDBG_WRN(("baudio_decode_start  0x%04x\n",p_chm->mpeg[CURR_CH].audio[0].pid));
3454                        bstream_update_mpeg(p_chm->curr_stream->stream,&p_chm->mpeg[CURR_CH]);
3455                        if (baudio_decode_start(p_app->audio, (void *)1, p_chm->curr_stream->stream))
3456                        {
3457                                BDBG_WRN(("baudio_decode_start failed\n"));
3458                                return eCHM_ERR_FAILED;
3459                        }
3460                }
3461        }
3462        return eCHM_ERR_OK;
3463}
3464
3465/*
3466Summary:
3467Open a stream given an mpeg program structure.
3468 */
3469static int chm_start_stream(chm_mgr_t *p_chm, chm_stream_t *p_stream,bstream_mpeg *p_mpeg)
3470{
3471        BDBG_ASSERT(p_stream);
3472        BDBG_ASSERT(p_mpeg);
3473
3474        if (p_stream->stream)
3475        {
3476                bstream_close(p_stream->stream);
3477                p_stream->stream = NULL;
3478        }
3479
3480        p_stream->stream = bstream_open(p_chm->band,p_mpeg);
3481        if (p_stream->stream)
3482        {
3483                p_stream->freq_hz = p_chm->last_freq_hz;
3484                p_stream->pid = p_mpeg->video[0].pid;
3485        }
3486        return (p_stream->stream) ? eCHM_ERR_OK : eCHM_ERR_FAILED;
3487}
3488
3489
3490/*
3491Summary:
3492Close the stream.
3493 */
3494void chm_stop_stream(chm_mgr_t *p_chm, chm_stream_t *p_stream)
3495{
3496        BDBG_ASSERT(p_stream);
3497
3498        if (p_stream->stream)
3499        {
3500                bstream_close(p_stream->stream);
3501                p_stream->stream = NULL;
3502                p_stream->pid = 0;
3503        }
3504}
3505/*
3506Summary:
3507Stop unused stream.
3508 */
3509static void chm_stop_unused_streams(chm_mgr_t *p_chm)
3510{
3511        int mpeg_idx,stream_idx;
3512        bool match;
3513
3514        for (stream_idx = 0; stream_idx < BSETTOP_MAX_STREAMS; ++stream_idx)
3515        {
3516                match = false;
3517                for (mpeg_idx = 0; mpeg_idx < BSETTOP_MAX_STREAMS; ++mpeg_idx)
3518                {
3519                        if (p_chm->mpeg[mpeg_idx].video[0].pid == p_chm->chm_stream[stream_idx].pid)
3520                        {
3521                                match = true;
3522                                continue;
3523                        }
3524                }
3525                if (!match)
3526                {
3527                        chm_stop_stream(p_chm,&(p_chm->chm_stream[stream_idx]));
3528                }
3529        }
3530}
3531/*
3532Summary:
3533Find the stream with this PID .
3534 */
3535static chm_stream_t *chm_find_stream(chm_mgr_t *p_chm, unsigned short pid)
3536{
3537        int stream_idx;
3538        BDBG_ASSERT(p_chm);
3539
3540        for (stream_idx = 0; stream_idx < BSETTOP_MAX_STREAMS; ++stream_idx)
3541        {
3542                if (pid == p_chm->chm_stream[stream_idx].pid)
3543                {
3544                        return &(p_chm->chm_stream[stream_idx]);
3545                }
3546        }
3547        return NULL;
3548}
3549/*
3550Summary:
3551Find an unused stream.
3552 */
3553static chm_stream_t *chm_find_unused_stream(chm_mgr_t *p_chm)
3554{
3555        int stream_idx;
3556        BDBG_ASSERT(p_chm);
3557
3558        for (stream_idx = 0; stream_idx < BSETTOP_MAX_STREAMS; ++stream_idx)
3559        {
3560                if (p_chm->chm_stream[stream_idx].stream == NULL)
3561                {
3562                        return &(p_chm->chm_stream[stream_idx]);
3563                }
3564        }
3565        return NULL;
3566}
3567
3568/*
3569Summary:
3570Start audio and video decode.
3571Description:
3572Handle tuning to the current channel. Returns non-zero on failure.
3573 */
3574static int chm_start_decode(chm_mgr_t *p_chm, bool force_restart)
3575{
3576        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3577        chm_stream_t *tmp_stream;
3578
3579        if ((p_chm->mpeg[CURR_CH].audio[0].pid == 0x0000) && (p_chm->mpeg[CURR_CH].video[0].pid == 0x0000))
3580        {
3581                BDBG_WRN(("%s (0x%04x,0x%04x,0x%04x,%d) failed \n",
3582                                        __func__,p_chm->mpeg[CURR_CH].video[0].pid,p_chm->mpeg[CURR_CH].pcr_pid,
3583                                        p_chm->mpeg[CURR_CH].audio[0].pid,p_chm->band));
3584                return eCHM_ERR_FAILED;
3585        }
3586
3587        if (p_chm->mpeg[CURR_CH].video[0].pid == 0x0000)
3588        {
3589                bdecode_config cfg;
3590                bdecode_get_config(p_app->decode,&cfg);
3591                cfg.mute = 1;
3592                cfg.channel_change = 0;
3593                bdecode_set_config(p_app->decode,&cfg);
3594        }
3595
3596        /* Stop the current decode (but not the streams) */
3597        chm_stop_decode(p_chm);
3598
3599        /* Handle audio only decode */
3600        if (p_app->audio && (p_chm->mpeg[CURR_CH].audio[0].pid != 0x0000) && (p_chm->mpeg[CURR_CH].video[0].pid == 0x0000))
3601        {
3602                BDBG_WRN(("%s (0x%04x,0x%04x,0x%04x,%d) audio only decode \n",
3603                                        __func__,p_chm->mpeg[CURR_CH].video[0].pid,p_chm->mpeg[CURR_CH].pcr_pid,
3604                                        p_chm->mpeg[CURR_CH].audio[0].pid,p_chm->band));
3605
3606                chm_stop_stream(p_chm,&(p_chm->chm_stream[CURR_CH]));
3607                chm_stop_stream(p_chm,&(p_chm->chm_stream[PREV_CH]));
3608                chm_stop_stream(p_chm,&(p_chm->chm_stream[NEXT_CH]));
3609
3610                if (chm_start_stream(p_chm,&(p_chm->chm_stream[CURR_CH]),&(p_chm->mpeg[CURR_CH])))
3611                {
3612                        BDBG_WRN(("chm_start_stream failed\n"));
3613                        return eCHM_ERR_FAILED;
3614                }
3615
3616                p_chm->curr_stream = &(p_chm->chm_stream[CURR_CH]);
3617
3618                if (baudio_decode_start(p_app->audio, (void *)1, p_chm->curr_stream->stream))
3619                {
3620                        BDBG_WRN(("baudio_decode_start failed\n"));
3621                        return eCHM_ERR_FAILED;
3622                }
3623                p_chm->decoding_audio = true;
3624                return eCHM_ERR_OK;
3625        }
3626
3627        /* Check if all streams need to be restarted */
3628        if (force_restart)
3629        {
3630                chm_stop_stream(p_chm,&(p_chm->chm_stream[CURR_CH]));
3631                chm_stop_stream(p_chm,&(p_chm->chm_stream[PREV_CH]));
3632                chm_stop_stream(p_chm,&(p_chm->chm_stream[NEXT_CH]));
3633
3634                if (chm_start_stream(p_chm,&(p_chm->chm_stream[CURR_CH]),&(p_chm->mpeg[CURR_CH])))
3635                {
3636                        BDBG_WRN(("chm_start_stream failed\n"));
3637                        return eCHM_ERR_FAILED;
3638                }
3639
3640                p_chm->curr_stream = &(p_chm->chm_stream[CURR_CH]);
3641
3642                if (p_chm->mpeg[NEXT_CH].video[0].pid != 0x0000)
3643                {
3644                        if (chm_start_stream(p_chm,&(p_chm->chm_stream[NEXT_CH]),&(p_chm->mpeg[NEXT_CH])))
3645                        {
3646                                BDBG_WRN(("chm_start_stream next failed\n"));
3647                        }
3648                }
3649
3650                if (p_chm->mpeg[PREV_CH].video[0].pid != 0x0000)
3651                {
3652                        if (chm_start_stream(p_chm,&(p_chm->chm_stream[PREV_CH]),&(p_chm->mpeg[PREV_CH])))
3653                        {
3654                                BDBG_WRN(("chm_start_stream prev failed\n"));
3655                        }
3656                }
3657        }
3658        else
3659        {
3660                chm_stop_unused_streams(p_chm);
3661
3662                p_chm->curr_stream = chm_find_stream(p_chm,p_chm->mpeg[CURR_CH].video[0].pid);
3663
3664                if (p_chm->curr_stream == NULL)
3665                {
3666                        if (chm_start_stream(p_chm,&(p_chm->chm_stream[CURR_CH]),&(p_chm->mpeg[CURR_CH])))
3667                        {
3668                                BDBG_WRN(("chm_start_stream current failed\n"));
3669                                return eCHM_ERR_FAILED;
3670                        }
3671                        p_chm->curr_stream = &(p_chm->chm_stream[CURR_CH]);
3672                }
3673
3674                if (p_chm->mpeg[NEXT_CH].video[0].pid != 0x0000)
3675                {
3676                        tmp_stream = chm_find_stream(p_chm,p_chm->mpeg[NEXT_CH].video[0].pid);
3677
3678                        if (tmp_stream == NULL)
3679                        {
3680                                tmp_stream = chm_find_unused_stream(p_chm);
3681
3682                                if (tmp_stream)
3683                                {
3684                                        if (chm_start_stream(p_chm,tmp_stream,&(p_chm->mpeg[NEXT_CH])))
3685                                        {
3686                                                BDBG_WRN(("chm_start_stream next failed\n"));
3687                                        }
3688                                }
3689                        }
3690                }
3691
3692                if (p_chm->mpeg[PREV_CH].video[0].pid != 0x0000)
3693                {
3694                        tmp_stream = chm_find_stream(p_chm,p_chm->mpeg[PREV_CH].video[0].pid);
3695
3696                        if (tmp_stream == NULL)
3697                        {
3698                                tmp_stream = chm_find_unused_stream(p_chm);
3699
3700                                if (tmp_stream)
3701                                {
3702                                        if (chm_start_stream(p_chm,tmp_stream,&(p_chm->mpeg[PREV_CH])))
3703                                        {
3704                                                BDBG_WRN(("chm_start_stream next failed\n"));
3705                                        }
3706                                }
3707                        }
3708                }
3709        }
3710
3711        if (!p_chm->curr_stream)
3712        {
3713                BDBG_WRN(("%s current stream NULL\n",__func__));
3714                return eCHM_ERR_FAILED;
3715        }
3716
3717        BDBG_MSG(("%s(0x%04x,0x%04x,0x%04x,%d)\n",
3718                                __func__,p_chm->mpeg[CURR_CH].video[0].pid,p_chm->mpeg[CURR_CH].pcr_pid,
3719                                p_chm->mpeg[CURR_CH].audio[0].pid,p_chm->band));
3720
3721        timing_profile_start(p_app->ptp_first_pts);
3722        timing_profile_start(p_app->ptp_decode);
3723        if (bdecode_start(p_app->decode, p_chm->curr_stream->stream, p_app->window[0]))
3724        {
3725                BDBG_WRN(("bdecode_start failed\n"));
3726                return eCHM_ERR_FAILED;
3727        }
3728        p_chm->decoding_video = true;
3729
3730        if (p_app->audio && (p_chm->mpeg[CURR_CH].audio[0].pid != 0))
3731        {
3732                if (baudio_decode_start(p_app->audio, (void *)1, p_chm->curr_stream->stream))
3733                {
3734                        BDBG_WRN(("baudio_decode_start failed\n"));
3735                        return eCHM_ERR_FAILED;
3736                }
3737                p_chm->decoding_audio = true;
3738        }
3739        return eCHM_ERR_OK;
3740}
3741/*
3742Summary:
3743Stop audio and video decode.
3744 */
3745static int chm_stop_decode(chm_mgr_t *p_chm)
3746{
3747        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3748
3749        chm_eas_stop(p_chm);
3750
3751        if (p_app->decode && p_chm->decoding_video)
3752                bdecode_stop(p_app->decode);
3753        if (p_app->audio && p_chm->decoding_audio)
3754                baudio_decode_stop(p_app->audio);
3755        p_chm->decoding_video = false;
3756        p_chm->decoding_audio = false;
3757
3758        return 0;
3759}
3760
3761/*
3762Summary:
3763        To check if adjacent channel (prev or next have same pids as current, and it yes, don't set them
3764Description:
3765        To check if adjacent channel (prev or next have same pids as current, and it yes, don't set them
3766       
3767 */
3768static int chm_pids_duplicated(chm_mgr_t *p_chm, bapp_ch_t *cur_pch, bapp_ch_t *cmp_pch)
3769{
3770        /* some adjacent channels have same pids as current, which will cause lost audio due to duplication and XPT will be failed */
3771        /* e.g 11.2 -> 13.1 in Mexico City has same pids on PCR and audio */
3772        if (cur_pch->pcr_pid) {
3773                if (cmp_pch->pcr_pid == cur_pch->pcr_pid || 
3774                        cmp_pch->video_pid == cur_pch->pcr_pid || cmp_pch->audio_pid[cmp_pch->cur_audio] == cur_pch->pcr_pid)
3775                        return true;
3776        }
3777        if (cur_pch->video_pid) {
3778                if (cmp_pch->pcr_pid == cur_pch->video_pid || 
3779                        cmp_pch->video_pid == cur_pch->video_pid || cmp_pch->audio_pid[cmp_pch->cur_audio] == cur_pch->video_pid)
3780                        return true;
3781        }
3782        if (cur_pch->audio_pid[cur_pch->cur_audio]) {
3783                if (cmp_pch->pcr_pid == cur_pch->audio_pid[cur_pch->cur_audio] || 
3784                        cmp_pch->video_pid == cur_pch->audio_pid[cur_pch->cur_audio] || 
3785                        cmp_pch->audio_pid[cmp_pch->cur_audio] == cur_pch->audio_pid[cur_pch->cur_audio])
3786                        return true;
3787        }
3788        return false;
3789}
3790
3791/*
3792Summary:
3793Configure mpeg with current video and audio pids
3794Description:
3795Tune to the current frequency and get the VCT. Returns non-zero on failure.
3796 */
3797
3798static int chm_config_mpeg(chm_mgr_t *p_chm, bapp_ch_t *pch)
3799{
3800        bapp_ch_t *tmp_pch;
3801        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3802        memset(&(p_chm->mpeg[CURR_CH]),0,sizeof(bstream_mpeg));
3803        memset(&(p_chm->mpeg[PREV_CH]),0,sizeof(bstream_mpeg));
3804        memset(&(p_chm->mpeg[NEXT_CH]),0,sizeof(bstream_mpeg));
3805
3806        p_chm->mpeg[CURR_CH].pcr_pid = pch->pcr_pid;
3807        p_chm->mpeg[CURR_CH].video[0].pid = pch->video_pid;
3808        p_chm->mpeg[CURR_CH].video[0].format = pch->video_type;
3809#if 0
3810        /* if always reset to audio same as language */
3811        p_chm->mpeg[CURR_CH].audio[0].pid = pch->audio_pid[p_app->lang] ? pch->audio_pid[p_app->lang] : pch->audio_pid[pch->cur_audio];
3812        p_chm->mpeg[CURR_CH].audio[0].format = pch->audio_type[p_app->lang] ? pch->audio_type[p_app->lang] : pch->audio_type[pch->cur_audio];
3813#else
3814        /* if follows the user change */
3815        p_chm->mpeg[CURR_CH].audio[0].pid = pch->audio_pid[pch->cur_audio] ? pch->audio_pid[pch->cur_audio] : pch->audio_pid[p_app->lang];
3816        p_chm->mpeg[CURR_CH].audio[0].format = pch->audio_type[pch->cur_audio] ? pch->audio_type[pch->cur_audio] : pch->audio_type[p_app->lang];
3817#endif
3818        if (p_chm->mpeg[CURR_CH].audio[0].pid == 0)
3819        {
3820                BDBG_WRN(("### Current audio PID is zero ###\n"));
3821        }
3822
3823        if (chm_ch_set_next(p_chm, &tmp_pch))
3824        {
3825                p_chm->mpeg[NEXT_CH].video[0].pid = tmp_pch->video_pid;
3826                p_chm->mpeg[NEXT_CH].video[0].format = tmp_pch->video_type;
3827                p_chm->mpeg[NEXT_CH].pcr_pid = tmp_pch->pcr_pid;
3828                if (tmp_pch->audio_pid[p_app->lang]) {
3829                        p_chm->mpeg[NEXT_CH].audio[0].pid = tmp_pch->audio_pid[p_app->lang];
3830                        p_chm->mpeg[NEXT_CH].audio[0].format =  tmp_pch->audio_type[p_app->lang];
3831                }
3832                else {
3833                        p_chm->mpeg[NEXT_CH].audio[0].pid = tmp_pch->audio_pid[tmp_pch->cur_audio];
3834                        p_chm->mpeg[NEXT_CH].audio[0].format =  tmp_pch->audio_type[tmp_pch->cur_audio];
3835                }
3836                if (chm_pids_duplicated(p_chm, pch, tmp_pch)) {
3837                        BDBG_WRN(("%s pids duplicated",__func__));
3838                        p_chm->mpeg[NEXT_CH].pcr_pid = 0;
3839                        p_chm->mpeg[NEXT_CH].video[0].pid = 0;
3840                        p_chm->mpeg[NEXT_CH].audio[0].pid = 0;
3841
3842                }
3843        }
3844
3845        if (chm_ch_set_prev(p_chm, &tmp_pch))
3846        {
3847                p_chm->mpeg[PREV_CH].video[0].pid = tmp_pch->video_pid;
3848                p_chm->mpeg[PREV_CH].video[0].format = tmp_pch->video_type;
3849                p_chm->mpeg[PREV_CH].pcr_pid = tmp_pch->pcr_pid;
3850                if (tmp_pch->audio_pid[p_app->lang]) {
3851                        p_chm->mpeg[PREV_CH].audio[0].pid = tmp_pch->audio_pid[p_app->lang];
3852                        p_chm->mpeg[PREV_CH].audio[0].format =  tmp_pch->audio_type[p_app->lang];
3853                }
3854                else {
3855                        p_chm->mpeg[PREV_CH].audio[0].pid = tmp_pch->audio_pid[tmp_pch->cur_audio];
3856                        p_chm->mpeg[PREV_CH].audio[0].format = tmp_pch->audio_type[tmp_pch->cur_audio];
3857                }
3858                if (chm_pids_duplicated(p_chm, pch, tmp_pch)) {
3859                        BDBG_WRN(("%s pids duplicated",__func__));
3860                        p_chm->mpeg[PREV_CH].pcr_pid = 0;
3861                        p_chm->mpeg[PREV_CH].video[0].pid = 0;
3862                        p_chm->mpeg[PREV_CH].audio[0].pid = 0;
3863
3864                }
3865        }
3866        //TODO, check audio pid and type for giving language
3867        return 0;
3868}
3869
3870/*
3871Summary:
3872Tune to the current frequency and enter steady channel processing state..
3873Description:
3874Tune to the current frequency and enter steady channel processing state..
3875 */
3876int chm_tune(chm_mgr_t *p_chm)
3877{
3878        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3879        int result = eCHM_ERR_FAILED;
3880        bool force_restart = false;
3881        bapp_ch_t *pch;
3882        int freq;
3883        uint16_t apid;
3884        bresult rc = b_ok;
3885
3886        if (chm_check_cancel(p_chm))
3887        {
3888                BDBG_WRN(("%s cancel detected at line %d\n",__func__,__LINE__));
3889                return eCHM_ERR_CANCELED;
3890        }
3891
3892        if (!p_app->settings.num_channels)
3893                return result;
3894
3895        chm_stop_filter_monitoring(p_chm, eCHM_MSG_FILTER_RRT | eCHM_MSG_FILTER_EAS);
3896
3897        chm_clear_current(p_chm);
3898
3899        /* check frequency to tune */
3900        rc = bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT);
3901        if (b_ok != rc) {
3902                BDBG_WRN(("####%s bos_acquire_mutex timeout###",__func__));
3903        }
3904        p_chm->cur_ch_num = p_app->cur_ch_num;
3905        p_app->cur_ch = p_app->settings.ch[p_app->cur_ch_num];
3906        if (b_ok == rc) {
3907                bos_release_mutex(&p_chm->mutex);
3908        }
3909        pch = &p_app->cur_ch;
3910
3911        freq = pch->frequency_khz * 1000;
3912        force_restart = (freq == p_chm->last_freq_hz) ? false : true;
3913
3914        if (force_restart)
3915                chm_stop_decode(p_chm);
3916
3917        if (chm_tune_freq(p_chm, freq) != 0)
3918        {
3919                BDBG_MSG(("%s tune frequency %d failed", __func__, freq));
3920                return eCHM_ERR_FAILED;
3921        }
3922
3923        if (chm_check_cancel(p_chm))
3924        {
3925                BDBG_WRN(("%s cancel detected at line %d\n",__func__,__LINE__));
3926                return eCHM_ERR_CANCELED;
3927        }
3928
3929        apid = chm_check_audio(p_chm, pch);
3930        /* if no pids exist get them */
3931        if ((0 == pch->video_pid) && (0 == apid) && (0 == pch->pcr_pid))
3932        {
3933                BDBG_WRN(("%s no PIDS\n",__func__));
3934                return result;
3935        }
3936        timing_profile_start(p_app->ptp_psi);
3937        /* Do not start decode if PIDs are all 0.  Doing so can prevent SI filtering from operating correctly. */
3938        if (pch->video_pid || apid || (0 != pch->pcr_pid))
3939        {
3940                chm_config_mpeg(p_chm,pch);
3941                if ((result = chm_start_decode(p_chm,force_restart)) != 0)
3942                {
3943                        BDBG_WRN(("chm_start_decode failed\n"));
3944                        timing_profile_stop(p_app->ptp_psi);           
3945                        return result;
3946                }
3947        }
3948        timing_profile_stop(p_app->ptp_psi);           
3949
3950        if (result == 0)
3951        {
3952                p_chm->pmt_crc = p_chm->pat_crc = 0;
3953                /* for SAP handling */
3954                p_app->num_sap = pch->num_audio;
3955                p_app->current_sap = pch->cur_audio;
3956                chm_make_current(p_chm, &p_chm->p_info[p_app->cur_ch_num]);
3957
3958                /* start decode success so transition to info acquire state */
3959                p_chm->cmd = eCHM_INFO;
3960                /* alwasy get STT in case it is recorded source */
3961                p_chm->state = eCHM_GET_STT; 
3962                /* we use this count */
3963                p_chm->mgt_cnt = 0;
3964                p_chm->got_eit = false;
3965                /* we use this to track ETT */
3966                p_chm->got_ett = false;
3967                /* have not check PAT/PMT yet */
3968                p_chm->first_pat_pmt = false;
3969
3970                if (0 == p_app->settings.time_zone) {
3971                        //p_chm->local_time_source = eTS_NONE;
3972                }
3973
3974                chm_start_filter_monitoring(p_chm, eCHM_MSG_FILTER_EAS);
3975                p_chm->eas_cnt = 0;
3976                /* use this variable instead of eas_cnt to track new eas message */
3977                p_chm->eas_reset = true;
3978        }
3979
3980        /* RLQ */
3981        chm_send_status(p_chm,freq,true);
3982
3983        return result;
3984}
3985
3986/*
3987Summary:
3988Do a tune for the purpose of checking the signal strength.
3989 */
3990int chm_check_signal(chm_mgr_t *p_chm)
3991{
3992        int result = eCHM_ERR_FAILED;
3993        //btuner_status status;
3994        bapp_t *p_app = (bapp_t*)p_chm->p_app;
3995        unsigned int freq_hz = 0;
3996
3997        if (chm_check_cancel(p_chm))
3998                return eCHM_ERR_CANCELED;
3999
4000#if 0
4001        freq_hz = p_app->cur_ch.frequency_khz * 1000;
4002
4003        if (chm_tune_freq(p_chm, freq_hz) != 0)
4004        {
4005                p_chm->signal_evt.type = eCHM_EVT_SIGNAL;
4006                p_chm->signal_evt.power = 0;
4007                p_chm->signal_evt.SNR = 0;
4008                p_chm->signal_evt.freq_hz = freq_hz;
4009                p_chm->signal_evt.lock = 0;
4010                p_chm->signal_evt.signal_quality = 0;
4011                chm_post_app_event(p_chm,(chm_event_t*)&p_chm->signal_evt);
4012                return result;
4013        }
4014#endif
4015
4016        if (chm_check_cancel(p_chm))
4017                return result;
4018
4019        if (btuner_get_status(p_chm->tuner,&p_app->tuner_status) == b_ok)
4020        {
4021                p_chm->signal_evt.type = eCHM_EVT_SIGNAL;
4022                p_chm->signal_evt.power = p_app->tuner_status.power;
4023                p_chm->signal_evt.SNR = p_app->tuner_status.snr;
4024                p_chm->signal_evt.freq_hz = freq_hz;
4025                p_chm->signal_evt.lock = p_app->tuner_status.lock;
4026                p_chm->signal_evt.signal_quality = p_app->tuner_status.PreRS;
4027                chm_post_app_event(p_chm,(chm_event_t*)&p_chm->signal_evt);
4028        }
4029
4030        return result;
4031}
4032
4033/*
4034Summary:
4035Start EAS monitoring..
4036 */
4037static int chm_eas_start(chm_mgr_t *p_chm, unsigned short network_pid)
4038{
4039        int cerr = eCHM_ERR_OK;
4040
4041        chm_eas_stop(p_chm);
4042
4043        p_chm->eas_msg = smessage_open(smessage_format_psi);
4044        if (NULL == p_chm->eas_msg)
4045        {
4046                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
4047                cerr = eCHM_ERR_FAILED;
4048                goto ExitFunc;
4049        }
4050        smessage_stream_params_init(&p_chm->msg_params, NULL);
4051        p_chm->msg_params.band = p_chm->band;
4052        p_chm->msg_params.pid = 0x1ffb;
4053        p_chm->msg_params.filter.coef[0] = 0xD8;
4054        p_chm->msg_params.filter.mask[0] = 0x00;
4055        //p_chm->msg_params.filter.excl[0] = 0xff;
4056        /* All PSIP tables have protocol_version which must be = 0 */
4057        p_chm->msg_params.filter.coef[8] = 0x00;        /* protocol_version */
4058        p_chm->msg_params.filter.mask[8] = 0x00;
4059        p_chm->msg_params.buffer = p_chm->eas_buf;
4060        p_chm->msg_params.buffer_size = EAS_BUF_LEN;
4061        /* processing is done in callback */
4062        p_chm->msg_params.data_ready_callback = chm_smessage_eas_callback;
4063        p_chm->msg_params.overflow = NULL;
4064        p_chm->msg_params.callback_context = (void *)p_chm;
4065        if (b_ok != smessage_start(&p_chm->msg_params, p_chm->eas_msg))
4066        {
4067                BDBG_ERR(("%s:%d",__FILE__, __LINE__));
4068                cerr = eCHM_ERR_FAILED;
4069        }
4070        p_chm->eas_timer_started = false;
4071
4072ExitFunc:
4073        return cerr;
4074}
4075
4076/*
4077Summary:
4078to start filter monitoring
4079 */
4080void chm_start_filter_monitoring(chm_mgr_t *p_chm, chm_msg_filter_t which)
4081{
4082        if (which & eCHM_MSG_FILTER_STT)
4083                chm_stt_start(p_chm,p_chm->network_pid);
4084        if (which & eCHM_MSG_FILTER_RRT)
4085                chm_rrt_start(p_chm,p_chm->network_pid);
4086        if (which & eCHM_MSG_FILTER_MGT)
4087                chm_mgt_start(p_chm,p_chm->network_pid);
4088        if (which & eCHM_MSG_FILTER_EAS)
4089                chm_eas_start(p_chm,p_chm->network_pid);
4090}
4091
4092/*
4093Summary:
4094to stop filter monitoring
4095 */
4096void chm_stop_filter_monitoring(chm_mgr_t *p_chm, chm_msg_filter_t which)
4097{
4098        if (which & eCHM_MSG_FILTER_STT)
4099                chm_stt_stop(p_chm);
4100        if (which & eCHM_MSG_FILTER_RRT)
4101                chm_rrt_stop(p_chm);
4102        if (which & eCHM_MSG_FILTER_MGT)
4103                chm_mgt_stop(p_chm);
4104        if (which & eCHM_MSG_FILTER_EAS)
4105                chm_eas_stop(p_chm);
4106}
4107
4108/*
4109 *  This routine will return valid wide_aspect_ratio for given channel's current digital caption service
4110 * 
4111 *  Return:
4112 *      true if has valid wide_aspect_ratio for given channel's current digital caption service
4113 *      false if not
4114 */
4115bool chm_has_valid_cc_service(chm_mgr_t *p_chm, bool *wide_aspect_ratio)
4116{
4117        bapp_t *p_app = (bapp_t*)p_chm->p_app;
4118        uint32_t utc_time;
4119
4120        /* if not get STT */
4121        if (eCHM_ERR_OK != chm_get_utctime(p_chm, &utc_time))
4122                return false;
4123
4124        utc_time += p_chm->stt.GPS_UTC_offset;
4125        /* if now match current time, then we have valid wide_aspect_ratio information */
4126        if ((p_app->captions_basic > 0) && 
4127                        ((utc_time >= (p_chm->cur_info.eit_info[EIT_CURRENT].start_time) && 
4128                          (utc_time <= (p_chm->cur_info.eit_info[EIT_CURRENT].start_time + p_chm->cur_info.eit_info[EIT_CURRENT].length))))) {
4129                *wide_aspect_ratio = p_chm->cur_info.eit_info[EIT_CURRENT].cc_service[p_app->captions_basic - 1].wide_aspect_ratio;
4130                return true;
4131        }
4132
4133        return false;
4134}
4135
4136/*
4137 * This routine is used to check if there is valid EIT or not.
4138 *
4139 * Return:
4140 *      true if current program is completed
4141 *      false otherwise
4142 */
4143bool chm_check_program_end_time(chm_mgr_t *p_chm)
4144{
4145        uint32_t utc_time;
4146        unsigned int temp1,temp2;
4147        bool isTimeToTrue = false;
4148        static unsigned int old_time,Cnt_time;
4149        /* if got STT */
4150        if (eCHM_ERR_OK == chm_get_utctime(p_chm, &utc_time)) {
4151                if (p_chm->cur_info.eit_info[EIT_CURRENT].start_time && p_chm->cur_info.eit_info[EIT_CURRENT].length) {
4152                        utc_time += p_chm->stt.GPS_UTC_offset;
4153
4154                        temp1 = (p_chm->cur_info.eit_info[EIT_NEXT].start_time);
4155                        temp2 = (p_chm->cur_info.eit_info[EIT_CURRENT].start_time + p_chm->cur_info.eit_info[EIT_CURRENT].length);
4156
4157                        if (utc_time >= temp1)
4158                        {
4159                                isTimeToTrue =  true;
4160                        }
4161
4162                        if (utc_time >= temp2)
4163                        {
4164                                isTimeToTrue =  true;
4165                        }
4166
4167                }
4168        }
4169
4170        if(isTimeToTrue)
4171        {
4172                if(Cnt_time == 0)
4173                {
4174                        old_time = utc_time;
4175                        Cnt_time = 1;
4176                }
4177                if(utc_time != 0 && old_time != 0)
4178                        Cnt_time += (utc_time -old_time);
4179
4180                old_time = utc_time;
4181        }
4182        else
4183        {
4184                Cnt_time = 0;
4185                old_time = utc_time;
4186        }
4187
4188        if(Cnt_time > 6)
4189        {
4190                Cnt_time = 0;
4191                old_time = utc_time;
4192                return true;
4193        }
4194        return false;
4195}
4196
4197/*
4198 * This routine is used to check if there is a need to update MGT and its associated tables
4199 *
4200 * Return:
4201 *      true if need
4202 *      false if not
4203 */
4204static bool chm_need_mgt_update(chm_mgr_t *p_chm)
4205{
4206        uint32_t utc_time;
4207        bool need_update;
4208        bapp_t *p_app = (bapp_t*)p_chm->p_app;
4209
4210        /* if not got STT yet */
4211        if (eCHM_ERR_OK != chm_get_utctime(p_chm, &utc_time))
4212                return false;
4213
4214        utc_time += p_chm->stt.GPS_UTC_offset;
4215        /* if now does not match or have not get the ETT, then need MGT update */
4216        need_update = (utc_time >= (p_chm->cur_info.eit_info[EIT_CURRENT].start_time + p_chm->cur_info.eit_info[EIT_CURRENT].length));
4217        /* check if current setting is end of program? */
4218        if (2 == p_app->settings.auto_power && need_update) {
4219                /* make sure current is valid */
4220                if (p_chm->cur_info.eit_info[EIT_CURRENT].start_time && p_chm->cur_info.eit_info[EIT_CURRENT].length) {
4221                        /* TODO confirm the logic if the user change channel around transition time? */
4222                        if (p_chm->got_eit && (p_chm->mgt_cnt > 0)) {
4223                                /* current program is end, don't update to new EIT so that is can be powered off as expected */
4224                                need_update = false;
4225                        }
4226                }       
4227        }
4228        /* don't check program desc here as we have to deal with end of program case */
4229        //need_update |= (0 == strlen(p_chm->cur_info.eit_info[EIT_CURRENT].prog_desc));
4230        return need_update;
4231}
4232
4233/*
4234 * Summary:
4235 *      Get channel detailed program info.
4236 * Description:
4237 *      Get channel detailed program info.
4238 * Returns non-zero on failure.
4239 *  */
4240static int chm_get_prog_details(chm_mgr_t *p_chm)
4241{
4242        bapp_t *p_app = (bapp_t*)p_chm->p_app;
4243        chm_state_t orig_state;
4244        int result = 0;
4245
4246        //BDBG_MSG(("CHM State %s ",s_chm_state[p_chm->state]));
4247
4248        /* check it in case we tune to a channel from CLI */
4249        if (p_app->settings.num_channels < 1) {
4250                return 0;
4251        }
4252
4253        orig_state = p_chm->state;
4254
4255        if (chm_check_cancel(p_chm))
4256                return result;
4257
4258        switch (p_chm->state)
4259        {
4260                case eCHM_GET_STT:
4261                        chm_get_stt(p_chm);
4262                        p_chm->state = eCHM_GET_VCT;
4263#ifdef CHECK_PROGRAM
4264            /* workaround for the channels that programed wrong pcr_pid */
4265            chm_check_program(p_chm);
4266            p_chm->first_pat_pmt = true;
4267            p_chm->state = eCHM_GET_VCT;
4268#endif
4269                        break;
4270
4271                case eCHM_GET_VCT:
4272                        /* if PSI scan, don't check VCT */
4273                        if (p_app->settings.ch[p_chm->cur_ch_num].psi) {
4274                                p_chm->state = eCHM_PROG_IDLE;
4275                                break;
4276                        }
4277                        if (p_chm->local_time_source == eTS_NONE) {
4278                                /* force to check VCT again until we get local_time_source */
4279                                p_chm->p_info[p_chm->cur_ch_num].got_vct = false;
4280                                p_chm->got_vct = false;
4281                        }
4282                        if (!p_chm->p_info[p_chm->cur_ch_num].got_vct) {
4283                                /* TODO using callback to process VCT to reduce channel change time */
4284                                result = chm_get_vct(p_chm, &p_chm->p_info[p_chm->cur_ch_num]);
4285#ifdef CHECK_PROGRAM
4286                                if (eCHM_ERR_TIMEOUT == result && !p_chm->first_pat_pmt) {
4287                                        p_chm->first_pat_pmt = true;
4288                        chm_check_program(p_chm);
4289                                        /* chm_check_program will change state if get pat/pmt successfully, so reset the state */
4290                        p_chm->state = eCHM_GET_VCT;
4291                                }
4292#endif
4293                        }
4294                        else
4295                                p_chm->state = eCHM_GET_MGT;
4296                        break;
4297
4298                case eCHM_GET_MGT:
4299                        if (chm_need_mgt_update(p_chm)) {
4300                                p_chm->got_ett = 0;
4301                                p_chm->p_info->eit_info[EIT_CURRENT].prog_desc[0] = 0;
4302                                result = chm_get_mgt(p_chm);           
4303                        }
4304                        else  {
4305                                /* if just missing program descriptor, then just update ETT */
4306                                if (0 == strlen(p_chm->cur_info.eit_info[EIT_CURRENT].prog_desc)) {
4307                                        p_chm->got_ett = false;
4308                                        result = chm_get_mgt(p_chm);           
4309                                        if (eCHM_ERR_OK == result) {
4310                                                /* just check ETT entry */
4311                                                p_chm->mgt_state = eMGT_ETT;
4312                                        }
4313                                }
4314                                else  {
4315                                        result = eCHM_ERR_OK;
4316                                        p_chm->state = eCHM_PROG_IDLE;
4317                                }
4318                        }
4319#ifdef CHECK_PROGRAM
4320                        if (eCHM_ERR_TIMEOUT == result && !p_chm->first_pat_pmt) {
4321                                p_chm->first_pat_pmt = true;
4322                                chm_check_program(p_chm);
4323                                /* chm_check_program will change state if get pat/pmt successfully, so reset the state */
4324                                p_chm->state = eCHM_GET_MGT;
4325                        }
4326#endif
4327                        break;
4328
4329                case eCHM_PROCESS_MGT:
4330                        if (eMGT_EIT == p_chm->mgt_state) {
4331                                if (chm_process_mgt(p_chm, p_chm->mgt_buf,p_chm->mgt_size,&p_chm->p_info[p_chm->cur_ch_num],false,true) != 0)
4332                                {
4333                                        BDBG_MSG(("Failed to process EIT"));
4334                                        p_chm->state = eCHM_PROG_IDLE;
4335                                        break;
4336                                }
4337                                else {
4338                                        /* we should get the valid EIT with cc_service information, update wide_aspect_ratio information */
4339                                        bapp_set_wide_aspect_ratio(p_app);
4340                                }
4341                        }
4342                        if (eMGT_ETT == p_chm->mgt_state) {
4343                                if (chm_process_mgt(p_chm, p_chm->mgt_buf,p_chm->mgt_size,&p_chm->p_info[p_chm->cur_ch_num],true,true) != 0)
4344                                {
4345                                        BDBG_WRN(("Failed to process ETT"));
4346                                        p_chm->state = eCHM_PROG_IDLE;
4347                                }
4348                        }
4349                        /* a patch to fix no audio issue that no audio info given in VCT */
4350                        if ((1 == p_chm->mgt_cnt) && (0 == p_app->cur_ch.num_audio)) {
4351                                /* check PAT/PMT immediately */
4352                                p_chm->state = eCHM_PROG_IDLE;
4353                        }
4354
4355                        /* if transited to IDLE means we got the EIT and most likely the ETT */
4356                        if (eCHM_PROG_IDLE == p_chm->state) {
4357                                chm_make_current(p_chm, &p_chm->p_info[p_chm->cur_ch_num]);
4358                        }
4359#ifndef NO_VCHIP
4360                        /* indicate that we get eit information, so update current to so that it can update the Banner screen as well */
4361                        if (p_app->psip_rating_str[0]) {
4362                                memcpy(&p_chm->p_info[p_chm->cur_ch_num].psip_rating_str, &p_app->psip_rating_str, sizeof(p_app->psip_rating_str));
4363                                chm_make_current(p_chm, &p_chm->p_info[p_chm->cur_ch_num]);
4364                        }
4365#endif
4366                        break;
4367
4368                case eCHM_PROG_IDLE:
4369                        result = chm_prog_idle(p_chm);
4370                        break;
4371
4372                default:
4373                        break;
4374        }
4375
4376        if (orig_state != p_chm->state)
4377        {
4378                BDBG_MSG(("CHM State changed from %s to %s\n",s_chm_state[orig_state],s_chm_state[p_chm->state]));
4379        }
4380        return result;
4381}
4382
4383/*
4384 * Summary:
4385 *      background handling in idle time
4386 */
4387static int chm_prog_idle(chm_mgr_t *p_chm)
4388{
4389        b_timeval tv;
4390
4391        gettimeofday(&tv);
4392        if (tv.tv_sec > (p_chm->mgt_tv.tv_sec + CHM_IDLE_TIMEOUT))
4393        {
4394                bapp_t *p_app = (bapp_t*)p_chm->p_app;
4395#ifndef NO_VCHIP
4396                if (p_app->settings.ratings.ratings_lock == 2) {
4397                        if (!p_chm->rrt_msg) {
4398                                /* downloadable RRT */
4399                                chm_start_filter_monitoring(p_chm, eCHM_MSG_FILTER_RRT);
4400                        }       
4401                }
4402#endif
4403                if (p_app->chm.local_time_source == eTS_NONE)
4404                {
4405                        p_chm->state = eCHM_GET_VCT;
4406                        p_chm->p_info[p_chm->cur_ch_num].got_vct = false;
4407                } else {
4408                        if (chm_need_mgt_update(p_chm)) {
4409                                p_chm->state = eCHM_GET_MGT;
4410                        }
4411                        else
4412                                p_chm->state = eCHM_GET_STT;
4413                }
4414                /* check signal */
4415                chm_check_signal(p_chm);
4416        } else {
4417#if 1
4418                static unsigned int last_signal_check = 0;
4419                static unsigned int last_prog_check = 0;
4420
4421                if (last_prog_check < bos_getticks())
4422                {
4423#ifdef CHECK_PROGRAM
4424                        p_chm->state = chm_check_program(p_chm);
4425#endif
4426
4427                        last_prog_check = bos_getticks() + MS_TO_TICKS(CHM_CHECK_PROG_FREQ);
4428                }
4429
4430                if (last_signal_check < bos_getticks())
4431                {
4432                        chm_send_status(p_chm,p_chm->last_freq_hz,true);
4433                        last_signal_check = bos_getticks() + MS_TO_TICKS(CHM_CHECK_SIGNAL_FREQ);
4434                }
4435                p_chm->chmap_evt.ticks = 0;
4436#endif
4437        }
4438        return 0;
4439}
4440
4441#ifdef CHECK_PROGRAM
4442/*
4443Summary:
4444check the program for changes..
4445 */
4446int chm_check_program(chm_mgr_t *p_chm)
4447{
4448        int result = eCHM_PROG_IDLE, i;
4449        bapp_t *p_app = (bapp_t*)p_chm->p_app;
4450        bapp_ch_t ch, *pch, cur_ch;
4451        unsigned int pmt_crc,pat_crc;
4452        int restart = 0, cur_ch_num;    /* will use bit map */
4453
4454        /* serialize the update process to avoid a race condition */
4455        if (b_ok != bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT)) {
4456                BDBG_WRN(("bos_acquire_mutex failed"));
4457                return eCHM_PROG_IDLE;
4458        }
4459        /* verify the cur_ch_num? */
4460        if (p_chm->cur_ch_num != p_app->cur_ch_num) {
4461                /* race condiction? */
4462                BDBG_WRN(("%d, cur_ch_num not match, race condition?", __func__));
4463                bos_release_mutex(&p_chm->mutex);
4464                return eCHM_PROG_IDLE;
4465        }       
4466        /* remember current PAT and PMT CRC so that we know if PAT/PMT changes or not */
4467        pmt_crc = p_chm->pmt_crc;
4468        pat_crc = p_chm->pat_crc;
4469
4470        cur_ch_num = p_chm->cur_ch_num;
4471        /* make a local copy instead use p_app->cur_ch*/
4472        //pch = &p_app->cur_ch;
4473        memcpy(&cur_ch, &p_app->settings.ch[cur_ch_num], sizeof(bapp_ch_t));
4474        pch = &cur_ch;
4475
4476        /* initalize it here and also assign the program_num with mutex protection to avoid possible race condition */
4477        memset(&ch, 0, sizeof(ch));
4478        ch.program_num = pch->program_num;
4479
4480        bos_release_mutex(&p_chm->mutex);
4481
4482        BDBG_MSG(("***** chm_check_program *****"));
4483        if ((result = chm_get_program(p_chm, &ch)) != b_ok)
4484        {
4485                BDBG_WRN(("chm_get_program failed %d",result));
4486                return eCHM_PROG_IDLE; /* return state expected */
4487        }
4488
4489        /* Check if pat/pmt changed */
4490        if ((pat_crc == p_chm->pat_crc) && (pmt_crc == p_chm->pmt_crc))
4491                return eCHM_PROG_IDLE;
4492
4493        /* serialize the update process to avoid a race condition */
4494        if (b_ok != bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT)) {
4495                BDBG_WRN(("bos_acquire_mutex failed"));
4496                return eCHM_PROG_IDLE;
4497        }
4498        if (ch.pcr_pid && (ch.pcr_pid != pch->pcr_pid))
4499        {
4500                BDBG_WRN(("PCR PID changed (new 0x%04x, current 0x%04x)",ch.pcr_pid, pch->pcr_pid));
4501                pch->pcr_pid = ch.pcr_pid;
4502                pch->psi = true;
4503                restart |= 0x01;        /* need to restart video */
4504        }
4505        if (ch.video_pid && ((ch.video_pid != pch->video_pid) || (ch.video_type != pch->video_type)))
4506        {
4507                if (ch.video_pid != pch->video_pid) {
4508                        BDBG_WRN(("Video PID changed (new 0x%04x, current 0x%04x)",ch.video_pid, pch->video_pid));
4509                        pch->video_pid = ch.video_pid;
4510                }
4511                if (ch.video_type != pch->video_type) {
4512                        BDBG_WRN(("Video type changed (new 0x%04x, current 0x%04x)",ch.video_type, pch->video_type));
4513                        pch->video_type = ch.video_type;
4514                }
4515                restart |= 0x01;        /* need to restart video */
4516                pch->psi = true;
4517        }
4518        for (i = 0; i < MAX_AUDIO_PIDS && i < ch.num_audio; i++) {
4519                if (ch.audio_pid[i] && ((ch.audio_pid[i] != pch->audio_pid[i]) || (ch.audio_type[i] != pch->audio_type[i])))
4520                {
4521                        if (ch.audio_pid != pch->audio_pid) {
4522                                BDBG_WRN(("Audio PID[%d] changed (new 0x%04x, current 0x%04x)", i, ch.audio_pid[i], pch->audio_pid[i]));
4523                                pch->audio_pid[i] = ch.audio_pid[i];
4524                                if (i == pch->cur_audio)
4525                                        restart |= 0x02;        /* need to restart audio */
4526                        }
4527                        if (ch.audio_type != pch->audio_type) {
4528                                BDBG_WRN(("Audio type [%d] changed (new 0x%04x, current 0x%04x)", i, ch.audio_type[i], pch->audio_type[i]));
4529                                pch->audio_type[i] = ch.audio_type[i];
4530                                if (i == pch->cur_audio)
4531                                        restart |= 0x02;        /* need to restart audio */
4532                        }
4533                        memcpy(&pch->audio_lang[i][0],&ch.audio_lang[i][0], 3);
4534                        pch->psi = true;
4535                }
4536        }
4537        if (ch.num_audio != pch->num_audio || ch.has_lang != pch->has_lang || ch.cur_audio != pch->cur_audio) {
4538                pch->num_audio = ch.num_audio;
4539                p_app->num_sap = ch.num_audio;  /* need to update this as well so that it can select audio channel from UI */
4540                pch->has_lang = ch.has_lang;
4541                pch->cur_audio = ch.cur_audio;
4542        }
4543        /* if changed, resync the changes */
4544        if (0 != memcmp(&p_app->settings.ch[cur_ch_num], pch, sizeof(bapp_ch_t))) {
4545                p_app->settings.ch[cur_ch_num] = *pch;
4546        }
4547        bos_release_mutex(&p_chm->mutex);
4548
4549        if (restart)
4550        {
4551                chm_config_mpeg(p_chm, pch);
4552                if (0x01 & restart) {
4553                        result = chm_start_decode(p_chm,true);
4554                }
4555                else {
4556                        /* if video PID/PCR PID are not changed, then just restart audio to avoid video flushing */
4557                        bstream_update_mpeg(p_chm->curr_stream->stream,&p_chm->mpeg[CURR_CH]);
4558                        result = baudio_decode_start(p_app->audio, (void *)1, p_chm->curr_stream->stream);
4559                }
4560                if (result)
4561                {
4562                        BDBG_WRN(("%s %s failed\n",__func__, (0x01 & restart) ? "chm_start_decode" : "baudio_decode_start"));
4563                }
4564                /* sync with current cur_ch as some of process refer to that cur_ch structure */               
4565                p_app->cur_ch = p_app->settings.ch[cur_ch_num];
4566        }
4567        return eCHM_PROG_IDLE;
4568}
4569#endif  /*CHECK_PROGRAM*/
4570
4571/*
4572Summary:
4573Channel Manager Task.
4574 */
4575static void chm_handler(void *data)
4576{
4577        chm_cmd_t orig_cmd;
4578        chm_mgr_t *p_chm = (chm_mgr_t *)data;
4579        chm_cmd_event_t *p_cmd;
4580
4581        while (1)
4582        {
4583                orig_cmd = p_chm->cmd;
4584                switch (p_chm->cmd)
4585                {
4586                        case eCHM_CANCEL:
4587                                p_cmd = (chm_cmd_event_t*)bos_pend_event(p_chm->queue,-1);
4588                                if (p_cmd == NULL)
4589                                        break;
4590
4591                                p_chm->cmd = (chm_cmd_t)p_cmd->cmd_id;
4592                                break;
4593                        case eCHM_SAP:
4594                                p_chm->cmd = eCHM_CANCEL;
4595                                break;
4596
4597                        case eCHM_STOP:
4598                                chm_stop_decode(p_chm);
4599                                p_chm->cmd = eCHM_CANCEL;
4600                                break;
4601
4602                        case eCHM_TUNE:
4603                                chm_tune(p_chm);
4604                                break;
4605                        case eCHM_HUNT:
4606                                chm_hunt(p_chm); 
4607                                break;
4608                        case eCHM_GUIDE:
4609                                chm_get_guide(p_chm);
4610                                break; 
4611                        case eCHM_INFO:
4612                                chm_get_prog_details(p_chm);
4613                                break;
4614                        case eCHM_CHECK_SIGNAL:
4615                                chm_check_signal(p_chm);
4616                                break;
4617                }
4618
4619                if (orig_cmd != p_chm->cmd)
4620                {
4621                        BDBG_WRN(("CHM CMD changed from %s to %s\n", s_chm_cmd_name[orig_cmd],s_chm_cmd_name[p_chm->cmd]));
4622                }
4623
4624                /* Yield a little */
4625                bos_sleep(40);
4626        }
4627}
4628
4629/*
4630Summary:
4631Initialize the channel manager.
4632 */
4633
4634void chm_init(chm_mgr_t *p_chm, void *p_app)
4635{
4636        b_task_params   params;
4637        bresult rc;
4638        memset(p_chm,0,sizeof(chm_mgr_t));
4639        p_chm->p_app = p_app;
4640        /* for NTIA project */
4641#ifdef CONFIG_ISDB
4642        p_chm->fe_type = eFREQ_TABLE_ISDB;
4643#else
4644        p_chm->fe_type = eFREQ_TABLE_NTIA_VSB;
4645#endif
4646        rc = bos_create_queue(&p_chm->queue,p_chm->event,MAX_CHM_EVENT);
4647        BDBG_ASSERT(rc == b_ok);
4648        rc = bos_create_queue(&p_chm->gen_queue,p_chm->gen_event,MAX_MSG_EVENTS);
4649        BDBG_ASSERT(rc == b_ok);
4650        rc = bos_create_mutex(&p_chm->mutex);
4651        BDBG_ASSERT(rc == b_ok);
4652        rc = bos_create_mutex(&p_chm->ch_map_mutex);
4653        BDBG_ASSERT(rc == b_ok);
4654
4655        /* will remove ch_map related functions and variables */
4656        //ch_map_init(&(p_chm->ch_map),&(p_chm->ch_map_mutex));
4657
4658        /* round to nearest chm_info_t size */
4659        p_chm->max_info_num = MAX_CHANNELS;
4660        p_chm->p_info = (chm_info_t*)malloc(p_chm->max_info_num * sizeof(chm_info_t));
4661
4662        BDBG_ASSERT(p_chm->p_info);
4663        memset(p_chm->p_info,0,p_chm->max_info_num * sizeof(chm_info_t));
4664
4665        BDBG_MSG(("Maximum guide entries = %d.\n",p_chm->max_info_num));
4666
4667        p_chm->stack = malloc(CHM_INT_STK_SIZE * 4);
4668        BDBG_ASSERT(p_chm->stack);
4669
4670        params.priority = CHM_INT_PRIORITY;
4671        params.stack = p_chm->stack;
4672        params.name = "chan_mgr";
4673        params.stack_size = CHM_INT_STK_SIZE;
4674
4675        p_chm->pat_buf = malloc(PAT_BUF_LEN);
4676        p_chm->pmt_buf = malloc(PMT_BUF_LEN);
4677        p_chm->stt_buf = malloc(STT_BUF_LEN);
4678        p_chm->vct_buf = malloc(VCT_BUF_LEN);
4679        p_chm->eit_buf = malloc(EIT_BUF_LEN);
4680        p_chm->ett_buf = malloc(ETT_BUF_LEN);
4681        p_chm->mgt_buf = malloc(MGT_BUF_LEN);
4682        p_chm->eas_buf = malloc(EAS_BUF_LEN);
4683
4684        BDBG_ASSERT(p_chm->pat_buf && p_chm->pmt_buf && p_chm->mgt_buf && p_chm->eit_buf &&
4685                        p_chm->stt_buf && p_chm->vct_buf && p_chm->eas_buf && p_chm->ett_buf);
4686
4687        bstream_mpeg_init(&p_chm->mpeg[CURR_CH]);
4688        bstream_mpeg_init(&p_chm->mpeg[NEXT_CH]);
4689        bstream_mpeg_init(&p_chm->mpeg[PREV_CH]);
4690
4691        p_chm->tuner = btuner_open((0));
4692        BAPP_ASSERT(p_chm->tuner);
4693
4694        p_chm->smsg = smessage_open(smessage_format_psi);
4695
4696        BAPP_ASSERT(p_chm->smsg);
4697
4698        p_chm->vendor_id = DEF_VENDOR_ID;
4699        p_chm->hardware_version_id = DEF_HARDWARE_ID;
4700
4701        p_chm->cmd = eCHM_CANCEL;
4702        p_chm->hunt_cnt = 0;
4703
4704        /* set default network pid */
4705        p_chm->network_pid = 0x1ffb;
4706
4707        bos_start_task(&p_chm->task,&params,chm_handler,p_chm);
4708
4709#ifdef BCM_DEBUG
4710        BDBG_SetModuleLevel("chan_mgr",BDBG_eWrn);
4711#endif
4712}
4713
4714/*
4715Summary:
4716Function to pass a command to the channel manager.
4717Any results and notification is handled by passing events to the app via
4718the msg_queue.
4719
4720 */
4721void chm_cmd(chm_mgr_t *p_chm,chm_cmd_event_t *p_cmd_evt)
4722{
4723        chm_cmd_t       cmd;
4724
4725        BAPP_ASSERT(p_chm);
4726        BAPP_ASSERT(p_cmd_evt);
4727
4728        cmd = p_cmd_evt->cmd_id;
4729
4730        /* Handle special case to rotate audio */
4731        if ((cmd == eCHM_SAP) && (p_chm->cmd != eCHM_CANCEL))
4732        {
4733                BDBG_WRN(("Command %s, during %s\n",s_chm_cmd_name[cmd], s_chm_cmd_name[p_chm->cmd]));
4734                bos_post_event(p_chm->queue,(b_event_t*)p_cmd_evt);
4735                return;
4736        }
4737        if ((cmd != eCHM_CANCEL) && (p_chm->cmd != eCHM_CANCEL))
4738        {
4739                BDBG_WRN(("Canceling previous command %s for %s\n", s_chm_cmd_name[p_chm->cmd],s_chm_cmd_name[cmd]));
4740                p_chm->cancel_cmd.cmd_id = eCHM_CANCEL;
4741                bos_post_event(p_chm->queue,(b_event_t*)&p_chm->cancel_cmd);
4742                bos_sleep(40); /* yield so thread can process event right away */
4743        }
4744
4745        bos_post_event(p_chm->queue,(b_event_t*)p_cmd_evt);
4746        bos_sleep(10); /* yield so thread can process event right away */
4747}
4748
4749bresult chm_write_software(struct image_t * image)
4750{
4751        return image_write(image);
4752}
4753
4754#define CHM_SC_MASK 0xc0
4755#define CHM_SC_BUFFER_SIZE (188*10)
4756static unsigned char chm_sc_buffer[CHM_SC_BUFFER_SIZE];
4757
4758static void * chm_sc_callback(void * c, size_t msg_size)
4759{
4760        unsigned int * pdata_ready = (unsigned int *)c;
4761        *pdata_ready = msg_size;
4762        return NULL;
4763}
4764
4765bool chm_check_sc(chm_mgr_t *p_chm, bband_t band, unsigned short pid)
4766{
4767        smessage_stream_t ms;
4768        smessage_stream_params_t params;
4769        bresult bres;
4770        bool result;
4771        unsigned int count;
4772        volatile unsigned int data_ready;
4773        unsigned char * walker;
4774
4775        result = false;
4776        ms = smessage_open(smessage_format_tsc);
4777        if (NULL == ms)
4778        {
4779                BDBG_ERR(("%s : smessage_open failed", __PRETTY_FUNCTION__));
4780                goto ExitFunc;
4781        }
4782        smessage_stream_params_init(&params, NULL);
4783        params.band = band;
4784        params.pid = pid;
4785        params.buffer_size = CHM_SC_BUFFER_SIZE;
4786        params.buffer = chm_sc_buffer;
4787        params.data_ready_callback = chm_sc_callback;
4788        params.overflow = chm_sc_callback;
4789        params.callback_context = (void *)&data_ready;
4790        data_ready = 0;
4791        bres = smessage_start(&params, ms);
4792        if (b_ok != bres)
4793        {
4794                smessage_close(ms);
4795                BDBG_ERR(("%s : smessage_start", __PRETTY_FUNCTION__));
4796                goto ExitFunc;
4797        }
4798        /* Updating unsigned int is atomic operation on mips. We can just wait for
4799           callback to update our flag when data is ready */
4800        count = 3;
4801        do
4802        {
4803                bos_sleep(50);
4804                count--;
4805        }while ((0 == data_ready)&&(0 != count));
4806
4807        bres = smessage_stop(ms);
4808        if (b_ok != bres)
4809        {
4810                smessage_close(ms);
4811                BDBG_ERR(("%s : smessage_stop", __PRETTY_FUNCTION__));
4812                goto ExitFunc;
4813        }
4814        smessage_close(ms);
4815        /* Figure out if we got data and if sc flags are set */
4816        if (0 != data_ready)
4817        {
4818                /* We have data. Check few packets for sc bits */
4819                walker = chm_sc_buffer;
4820                for (count = 0; count < 5; count++)
4821                {
4822                        if (0 != (walker[3] & CHM_SC_MASK))
4823                        {
4824                                goto ExitFunc;
4825                        }
4826                        walker += 188;
4827                }
4828                result = true;
4829        }
4830ExitFunc:
4831        BDBG_ERR(("pid %d %s", pid, (result == true ? "clear" : "encr")));
4832        return result;
4833}
4834
4835#ifndef NO_VCHIP
4836#define BAPP_MPAA_RATING_STR_NUM        8
4837static const char *bapp_mpa_rating_str[] =
4838{
4839        "",     /* unrated */
4840        "G",
4841        "PG",
4842        "PG-13",
4843        "R",
4844        "NC-17",
4845        "X",
4846        "NR" /* Not Rated */
4847};
4848
4849#define BAPP_TV_RATING_STR_NUM          8
4850static const char *bapp_tv_rating_str[BAPP_TV_RATING_STR_NUM] =
4851{
4852        "",     /* unrated */
4853        "TV-Y",
4854        "TV-Y7",
4855        "TV-G",
4856        "TV-PG",
4857        "TV-14",
4858        "TV-MA",
4859        ""      /* unrated */
4860};
4861
4862/*
4863Summary:
4864Use dimension and value to make a ratings decision based on the
4865static ratings configuration in the UI. 
4866
4867This function assumes region matches currently received RRT or current
4868region == 1 (USA).
4869 */
4870static int chm_psip_block(bapp_t *p_app, unsigned char region,unsigned char dim,unsigned char val, char *rating_str)
4871{
4872        int blocked = 0;
4873        int pos = 0;
4874
4875        BDBG_MSG(("%s - region:%d\n", __func__, region));
4876
4877        /* handle RRT ratings */
4878        /* only take effect if ratings is set for downloadable level */
4879        if ((p_app->settings.rrt_settings.rrt_status == eRRT_AVAILABLE) && (region != 1) && (2 == p_app->settings.ratings.ratings_lock))
4880        {
4881                if (p_app->settings.rrt_settings.ratings_rrt[dim] & (1 << val))
4882                        blocked |= 1;
4883        }
4884        BDBG_WRN(("RRT psip rating check - rrt dim:%d rrt val:%d blocked:%d\n", dim, val, blocked));
4885
4886        if ((region == 1) && (!blocked))/* US ratings are fixed */
4887        {
4888                BDBG_WRN(("%s (movie:%x tv:%x) dim:%d val:%d\n",__func__,p_app->settings.ratings.ratings_movies,p_app->settings.ratings.ratings_tv,dim,val));
4889
4890                if (val == 0)
4891                {
4892                        BDBG_WRN(("US PSIP rating value = 0 so assume unblocked!\n"));
4893                        return 0;
4894                }
4895
4896                if (dim == 7) /* check settings for MPAA ratings */
4897                {
4898                        pos = 0;
4899
4900                        /* map to xds values */
4901                        if (val > 0)
4902                                val--;
4903
4904                        p_app->movie_rating = val;
4905
4906                        pos = screen_ratings_movie_xds2pos(p_app->movie_rating);
4907
4908                        /* update rating string */
4909                        if (rating_str)
4910                        {
4911                                if (val < BAPP_MPAA_RATING_STR_NUM)
4912                                        strcpy(rating_str, bapp_mpa_rating_str[val]);
4913                        }
4914                        if (pos >= 0)
4915                                blocked |= ((p_app->settings.ratings.ratings_movies >> pos) & (0 | (0x1)));
4916                } else /* check settings for TV ratings */
4917                {
4918                        switch (dim)
4919                        {
4920                                case 0: /* entire audience */
4921                                        {
4922                                                int pos = 0;
4923                                                /* map to xds values */
4924                                                if (val <= 1)
4925                                                {
4926                                                        /* none (1) mapped to unrated */
4927                                                        p_app->tv_rating = 0;
4928                                                } else
4929                                                {
4930                                                        /* TV-G, TV-PG, TV-14, and TV-MA map to corresponding XDS TV ratings */
4931                                                        p_app->tv_rating =  val + 1;
4932                                                }
4933
4934                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
4935
4936                                                if (rating_str)
4937                                                {
4938                                                        if (p_app->tv_rating < BAPP_TV_RATING_STR_NUM)
4939                                                                strcpy(rating_str, bapp_tv_rating_str[p_app->tv_rating]);
4940                                                }
4941
4942                                                if (pos >= 0)
4943                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> pos) & (0 | (0x1)));
4944                                        }
4945                                        break;
4946                                case 1: /* dialogue */
4947                                        {
4948                                                if (val == 0)
4949                                                        break;
4950                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
4951                                                if (pos == ePOS_TV_14)
4952                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_14_D) & (0 | (0x1)));
4953                                                else
4954                                                        if (pos == ePOS_TV_PG)
4955                                                                blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_PG_D) & (0 | (0x1)));
4956                                                if (rating_str)
4957                                                {
4958                                                        strcpy(rating_str, "D");
4959                                                }
4960                                        }
4961                                        break;
4962                                case 2: /* language */
4963                                        {
4964                                                if (val == 0)
4965                                                        break;
4966                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
4967                                                if (pos == ePOS_TV_MA)
4968                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_MA_L) & (0 | (0x1)));
4969                                                else
4970                                                        if (pos == ePOS_TV_14)
4971                                                                blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_14_L) & (0 | (0x1)));
4972                                                        else
4973                                                                if (pos == ePOS_TV_PG)
4974                                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_PG_L) & (0 | (0x1)));
4975
4976                                                if (rating_str)
4977                                                {
4978                                                        strcpy(rating_str, "L");
4979                                                }
4980                                        }
4981                                        break;
4982                                case 3: /* sex */
4983                                        {
4984                                                if (val == 0)
4985                                                        break;
4986                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
4987                                                if (pos == ePOS_TV_MA)
4988                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_MA_S) & (0 | (0x1)));
4989                                                else
4990                                                        if (pos == ePOS_TV_14)
4991                                                                blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_14_S) & (0 | (0x1)));
4992                                                        else
4993                                                                if (pos == ePOS_TV_PG)
4994                                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_PG_S) & (0 | (0x1)));
4995                                                if (rating_str)
4996                                                {
4997                                                        strcpy(rating_str, "S");
4998                                                }
4999                                        }
5000                                        break;
5001                                case 4: /* violence */
5002                                        {
5003                                                if (val == 0)
5004                                                        break;
5005                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
5006                                                if (pos == ePOS_TV_MA)
5007                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_MA_V) & (0 | (0x1)));
5008                                                else
5009                                                        if (pos == ePOS_TV_14)
5010                                                                blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_14_V) & (0 | (0x1)));
5011                                                        else
5012                                                                if (pos == ePOS_TV_PG)
5013                                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_PG_V) & (0 | (0x1)));
5014                                                if (rating_str)
5015                                                {
5016                                                        strcpy(rating_str, "V");
5017                                                }
5018                                        }
5019                                        break;
5020                                case 5: /* children */
5021                                        {
5022                                                if (val == 0)
5023                                                        break;
5024                                                pos = 0;
5025
5026                                                /* TV-Y7 and TV-Y map to corresponding XDS TV ratings */
5027                                                p_app->tv_rating = val;
5028
5029                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
5030
5031                                                if (rating_str)
5032                                                {
5033                                                        if (p_app->tv_rating < BAPP_TV_RATING_STR_NUM)
5034                                                                strcpy(rating_str, bapp_tv_rating_str[p_app->tv_rating]);
5035                                                }
5036                                                if (pos >= 0)
5037                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> pos) & (0 | (0x1)));
5038                                        }
5039                                        break;
5040                                case 6: /* fantasy violence */
5041                                        {
5042                                                if (val == 0)
5043                                                        break;
5044                                                pos = screen_ratings_tv_xds2pos(p_app->tv_rating);
5045                                                if (pos == ePOS_TV_Y7)
5046                                                        blocked |= ((p_app->settings.ratings.ratings_tv >> ePOS_TV_Y7_FV) & (0 | (0x1)));
5047                                                if (rating_str)
5048                                                {
5049                                                        strcpy(rating_str, "FV");
5050                                                }
5051                                        }
5052                                        break;
5053                                default:
5054                                        break;
5055                        }
5056                }
5057        }
5058
5059        if (p_app->settings.ratings.ratings_lock == 0)
5060                blocked = 0;
5061
5062        return blocked;
5063}
5064#endif
5065
5066/*
5067Summary:
5068Get the current utc time in seconds.
5069Return non-zero on failure.
5070 */
5071static int chm_get_utctime(chm_mgr_t *p_chm, unsigned int *time )
5072{
5073        b_timeval tv;
5074
5075        if (!p_chm->got_stt)
5076                return eCHM_ERR_FAILED;
5077
5078        GETTIMEOFDAY(&tv);
5079
5080        *time = p_chm->sys_time + (tv.tv_sec - p_chm->sys_offset);
5081
5082        return 0;
5083}
5084
5085/*
5086Summary:
5087Get the current UTC time, local offset and dst flag.
5088Returns non-zero when it is not possible to determine local time.
5089Currently this function uses XDS local offset over one obtained from the TSIDs
5090
5091 */
5092unsigned int g_xds_time_offset = 0;
5093bool g_xds_dst = false;
5094
5095int chm_get_time_info(chm_mgr_t *p_chm, 
5096                unsigned int *utc_secs,                 /* Current UTC time in seconds */
5097                int *local_offset,                              /* Local time offset from UTC time in seconds */
5098                bool *dst                                               /* Daylight savings flag */
5099                )
5100{
5101        int result;
5102
5103        if ((result = chm_get_utctime(p_chm,utc_secs)) != 0)
5104                return result;
5105
5106        /* Use XDS local time over time obtained from a TSID */
5107        if (g_xds_time_offset != 0)
5108        {
5109                p_chm->local_offset = 3600 * g_xds_time_offset;
5110                p_chm->local_time_source = eTS_XDS;
5111                p_chm->local_dst_obs = g_xds_dst;
5112        }
5113
5114        if (p_chm->local_time_source == eTS_NONE)
5115                return eCHM_ERR_FAILED;
5116
5117        *local_offset = p_chm->local_offset;
5118        *dst = ((p_chm->stt.daylight_savings.DS_status != 0) && p_chm->local_dst_obs) ? true : false;
5119
5120        BDBG_MSG(("STT system_time = %u\n",p_chm->stt.system_time));
5121        BDBG_MSG(("STT GPS_UTC_offset = %u\n",p_chm->stt.GPS_UTC_offset));
5122        BDBG_MSG(("STT DS_status = %d\n",p_chm->stt.daylight_savings.DS_status));
5123
5124        if (*dst)
5125        {
5126                *utc_secs += 3600;
5127        }
5128
5129        return 0;
5130}
5131
5132static void chm_post_progress(chm_mgr_t *p_chm, int cnt)
5133{
5134        bapp_t *p_app = (bapp_t*)p_chm->p_app;
5135
5136        if (p_app->settings.num_channels > 0) {
5137                p_chm->redraw_evt.type = eCHM_EVT_PROGRESS;
5138                cnt %= p_app->settings.num_channels;
5139                p_chm->redraw_evt.id = (100 * cnt) / p_app->settings.num_channels;
5140                chm_post_app_event(p_chm,&p_chm->redraw_evt);
5141                bos_sleep(10);
5142        }
5143}
5144
5145/*
5146Summary:
5147Get program guide info.
5148Description:
5149Get program guide info in Program List screen
5150Returns non-zero on failure.
5151 */
5152
5153static int chm_get_guide(chm_mgr_t *p_chm)
5154{
5155        unsigned int utc_secs,local_offset,idx, freq;
5156        bool dst;
5157        bapp_t *p_app = (bapp_t*)p_chm->p_app;
5158        chm_info_t *p_info;
5159        b_timeval tv;
5160        int num_channels;
5161
5162        chm_stop_decode(p_chm);
5163
5164        /* Check to see if scan was canceled */
5165        if (chm_check_cancel(p_chm))
5166                return eCHM_ERR_FAILED;
5167
5168        if (p_app->settings.num_channels < 1) {
5169                /* if no channels */
5170                p_chm->cmd = eCHM_CANCEL;
5171                return eCHM_ERR_OK; 
5172        }
5173
5174        num_channels = p_app->settings.num_channels;
5175
5176        /* Completely reset and start over */
5177        BDBG_MSG(("To get Guide for all %d channels",num_channels));
5178
5179        if ((chm_get_time_info(p_chm,&utc_secs,&local_offset,&dst) != 0) || (p_chm->local_time_source == eTS_NONE))
5180        {
5181                BDBG_WRN(("Need local time and UTC offset before guide can be displayed with time info.\n"));
5182        }
5183
5184        gettimeofday(&tv);
5185        if (tv.tv_sec > (p_chm->guide_tv.tv_sec + (60 * 15)))
5186        {
5187                /*RLQ, TODO check if EIT is valid and reset only invalid one */
5188                for (idx = 0; idx < num_channels; ++idx)
5189                {
5190                        p_info = &p_chm->p_info[idx];
5191                        memset(p_info,0,sizeof(chm_info_t));
5192                        p_chm->redraw_evt.type = eCHM_EVT_REDRAW;
5193                        p_chm->redraw_evt.id = idx;
5194                        p_chm->redraw_evt.ticks = 1;
5195                        chm_post_app_event(p_chm,&p_chm->redraw_evt);
5196                        //bos_sleep(50);
5197                }
5198        }
5199        gettimeofday(&p_chm->guide_tv);
5200
5201        p_chm->cur_ch_num = p_app->chm.epg_update_ch_num;
5202        while (p_chm->cmd == eCHM_GUIDE)
5203        {
5204                if (p_chm->cur_ch_num >= num_channels)
5205                {
5206                        p_chm->cur_ch_num = 0;
5207                }
5208
5209                BDBG_MSG(("Get program info for CH %d of %d, vpid=0x%04x, apid=0x%04x",p_chm->cur_ch_num,num_channels,
5210                                        p_app->settings.ch[p_chm->cur_ch_num].video_pid, p_app->settings.ch[p_chm->cur_ch_num].audio_pid[0]));
5211
5212                /* Check to see if scan was canceled */
5213                if (chm_check_cancel(p_chm))
5214                {
5215                        BDBG_WRN(("Get Guide canceled"));
5216                        break;
5217                }
5218
5219                freq = p_app->settings.ch[p_chm->cur_ch_num].frequency_khz * 1000;
5220                if (freq != p_chm->last_freq_hz) {
5221                        if (chm_tune_freq(p_chm, freq) != 0)
5222                        {
5223                                BDBG_WRN(("Tune to channel[%d] %d.%d failed\n",p_chm->cur_ch_num, 
5224                                                        p_app->settings.ch[p_chm->cur_ch_num].major,p_app->settings.ch[p_chm->cur_ch_num].minor));
5225                                goto POST_PROG;
5226                        }
5227                }
5228
5229#if 0
5230                /* Some channels are sending STT correctly for DST and others do not. 
5231                   To work around this get STT for each channel */
5232                if (chm_get_stt(p_chm)) {
5233                        goto POST_PROG;
5234                }
5235#endif
5236
5237                p_info = &p_chm->p_info[p_chm->cur_ch_num];
5238                BDBG_MSG(("### Get VCT"));
5239                if (!p_info->got_vct && eCHM_ERR_OK != chm_get_vct(p_chm, p_info))
5240                {
5241                        BDBG_MSG(("Failed to get VCT for guide"));
5242                        goto POST_PROG;
5243                }
5244
5245                BDBG_MSG(("### Get MGT for channel %d\n", p_chm->cur_ch_num));
5246                if (eCHM_ERR_OK != chm_get_mgt(p_chm)) {
5247                        BDBG_WRN(("Failed to get MGT for guide"));
5248                        goto POST_PROG;
5249                }
5250
5251                BDBG_MSG(("### Process MGT ###"));
5252                p_chm->mgt_state = eMGT_EIT;
5253                chm_process_mgt(p_chm, p_chm->mgt_buf,p_chm->mgt_size,p_info,false,true);
5254
5255POST_PROG:
5256                chm_post_progress(p_chm, p_chm->cur_ch_num);
5257
5258                /* if updated from GUIDE UI by the user, resync it */
5259                if (p_chm->epg_update_ch_num != p_chm->cur_ch_num) {
5260                        p_chm->cur_ch_num = p_chm->epg_update_ch_num;
5261                }
5262                p_chm->cur_ch_num++;
5263                p_chm->cur_ch_num %= num_channels;
5264                p_chm->epg_update_ch_num = p_chm->cur_ch_num;
5265                /* rescan ? */
5266                if (p_app->settings.num_channels != num_channels)
5267                        break;
5268        }
5269
5270        /* leave guide state */
5271        p_chm->cmd = eCHM_CANCEL;
5272        return 0;
5273}
5274
5275/*
5276 * Summary:
5277 * Get a copy of the current channel manager info structure.
5278 *
5279 *  */
5280void chm_get_cur_ch_info(
5281                chm_mgr_t *p_chm,
5282                chm_info_t *p_info,
5283                bstream_mpeg *p_mpeg)
5284{
5285        bapp_t *p_app = (bapp_t*)p_chm->p_app;
5286
5287        memset(p_info,0,sizeof(chm_info_t));
5288        memset(p_mpeg,0,sizeof(bstream_mpeg));
5289
5290        if (bos_acquire_mutex(&p_chm->mutex,CHM_MUTEX_TIMEOUT) == b_ok)
5291        {
5292                *p_mpeg = p_chm->mpeg[CURR_CH];
5293                memcpy(&p_chm->cur_info,&p_chm->p_info[p_app->cur_ch_num],sizeof(chm_info_t));
5294                *p_info = p_chm->cur_info;
5295                bos_release_mutex(&p_chm->mutex);
5296        } else
5297        {
5298                BDBG_WRN(("%s mutex timeout\n", __func__));
5299        }
5300}
5301
5302#ifdef CONFIG_NXP_TDA182I4
5303void NXP_TDA182I4_SetStandby()
5304{
5305        NXP_TDA182I4_SetPowerState();
5306        return;
5307}
5308#endif
5309
5310#ifdef TUNER_DEBUG
5311/*
5312Summary:
5313Scan for channels using PSI for given frequency
5314Description:
5315Scan for channels using PSI.
5316Returns:
5317Number of channels added
5318Or error code if < 0
5319 */
5320int chm_scan_psi_a_freq(
5321                chm_mgr_t *p_chm,               /* Channel manager reference */
5322                unsigned int freq_khz)
5323{
5324        bapp_t *p_app = (bapp_t*)p_chm->p_app;
5325        unsigned int section_size, pmt_section_size;
5326        TS_PMT_stream pmt;
5327        TS_PAT_program pat;
5328        int result = 0;
5329        int idx,p_idx,tresult, desc_idx = 0, programs, freq_idx = -1;
5330        TS_PSI_descriptor psi_desc;
5331        unsigned short ca_pid = 0, minor = 1;
5332        bapp_ch_t ch;
5333
5334        /* stop decoder */
5335        chm_stop_decode(p_chm);
5336
5337        p_chm->cmd = eCHM_CANCEL;
5338        bos_sleep(200);
5339
5340        if (eFREQ_TABLE_USER_DEFINED == p_chm->fe_type)
5341                bapp_user_freq_table_get(p_app, &p_chm->freq_table, &p_chm->num_freq);
5342        else
5343                bapp_freq_table_get(p_chm->fe_type,(const unsigned int **)&(p_chm->freq_table),&(p_chm->num_freq));
5344
5345        /* search for the frequency from the frequency list */
5346        for (idx = 0; idx < p_chm->num_freq; idx++) {
5347                if (freq_khz == (int)p_chm->freq_table[idx]) {
5348                        freq_idx = idx;
5349                        break;
5350                }
5351        } 
5352
5353        /* can't find the given frequency */
5354        if (idx >= p_chm->num_freq)
5355                return -1;
5356
5357        /* clear channel map for a new scan */
5358        p_app->settings.num_channels = 0;
5359        memset(p_app->settings.ch, 0, sizeof(p_app->settings.ch));
5360        memset(p_chm->p_info,0,p_chm->num_freq * sizeof(chm_info_t));
5361
5362        p_chm->cmd = eCHM_CANCEL;
5363        bos_sleep(200);
5364
5365        /* tuning to given frequency */
5366        btuner_params_init(&p_chm->tuner_params, p_chm->tuner);
5367        //p_chm->tuner_params.cancel_callback = chm_tune_cancel_callback;
5368        //p_chm->tuner_params.cancel_callback_context = p_chm;
5369        p_chm->tuner_params.wait_for_lock = true;
5370
5371        if (btuner_tune(p_chm->tuner, freq_khz * 1000, &p_chm->tuner_params) < 0) {
5372                BDBG_WRN(("### tune freqency %d failed\n", freq_khz * 1000));
5373                return -1;
5374        }
5375
5376        p_chm->band = TUNER_BAND;
5377
5378        p_chm->select_idx = freq_idx;
5379        p_chm->not_check_cancel = true;
5380        result = chm_scan_vct(p_chm,p_chm->band,p_chm->select_idx);
5381        p_chm->not_check_cancel = false;
5382        if (result > 0) {
5383                BDBG_WRN(("### Got VCT"));
5384                /* we got the channels, set first channel to start after a new scan */
5385                p_app->cur_ch_num = 0;
5386                return result;
5387        }
5388
5389        BDBG_WRN(("### VCT scan on frequency %d failed, perform PSI scan instead\n", freq_khz * 1000));
5390
5391        /* Get the PAT */
5392        smessage_stream_params_init(&p_chm->msg_params, NULL);
5393        p_chm->msg_params.band = p_chm->band;
5394        p_chm->msg_params.pid = (unsigned short)0;      /* PAT */
5395        /* All PSIP tables have protocol_version which must be = 0 */
5396        //p_chm->msg_params.filter.coef[8] = 0x00;      /* protocol_version */
5397        //p_chm->msg_params.filter.mask[8] = 0x00;
5398        section_size = PAT_BUF_LEN;
5399
5400        if ((result = chm_getmessage(p_chm,p_chm->pat_buf,&section_size, PAT_TIMEOUT)) != 0)
5401        {
5402                BDBG_WRN(("%s Timeout getting PAT\n",__func__));
5403                return result;
5404        }
5405
5406        if (TS_PAT_validate(p_chm->pat_buf, section_size) != true)
5407        {
5408                BDBG_WRN(("TS_PAT_validate failed\n"));
5409                return eCHM_ERR_FAILED;
5410        }
5411
5412        programs = TS_PAT_getNumPrograms(p_chm->pat_buf);
5413        BDBG_MSG(("Programs %d in PAT", programs));
5414
5415        if (0 == programs)
5416        {
5417                BDBG_WRN(("%s TS_PAT_getNumPrograms = 0,section_size = %d\n",__func__,section_size));
5418                return eCHM_ERR_FAILED;
5419        }
5420        p_chm->pat_crc = chm_section_crc(p_chm->pat_buf,section_size);
5421
5422        for (idx = 0; idx < programs; idx++)
5423        {
5424                section_size = PAT_BUF_LEN;
5425                if ((tresult = TS_PAT_getProgram( p_chm->pat_buf, section_size, idx, &pat )) != b_ok)
5426                {
5427                        BDBG_WRN(("TS_PAT_getProgram failed 0x%x", tresult));
5428                        return eCHM_ERR_FAILED;
5429                }
5430
5431                smessage_stream_params_init(&p_chm->msg_params, NULL);
5432                p_chm->msg_params.band = p_chm->band;
5433                p_chm->msg_params.pid = (unsigned short)pat.PID;        /* PMT */
5434                /* All PSIP tables have protocol_version which must be = 0 */
5435                //p_chm->msg_params.filter.coef[8] = 0x00;      /* protocol_version */
5436                //p_chm->msg_params.filter.mask[8] = 0x00;
5437                pmt_section_size = PMT_BUF_LEN;
5438                if ((tresult = chm_getmessage(p_chm,p_chm->pmt_buf,&pmt_section_size, PMT_TIMEOUT * 2)) != 0)
5439                {
5440                        BDBG_WRN(("Failed getting PMT 0x%04x\n",pat.PID));
5441                        continue;
5442                }
5443                p_chm->pmt_crc = chm_section_crc(p_chm->pmt_buf,pmt_section_size);
5444
5445                memset(&ch,0,sizeof(ch));
5446                ch.major = (freq_idx == 0x7F) ? 0 : freq_idx + 2;       /* freq_idx is off by 2 */
5447                ch.minor = minor++;
5448                ch.freq_idx = freq_idx;
5449                ch.pcr_pid = TS_PMT_getPcrPid(p_chm->pmt_buf,pmt_section_size);
5450                ch.program_num = pat.program_number;
5451                ch.psi = true;          /* we got this entry using PSI scan vs VCT */
5452                /* Get CA pid if */
5453                while ((psi_desc = TS_PMT_getDescriptor(p_chm->pmt_buf, pmt_section_size,desc_idx++)) != NULL)
5454                {
5455                        if (desc_idx > 0xFF)
5456                        {
5457                                BDBG_ERR(("PMT Desc limit exceeded %d\n",desc_idx));
5458                                break;
5459                        }
5460                        if (psi_desc[0] == 9)
5461                        {
5462                                ca_pid = (((unsigned short)(psi_desc[4] & 0x1F)) << 8) | (unsigned short)psi_desc[5];
5463                                BDBG_MSG(("CA PID = 0x%04x\n",ca_pid));
5464                                break;
5465                        }
5466                }
5467                if (ca_pid != 0x0000)
5468                {
5469                        BDBG_MSG(("Program has CA PID 0x%02x check for scrambling control bit.\n",ca_pid));
5470                }
5471
5472                for (p_idx = 0; p_idx < TS_PMT_getNumStreams(p_chm->pmt_buf,pmt_section_size); p_idx++)
5473                {
5474                        bsettop_av_stream_type_t *stream_type;
5475
5476                        if (TS_PMT_getStream( p_chm->pmt_buf, pmt_section_size, p_idx, &pmt ) != b_ok)
5477                        {
5478                                BDBG_WRN(("Failure processing PMT %d\n",p_idx));
5479                                return eCHM_ERR_FAILED;
5480                        }
5481                        if ((stream_type = bdecode_supported_video(pmt.stream_type)) != NULL)
5482                        {
5483                                BDBG_MSG(("Video PID[%d] = 0x%04x\n",p_idx,pmt.elementary_PID ));
5484                                if (!ch.video_pid)
5485                                {
5486                                        ch.video_pid = pmt.elementary_PID;
5487                                        ch.video_type = stream_type->codec_id;
5488                                }
5489                        }
5490                        else if ((stream_type = bdecode_supported_audio(pmt.stream_type)) != NULL)
5491                        {
5492                                BDBG_MSG(("Audio PID[%d] = 0x%04x\n",ch.num_audio,pmt.elementary_PID ));
5493                                if (!ch.audio_pid[ch.num_audio] && (ch.num_audio < MAX_AUDIO_PIDS))
5494                                {
5495                                        ch.audio_pid[ch.num_audio] = pmt.elementary_PID;
5496                                        ch.audio_type[ch.num_audio] = stream_type->codec_id;
5497                                        if (0 == ch.num_audio)
5498                                                ch.cur_audio = 0;
5499                                        ch.num_audio++;
5500                                }
5501                        }
5502                }
5503
5504                if (ch.video_pid || ch.audio_pid[0])
5505                {
5506                        bool clear = true;
5507                        unsigned short pid;
5508
5509                        /* if has video, use video first */
5510                        if (ch.video_pid)
5511                                pid = ch.video_pid;
5512                        else
5513                                pid     = ch.audio_pid[0];
5514                        /* correct pid in case video pid carries too few frames */
5515                        if(ch.pcr_pid == ch.audio_pid[0])
5516                                pid = ch.audio_pid[0];
5517
5518                        if (ca_pid != 0x0000)
5519                                clear = chm_check_sc(p_chm, p_chm->band, pid);
5520
5521                        if (clear)
5522                        {
5523#if 0
5524                                p_chm->chm_pat_evt.type = eCHM_EVT_STATUS;
5525                                p_chm->chm_pat_evt.id = eCHM_STATUS_PAT;
5526                                p_chm->chm_pat_evt.ticks = 0;
5527                                chm_post_app_event(p_chm,&p_chm->chm_pat_evt);
5528#endif
5529                                ch.frequency_khz = freq_khz;
5530                                chm_add_vsb_channel(p_chm,&ch);
5531                                result += 1;
5532
5533#if 0
5534                                /* in the chm_scan_psi, it will post STATUS_PAT. but sometimes the event is missed.. don't know why.. */
5535                                if (p_app->screen_id == eSCREEN_CH_SCAN_PROGRESS) {
5536                                        bos_sleep(100);
5537                                }
5538#endif
5539                        }
5540                }
5541        }
5542
5543        if (result > 0) {
5544                /* first channel to start after a new scan */
5545                p_app->cur_ch_num = 0;
5546        }
5547
5548        return result;
5549}
5550#endif
Note: See TracBrowser for help on using the repository browser.