/*************************************************************************** * Copyright (c) 2011, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ****************************************************************************/ #include "bstd.h" #include "bkni.h" #include "ts_priv.h" #include "ts_psi.h" #include "ministd.h" #include "dvb_parser.h" #include "si.h" #include "si_util.h" BDBG_MODULE(dvb_eit); /* TODO:: schedule event is not handled... */ typedef enum eit_entry_state_t { eEIT_ENTRY_NEW, eEIT_ENTRY_UPDATE, eEIT_ENTRY_SAME } eit_entry_state_t ; static eit_map_t eit_map; static eit_sched_map_t eit_sched_map; static eit_entry_state_t dvb_eit_check_ver( uint16_t stream_id, uint16_t service_id, uint8_t version_num, uint8_t cur_section, uint8_t sched_idx, bool fp); void dvb_eit_init(void) { eit_map.num_eit = 0; BLST_D_INIT(&eit_map.eit_list.list); eit_sched_map.num_eit = 0; BLST_D_INIT(&eit_sched_map.eit_list.list); } int dvb_eit_parse(const uint8_t *eit_buf, size_t *psize) { uint16_t section_len, stream_id, orig_network_id, service_id, parsed, desc_len; uint8_t version_num, section_num, last_section, seg_last_section, last_table_id; eit_entry_t *p_eit_entry; eit_sched_entry_t *p_eit_sched_entry; uint16_t event_id; uint32_t start_time; uint32_t duration; uint8_t tid, sched_idx=0; uint16_t idx; eit_t *p_eit; bool add = false, sched = false; #ifdef BCM_DEBUG b_tm s_tm; #endif eit_entry_state_t eit_state; struct bit_state_t bs; int i; BDBG_ASSERT((eit_buf&&psize)); BDBG_MSG(("%s: enter", __func__)); if (!dvb_get_cur_time()) { BDBG_MSG(("time information is not delivered yet")); return 0; } bs.bindex = 0; bs.data = (unsigned char *)eit_buf; tid = get_bits(8, &bs); //if (tid == DVB_TID_EIT_SCH_ACT) { if ((tid >= DVB_TID_EIT_SCH_ACT) && (tid <= (DVB_TID_EIT_SCH_OTH+0x0F))) { /* scheduled event */ sched_idx = (tid&0x0F); sched = true; } else if ((DVB_TID_EIT_ACT != tid) && (DVB_TID_EIT_OTH != tid)) { BDBG_WRN(("%s: Invalid EIT table Id (0x%02x)", __func__, tid)); return 0; } get_bits(4, &bs); /* skip section_syntax_indicator,reserved */ section_len = get_bits(12, &bs); if (*psize < (section_len+3)) { BDBG_WRN(("%s: incomplete eit section", __func__)); return 0; } service_id = get_bits(16, &bs); get_bits(2, &bs); /* skip reserved */ version_num = get_bits(5, &bs); get_bits(1, &bs); /* skip current_next_indicator */ section_num = get_bits(8, &bs); last_section = get_bits(8, &bs); stream_id = get_bits(16, &bs); orig_network_id = get_bits(16, &bs); seg_last_section = get_bits(8, &bs); last_table_id = get_bits(8, &bs); eit_state = dvb_eit_check_ver(stream_id, service_id, version_num, section_num, sched_idx, !sched); if (eit_state == eEIT_ENTRY_SAME) { BDBG_MSG(("same eit table for 0x%x (ver:%x)", service_id, version_num)); return 1; } if (eit_state == eEIT_ENTRY_NEW) { if (!sched) { p_eit_entry = (eit_entry_t *)BKNI_Malloc(sizeof(eit_entry_t)); if (!p_eit_entry) { BDBG_ERR(("memory allocation failed..:%s %d", __FUNCTION__, __LINE__)); return 0; } BKNI_Memset(p_eit_entry, 0, sizeof(eit_entry_t)); add = true; p_eit_entry->eit_present.event_id = 0xFFFF; p_eit_entry->eit_following.event_id = 0xFFFF; p_eit_entry->version = version_num; p_eit_entry->service_id = service_id; p_eit_entry->stream_id = stream_id; SI_Init_Section_Mask((unsigned long *)p_eit_entry->section_mask, last_section); } else { p_eit_sched_entry = (eit_sched_entry_t *)BKNI_Malloc(sizeof(eit_sched_entry_t)); if (!p_eit_sched_entry) { BDBG_ERR(("memory allocation failed:.. %s %d for (0x%x)", __FUNCTION__, __LINE__, service_id)); return 0; } BKNI_Memset(p_eit_sched_entry, 0, sizeof(eit_sched_entry_t)); add = true; for (i=0; ieit_sched[i].event_id = 0xFFFF; } p_eit_sched_entry->count = 0; p_eit_sched_entry->version[sched_idx] = version_num; p_eit_sched_entry->service_id = service_id; p_eit_sched_entry->stream_id = stream_id; SI_Init_Section_Mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], last_section); } } else{ if (!sched) p_eit_entry = dvb_eit_get_entry(stream_id, service_id); else { p_eit_sched_entry = dvb_eit_get_sched_entry(stream_id, service_id); p_eit_sched_entry->version[sched_idx] = version_num; SI_Init_Section_Mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], last_section); } } if (!sched) { SI_Set_Section_mask((unsigned long *)p_eit_entry->section_mask, section_num); } else { SI_Set_Section_mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], section_num); } parsed = DVB_EIT_LEN + 4; /* exclude crc */ while (parsed < section_len) { event_id = get_bits(16, &bs); idx = bs.bindex/8; start_time = MJD_TO_TIME(eit_buf[idx], eit_buf[idx+1]) + BCD_TO_SEC(eit_buf[idx+2], eit_buf[idx+3], eit_buf[idx+4]); duration = BCD_TO_SEC(eit_buf[idx+5], eit_buf[idx+6], eit_buf[idx+7]); bs.bindex += 64; if (!sched) { /* find the present or following */ if ((start_time <= dvb_get_cur_time()) && (start_time+duration >= dvb_get_cur_time())) { p_eit = &p_eit_entry->eit_present; } else { p_eit = &p_eit_entry->eit_following; } } else { if (p_eit_sched_entry->count >= MAX_SCHED_ENTRY) { break; } if (p_eit_sched_entry->count==0) { p_eit = &p_eit_sched_entry->eit_sched[p_eit_sched_entry->count]; p_eit_sched_entry->count++; } else { for (i=0; icount; i++) { if (p_eit_sched_entry->eit_sched[i].event_id == event_id) break; } p_eit = &p_eit_sched_entry->eit_sched[i]; if (i == p_eit_sched_entry->count) { p_eit_sched_entry->count++; } } } BKNI_Memset(p_eit, 0, sizeof(eit_t)); p_eit->event_id = event_id; p_eit->start_time = start_time; p_eit->duration = duration; p_eit->running_status = get_bits(3, &bs); p_eit->free_ca_mode = get_bits(1, &bs); parsed += 10; if (parsed>=section_len) break; desc_len = get_bits(12, &bs); dvb_parse_descriptors((uint8_t *)&eit_buf[bs.bindex/8], desc_len, DVB_TID_EIT_ACT, (void *)p_eit); #ifdef BCM_DEBUG utctime(p_eit->start_time, &s_tm); BDBG_MSG(("%c [%d:%d]s:0x%04x 0x%04x %02d/%02d/%04d %02d:%02d:%02d %dm (%d) %s (%s) %d", sched?'S':'C', section_num, last_section, service_id, p_eit->event_id, s_tm.tm_mon+1, s_tm.tm_mday, s_tm.tm_year+1980, s_tm.tm_hour, s_tm.tm_min, s_tm.tm_sec, p_eit->duration/60, sched?eit_sched_map.num_eit:eit_map.num_eit, p_eit->event_name, add?"new":"update", sched?p_eit_sched_entry->count:0)); #endif bs.bindex = bs.bindex + desc_len*8; parsed += desc_len + 2; } if (add) { if (!sched) { BLST_D_INSERT_HEAD(&eit_map.eit_list.list, p_eit_entry, link); eit_map.num_eit++; } else { BLST_D_INSERT_HEAD(&eit_sched_map.eit_list.list, p_eit_sched_entry, link); eit_sched_map.num_eit++; } } return 1; } //void dvb_get_current_event(vch_t vch, int *eit_cnt, eit_t *p_eit_cur, eit_t *p_eit_next) void dvb_get_current_event(vch_t vch, int *eit_cnt, eit_t *p_eit) { eit_entry_t *p_entry; *eit_cnt = 0; for (p_entry = BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { if (p_entry->service_id == vch.program_num) { if (p_entry->eit_present.event_id == 0xFFFF) { *eit_cnt = 0; } else { BKNI_Memcpy(&p_eit[0], &p_entry->eit_present, sizeof(eit_t)); // *p_eit_cur = p_entry->eit_present; if (p_entry->eit_following.event_id != 0xFFFF) { *eit_cnt = 2; // *p_eit_next = p_entry->eit_following; BKNI_Memcpy(&p_eit[1], &p_entry->eit_following, sizeof(eit_t)); } else { *eit_cnt = 1; } } break; } } } eit_entry_t *dvb_eit_get_entry(uint16_t stream_id, uint16_t service_id) { eit_entry_t *p_entry; for (p_entry = BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { if ((p_entry->stream_id == stream_id) && (p_entry->service_id == service_id)) { break; } } return p_entry; } eit_sched_entry_t *dvb_eit_get_sched_entry(uint16_t stream_id, uint16_t service_id) { eit_sched_entry_t *p_entry; for (p_entry = BLST_D_FIRST(&eit_sched_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { if ((p_entry->stream_id == stream_id) && (p_entry->service_id == service_id)) { break; } } return p_entry; } static eit_entry_state_t dvb_eit_check_ver( uint16_t stream_id, /* stream id */ uint16_t service_id, /* service id in the stream_id */ uint8_t version_num, /* section version number */ uint8_t cur_section, /* current section number */ uint8_t sched_idx, /* idx for sched event depending on table id*/ bool fp /* present following */) { if (fp) { eit_entry_t *p_entry; for (p_entry=BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { if ( (p_entry->service_id == service_id) && (p_entry->stream_id == stream_id)) { if (p_entry->version != version_num) { BDBG_MSG(("CEIT version updated from (0x%x) %x -> %x", service_id, p_entry->version, version_num)); BLST_D_REMOVE(&eit_map.eit_list.list, p_entry, link); BKNI_Free(p_entry); p_entry = NULL; eit_map.num_eit--; break; } else if ( SI_Chk_Section_mask((unsigned long *)p_entry->section_mask, cur_section)) { return eEIT_ENTRY_SAME; } else { return eEIT_ENTRY_UPDATE; } } } } else { eit_sched_entry_t *p_entry; for (p_entry=BLST_D_FIRST(&eit_sched_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { if ( (p_entry->service_id == service_id) && (p_entry->stream_id == stream_id)) { if (p_entry->version[sched_idx] != version_num) { BDBG_MSG(("SEIT(%d) version updated for (0x%x) %x -> %x", sched_idx, service_id, p_entry->version[sched_idx], version_num)); #if 0 BLST_D_REMOVE(&eit_sched_map.eit_list.list, p_entry, link); BKNI_Free(p_entry); p_entry = NULL; eit_sched_map.num_eit--; #endif return eEIT_ENTRY_UPDATE; } else if (SI_Chk_Section_mask((unsigned long *)p_entry->section_mask[sched_idx], cur_section)) { return eEIT_ENTRY_SAME; } else { return eEIT_ENTRY_UPDATE; } } } } return eEIT_ENTRY_NEW; }