| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2011, 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 "bstd.h" |
|---|
| 23 | #include "bkni.h" |
|---|
| 24 | #include "ts_priv.h" |
|---|
| 25 | #include "ts_psi.h" |
|---|
| 26 | #include "ministd.h" |
|---|
| 27 | #include "dvb_parser.h" |
|---|
| 28 | |
|---|
| 29 | #include "si.h" |
|---|
| 30 | #include "si_util.h" |
|---|
| 31 | |
|---|
| 32 | BDBG_MODULE(dvb_eit); |
|---|
| 33 | |
|---|
| 34 | /* TODO:: schedule event is not handled... */ |
|---|
| 35 | |
|---|
| 36 | typedef enum eit_entry_state_t |
|---|
| 37 | { |
|---|
| 38 | eEIT_ENTRY_NEW, |
|---|
| 39 | eEIT_ENTRY_UPDATE, |
|---|
| 40 | eEIT_ENTRY_SAME |
|---|
| 41 | } eit_entry_state_t ; |
|---|
| 42 | |
|---|
| 43 | static eit_map_t eit_map; |
|---|
| 44 | static eit_sched_map_t eit_sched_map; |
|---|
| 45 | |
|---|
| 46 | static eit_entry_state_t dvb_eit_check_ver( |
|---|
| 47 | uint16_t stream_id, uint16_t service_id, uint8_t version_num, uint8_t cur_section, uint8_t sched_idx, bool fp); |
|---|
| 48 | |
|---|
| 49 | void dvb_eit_init(void) |
|---|
| 50 | { |
|---|
| 51 | eit_map.num_eit = 0; |
|---|
| 52 | BLST_D_INIT(&eit_map.eit_list.list); |
|---|
| 53 | |
|---|
| 54 | eit_sched_map.num_eit = 0; |
|---|
| 55 | BLST_D_INIT(&eit_sched_map.eit_list.list); |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | int dvb_eit_parse(const uint8_t *eit_buf, size_t *psize) |
|---|
| 59 | { |
|---|
| 60 | uint16_t section_len, stream_id, orig_network_id, service_id, parsed, desc_len; |
|---|
| 61 | uint8_t version_num, section_num, last_section, seg_last_section, last_table_id; |
|---|
| 62 | |
|---|
| 63 | eit_entry_t *p_eit_entry; |
|---|
| 64 | eit_sched_entry_t *p_eit_sched_entry; |
|---|
| 65 | |
|---|
| 66 | uint16_t event_id; |
|---|
| 67 | uint32_t start_time; |
|---|
| 68 | uint32_t duration; |
|---|
| 69 | uint8_t tid, sched_idx=0; |
|---|
| 70 | uint16_t idx; |
|---|
| 71 | |
|---|
| 72 | eit_t *p_eit; |
|---|
| 73 | bool add = false, sched = false; |
|---|
| 74 | #ifdef BCM_DEBUG |
|---|
| 75 | b_tm s_tm; |
|---|
| 76 | #endif |
|---|
| 77 | eit_entry_state_t eit_state; |
|---|
| 78 | struct bit_state_t bs; |
|---|
| 79 | |
|---|
| 80 | int i; |
|---|
| 81 | |
|---|
| 82 | BDBG_ASSERT((eit_buf&&psize)); |
|---|
| 83 | BDBG_MSG(("%s: enter", __func__)); |
|---|
| 84 | |
|---|
| 85 | if (!dvb_get_cur_time()) { |
|---|
| 86 | BDBG_MSG(("time information is not delivered yet")); |
|---|
| 87 | return 0; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | bs.bindex = 0; |
|---|
| 91 | bs.data = (unsigned char *)eit_buf; |
|---|
| 92 | |
|---|
| 93 | tid = get_bits(8, &bs); |
|---|
| 94 | //if (tid == DVB_TID_EIT_SCH_ACT) { |
|---|
| 95 | if ((tid >= DVB_TID_EIT_SCH_ACT) && (tid <= (DVB_TID_EIT_SCH_OTH+0x0F))) { |
|---|
| 96 | /* scheduled event */ |
|---|
| 97 | sched_idx = (tid&0x0F); |
|---|
| 98 | sched = true; |
|---|
| 99 | } |
|---|
| 100 | else if ((DVB_TID_EIT_ACT != tid) && (DVB_TID_EIT_OTH != tid)) { |
|---|
| 101 | BDBG_WRN(("%s: Invalid EIT table Id (0x%02x)", __func__, tid)); |
|---|
| 102 | return 0; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | get_bits(4, &bs); /* skip section_syntax_indicator,reserved */ |
|---|
| 106 | section_len = get_bits(12, &bs); |
|---|
| 107 | if (*psize < (section_len+3)) { |
|---|
| 108 | BDBG_WRN(("%s: incomplete eit section", __func__)); |
|---|
| 109 | return 0; |
|---|
| 110 | } |
|---|
| 111 | service_id = get_bits(16, &bs); |
|---|
| 112 | get_bits(2, &bs); /* skip reserved */ |
|---|
| 113 | version_num = get_bits(5, &bs); |
|---|
| 114 | get_bits(1, &bs); /* skip current_next_indicator */ |
|---|
| 115 | section_num = get_bits(8, &bs); |
|---|
| 116 | last_section = get_bits(8, &bs); |
|---|
| 117 | stream_id = get_bits(16, &bs); |
|---|
| 118 | orig_network_id = get_bits(16, &bs); |
|---|
| 119 | |
|---|
| 120 | seg_last_section = get_bits(8, &bs); |
|---|
| 121 | last_table_id = get_bits(8, &bs); |
|---|
| 122 | eit_state = dvb_eit_check_ver(stream_id, service_id, version_num, section_num, sched_idx, !sched); |
|---|
| 123 | if (eit_state == eEIT_ENTRY_SAME) { |
|---|
| 124 | BDBG_MSG(("same eit table for 0x%x (ver:%x)", service_id, version_num)); |
|---|
| 125 | return 1; |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | if (eit_state == eEIT_ENTRY_NEW) { |
|---|
| 129 | if (!sched) { |
|---|
| 130 | p_eit_entry = (eit_entry_t *)BKNI_Malloc(sizeof(eit_entry_t)); |
|---|
| 131 | if (!p_eit_entry) { |
|---|
| 132 | BDBG_ERR(("memory allocation failed..:%s %d", __FUNCTION__, __LINE__)); |
|---|
| 133 | return 0; |
|---|
| 134 | } |
|---|
| 135 | BKNI_Memset(p_eit_entry, 0, sizeof(eit_entry_t)); |
|---|
| 136 | add = true; |
|---|
| 137 | p_eit_entry->eit_present.event_id = 0xFFFF; |
|---|
| 138 | p_eit_entry->eit_following.event_id = 0xFFFF; |
|---|
| 139 | p_eit_entry->version = version_num; |
|---|
| 140 | p_eit_entry->service_id = service_id; |
|---|
| 141 | p_eit_entry->stream_id = stream_id; |
|---|
| 142 | SI_Init_Section_Mask((unsigned long *)p_eit_entry->section_mask, last_section); |
|---|
| 143 | } |
|---|
| 144 | else { |
|---|
| 145 | p_eit_sched_entry = (eit_sched_entry_t *)BKNI_Malloc(sizeof(eit_sched_entry_t)); |
|---|
| 146 | if (!p_eit_sched_entry) { |
|---|
| 147 | BDBG_ERR(("memory allocation failed:.. %s %d for (0x%x)", __FUNCTION__, __LINE__, service_id)); |
|---|
| 148 | return 0; |
|---|
| 149 | } |
|---|
| 150 | BKNI_Memset(p_eit_sched_entry, 0, sizeof(eit_sched_entry_t)); |
|---|
| 151 | add = true; |
|---|
| 152 | for (i=0; i<MAX_SCHED_ENTRY; i++) { |
|---|
| 153 | p_eit_sched_entry->eit_sched[i].event_id = 0xFFFF; |
|---|
| 154 | } |
|---|
| 155 | p_eit_sched_entry->count = 0; |
|---|
| 156 | p_eit_sched_entry->version[sched_idx] = version_num; |
|---|
| 157 | p_eit_sched_entry->service_id = service_id; |
|---|
| 158 | p_eit_sched_entry->stream_id = stream_id; |
|---|
| 159 | SI_Init_Section_Mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], last_section); |
|---|
| 160 | } |
|---|
| 161 | } |
|---|
| 162 | else{ |
|---|
| 163 | if (!sched) |
|---|
| 164 | p_eit_entry = dvb_eit_get_entry(stream_id, service_id); |
|---|
| 165 | else { |
|---|
| 166 | p_eit_sched_entry = dvb_eit_get_sched_entry(stream_id, service_id); |
|---|
| 167 | p_eit_sched_entry->version[sched_idx] = version_num; |
|---|
| 168 | SI_Init_Section_Mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], last_section); |
|---|
| 169 | } |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | if (!sched) { |
|---|
| 173 | SI_Set_Section_mask((unsigned long *)p_eit_entry->section_mask, section_num); |
|---|
| 174 | } else { |
|---|
| 175 | SI_Set_Section_mask((unsigned long *)p_eit_sched_entry->section_mask[sched_idx], section_num); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | parsed = DVB_EIT_LEN + 4; /* exclude crc */ |
|---|
| 179 | while (parsed < section_len) |
|---|
| 180 | { |
|---|
| 181 | event_id = get_bits(16, &bs); |
|---|
| 182 | idx = bs.bindex/8; |
|---|
| 183 | start_time = MJD_TO_TIME(eit_buf[idx], eit_buf[idx+1]) + |
|---|
| 184 | BCD_TO_SEC(eit_buf[idx+2], eit_buf[idx+3], eit_buf[idx+4]); |
|---|
| 185 | duration = BCD_TO_SEC(eit_buf[idx+5], eit_buf[idx+6], eit_buf[idx+7]); |
|---|
| 186 | bs.bindex += 64; |
|---|
| 187 | |
|---|
| 188 | if (!sched) { |
|---|
| 189 | /* find the present or following */ |
|---|
| 190 | if ((start_time <= dvb_get_cur_time()) && (start_time+duration >= dvb_get_cur_time())) { |
|---|
| 191 | p_eit = &p_eit_entry->eit_present; |
|---|
| 192 | } |
|---|
| 193 | else { |
|---|
| 194 | p_eit = &p_eit_entry->eit_following; |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | else { |
|---|
| 198 | if (p_eit_sched_entry->count >= MAX_SCHED_ENTRY) { |
|---|
| 199 | break; |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | if (p_eit_sched_entry->count==0) { |
|---|
| 203 | p_eit = &p_eit_sched_entry->eit_sched[p_eit_sched_entry->count]; |
|---|
| 204 | p_eit_sched_entry->count++; |
|---|
| 205 | } |
|---|
| 206 | else { |
|---|
| 207 | for (i=0; i<p_eit_sched_entry->count; i++) { |
|---|
| 208 | if (p_eit_sched_entry->eit_sched[i].event_id == event_id) |
|---|
| 209 | break; |
|---|
| 210 | } |
|---|
| 211 | p_eit = &p_eit_sched_entry->eit_sched[i]; |
|---|
| 212 | if (i == p_eit_sched_entry->count) { |
|---|
| 213 | p_eit_sched_entry->count++; |
|---|
| 214 | } |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | BKNI_Memset(p_eit, 0, sizeof(eit_t)); |
|---|
| 219 | p_eit->event_id = event_id; |
|---|
| 220 | p_eit->start_time = start_time; |
|---|
| 221 | p_eit->duration = duration; |
|---|
| 222 | p_eit->running_status = get_bits(3, &bs); |
|---|
| 223 | p_eit->free_ca_mode = get_bits(1, &bs); |
|---|
| 224 | |
|---|
| 225 | parsed += 10; |
|---|
| 226 | if (parsed>=section_len) |
|---|
| 227 | break; |
|---|
| 228 | |
|---|
| 229 | desc_len = get_bits(12, &bs); |
|---|
| 230 | dvb_parse_descriptors((uint8_t *)&eit_buf[bs.bindex/8], desc_len, DVB_TID_EIT_ACT, (void *)p_eit); |
|---|
| 231 | |
|---|
| 232 | #ifdef BCM_DEBUG |
|---|
| 233 | utctime(p_eit->start_time, &s_tm); |
|---|
| 234 | BDBG_MSG(("%c [%d:%d]s:0x%04x 0x%04x %02d/%02d/%04d %02d:%02d:%02d %dm (%d) %s (%s) %d", |
|---|
| 235 | sched?'S':'C', section_num, last_section, |
|---|
| 236 | service_id, p_eit->event_id, s_tm.tm_mon+1, s_tm.tm_mday, s_tm.tm_year+1980, |
|---|
| 237 | 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, |
|---|
| 238 | p_eit->event_name, add?"new":"update", sched?p_eit_sched_entry->count:0)); |
|---|
| 239 | #endif |
|---|
| 240 | |
|---|
| 241 | bs.bindex = bs.bindex + desc_len*8; |
|---|
| 242 | parsed += desc_len + 2; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | if (add) { |
|---|
| 246 | if (!sched) { |
|---|
| 247 | BLST_D_INSERT_HEAD(&eit_map.eit_list.list, p_eit_entry, link); |
|---|
| 248 | eit_map.num_eit++; |
|---|
| 249 | } |
|---|
| 250 | else { |
|---|
| 251 | BLST_D_INSERT_HEAD(&eit_sched_map.eit_list.list, p_eit_sched_entry, link); |
|---|
| 252 | eit_sched_map.num_eit++; |
|---|
| 253 | } |
|---|
| 254 | } |
|---|
| 255 | return 1; |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | //void dvb_get_current_event(vch_t vch, int *eit_cnt, eit_t *p_eit_cur, eit_t *p_eit_next) |
|---|
| 259 | void dvb_get_current_event(vch_t vch, int *eit_cnt, eit_t *p_eit) |
|---|
| 260 | { |
|---|
| 261 | eit_entry_t *p_entry; |
|---|
| 262 | |
|---|
| 263 | *eit_cnt = 0; |
|---|
| 264 | for (p_entry = BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { |
|---|
| 265 | if (p_entry->service_id == vch.program_num) { |
|---|
| 266 | |
|---|
| 267 | if (p_entry->eit_present.event_id == 0xFFFF) { |
|---|
| 268 | *eit_cnt = 0; |
|---|
| 269 | } |
|---|
| 270 | else { |
|---|
| 271 | BKNI_Memcpy(&p_eit[0], &p_entry->eit_present, sizeof(eit_t)); |
|---|
| 272 | // *p_eit_cur = p_entry->eit_present; |
|---|
| 273 | if (p_entry->eit_following.event_id != 0xFFFF) { |
|---|
| 274 | *eit_cnt = 2; |
|---|
| 275 | // *p_eit_next = p_entry->eit_following; |
|---|
| 276 | BKNI_Memcpy(&p_eit[1], &p_entry->eit_following, sizeof(eit_t)); |
|---|
| 277 | } |
|---|
| 278 | else { |
|---|
| 279 | *eit_cnt = 1; |
|---|
| 280 | } |
|---|
| 281 | } |
|---|
| 282 | break; |
|---|
| 283 | } |
|---|
| 284 | } |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | eit_entry_t *dvb_eit_get_entry(uint16_t stream_id, uint16_t service_id) |
|---|
| 288 | { |
|---|
| 289 | eit_entry_t *p_entry; |
|---|
| 290 | |
|---|
| 291 | for (p_entry = BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { |
|---|
| 292 | if ((p_entry->stream_id == stream_id) && (p_entry->service_id == service_id)) { |
|---|
| 293 | break; |
|---|
| 294 | } |
|---|
| 295 | } |
|---|
| 296 | return p_entry; |
|---|
| 297 | } |
|---|
| 298 | |
|---|
| 299 | eit_sched_entry_t *dvb_eit_get_sched_entry(uint16_t stream_id, uint16_t service_id) |
|---|
| 300 | { |
|---|
| 301 | eit_sched_entry_t *p_entry; |
|---|
| 302 | |
|---|
| 303 | for (p_entry = BLST_D_FIRST(&eit_sched_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { |
|---|
| 304 | if ((p_entry->stream_id == stream_id) && (p_entry->service_id == service_id)) { |
|---|
| 305 | break; |
|---|
| 306 | } |
|---|
| 307 | } |
|---|
| 308 | return p_entry; |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | static eit_entry_state_t dvb_eit_check_ver( |
|---|
| 312 | uint16_t stream_id, /* stream id */ |
|---|
| 313 | uint16_t service_id, /* service id in the stream_id */ |
|---|
| 314 | uint8_t version_num, /* section version number */ |
|---|
| 315 | uint8_t cur_section, /* current section number */ |
|---|
| 316 | uint8_t sched_idx, /* idx for sched event depending on table id*/ |
|---|
| 317 | bool fp /* present following */) |
|---|
| 318 | { |
|---|
| 319 | if (fp) { |
|---|
| 320 | eit_entry_t *p_entry; |
|---|
| 321 | for (p_entry=BLST_D_FIRST(&eit_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { |
|---|
| 322 | if ( (p_entry->service_id == service_id) && (p_entry->stream_id == stream_id)) { |
|---|
| 323 | if (p_entry->version != version_num) { |
|---|
| 324 | BDBG_MSG(("CEIT version updated from (0x%x) %x -> %x", service_id, p_entry->version, version_num)); |
|---|
| 325 | BLST_D_REMOVE(&eit_map.eit_list.list, p_entry, link); |
|---|
| 326 | BKNI_Free(p_entry); |
|---|
| 327 | p_entry = NULL; |
|---|
| 328 | eit_map.num_eit--; |
|---|
| 329 | break; |
|---|
| 330 | } |
|---|
| 331 | else if ( SI_Chk_Section_mask((unsigned long *)p_entry->section_mask, cur_section)) { |
|---|
| 332 | return eEIT_ENTRY_SAME; |
|---|
| 333 | } |
|---|
| 334 | else { |
|---|
| 335 | return eEIT_ENTRY_UPDATE; |
|---|
| 336 | } |
|---|
| 337 | } |
|---|
| 338 | } |
|---|
| 339 | } |
|---|
| 340 | else { |
|---|
| 341 | eit_sched_entry_t *p_entry; |
|---|
| 342 | for (p_entry=BLST_D_FIRST(&eit_sched_map.eit_list.list); p_entry; p_entry = BLST_D_NEXT(p_entry, link)) { |
|---|
| 343 | if ( (p_entry->service_id == service_id) && (p_entry->stream_id == stream_id)) { |
|---|
| 344 | if (p_entry->version[sched_idx] != version_num) { |
|---|
| 345 | BDBG_MSG(("SEIT(%d) version updated for (0x%x) %x -> %x", sched_idx, service_id, p_entry->version[sched_idx], version_num)); |
|---|
| 346 | #if 0 |
|---|
| 347 | BLST_D_REMOVE(&eit_sched_map.eit_list.list, p_entry, link); |
|---|
| 348 | BKNI_Free(p_entry); |
|---|
| 349 | p_entry = NULL; |
|---|
| 350 | eit_sched_map.num_eit--; |
|---|
| 351 | #endif |
|---|
| 352 | return eEIT_ENTRY_UPDATE; |
|---|
| 353 | } |
|---|
| 354 | else if (SI_Chk_Section_mask((unsigned long *)p_entry->section_mask[sched_idx], cur_section)) { |
|---|
| 355 | return eEIT_ENTRY_SAME; |
|---|
| 356 | } |
|---|
| 357 | else { |
|---|
| 358 | return eEIT_ENTRY_UPDATE; |
|---|
| 359 | } |
|---|
| 360 | } |
|---|
| 361 | } |
|---|
| 362 | } |
|---|
| 363 | return eEIT_ENTRY_NEW; |
|---|
| 364 | } |
|---|
| 365 | |
|---|