DVBCore  20.3.0
DVBCore Documentation
ap_si.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2004 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
23 //#define DEBUG_PRINTING_ENABLED
24 // gives direct COM port access
25 /*#define AP_DEBUG*/
26 
27 /*#define DEBUG_SI_CHAN_SEARCH*/
28 /*#define DEBUG_SI_STARTUP_SEARCH*/
29 /*#define DEBUG_SI_EVENT_SCHED_SEARCH*/
30 /*#define DEBUG_SI_UPDATE*/
31 /*#define DEBUG_SI_RECORDING*/
32 /*#define DEBUG_SI_PLAYBACK*/
33 /*#define DEBUG_SI_ICS*/
34 /*#define DEBUG_SI_TOT_SEARCH*/
35 /*#define DEBUG_CI_SI_UPDATE*/
36 /*#define DEBUG_SI_RCT*/
37 /*#define DEBUG_DYNAMIC_UPDATE*/
38 
39 // prints table debug messages
40 /*#define DEBUG_SI_CAT*/
41 /*#define DEBUG_SI_PAT*/
42 /*#define DEBUG_SI_NIT*/
43 /*#define DEBUG_SI_SDT*/
44 /*#define DEBUG_SI_PMT*/
45 /*#define DEBUG_SI_PMT_VIDEO*/
46 /*#define DEBUG_SI_PMT_AUDIO*/
47 /*#define DEBUG_SI_EIT*/
48 /*#define DEBUG_SI_TOT*/
49 /*#define DEBUG_SI_TDT*/
50 /*#define DEBUG_SI_BAT*/
51 
52 //#define DEBUG_SI_CAT_PLAYBACK
53 /*#define DEBUG_SI_PAT_PLAYBACK*/
54 /*#define DEBUG_SI_PMT_PLAYBACK*/
55 
56 // prints the transport parameters being stored into database
57 //#define DEBUG_TRANS_PARAMS
58 
59 /*#define DEBUG_DVB_SSU*/
60 /*#define DEBUG_SI_DVB_SSU_SEARCH*/
61 
62 
63 //---includes for this file----------------------------------------------------
64 // compiler library header files
65 
66 #include <stdio.h>
67 #include <string.h>
68 
69 // third party header files
70 
71 // Ocean Blue Software header files
72 
73 #include "techtype.h"
74 #include "dbgfuncs.h"
75 #include "stbhwos.h"
76 #include "stbhwtun.h"
77 #include "stbhwav.h"
78 
79 #include "stbheap.h"
80 #include "stberc.h"
81 #include "stbgc.h"
82 #include "stbdpc.h"
83 #include "stbsiflt.h"
84 #include "stbsitab.h"
85 #include "stbllist.h"
86 #include "stbdsapi.h"
87 #include "stbuni.h"
88 
89 #include "media_image.h"
90 
91 #if defined(INCLUDE_DSMCC_FILE_REQUEST)
92 #include "dsm_client.h"
93 #include "dsm_control.h"
94 #endif
95 #ifdef INTEGRATE_HBBTV
96 #include "hbbtv_api.h"
97 #endif
98 
99 #include "app.h"
100 #include "ap_cfg.h"
101 #include "ap_cfdat.h"
102 #include "ap_dbacc.h"
103 #include "ap_tmr.h"
104 #include "ap_dbdef.h"
105 #include "ap_cntrl.h"
106 #include "ap_si.h"
107 #include "ap_pvr.h"
108 #include "app_nvm.h"
109 
110 #ifdef COMMON_INTERFACE
111 #include "ap_ci_int.h"
112 #include "stbcicc.h"
113 #include "ap_ci.h"
114 #endif
115 #include "ca_glue.h"
116 #include "ap_ca.h"
117 
118 #include "dba.h"
119 
120 //---constant definitions for this file----------------------------------------
121 #ifdef AP_DEBUG
122  #define AP_SI_PRINT(x) STB_SPDebugWrite x
123  #define AP_SI_PRINT1(x) STB_SPDebugWrite x
124 #else
125  #define AP_SI_PRINT(x)
126 #endif
127 
128 // values passed to table request functions
129 #define DONT_CARE_ID_MATCH 0x0000
130 #define DONT_CARE_ID_MASK 0x0000
131 
132 // table id values
133 #define EITPF_ACTUAL_TID 0x4E
134 #define EITPF_OTHER_TID 0x4F
135 #define EITSC_ACTUAL_TID 0x50 // range 0x50 to 0x5f
136 #define EITSC_OTHER_TID 0x60 // range 0x60 to 0x6f
137 #define EITPF_PLUS_TID 0xd1 /* Freesat EITpf++ table ID */
138 #define TDT_TID 0x70
139 #define TOT_TID 0x73
140 
141 /* DVB descriptors */
142 #define AC3_DESC_DTAG 0x6a
143 #define EAC3_DESC_DTAG 0x7a
144 
145 // timeout values
146 #define BAT_TIMEOUT_MS 12000
147 #define CAT_TIMEOUT_MS 2000
148 #define PAT_TIMEOUT_MS 800
149 #define PMT_TIMEOUT_MS 3000
150 #define NIT_TIMEOUT_MS 15000
151 #define SDT_TIMEOUT_MS 5000
152 #define EIT_TIMEOUT_MS 3000
153 #define TOT_TIMEOUT_MS 32000
154 #define TDT_TIMEOUT_MS 32000
155 #define SCHED_TIMEOUT_MS 3600000 /* 1 hour */
156 #define EVENT_SCHED_SEARCH_TIMEOUT_MS 10000
157 
158 #define PMT_UPDATE_MS 1000
159 #define SI_UPDATE_DELAY_MS 100
160 
161 #define MAX_PMT_PRIORITY_LIST 4
162 
163 #define DVB_SSU_LINKAGE_TYPE 0x09
164 #define DVB_DVBH1_LINKAGE_TYPE 0x0B
165 #define DVB_DVBH2_LINKAGE_TYPE 0x0C
166 
167 // macros used as parameters to make code easier to understand
168 #define IGNORE_VERSION TRUE
169 #define CHECK_VERSION FALSE
170 
171 #define EIT_ACTUAL_ONLY TRUE
172 #define EIT_ACTUAL_OR_OTHER FALSE
173 
174 #define REPORT_PMT TRUE
175 #define DONT_REPORT_PMT FALSE
176 
177 #define EIT_LIST_REQD TRUE
178 #define EIT_LIST_NOT_REQD FALSE
179 
180 #define REPORT_CAT TRUE
181 #define DONT_REPORT_CAT FALSE
182 
183 #define INVALID_SERVICE_ID 0xffffffff
184 
185 /* Private data codes */
186 #define UK_DTT_PRIVATE_DATA_CODE 0x0000233a
187 #define FREESAT_PRIVATE_DATA_CODE 0x46534154
188 
189 //---local typedefs, structs, enumerations for this file--------------------------------------------
190 
191 typedef struct pmt_list_entry
192 {
193  U16BIT serv_id;
194  U16BIT ts_id;
195  U16BIT on_id;
196  U16BIT pid;
198 
199 typedef struct eit_list_entry
200 {
201  U16BIT serv_id;
202  BOOLEAN got_eit;
204 
205 typedef enum
206 {
207  DB_ACCESS_UPDATE,
208  DB_ACCESS_SEARCH,
209  DB_ACCESS_PLAYBACK
210 } E_DB_ACCESS_MODE;
211 
212 typedef struct s_si_event_data
213 {
214  struct s_si_event_data *next;
215  U8BIT index;
216  U32BIT value;
218 
219 typedef enum
220 {
221  PMT_REQUEST_CURRENT,
222  PMT_REQUEST_MONITOR,
223  PMT_REQUEST_PRIORITY
224 } E_PMT_REQUEST_MODE;
225 
226 typedef struct
227 {
228  U16BIT tran_id;
229  U16BIT onet_id;
230 } S_IDS;
231 
232 typedef struct
233 {
234  U16BIT bouquet_id;
235  BOOLEAN received;
237 
239 {
240  /* Transport and service record of service being added */
241  ADB_TRANSPORT_REC *add_t_ptr;
242  ADB_SERVICE_REC *add_s_ptr;
243 
244  /* Transport and service record of service being deleted */
245  ADB_TRANSPORT_REC *delete_t_ptr;
246  ADB_SERVICE_REC *delete_s_ptr;
247 
248  struct s_dynamic_update_service *next;
250 
252 {
253  ADB_TRANSPORT_REC *t_ptr;
254 
255  U16BIT num_lcns;
256  SI_LCN_DESC *lcn_array;
257  U16BIT num_hd_lcns;
258  SI_LCN_DESC *hd_lcn_array;
259  U16BIT num_nordig_lcns;
260  SI_NORDIG_LCN_DESC *nordig_lcn_array;
261 
262  S_DYNAMIC_UPDATE_SERVICE *service_head;
263  S_DYNAMIC_UPDATE_SERVICE *service_tail;
264 
265  struct s_dynamic_update_transport *next;
267 
268 typedef struct
269 {
270  BOOLEAN terrestrial;
271  BOOLEAN cable;
272  BOOLEAN satellite;
274 
275 
276 //---local (static) variable declarations for this file------------------------
277 // (internal variables declared static to make them local)
278 
279 static E_APP_SI_MODE *required_si_mode;
280 static F_SIManager *current_manager;
281 static E_SEARCH_SERVICE_TYPE required_service_type;
282 
283 static ADB_NETWORK_REC **current_network_rec;
284 static ADB_TRANSPORT_REC **current_transport_rec;
285 static ADB_SERVICE_REC **current_service_rec;
286 // used to track transport changes
287 static ADB_TRANSPORT_REC **last_transport_rec;
288 
289 static void **pat_filter;
290 static void **pmt_filter;
291 static void **eit_filter;
292 
293 static void **sched_filter;
294 static void **nit_filter;
295 static void **sdt_filter;
296 static void **bat_filter;
297 static void **tot_filter;
298 static void **tdt_filter;
299 static void **cat_filter;
300 static void **rct_filter;
301 static void **ait_filter;
302 
303 static U32BIT *pat_start_timestamp;
304 static U32BIT *pmt_start_timestamp;
305 static U32BIT *nit_start_timestamp;
306 static U32BIT *sdt_start_timestamp;
307 static U32BIT *bat_start_timestamp;
308 static U32BIT *eit_start_timestamp;
309 static U32BIT *sched_start_timestamp;
310 static U32BIT *sched_timeout_ms;
311 static U32BIT *tot_start_timestamp;
312 static U32BIT *tdt_start_timestamp;
313 static U32BIT *si_update_delay_timestamp;
314 static U32BIT *pmt_update_timestamp;
315 static U32BIT *cat_start_timestamp;
316 static U32BIT *pmt_update_period_ms;
317 static U32BIT *last_timestamp;
318 
319 static BOOLEAN *sdt_complete;
320 static BOOLEAN *bat_complete;
321 static BOOLEAN *nit_complete;
322 static BOOLEAN *pmts_complete;
323 static BOOLEAN *eits_complete;
324 static BOOLEAN *tot_complete;
325 
326 static BOOLEAN *tot_already_received;
327 
328 static BOOLEAN *pat_rcvd_on_this_trnsprt;
329 
330 static PMT_LIST_ENTRY **pmt_list;
331 static U16BIT *num_pmt_list_entries;
332 static U16BIT *pmt_list_id;
333 static U16BIT *pmt_filter_pid;
334 static BOOLEAN *pmt_service_changed;
335 static BOOLEAN *report_pmt_allowed;
336 static BOOLEAN *pmt_reported;
337 static BOOLEAN *stop_pmt_reporting;
338 static E_PMT_REQUEST_MODE *pmt_request_mode;
339 static U32BIT pmt_priority_list[MAX_PMT_PRIORITY_LIST] = {INVALID_SERVICE_ID};
340 static void *si_pmt_list_sem;
341 
342 static EIT_LIST_ENTRY **eit_list;
343 static U16BIT *num_eit_list_entries;
344 
345 static U16BIT eit_schedule_limit;
346 
347 // set during search to indicate that service list is ready to be read - i.e. sdt processing complete
348 static BOOLEAN *service_list_ready;
349 
350 static S16BIT *last_reported_cat_version;
351 static S16BIT *last_reported_nit_version;
352 static U8BIT *last_reported_pmt_version;
353 
354 static BOOLEAN use_bats_active;
355 static S_ACTIVE_BOUQUET *active_bouquet_ids;
356 static U16BIT num_active_bouquet_ids;
357 
358 /* 0 is an unused reserved network ID so can be used to indicate the value hasn't been set */
359 static U16BIT active_network_id = 0;
360 
361 static S16BIT last_playback_pmt_version = -1;
362 static S16BIT last_playback_pat_version = -1;
363 
364 /* Data related to dynamic SI updates */
365 static S_DYNAMIC_UPDATE_TRANSPORT *dynamic_update_head;
366 static S_DYNAMIC_UPDATE_TRANSPORT *dynamic_update_tail;
367 
368 // dvb ssu status data
369 static BOOLEAN ssu_refused;
370 static BOOLEAN dvb_ssu_mandatory;
371 static U8BIT dvb_oui[3] = {0x00, 0x01, 0x5a};
372 
373 static F_EitParser eit_parser_func = NULL;
374 static F_BatTableUpdate update_bat_func = NULL;
375 static F_EitTableUpdate update_eit_func = NULL;
376 static F_NitTableUpdate update_nit_func = NULL;
377 static F_PmtTableUpdate update_pmt_func = NULL;
378 static F_SdtTableUpdate update_sdt_func = NULL;
379 
380 static F_EitSchedUpdateCB eit_sched_update_callback = NULL;
381 
382 static S_DATABASE_UPDATES_ALLOWED db_updates_allowed = {TRUE, TRUE, TRUE};
383 
384 
385 //---local function prototypes for this file-----------------------------------
386 // (internal functions declared static to make them local)
387 
388 static void HandleSiEvent(U8BIT path, E_APP_SI_EVENT_TYPE event);
389 static void CheckForTimeout(U8BIT path, U32BIT timestamp, U32BIT timeout, U32BIT event);
390 static void ReceiveSiTable(void *filter_ptr, U32BIT ret_param, SI_TABLE_RECORD *table_rec);
391 
392 static BOOLEAN ManageChannelSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
393 static BOOLEAN ManageStartupSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
394 static BOOLEAN ManageEventSchedSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
395 static BOOLEAN ManageUpdate(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
396 static BOOLEAN ManageTotSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
397 
398 #ifdef COMMON_INTERFACE
399 static BOOLEAN ManageCIPlusUpdate(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
400 static BOOLEAN ManageCIPlusNoPatPmt(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
401 #endif
402 
403 static BOOLEAN ProcessPatTablePlayback(SI_TABLE_RECORD *table_rec);
404 static BOOLEAN ManageUpdatePlayback(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
405 static BOOLEAN ManageRecording(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
406 static void StartEITScheduleFilter(U8BIT path);
407 
408 static BOOLEAN ProcessSdtTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode,
409  BOOLEAN ignore_version, BOOLEAN eit_list_reqd);
410 static BOOLEAN ProcessPatTable(SI_TABLE_RECORD *table_rec);
411 static BOOLEAN ProcessPmtTable(SI_TABLE_RECORD *table_rec, BOOLEAN ignore_version, BOOLEAN report_pmt,
412  U16BIT *service_id, E_DB_ACCESS_MODE mode);
413 static BOOLEAN InternalProcessPmtTable(U8BIT path, ADB_SERVICE_REC *s_ptr, SI_TABLE_RECORD *table_rec,
414  BOOLEAN db_services, E_DB_ACCESS_MODE mode);
415 
416 static BOOLEAN ProcessNitTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode, BOOLEAN report_nit,
417  BOOLEAN transport_changed);
418 
419 static U32DHMS ReadEventStart(U8BIT *data_ptr);
420 static U32DHMS ReadEventDuration(U8BIT *data_ptr);
421 static BOOLEAN DeleteOutOfDateEvents(ADB_SERVICE_REC *s_ptr);
422 static BOOLEAN UpdateEvents(ADB_EVENT_REC *event_ptr, ADB_SERVICE_REC *s_ptr, BOOLEAN update_only);
423 static BOOLEAN DeleteEventsForPeriod(ADB_SERVICE_REC *s_ptr, U32DHMS start_time, U32DHMS end_time);
424 
425 static void ProcessEitTable(SI_TABLE_RECORD *table_rec, BOOLEAN ignore_version, E_DB_ACCESS_MODE mode, BOOLEAN playback);
426 
427 static void ProcessCatTable(U8BIT path, SI_TABLE_RECORD *table_rec, BOOLEAN report_cat, BOOLEAN transport_changed);
428 static void ProcessRctTable(SI_TABLE_RECORD *table_rec);
429 static BOOLEAN ProcessBatTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode, BOOLEAN report_bat);
430 
431 static ADB_IMAGE_ICON* ProcessImageIcon(SI_IMAGE_ICON_DESC *si_icon);
432 
433 #if defined(INCLUDE_DSMCC_FILE_REQUEST)
434 static void IconFileRequest(ADB_IMAGE_ICON *icon_ptr,U8BIT path);
435 #endif
436 
437 static BOOLEAN MakeNewPmtRequest(U8BIT path);
438 static U16BIT GetPriorityListId(U8BIT path);
439 static void CancelTableRequests(U8BIT path, BOOLEAN this_path_only);
440 static void UpdateTransportParameters(U8BIT path);
441 
442 static BOOLEAN ManageDvbSsuSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec);
443 static BOOLEAN CheckSsuLinkageDescForUpgrade(SI_LINKAGE_DESC_ENTRY *desc_ptr, U16BIT *onid_ptr,
444  U16BIT *tid_ptr, U16BIT *sid_ptr);
445 
446 static void CopyComponentTagArray(ADB_STREAM_REC *stream_rec, SI_PMT_STREAM_ENTRY *pmt_entry);
447 static BOOLEAN HaveStreamsChanged(ADB_STREAM_REC *slist1, ADB_STREAM_REC *slist2);
448 
449 static void CopyLinkageDesc(SI_LINKAGE_DESC_ENTRY *new_list_ptr, SI_LINKAGE_DESC_ENTRY **list_ptr,
450  SI_LINKAGE_DESC_ENTRY **last_entry_ptr, U16BIT *num_linkage_desc);
451 static void DeleteLinkageDescripterArray(SI_LINKAGE_DESC_ENTRY *list_ptr);
452 
453 static BOOLEAN DynamicUpdateAddTransport(ADB_TRANSPORT_REC *transport, U16BIT num_lcns, SI_LCN_DESC * lcn_array,
454  U16BIT num_hd_lcns, SI_LCN_DESC *hd_lcn_array, U16BIT num_nordig_lcns, SI_NORDIG_LCN_DESC *nordig_lcn_array);
455 static void DynamicUpdateAddService(ADB_TRANSPORT_REC *transport, ADB_SERVICE_REC *service, BOOLEAN check_move);
456 static void DynamicUpdateDeleteService(ADB_TRANSPORT_REC *transport, ADB_SERVICE_REC *service, BOOLEAN check_move);
457 static void ApplyDynamicUpdates(U8BIT path);
458 static void ClearDynamicUpdates(void);
459 
460 
461 //--------------------------------------------------------------------------------------------------
462 // local function definitions
463 //--------------------------------------------------------------------------------------------------
464 
465 
477 static void HandleSiEvent(U8BIT path, E_APP_SI_EVENT_TYPE event)
478 {
479  BOOLEAN finished;
480  U8BIT last_path;
481 
482  FUNCTION_START(HandleSiEvent);
483 
484  switch (event)
485  {
486  case STOP_SI:
487  {
488  AP_SI_PRINT(("APSI Stop(%d)", path));
489  if (current_manager[path] != NULL)
490  {
491  finished = (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
492  current_manager[path] = NULL;
493  }
494  break;
495  }
496  case START_SI_SEARCHING:
497  {
498  // check there is no manager running - if there is stop it
499  if (current_manager[path] != NULL)
500  {
501  finished = (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
502  current_manager[path] = NULL;
503  }
504  // decide which manager to start...
505  switch (required_si_mode[path])
506  {
507  case APP_SI_MODE_CHANNEL_SEARCH:
508  case APP_SI_MODE_CHANNEL_SEARCH_NO_NIT:
509  {
510  AP_SI_PRINT(("APSI(%d): channel search", path));
511  current_manager[path] = ManageChannelSearch;
512  break;
513  }
514 
515  case APP_SI_MODE_STARTUP_SEARCH:
516  {
517  AP_SI_PRINT(("APSI(%d): startup search", path));
518  current_manager[path] = ManageStartupSearch;
519  break;
520  }
521 
522  case APP_SI_MODE_TOT_SEARCH:
523  {
524  AP_SI_PRINT(("APSI(%d): tot search", path));
525  current_manager[path] = ManageTotSearch;
526  break;
527  }
528 
529  case APP_SI_MODE_EVENT_PF_SEARCH:
530  case APP_SI_MODE_EVENT_SCHED_SEARCH:
531  case APP_SI_MODE_EVENT_PF_SCHED_SEARCH:
532  {
533  AP_SI_PRINT(("APSI(%d): schedule search", path));
534  current_manager[path] = ManageEventSchedSearch;
535  break;
536  }
537 
538  case APP_SI_MODE_DVB_SSU_SEARCH:
539  {
540  AP_SI_PRINT(("APSI(%d): dvb ssu search", path));
541  current_manager[path] = ManageDvbSsuSearch;
542  break;
543  }
544 
545  #ifdef COMMON_INTERFACE
546  case APP_SI_MODE_CIPLUS_UPDATE:
547  {
548  AP_SI_PRINT(("APSI(%d): CI+ update search", path));
549  current_manager[path] = ManageCIPlusUpdate;
550  break;
551  }
552 
553  case APP_SI_MODE_CIPLUS_NO_PAT_PMT:
554  {
555  AP_SI_PRINT(("APSI(%d): CI+ no PAT/PMT search", path));
556  current_manager[path] = ManageCIPlusNoPatPmt;
557  break;
558  }
559  #endif
560 
561  case APP_SI_MODE_USER_DEFINED:
562  {
563  AP_SI_PRINT(("APSI(%d): user defined search", path));
564  break;
565  }
566 
567  case APP_SI_MODE_NO_SI:
568  case APP_SI_MODE_UPDATE:
569  default:
570  {
571  AP_SI_PRINT(("APSI(%d): search failed - invalid mode %d", path, required_si_mode[path]));
572  break;
573  }
574  }
575  // start the new manager
576  if (current_manager[path] != NULL)
577  {
578  finished = (current_manager[path])(path, APP_SI_START_MANAGER, NULL);
579  if (finished == TRUE)
580  {
581  current_manager[path] = NULL;
582  }
583  }
584  break;
585  }
586 
587  case START_SI_UPDATING_NEW_TRANSPORT:
588  {
589  if (ACFG_GetCountry() == COUNTRY_CODE_UK)
590  {
591  ADB_TRANSPORT_REC *t_ptr;
592 
593  /* When changing transport the sdt versions stored in the transport are invalid:
594  * "There is no requirement that actual and other tables should carry the
595  * same version number." (Dbook7) */
597  t_ptr = DBDEF_GetNextTransportRec(NULL);
598  while (t_ptr != NULL)
599  {
600  t_ptr->sdt_version = 0xFF;
601  t_ptr = DBDEF_GetNextTransportRec(t_ptr);
602  }
604  }
605 
606  // check there is no manager running - if there is stop it
607  if (current_manager[path] != NULL)
608  {
609  finished = (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
610  current_manager[path] = NULL;
611  }
612 
613  if (required_si_mode[path] == APP_SI_MODE_UPDATE)
614  {
615  finished = FALSE;
616 
617  if (STB_DPIsRecordingPath(path))
618  {
619  AP_SI_PRINT(("APSI(%d): recording", path));
620  current_manager[path] = ManageRecording;
621  finished = ManageRecording(path, APP_SI_START_MANAGER, NULL);
622  }
623  else if (path == APVR_GetPlaybackPath())
624  {
625  AP_SI_PRINT(("APSI(%d): update for playback", path));
626  current_manager[path] = ManageUpdatePlayback;
627  finished = ManageUpdatePlayback(path, APP_SI_START_MANAGER, NULL);
628  }
629  else
630  {
631  AP_SI_PRINT(("APSI(%d): update", path));
632  current_manager[path] = ManageUpdate;
633  finished = ManageUpdate(path, APP_SI_START_MANAGER, NULL);
634  }
635 
636  if (finished == TRUE)
637  {
638  current_manager[path] = NULL;
639  }
640  }
641  else
642  {
643  AP_SI_PRINT(("APSI(%d): update failed - invalid mode %d", path, required_si_mode[path]));
644  }
645  break;
646  }
647 
648  case START_SI_UPDATING_SAME_TRANSPORT:
649  {
650  // the ManageUpdate manager should be running
651  if (required_si_mode[path] == APP_SI_MODE_UPDATE)
652  {
653  finished = FALSE;
654 
655  if (!STB_DPIsLivePath(path) && STB_DPIsRecordingPath(path))
656  {
657  AP_SI_PRINT(("APSI(%d): recording", path));
658 
659  if (current_manager[path] != NULL)
660  {
661  finished = (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
662  current_manager[path] = NULL;
663  }
664 
665  current_manager[path] = ManageRecording;
666  finished = ManageRecording(path, APP_SI_START_MANAGER, NULL);
667  }
668  else
669  {
670  /* SI is only monitored on the live path */
671  if (STB_DPIsLivePath(path))
672  {
673  AP_SI_PRINT(("APSI(%d): update", path));
674 
675  if (current_manager[path] != ManageUpdate)
676  {
677  // if current manager is not ManageUpdate stop it and start ManageUpdate
678  if (current_manager[path] != NULL)
679  {
680  (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
681  }
682 
683  current_manager[path] = ManageUpdate;
684  finished = ManageUpdate(path, APP_SI_START_MANAGER, NULL);
685  }
686  else
687  {
688  // ManageUpdate is running - tell it about the channel change
689  finished = ManageUpdate(path, APP_SI_CHANNEL_CHANGE, NULL);
690  }
691  }
692  else if (path == APVR_GetPlaybackPath())
693  {
694  AP_SI_PRINT(("APSI(%d): update for playback", path));
695 
696  if (current_manager[path] != ManageUpdatePlayback)
697  {
698  // if current manager is not ManageUpdatePlayback stop it and start ManageUpdatePlayback
699  (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
700  current_manager[path] = ManageUpdatePlayback;
701  finished = ManageUpdatePlayback(path, APP_SI_START_MANAGER, NULL);
702  }
703  else
704  {
705  // ManageUpdatePlayback is running - tell it about the channel change
706  finished = ManageUpdatePlayback(path, APP_SI_CHANNEL_CHANGE, NULL);
707  }
708  }
709  }
710 
711  if (finished == TRUE)
712  {
713  current_manager[path] = NULL;
714  }
715  }
716  else
717  {
718  AP_SI_PRINT(("APSI(%d): update failed - invalid mode %d", path, required_si_mode[path]));
719  if (current_manager[path] != NULL)
720  {
721  (current_manager[path])(path, APP_SI_STOP_MANAGER, NULL);
722  current_manager[path] = NULL;
723  }
724  }
725  break;
726  }
727 
728  case SI_TIMEOUT:
729  {
730  U32BIT time_now, time_adjust;
731  /* No events received for 1 second */
732  if (path == INVALID_RES_ID)
733  {
734  /* Check timeouts on all paths */
735  path = 0;
736  last_path = STB_DPGetNumPaths();
737  }
738  else
739  {
740  /* Only check timeout for the specified path */
741  last_path = path + 1;
742  }
743 
744  for (; path < last_path; path++)
745  {
746  time_now = STB_OSGetClockMilliseconds();
747  if ((STB_DPGetPathTuner(path) != INVALID_RES_ID) && (STB_DPGetTuneStatus(path) == TUNE_LOCKED))
748  {
749  time_adjust = 0;
750  }
751  else
752  {
753  time_adjust = time_now - last_timestamp[path];
754  }
755  last_timestamp[path] = time_now;
756 
757  if (current_manager[path] != NULL)
758  {
759  if (time_adjust != 0)
760  {
761  if (cat_start_timestamp[path] != 0)
762  {
763  cat_start_timestamp[path] += time_adjust;
764  }
765  if (pat_start_timestamp[path] != 0)
766  {
767  pat_start_timestamp[path] += time_adjust;
768  }
769  if (pmt_start_timestamp[path] != 0)
770  {
771  pmt_start_timestamp[path] += time_adjust;
772  }
773  if (eit_start_timestamp[path] != 0)
774  {
775  eit_start_timestamp[path] += time_adjust;
776  }
777  if (sched_start_timestamp[path] != 0)
778  {
779  sched_start_timestamp[path] += time_adjust;
780  }
781  if (pmt_update_timestamp[path] != 0)
782  {
783  pmt_update_timestamp[path] += time_adjust;
784  }
785  if (si_update_delay_timestamp[path] != 0)
786  {
787  si_update_delay_timestamp[path] += time_adjust;
788  }
789  if (nit_start_timestamp[path] != 0)
790  {
791  nit_start_timestamp[path] += time_adjust;
792  }
793  if (sdt_start_timestamp[path] != 0)
794  {
795  sdt_start_timestamp[path] += time_adjust;
796  }
797  if (tot_start_timestamp[path] != 0)
798  {
799  tot_start_timestamp[path] += time_adjust;
800  }
801  if (tdt_start_timestamp[path] != 0)
802  {
803  tdt_start_timestamp[path] += time_adjust;
804  }
805  if (bat_start_timestamp[path] != 0)
806  {
807  bat_start_timestamp[path] += time_adjust;
808  }
809  }
810  // check filter timeouts and pass on to current manager
811  CheckForTimeout(path, cat_start_timestamp[path], CAT_TIMEOUT_MS, APP_SI_CAT_TIMEOUT);
812  CheckForTimeout(path, pat_start_timestamp[path], PAT_TIMEOUT_MS, APP_SI_PAT_TIMEOUT);
813  CheckForTimeout(path, pmt_start_timestamp[path], PMT_TIMEOUT_MS, APP_SI_PMT_TIMEOUT);
814  CheckForTimeout(path, eit_start_timestamp[path], EIT_TIMEOUT_MS, APP_SI_EIT_TIMEOUT);
815  CheckForTimeout(path, sched_start_timestamp[path], sched_timeout_ms[path],
816  APP_SI_SCHED_TIMEOUT);
817 
818  if (path != STB_DPGetPlaybackPath())
819  {
820  CheckForTimeout(path, nit_start_timestamp[path], NIT_TIMEOUT_MS, APP_SI_NIT_TIMEOUT);
821  CheckForTimeout(path, sdt_start_timestamp[path], SDT_TIMEOUT_MS, APP_SI_SDT_TIMEOUT);
822  CheckForTimeout(path, tot_start_timestamp[path], TOT_TIMEOUT_MS, APP_SI_TOT_TIMEOUT);
823  CheckForTimeout(path, tdt_start_timestamp[path], TDT_TIMEOUT_MS, APP_SI_TDT_TIMEOUT);
824  CheckForTimeout(path, bat_start_timestamp[path], BAT_TIMEOUT_MS, APP_SI_BAT_TIMEOUT);
825  }
826 
827  // check control timeouts
828  CheckForTimeout(path, pmt_update_timestamp[path], pmt_update_period_ms[path], APP_SI_PMT_UPDATE);
829  CheckForTimeout(path, si_update_delay_timestamp[path], SI_UPDATE_DELAY_MS, APP_SI_UPDATE_DELAY_EXPIRED);
830 
831  // check application commands
832  if (stop_pmt_reporting[path] == TRUE)
833  {
834  stop_pmt_reporting[path] = FALSE;
835  finished = (current_manager[path])(path, APP_SI_STOP_PMT_REPORTING, NULL);
836  if (finished == TRUE)
837  {
838  current_manager[path] = NULL;
839  }
840  }
841  }
842  }
843  break;
844  }
845  }
846 
847  FUNCTION_FINISH(HandleSiEvent);
848 }
849 
863 static void CheckForTimeout(U8BIT path, U32BIT timestamp, U32BIT timeout, U32BIT event)
864 {
865  BOOLEAN finished;
866 
867  FUNCTION_START(CheckForTimeout);
868 
869  if (timestamp != 0)
870  {
871  if (STB_OSGetClockDiff(timestamp) > timeout)
872  {
873  finished = (current_manager[path])(path, event, NULL);
874  if (finished == TRUE)
875  {
876  current_manager[path] = NULL;
877  }
878  }
879  }
880  FUNCTION_FINISH(CheckForTimeout);
881 }
882 
897 static void ReceiveSiTable(void *filter_ptr, U32BIT ret_param, SI_TABLE_RECORD *table_rec)
898 {
899  U8BIT path;
900 
901  FUNCTION_START(ReceiveSiTable);
902 
903  USE_UNWANTED_PARAM(filter_ptr);
904 
905  if (table_rec != NULL)
906  {
907  path = table_rec->path;
908  }
909  else
910  {
911  AP_SI_PRINT(("===ReceiveSiTable: table_rec is NULL, so path = 0\n"));
912  path = 0;
913  }
914 
915  if (current_manager[path] != NULL)
916  {
917  // ret_param will contain the event code relevant for the table e.g. APP_SI_PAT_RECEIVED
918  // pass event and table_rec to manager
919  (current_manager[path])(path, ret_param, table_rec);
920  }
921  else
922  {
923  // there should always be a current manager, but in case there isn't release table_rec here
924  // otherwise it won't get released and cancel all filters because there shouldn't be any
925  // running
926  STB_SIReleaseTableRecord(table_rec);
927  CancelTableRequests(path, TRUE);
928  }
929 
930  FUNCTION_FINISH(ReceiveSiTable);
931 }
932 
946 static BOOLEAN ManageChannelSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
947 {
948  U32BIT freq;
949  BOOLEAN finished;
950  BOOLEAN success;
951  U16BIT i;
952  E_STB_DP_SIGNAL_TYPE tuner_type;
953  BOOLEAN stop_search;
954  U8BIT plp_id;
955 
956  FUNCTION_START(ManageChannelSearch);
957 
958  finished = FALSE;
959  if (event == APP_SI_START_MANAGER)
960  {
961  // clear service list ready flag
962  service_list_ready[path] = FALSE;
963 
964  // first ensure there is a transport record for the transport we are tuned to and set
965  // current transport accordingly
966  freq = STB_DPGetFrequency(path);
967  tuner_type = STB_DPGetSignalType(path);
968 
970 
971  switch (tuner_type)
972  {
973  case SIGNAL_COFDM:
974  plp_id = STB_DPGetTerrPLP(path);
975  current_transport_rec[path] = DBDEF_FindTerrestrialTransportRec(freq, plp_id);
976  if (current_transport_rec[path] == NULL)
977  {
978  /* Transport does not exist - add one */
979  #ifdef DEBUG_SI_CHAN_SEARCH
980  AP_SI_PRINT(("Chan search(%d): start - new terrestrial transport (%s), PLP=%u", path,
981  ACTL_GetRfNameFromFreq(tuner_type, freq), plp_id));
982  #endif
983  current_transport_rec[path] = DBDEF_AddTerrestrialTransportRec(freq, plp_id, NULL);
984  }
985  #ifdef DEBUG_SI_CHAN_SEARCH
986  else
987  {
988  AP_SI_PRINT(("Chan search(%d): start - existing transport (%s)", path,
989  ACTL_GetRfNameFromFreq(tuner_type, freq)));
990  }
991  #endif
992  break;
993  case SIGNAL_QAM:
994  current_transport_rec[path] = DBDEF_FindCableTransportRec(freq, STB_DPGetSymbolRate(path));
995  if (current_transport_rec[path] == NULL)
996  {
997  /* Transport does not exist - add one */
998  #ifdef DEBUG_SI_CHAN_SEARCH
999  AP_SI_PRINT(("Chan search(%d): start - new cable transport (%s), sym_rate=%u", path,
1000  ACTL_GetRfNameFromFreq(tuner_type, freq), STB_DPGetSymbolRate(path)));
1001  #endif
1002  current_transport_rec[path] = DBDEF_AddCableTransportRec(freq,
1003  STB_DPGetSymbolRate(path), NULL);
1004  }
1005  #ifdef DEBUG_SI_CHAN_SEARCH
1006  else
1007  {
1008  AP_SI_PRINT(("Chan search(%d): start - existing transport (%s)", path,
1009  ACTL_GetRfNameFromFreq(tuner_type, freq)));
1010  }
1011  #endif
1012  break;
1013  case SIGNAL_QPSK:
1014  current_transport_rec[path] = DBDEF_FindSatTransportRec(freq, STB_DPGetSymbolRate(path),
1016  ACTL_GetCurrentSatellite(path));
1017  if (current_transport_rec[path] == NULL)
1018  {
1019  /* Transport does not exist - add one */
1020  #ifdef DEBUG_SI_CHAN_SEARCH
1021  AP_SI_PRINT(("Chan search(%d): start - new sat transport (%s), sym_rate=%u, polarity=%u",
1022  path, ACTL_GetRfNameFromFreq(tuner_type, freq), STB_DPGetSymbolRate(path),
1023  STB_DPGetPolarity(path)));
1024  #endif
1025  current_transport_rec[path] = DBDEF_AddSatTransportRec(freq, STB_DPGetSymbolRate(path),
1026  STB_DPGetPolarity(path), STB_DPGetDVBS2(path), STB_DPGetModulation(path), NULL);
1027  }
1028  #ifdef DEBUG_SI_CHAN_SEARCH
1029  else
1030  {
1031  AP_SI_PRINT(("Chan search(%d): start - existing transport (%s)", path,
1032  ACTL_GetRfNameFromFreq(tuner_type, freq)));
1033  }
1034  #endif
1035  break;
1036  default:
1037  #ifdef DEBUG_SI_CHAN_SEARCH
1038  AP_SI_PRINT(("Chan search(%u): Unknown tuner type, %u", path, tuner_type));
1039  #endif
1040  current_transport_rec[path] = NULL;
1041  break;
1042  }
1043 
1045 
1046  if (current_transport_rec[path] != NULL)
1047  {
1048  DBDEF_SetTunedTransport(path, current_transport_rec[path]);
1049 
1050  current_network_rec[path] = current_transport_rec[path]->network;
1051  current_service_rec[path] = NULL;
1052 
1053  pat_rcvd_on_this_trnsprt[path] = FALSE;
1054  last_transport_rec[path] = NULL;
1055  pmts_complete[path] = FALSE;
1056  sdt_complete[path] = FALSE;
1057  nit_complete[path] = FALSE;
1058  eits_complete[path] = FALSE;
1059  tot_complete[path] = FALSE;
1060  bat_complete[path] = FALSE;
1061 
1062 #ifdef COMMON_INTERFACE
1063  /* Ensure the routing of the TS is correct for acquiring the SDT for CI+ */
1064  if (ACI_SetSecureRouting(path))
1065 #endif
1066  {
1067  // start search for sdt and tot
1068  sdt_start_timestamp[path] = STB_OSGetClockMilliseconds();
1069  sdt_filter[path] = STB_SIRequestSdt(path, ONE_SHOT_REQUEST, TRUE, FALSE, DONT_CARE_ID_MATCH,
1070  DONT_CARE_ID_MASK, 1, ReceiveSiTable, APP_SI_SDT_RECEIVED);
1071 
1072  /* Request TOT and TDT as TOT isn't always available */
1073  tot_start_timestamp[path] = STB_OSGetClockMilliseconds();
1074  tot_filter[path] = STB_SIRequestTot(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
1075 
1076  tdt_start_timestamp[path] = STB_OSGetClockMilliseconds();
1077  tdt_filter[path] = STB_SIRequestTdt(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TDT_RECEIVED);
1078  }
1079 #ifdef COMMON_INTERFACE
1080  else
1081  {
1082  #ifdef DEBUG_SI_CHAN_SEARCH
1083  AP_SI_PRINT(("Chan search(%d): start - failed to route TS securely", path));
1084  #endif
1085  // report end of search
1086  STB_SISearchComplete(path, FALSE, NULL, 0);
1087  finished = TRUE;
1088  }
1089 #endif
1090  }
1091  else
1092  {
1093  #ifdef DEBUG_SI_CHAN_SEARCH
1094  AP_SI_PRINT(("Chan search(%d): start - failed, no transport", path));
1095  #endif
1096  // report end of search
1097  STB_SISearchComplete(path, FALSE, NULL, 0);
1098  finished = TRUE;
1099  }
1100  }
1101  else if (event == APP_SI_STOP_MANAGER)
1102  {
1103  #ifdef DEBUG_SI_CHAN_SEARCH
1104  AP_SI_PRINT(("Chan search(%d): stop", path));
1105  #endif
1106  CancelTableRequests(path, FALSE);
1107  finished = TRUE;
1108  }
1109  else
1110  {
1111  switch (event)
1112  {
1113  case APP_SI_SDT_RECEIVED:
1114  {
1115  #ifdef DEBUG_SI_CHAN_SEARCH
1116  AP_SI_PRINT(("Chan search(%d): SDT received (tid 0x%04x)", path, table_rec->xtid));
1117  #endif
1118  ProcessSdtTable(table_rec, DB_ACCESS_SEARCH, IGNORE_VERSION, EIT_LIST_REQD);
1119 
1120  /* Finished with the filter - release it and flag sdt complete */
1121  sdt_complete[path] = TRUE;
1122  service_list_ready[path] = TRUE;
1123 
1124  STB_SICancelTableRequest(sdt_filter[path]);
1125  sdt_filter[path] = NULL;
1126  sdt_start_timestamp[path] = 0;
1127 
1128  /* Start search for PAT */
1129  pat_start_timestamp[path] = STB_OSGetClockMilliseconds();
1130  pat_filter[path] = STB_SIRequestPat(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_PAT_RECEIVED);
1131 
1132  if (required_si_mode[path] != APP_SI_MODE_CHANNEL_SEARCH_NO_NIT)
1133  {
1134  /* Start search for NIT */
1135  nit_start_timestamp[path] = STB_OSGetClockMilliseconds();
1136 
1137  if (active_network_id == 0)
1138  {
1139  nit_filter[path] = STB_SIRequestNit(path, ONE_SHOT_REQUEST, ReceiveSiTable,
1140  APP_SI_NIT_RECEIVED);
1141  }
1142  else
1143  {
1144  nit_filter[path] = STB_SIRequestNitWithId(path, active_network_id, ONE_SHOT_REQUEST,
1145  ReceiveSiTable, APP_SI_NIT_RECEIVED);
1146  }
1147  }
1148  else
1149  {
1150  nit_complete[path] = TRUE;
1151  }
1152 
1153  if (use_bats_active)
1154  {
1155  /* Start search for the BATs */
1156  bat_start_timestamp[path] = STB_OSGetClockMilliseconds();
1157  bat_filter[path] = STB_SIRequestBat(path, CONTINUOUS_REQUEST, DONT_CARE_ID_MATCH,
1158  DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_BAT_RECEIVED);
1159  }
1160  else
1161  {
1162  bat_complete[path] = TRUE;
1163  }
1164 
1165  /* Start search for eits on current transport only */
1166  eit_start_timestamp[path] = STB_OSGetClockMilliseconds();
1167  eit_filter[path] = STB_SIRequestEit(path, ONE_SHOT_REQUEST, EIT_NOW_NEXT_ACT,
1168  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff,
1169  ReceiveSiTable, APP_SI_EIT_RECEIVED);
1170  break;
1171  }
1172 
1173  case APP_SI_SDT_TIMEOUT:
1174  {
1175  /* timeout - no point in searching any further if there is no SDT. Set the complete
1176  * flags to indicate end of search */
1177  #ifdef DEBUG_SI_CHAN_SEARCH
1178  AP_SI_PRINT(("Chan search(%d): SDT timeout", path));
1179  #endif
1180 
1181  /* Finished with the filter - release it and flag sdt complete */
1182  STB_SICancelTableRequest(sdt_filter[path]);
1183  sdt_filter[path] = NULL;
1184  sdt_start_timestamp[path] = 0;
1185  finished = TRUE;
1186  break;
1187  }
1188 
1189  case APP_SI_PAT_RECEIVED:
1190  {
1191  #ifdef DEBUG_SI_CHAN_SEARCH
1192  AP_SI_PRINT(("Chan search(%d): PAT received (tid 0x%04x)", path, table_rec->xtid));
1193  #endif
1194  ProcessPatTable(table_rec);
1195  if (pmt_list[path] != NULL)
1196  {
1197  pmt_list_id[path] = 0;
1198  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
1199  MakeNewPmtRequest(path);
1200  }
1201  else
1202  {
1203  pmts_complete[path] = TRUE;
1204  }
1205 
1206  /* Finished with the filter - release it */
1207  STB_SICancelTableRequest(pat_filter[path]);
1208  pat_filter[path] = NULL;
1209  pat_start_timestamp[path] = 0;
1210  break;
1211  }
1212 
1213  case APP_SI_PAT_TIMEOUT:
1214  {
1215  #ifdef DEBUG_SI_CHAN_SEARCH
1216  AP_SI_PRINT(("Chan search(%d): PAT timeout", path));
1217  #endif
1218 
1219  /* Finished with the filter - release it */
1220  STB_SICancelTableRequest(pat_filter[path]);
1221  pat_filter[path] = NULL;
1222  pat_start_timestamp[path] = 0;
1223  finished = TRUE;
1224  break;
1225  }
1226 
1227  case APP_SI_PMT_RECEIVED:
1228  case APP_SI_PMT_TIMEOUT:
1229  {
1230  if (event == APP_SI_PMT_RECEIVED)
1231  {
1232  #ifdef DEBUG_SI_CHAN_SEARCH
1233  AP_SI_PRINT(("Chan search(%d): PMT received (sid 0x%04x)", path, table_rec->xtid));
1234  #endif
1235  // process the pmt (regardless of version and do not report to other parties)
1236  ProcessPmtTable(table_rec, IGNORE_VERSION, DONT_REPORT_PMT, NULL, DB_ACCESS_SEARCH);
1237  }
1238  #ifdef DEBUG_SI_CHAN_SEARCH
1239  else
1240  {
1241  AP_SI_PRINT(("Chan search(%d): PMT timeout (sid 0x%04x)", path,
1242  pmt_list[path][pmt_list_id[path]].serv_id));
1243  }
1244  #endif
1245 
1246  if ((pmt_list_id[path] + 1) >= num_pmt_list_entries[path])
1247  {
1248  // finished list - release the filter and flag pmts complete
1249  pmts_complete[path] = TRUE;
1250  STB_SICancelTableRequest(pmt_filter[path]);
1251  pmt_filter[path] = NULL;
1252  pmt_start_timestamp[path] = 0;
1253  }
1254  else
1255  {
1256  // not finished yet - move on to next pmt...
1257  pmt_list_id[path]++;
1258  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
1259  MakeNewPmtRequest(path);
1260  }
1261  break;
1262  }
1263 
1264  case APP_SI_NIT_RECEIVED:
1265  case APP_SI_NIT_TIMEOUT:
1266  {
1267  if (event == APP_SI_NIT_RECEIVED)
1268  {
1269  #ifdef DEBUG_SI_CHAN_SEARCH
1270  AP_SI_PRINT(("Chan search(%d): NIT received (nid 0x%04x)", path, table_rec->xtid));
1271  #endif
1272  ProcessNitTable(table_rec, DB_ACCESS_SEARCH, FALSE, FALSE);
1273  }
1274  else
1275  {
1276  if (current_transport_rec[path]->sig_type == SIGNAL_QPSK)
1277  {
1279  current_network_rec[path] = DBDEF_FindOrAddPrivateNetwork(ACTL_GetCurrentSatellite(path));
1280  if (current_network_rec[path] != NULL)
1281  {
1282  DBDEF_SetTunedNetwork(path, current_network_rec[path]);
1283 
1284  /* Link the current transport to the network */
1285  current_transport_rec[path]->network = current_network_rec[path];
1286  DBA_SetRecordParent(current_transport_rec[path]->dba_rec,
1287  current_network_rec[path]->dba_rec);
1288  DBA_SaveRecord(current_transport_rec[path]->dba_rec);
1289  }
1291  }
1292  AP_SI_PRINT(("Chan search(%d): NIT timeout", path));
1293  }
1294 
1295  // finished with the filter - release it and flag nit complete
1296  nit_complete[path] = TRUE;
1297  STB_SICancelTableRequest(nit_filter[path]);
1298  nit_filter[path] = NULL;
1299  nit_start_timestamp[path] = 0;
1300  break;
1301  }
1302 
1303  case APP_SI_BAT_RECEIVED:
1304  {
1305  #ifdef DEBUG_SI_CHAN_SEARCH
1306  AP_SI_PRINT(("Chan search(%d): BAT received (bouquet id 0x%04x, v%d)", path,
1307  table_rec->xtid, table_rec->version));
1308  #endif
1309  ProcessBatTable(table_rec, DB_ACCESS_SEARCH, FALSE);
1310 
1311  /* Check whether all BATs have now been received.
1312  * If all BATs are to be collected then the search will continue until
1313  * there's a timeout because we don't know how many BATs there are */
1314  stop_search = FALSE;
1315 
1316  if (active_bouquet_ids != NULL)
1317  {
1318  stop_search = TRUE;
1319 
1320  for (i = 0; i < num_active_bouquet_ids; i++)
1321  {
1322  if (!active_bouquet_ids[i].received)
1323  {
1324  /* Found one that hasn't been received yet */
1325  stop_search = FALSE;
1326  break;
1327  }
1328  }
1329  }
1330 
1331  if (stop_search)
1332  {
1333  bat_complete[path] = TRUE;
1334  STB_SICancelTableRequest(bat_filter[path]);
1335  bat_filter[path] = NULL;
1336  bat_start_timestamp[path] = 0;
1337  }
1338  else
1339  {
1340  /* More BATs are needed, continue collecting */
1341  bat_start_timestamp[path] = STB_OSGetClockMilliseconds();
1342  }
1343  break;
1344  }
1345 
1346  case APP_SI_BAT_TIMEOUT:
1347  {
1348  #ifdef DEBUG_SI_CHAN_SEARCH
1349  AP_SI_PRINT(("Chan search(%d): BAT timeout", path));
1350  #endif
1351  // finished with the filter - release it and flag BAT complete
1352  bat_complete[path] = TRUE;
1353  STB_SICancelTableRequest(bat_filter[path]);
1354  bat_filter[path] = NULL;
1355  bat_start_timestamp[path] = 0;
1356  break;
1357  }
1358 
1359  case APP_SI_EIT_RECEIVED:
1360  {
1361  #ifdef DEBUG_SI_CHAN_SEARCH
1362  AP_SI_PRINT(("Chan search(%d): EIT received (sid 0x%04x)", path, table_rec->xtid));
1363  #endif
1364  ProcessEitTable(table_rec, IGNORE_VERSION, DB_ACCESS_SEARCH, FALSE);
1365 
1366  // check if we have received all eits yet
1367  if (eit_list[path] != NULL)
1368  {
1369  eits_complete[path] = TRUE;
1370  for (i = 0; i < num_eit_list_entries[path]; i++)
1371  {
1372  if (eit_list[path][i].got_eit == FALSE)
1373  {
1374  eits_complete[path] = FALSE;
1375  break;
1376  }
1377  }
1378  }
1379  if (eits_complete[path] == TRUE)
1380  {
1381  STB_SICancelTableRequest(eit_filter[path]);
1382  eit_filter[path] = NULL;
1383  eit_start_timestamp[path] = 0;
1384 
1385  STB_SICancelTableRequest(sched_filter[path]);
1386  sched_filter[path] = NULL;
1387  sched_start_timestamp[path] = 0;
1388  }
1389  break;
1390  }
1391 
1392  case APP_SI_EIT_TIMEOUT:
1393  {
1394  #ifdef DEBUG_SI_CHAN_SEARCH
1395  AP_SI_PRINT(("Chan search(%d): EIT timeout", path));
1396  #endif
1397  // finished with the filter - release it and flag nit complete
1398  eits_complete[path] = TRUE;
1399  if (eit_filter[path] != NULL)
1400  {
1401  STB_SICancelTableRequest(eit_filter[path]);
1402  eit_filter[path] = NULL;
1403  eit_start_timestamp[path] = 0;
1404 
1405  STB_SICancelTableRequest(sched_filter[path]);
1406  sched_filter[path] = NULL;
1407  sched_start_timestamp[path] = 0;
1408  }
1409  break;
1410  }
1411 
1412  case APP_SI_TOT_RECEIVED:
1413  case APP_SI_TOT_TIMEOUT:
1414  {
1415  if (event == APP_SI_TOT_RECEIVED)
1416  {
1417  #ifdef DEBUG_SI_CHAN_SEARCH
1418  AP_SI_PRINT(("Chan search(%d): TOT received", path));
1419  #endif
1420  ASI_ProcessTotTable(table_rec);
1421  }
1422  #ifdef DEBUG_SI_CHAN_SEARCH
1423  else
1424  {
1425  AP_SI_PRINT(("Chan search(%d): TOT timeout", path));
1426  }
1427  #endif
1428 
1429  // finished with the filter - release it and flag tot complete
1430  tot_complete[path] = TRUE;
1431  STB_SICancelTableRequest(tot_filter[path]);
1432  tot_filter[path] = NULL;
1433  tot_start_timestamp[path] = 0;
1434  break;
1435  }
1436 
1437  case APP_SI_TDT_RECEIVED:
1438  case APP_SI_TDT_TIMEOUT:
1439  {
1440  if (event == APP_SI_TDT_RECEIVED)
1441  {
1442  #ifdef DEBUG_SI_CHAN_SEARCH
1443  AP_SI_PRINT(("Chan search(%u): TDT received", path));
1444  #endif
1445 
1446  ASI_ProcessTdtTable(table_rec);
1447  }
1448  #ifdef DEBUG_SI_CHAN_SEARCH
1449  else
1450  {
1451  AP_SI_PRINT(("Chan search(%u): TDT timeout", path));
1452  }
1453  #endif
1454 
1455  /* Finished with the filter - release it and flag TOT complete
1456  * because it doesn't matter at this stage which has been seen */
1457  tot_complete[path] = TRUE;
1458  STB_SICancelTableRequest(tdt_filter[path]);
1459  tdt_filter[path] = NULL;
1460  tdt_start_timestamp[path] = 0;
1461  break;
1462  }
1463  }
1464 
1465  // check if search is complete - if so report fact
1466  if (finished || (sdt_complete[path] && nit_complete[path] && pmts_complete[path] &&
1467  eits_complete[path] && tot_complete[path] && bat_complete[path]))
1468  {
1469  if (current_transport_rec[path] != NULL)
1470  {
1471  UpdateTransportParameters(path);
1472  }
1473 
1474  // report end of search
1475  #ifdef DEBUG_SI_CHAN_SEARCH
1476  AP_SI_PRINT(("Chan search(%d): search complete", path));
1477  #endif
1478  CancelTableRequests(path, FALSE);
1479 
1480  success = (sdt_complete[path] && nit_complete[path] && pmts_complete[path] &&
1481  eits_complete[path] && tot_complete[path] && bat_complete[path]);
1482 
1483  STB_SISearchComplete(path, success, &current_transport_rec[path], sizeof(void *));
1484  finished = TRUE;
1485  }
1486  }
1487 
1488  FUNCTION_FINISH(ManageChannelSearch);
1489  return(finished);
1490 }
1491 
1506 static BOOLEAN ManageTotSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
1507 {
1508  BOOLEAN finished;
1509 
1510  FUNCTION_START(ManageTotSearch);
1511 
1512  finished = FALSE;
1513  if (event == APP_SI_START_MANAGER)
1514  {
1515  // first ensure there is a transport record for the transport we are tuned to and set
1516  // current transport accordingly
1517  current_transport_rec[path] = DBDEF_GetTunedTransport(path);
1518  if (current_transport_rec[path] != NULL)
1519  {
1520  #ifdef DEBUG_SI_TOT_SEARCH
1521  AP_SI_PRINT(("Tot search(%d): start (%s)", path,
1522  ACTL_GetRfNameFromFreq(current_transport_rec[path]->sig_type, current_transport_rec[path]->frequency)));
1523  #endif
1524 
1525  /* The TOT only needs to be requested once on startup,
1526  * so don't request it if it's already been received */
1527  if (tot_already_received[path])
1528  {
1529  tot_complete[path] = TRUE;
1530  finished = TRUE;
1531  STB_SISearchComplete(path, TRUE, NULL, 0);
1532  }
1533  else
1534  {
1535  // start search for tot
1536  tot_complete[path] = FALSE;
1537  tot_start_timestamp[path] = STB_OSGetClockMilliseconds();
1538  tot_filter[path] = STB_SIRequestTot(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
1539  }
1540  }
1541  else
1542  {
1543  #ifdef DEBUG_SI_TOT_SEARCH
1544  AP_SI_PRINT(("Tot search(%d): start - failed, no transport", path));
1545  #endif
1546  // report end of search
1547  STB_SISearchComplete(path, FALSE, NULL, 0);
1548  finished = TRUE;
1549  }
1550  }
1551  else if (event == APP_SI_STOP_MANAGER)
1552  {
1553  #ifdef DEBUG_SI_TOT_SEARCH
1554  AP_SI_PRINT(("Tot search(%d): stop", path));
1555  #endif
1556  CancelTableRequests(path, FALSE);
1557  finished = TRUE;
1558  }
1559  else
1560  {
1561  switch (event)
1562  {
1563  case APP_SI_TOT_RECEIVED:
1564  {
1565  #ifdef DEBUG_SI_TOT_SEARCH
1566  AP_SI_PRINT(("Tot search(%d): TOT received, search complete", path));
1567  #endif
1568  ASI_ProcessTotTable(table_rec);
1569  tot_already_received[path] = TRUE;
1570  STB_SISearchComplete(path, TRUE, NULL, 0);
1571  break;
1572  }
1573  case APP_SI_TOT_TIMEOUT:
1574  {
1575  #ifdef DEBUG_SI_TOT_SEARCH
1576  AP_SI_PRINT(("Tot search(%d): TOT timeout, search complete", path));
1577  #endif
1578  STB_SISearchComplete(path, FALSE, NULL, 0);
1579  }
1580  }
1581 
1582  finished = TRUE;
1583  // finished with the filter - release it and flag tot complete
1584  tot_complete[path] = TRUE;
1585  STB_SICancelTableRequest(tot_filter[path]);
1586  tot_filter[path] = NULL;
1587  tot_start_timestamp[path] = 0;
1588  }
1589 
1590  FUNCTION_FINISH(ManageTotSearch);
1591  return(finished);
1592 }
1593 
1610 static BOOLEAN ManageStartupSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
1611 {
1612  BOOLEAN finished;
1613  U16BIT i;
1614 
1615  FUNCTION_START(ManageStartupSearch);
1616 
1617  finished = FALSE;
1618  if (event == APP_SI_START_MANAGER)
1619  {
1620  // clear service list ready flag
1621  service_list_ready[path] = FALSE;
1622 
1623  // first ensure there is a transport record for the transport we are tuned to and set
1624  // current transport accordingly
1625  current_transport_rec[path] = DBDEF_GetTunedTransport(path);
1626  if (current_transport_rec[path] != NULL)
1627  {
1628  #ifdef DEBUG_SI_STARTUP_SEARCH
1629  AP_SI_PRINT(("Startup search(%d): start (%s)", path,
1630  ACTL_GetRfNameFromFreq(current_transport_rec[path]->sig_type, current_transport_rec[path]->frequency)));
1631  #endif
1632 
1633  current_network_rec[path] = current_transport_rec[path]->network;
1634  current_service_rec[path] = NULL;
1635 
1636  pat_rcvd_on_this_trnsprt[path] = FALSE;
1637  last_transport_rec[path] = NULL;
1638  pmts_complete[path] = FALSE;
1639  sdt_complete[path] = FALSE;
1640  eits_complete[path] = FALSE;
1641  tot_complete[path] = FALSE;
1642 
1643 #ifdef COMMON_INTERFACE
1644  /* Ensure the routing of the TS is correct for acquiring the SDT for CI+ */
1645  if (ACI_SetSecureRouting(path))
1646 #endif
1647  {
1648  // start search for sdt
1649  sdt_start_timestamp[path] = STB_OSGetClockMilliseconds();
1650  sdt_filter[path] = STB_SIRequestSdt(path, ONE_SHOT_REQUEST, TRUE, FALSE, DONT_CARE_ID_MATCH,
1651  DONT_CARE_ID_MASK, 1, ReceiveSiTable, APP_SI_SDT_RECEIVED);
1652 
1653  /* The TOT only needs to be requested once on startup,
1654  * so don't request it if it's already been received */
1655  if (tot_already_received[path])
1656  {
1657  tot_complete[path] = TRUE;
1658  }
1659  else
1660  {
1661  // start search for tot
1662  tot_start_timestamp[path] = STB_OSGetClockMilliseconds();
1663  tot_filter[path] = STB_SIRequestTot(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
1664  }
1665 
1666  // start search for PAT
1667  pat_start_timestamp[path] = STB_OSGetClockMilliseconds();
1668  pat_filter[path] = STB_SIRequestPat(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_PAT_RECEIVED);
1669  }
1670 #ifdef COMMON_INTERFACE
1671  else
1672  {
1673  #ifdef DEBUG_SI_STARTUP_SEARCH
1674  AP_SI_PRINT(("Startup search(%d): start - failed to route TS securely", path));
1675  #endif
1676  // report end of search
1677  STB_SISearchComplete(path, FALSE, NULL, 0);
1678  finished = TRUE;
1679  }
1680 #endif
1681  }
1682  else
1683  {
1684  #ifdef DEBUG_SI_STARTUP_SEARCH
1685  AP_SI_PRINT(("Startup search(%d): start - failed, no transport", path));
1686  #endif
1687  // report end of search
1688  STB_SISearchComplete(path, TRUE, NULL, 0);
1689  finished = TRUE;
1690  }
1691  }
1692  else if (event == APP_SI_STOP_MANAGER)
1693  {
1694  #ifdef DEBUG_SI_STARTUP_SEARCH
1695  AP_SI_PRINT(("Startup search(%d): stop", path));
1696  #endif
1697  CancelTableRequests(path, FALSE);
1698  finished = TRUE;
1699  }
1700  else
1701  {
1702  switch (event)
1703  {
1704  case APP_SI_SDT_RECEIVED:
1705  {
1706  #ifdef DEBUG_SI_STARTUP_SEARCH
1707  AP_SI_PRINT(("Startup search(%d): SDT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
1708  #endif
1709  ProcessSdtTable(table_rec, DB_ACCESS_UPDATE, IGNORE_VERSION, EIT_LIST_REQD);
1710 
1711  // start search for eits on current transport only. Prefer not to get eits until sdt
1712  // has been received so that the eit_list is available. However, if the sdt has not
1713  // arrived start looking for events and use the eit timeout to indicate when eits are
1714  // complete
1715  eit_start_timestamp[path] = STB_OSGetClockMilliseconds();
1716  eit_filter[path] = STB_SIRequestEit(path, ONE_SHOT_REQUEST, EIT_NOW_NEXT_ACT, DONT_CARE_ID_MATCH,
1717  DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
1718 
1719  // finished with the filter - release it and flag sdt complete
1720  sdt_complete[path] = TRUE;
1721  service_list_ready[path] = TRUE;
1722  STB_SICancelTableRequest(sdt_filter[path]);
1723  sdt_filter[path] = NULL;
1724  sdt_start_timestamp[path] = 0;
1725  break;
1726  }
1727 
1728  case APP_SI_SDT_TIMEOUT:
1729  #ifdef DEBUG_SI_STARTUP_SEARCH
1730  AP_SI_PRINT(("Startup search(%d): SDT timeout", path));
1731  #endif
1732 
1733  /* If the SDT hasn't been received then there's no point trying to collect the rest
1734  * of the tables. E.g. the number of EITs to be collected is determined by the number
1735  * of services defined in the SDT. This will also speed up initialisation of the box
1736  * as the TOT takes longer to timeout. */
1737  sdt_complete[path] = TRUE;
1738  pmts_complete[path] = TRUE;
1739  eits_complete[path] = TRUE;
1740  tot_complete[path] = TRUE;
1741 
1742  // finished with the filter - release it
1743  service_list_ready[path] = TRUE;
1744  STB_SICancelTableRequest(sdt_filter[path]);
1745  sdt_filter[path] = NULL;
1746  sdt_start_timestamp[path] = 0;
1747  break;
1748 
1749  case APP_SI_PAT_RECEIVED:
1750  case APP_SI_PAT_TIMEOUT:
1751  {
1752  if (event == APP_SI_PAT_RECEIVED)
1753  {
1754  #ifdef DEBUG_SI_STARTUP_SEARCH
1755  AP_SI_PRINT(("Startup search(%d): PAT received (tid 0x%04x)", path, table_rec->xtid));
1756  #endif
1757  ProcessPatTable(table_rec);
1758  if (pmt_list[path] != NULL)
1759  {
1760  pmt_list_id[path] = 0;
1761  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
1762  MakeNewPmtRequest(path);
1763  }
1764  else
1765  {
1766  pmts_complete[path] = TRUE;
1767  }
1768  }
1769  else
1770  {
1771  #ifdef DEBUG_SI_STARTUP_SEARCH
1772  AP_SI_PRINT(("Startup search(%d): PAT timeout", path));
1773  #endif
1774  pmts_complete[path] = TRUE;
1775  }
1776 
1777  // finished with the filter - release it
1778  STB_SICancelTableRequest(pat_filter[path]);
1779  pat_filter[path] = NULL;
1780  pat_start_timestamp[path] = 0;
1781  break;
1782  }
1783 
1784  case APP_SI_PMT_RECEIVED:
1785  case APP_SI_PMT_TIMEOUT:
1786  {
1787  if (event == APP_SI_PMT_RECEIVED)
1788  {
1789  #ifdef DEBUG_SI_STARTUP_SEARCH
1790  AP_SI_PRINT(("Startup search(%d): PMT received (sid 0x%04x)", path, table_rec->xtid));
1791  #endif
1792  // process the pmt (regardless of version and do not report to other parties)
1793  ProcessPmtTable(table_rec, IGNORE_VERSION, DONT_REPORT_PMT, NULL, FALSE);
1794  }
1795  #ifdef DEBUG_SI_STARTUP_SEARCH
1796  else
1797  {
1798  AP_SI_PRINT(("Startup search(%d): PMT timeout (sid 0x%04x)", path,
1799  pmt_list[path][pmt_list_id[path]].serv_id));
1800  }
1801  #endif
1802 
1803  if ((pmt_list_id[path] + 1) >= num_pmt_list_entries[path])
1804  {
1805  // finished list - release the filter and flag pmts complete
1806  pmts_complete[path] = TRUE;
1807  STB_SICancelTableRequest(pmt_filter[path]);
1808  pmt_filter[path] = NULL;
1809  pmt_start_timestamp[path] = 0;
1810  }
1811  else
1812  {
1813  // not finished yet - move on to next pmt...
1814  pmt_list_id[path]++;
1815  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
1816  MakeNewPmtRequest(path);
1817  }
1818  break;
1819  }
1820 
1821  case APP_SI_EIT_RECEIVED:
1822  {
1823  #ifdef DEBUG_SI_STARTUP_SEARCH
1824  AP_SI_PRINT(("Startup search(%d): EIT received (sid 0x%04x)", path, table_rec->xtid));
1825  #endif
1826  ProcessEitTable(table_rec, IGNORE_VERSION, DB_ACCESS_SEARCH, FALSE);
1827 
1828  // check if we have received all eits yet
1829  if (eit_list[path] != NULL)
1830  {
1831  eits_complete[path] = TRUE;
1832  for (i = 0; i < num_eit_list_entries[path]; i++)
1833  {
1834  if (eit_list[path][i].got_eit == FALSE)
1835  {
1836  eits_complete[path] = FALSE;
1837  break;
1838  }
1839  }
1840  }
1841  if (eits_complete[path] == TRUE)
1842  {
1843  STB_SICancelTableRequest(eit_filter[path]);
1844  eit_filter[path] = NULL;
1845  eit_start_timestamp[path] = 0;
1846 
1847  STB_SICancelTableRequest(sched_filter[path]);
1848  sched_filter[path] = NULL;
1849  sched_start_timestamp[path] = 0;
1850  }
1851  break;
1852  }
1853 
1854  case APP_SI_EIT_TIMEOUT:
1855  {
1856  #ifdef DEBUG_SI_STARTUP_SEARCH
1857  AP_SI_PRINT(("Startup search(%d): EIT timeout", path));
1858  #endif
1859  // finished with the filter - release it and flag nit complete
1860  eits_complete[path] = TRUE;
1861  if (eit_filter[path] != NULL)
1862  {
1863  STB_SICancelTableRequest(eit_filter[path]);
1864  eit_filter[path] = NULL;
1865  eit_start_timestamp[path] = 0;
1866  }
1867 
1868  if (sched_filter[path] != NULL)
1869  {
1870  STB_SICancelTableRequest(sched_filter[path]);
1871  sched_filter[path] = NULL;
1872  sched_start_timestamp[path] = 0;
1873  }
1874  break;
1875  }
1876 
1877  case APP_SI_TOT_RECEIVED:
1878  case APP_SI_TOT_TIMEOUT:
1879  {
1880  if (event == APP_SI_TOT_RECEIVED)
1881  {
1882  #ifdef DEBUG_SI_STARTUP_SEARCH
1883  AP_SI_PRINT(("Startup search(%d): TOT received", path));
1884  #endif
1885  ASI_ProcessTotTable(table_rec);
1886 
1887  tot_already_received[path] = TRUE;
1888  }
1889  #ifdef DEBUG_SI_STARTUP_SEARCH
1890  else
1891  {
1892  AP_SI_PRINT(("Startup search(%d): TOT timeout", path));
1893  }
1894  #endif
1895 
1896  // finished with the filter - release it and flag tot complete
1897  tot_complete[path] = TRUE;
1898  STB_SICancelTableRequest(tot_filter[path]);
1899  tot_filter[path] = NULL;
1900  tot_start_timestamp[path] = 0;
1901  break;
1902  }
1903  }
1904 
1905  // check if search is complete - if so report fact
1906  if (sdt_complete[path] && pmts_complete[path] && eits_complete[path] && tot_complete[path])
1907  {
1908  // report end of search
1909  #ifdef DEBUG_SI_STARTUP_SEARCH
1910  AP_SI_PRINT(("Startup search(%d): search complete", path));
1911  #endif
1912  CancelTableRequests(path, FALSE);
1913  STB_SISearchComplete(path, TRUE, NULL, 0);
1914  finished = TRUE;
1915  }
1916  }
1917 
1918  FUNCTION_FINISH(ManageStartupSearch);
1919  return(finished);
1920 }
1921 
1935 static BOOLEAN ManageEventSchedSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
1936 {
1937  BOOLEAN finished;
1938 
1939  FUNCTION_START(ManageEventSchedSearch);
1940 
1941  finished = FALSE;
1942  if (event == APP_SI_START_MANAGER)
1943  {
1944  // first ensure there is a transport record for the transport we are tuned to and set
1945  // current transport accordingly
1946  current_transport_rec[path] = DBDEF_GetTunedTransport(path);
1947  if (current_transport_rec[path] != NULL)
1948  {
1949  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
1950  AP_SI_PRINT(("Event sched search: start, freq %lu", current_transport_rec[path]->frequency));
1951  #endif
1952 
1953  // update transport fields
1954  current_network_rec[path] = current_transport_rec[path]->network;
1955  current_service_rec[path] = NULL;
1956 
1957  if ((required_si_mode[path] == APP_SI_MODE_EVENT_PF_SEARCH) ||
1958  (required_si_mode[path] == APP_SI_MODE_EVENT_PF_SCHED_SEARCH))
1959  {
1960  eit_start_timestamp[path] = STB_OSGetClockMilliseconds();
1961  eit_filter[path] = STB_SIRequestEit(path, ONE_SHOT_REQUEST, EIT_NOW_NEXT_ACT, DONT_CARE_ID_MATCH,
1962  DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
1963  }
1964 
1965  if ((required_si_mode[path] == APP_SI_MODE_EVENT_SCHED_SEARCH) ||
1966  (required_si_mode[path] == APP_SI_MODE_EVENT_PF_SCHED_SEARCH))
1967  {
1968  StartEITScheduleFilter(path);
1969  sched_start_timestamp[path] = STB_OSGetClockMilliseconds();
1970  sched_timeout_ms[path] = EVENT_SCHED_SEARCH_TIMEOUT_MS;
1971  }
1972  }
1973  else
1974  {
1975  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
1976  AP_SI_PRINT(("Event sched search: start - failed, no transport"));
1977  #endif
1978  // report end of search
1979  STB_SISearchComplete(path, TRUE, NULL, 0);
1980  finished = TRUE;
1981  }
1982  }
1983  else if (event == APP_SI_STOP_MANAGER)
1984  {
1985  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
1986  AP_SI_PRINT(("Event sched search: stop"));
1987  #endif
1988  CancelTableRequests(path, FALSE);
1989  finished = TRUE;
1990  }
1991  else
1992  {
1993  switch (event)
1994  {
1995  case APP_SI_EIT_RECEIVED:
1996  {
1997  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
1998  AP_SI_PRINT(("Event sched search: EIT 0x%02x received (sid 0x%04x)",
1999  table_rec->tid, table_rec->xtid));
2000  #endif
2001  ProcessEitTable(table_rec, IGNORE_VERSION, DB_ACCESS_UPDATE, FALSE);
2002 
2003  /* Reset the start time for the appropriate EIT data so the timeout doesn't occur */
2004  if ((eit_start_timestamp[path] != 0) &&
2005  ((table_rec->tid == EITPF_ACTUAL_TID) || (table_rec->tid == EITPF_PLUS_TID)))
2006  {
2007  eit_start_timestamp[path] = STB_OSGetClockMilliseconds();
2008  }
2009  else if (sched_start_timestamp[path] != 0)
2010  {
2011  sched_start_timestamp[path] = STB_OSGetClockMilliseconds();
2012  }
2013  break;
2014  }
2015 
2016  case APP_SI_EIT_TIMEOUT:
2017  {
2018  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
2019  AP_SI_PRINT(("Event sched search: EIT timeout"));
2020  #endif
2021  STB_SICancelTableRequest(eit_filter[path]);
2022  eit_filter[path] = NULL;
2023  eit_start_timestamp[path] = 0;
2024 
2025  if (sched_filter[path] == NULL)
2026  {
2027  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
2028  AP_SI_PRINT(("Event sched search: Search complete"));
2029  #endif
2030  /* Only EITp/f is being collected so the search is now finished */
2031  STB_SISearchComplete(path, TRUE, NULL, 0);
2032  finished = TRUE;
2033  }
2034  break;
2035  }
2036 
2037  case APP_SI_SCHED_TIMEOUT:
2038  {
2039  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
2040  AP_SI_PRINT(("Event sched search: Schedule timeout"));
2041  #endif
2042  STB_SICancelTableRequest(sched_filter[path]);
2043  sched_filter[path] = NULL;
2044  sched_start_timestamp[path] = 0;
2045 
2046  if (eit_filter[path] == NULL)
2047  {
2048  #ifdef DEBUG_SI_EVENT_SCHED_SEARCH
2049  AP_SI_PRINT(("Event sched search: Search complete"));
2050  #endif
2051  /* Only EITp/f is being collected so the search is now finished */
2052  STB_SISearchComplete(path, TRUE, NULL, 0);
2053  finished = TRUE;
2054  }
2055  break;
2056  }
2057  }
2058  }
2059 
2060  FUNCTION_FINISH(ManageEventSchedSearch);
2061  return(finished);
2062 }
2063 
2077 static BOOLEAN ManageUpdate(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
2078 {
2079  static BOOLEAN transport_changed;
2080  static BOOLEAN first_pmt;
2081  BOOLEAN finished;
2082  BOOLEAN pmt_list_changed;
2083  BOOLEAN sdt_changed;
2084  U16BIT serv_id;
2085 
2086  FUNCTION_START(ManageUpdate);
2087 
2088  finished = FALSE;
2089  switch (event)
2090  {
2091  case APP_SI_START_MANAGER:
2092  {
2093  current_service_rec[path] = ADB_GetTunedService(path);
2094  current_transport_rec[path] = DBDEF_GetTunedTransport(path);
2095  current_network_rec[path] = DBDEF_GetTunedNetwork(path);
2096 
2097  if (current_transport_rec[path] != NULL)
2098  {
2099  #ifdef DEBUG_SI_UPDATE
2100  AP_SI_PRINT(("Update(%d): start, freq %luHz, (%s)", path,
2101  current_transport_rec[path]->frequency,
2102  ACTL_GetRfNameFromFreq(current_transport_rec[path]->sig_type, current_transport_rec[path]->frequency)));
2103  #endif
2104 
2105  pat_rcvd_on_this_trnsprt[path] = FALSE;
2106  pmt_service_changed[path] = TRUE;
2107  report_pmt_allowed[path] = TRUE;
2108  pmt_reported[path] = FALSE;
2109  si_update_delay_timestamp[path] = STB_OSGetClockMilliseconds();
2110  }
2111 
2112  if (last_transport_rec[path] != current_transport_rec[path])
2113  {
2114  transport_changed = TRUE;
2115  last_transport_rec[path] = current_transport_rec[path];
2116  }
2117  else
2118  {
2119  transport_changed = FALSE;
2120  }
2121  break;
2122  }
2123 
2124  case APP_SI_STOP_MANAGER:
2125  {
2126  #ifdef DEBUG_SI_UPDATE
2127  AP_SI_PRINT(("Update(%d): stop", path));
2128  #endif
2129  CancelTableRequests(path, FALSE);
2130  ClearDynamicUpdates();
2131  finished = TRUE;
2132  break;
2133  }
2134 
2135  case APP_SI_UPDATE_DELAY_EXPIRED:
2136  {
2137  // start delay has expired - start filter requests...
2138  #ifdef DEBUG_SI_UPDATE
2139  AP_SI_PRINT(("Update(%d): start delay expired", path));
2140  #endif
2141  si_update_delay_timestamp[path] = 0;
2142 
2143  // start search for CAT, no timeout
2144  #ifdef DEBUG_SI_UPDATE
2145  AP_SI_PRINT(("Update(%d): requesting CAT", path));
2146  #endif
2147  cat_start_timestamp[path] = 0;
2148  cat_filter[path] = STB_SIRequestCat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_CAT_RECEIVED);
2149 
2150  // start search for PAT, no timeout
2151  #ifdef DEBUG_SI_UPDATE
2152  AP_SI_PRINT(("Update(%d): requesting PAT", path));
2153  #endif
2154  pat_start_timestamp[path] = 0;
2155  pat_filter[path] = STB_SIRequestPat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_PAT_RECEIVED);
2156 
2157  ASI_RestartSITables(path, !ADB_IsFreesatService(current_service_rec[path]));
2158 
2159  if (current_service_rec[path]->rct_pid != 0)
2160  {
2161 #ifdef DEBUG_SI_RCT
2162  AP_SI_PRINT(("Requesting RCT for service 0x%04x on PID %u",
2163  current_service_rec[path]->serv_id, current_service_rec[path]->rct_pid));
2164 #endif
2165  rct_filter[path] = STB_SIRequestRct(path, CONTINUOUS_REQUEST,
2166  current_service_rec[path]->rct_pid, ReceiveSiTable, APP_SI_RCT_RECEIVED);
2167  }
2168  break;
2169  }
2170 
2171  case APP_SI_CHANNEL_CHANGE:
2172  {
2173  #ifdef DEBUG_SI_UPDATE
2174  AP_SI_PRINT(("Update(%d): Channel changed", path));
2175  #endif
2176 
2177  // setup status - start pmt update timer for start delay, pmts will then be re-started by
2178  // APP_SI_PMT_UPDATE event
2179  current_service_rec[path] = ADB_GetTunedService(path);
2180  pmt_service_changed[path] = TRUE;
2181  report_pmt_allowed[path] = TRUE;
2182  pmt_reported[path] = FALSE;
2183  pmt_update_timestamp[path] = STB_OSGetClockMilliseconds();
2184  pmt_update_period_ms[path] = SI_UPDATE_DELAY_MS;
2185  break;
2186  }
2187 
2188  case APP_SI_STOP_PMT_REPORTING:
2189  {
2190  #ifdef DEBUG_SI_UPDATE
2191  AP_SI_PRINT(("Update(%d): Stop pmt reporting", path));
2192  #endif
2193 
2194  // stop getting pmts
2195  if (pmt_filter[path] != NULL)
2196  {
2197  STB_SICancelTableRequest(pmt_filter[path]);
2198  pmt_filter[path] = NULL;
2199  pmt_start_timestamp[path] = 0;
2200  pmt_update_timestamp[path] = 0;
2201  }
2202  break;
2203  }
2204 
2205  case APP_SI_PAT_RECEIVED:
2206  {
2207  /* Check it is the right pat - can sometimes get the pat for the previous transport.
2208  * But if the tran_id for the current transport hasn't been set, such as when tuning
2209  * to a dynamically added transport, maybe from a delivery system descriptor, then
2210  * just take the PAT as it is because the actual tran_id won't be known */
2211  if ((current_transport_rec[path]->tran_id != 0) &&
2212  (table_rec->xtid != current_transport_rec[path]->tran_id))
2213  {
2214  #ifdef DEBUG_SI_UPDATE
2215  AP_SI_PRINT(("Update(%d): Wrong PAT (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
2216  #endif
2217  STB_SIRestartTableRequest(pat_filter[path]);
2218  }
2219  else
2220  {
2221  #ifdef DEBUG_SI_UPDATE
2222  AP_SI_PRINT(("Update(%d): PAT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
2223  #endif
2224 
2225  // process the pat table to build the new pmt list
2226  pmt_list_changed = ProcessPatTable(table_rec);
2227  if (pmt_list_changed == TRUE)
2228  {
2229  if ((pmt_list[path] != NULL) && (report_pmt_allowed[path] == TRUE))
2230  {
2231  /* Find the current service in the pmt list and start pmt gathering
2232  * from that service */
2233  first_pmt = TRUE;
2234  pmt_list_id[path] = 0;
2235  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
2236  if (!MakeNewPmtRequest(path))
2237  {
2238  /* Service isn't in the PAT, so it isn't running */
2239  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION,
2240  EV_SERVICE_NOT_RUNNING, &path, sizeof(U8BIT));
2241  }
2242  }
2243  else
2244  {
2245  // no list anymore - cancel existing pmt filter
2246  if (pmt_filter[path] != NULL)
2247  {
2248  STB_SICancelTableRequest(pmt_filter[path]);
2249  pmt_filter[path] = NULL;
2250  pmt_start_timestamp[path] = 0;
2251  }
2252  }
2253 
2254  /* Restart the pat filter - if the transport id has changed the filter will have more
2255  * than one table record. Calling Restart will clear out the filter records and start
2256  * again. It will mean we recieve the current table again but ProcessPatTable checks
2257  * for version so next time pmt_list_changed will be false */
2258  STB_SIRestartTableRequest(pat_filter[path]);
2259  }
2260  }
2261  break;
2262  }
2263 
2264  case APP_SI_PMT_RECEIVED:
2265  case APP_SI_PMT_TIMEOUT:
2266  case APP_SI_PMT_UPDATE:
2267  {
2268  if (event == APP_SI_PMT_RECEIVED)
2269  {
2270  // process the pmt (if new version and report to other parties)
2271  #ifdef DEBUG_SI_UPDATE
2272  AP_SI_PRINT(("Update(%d): PMT received (sid 0x%04x)", path, table_rec->xtid));
2273  #endif
2274 
2275  if (ProcessPmtTable(table_rec, first_pmt, REPORT_PMT, &serv_id, DB_ACCESS_UPDATE) &&
2276  (serv_id == current_service_rec[path]->serv_id))
2277  {
2278  /* Acquire a CA descrambler if needed */
2279  if (ACA_AcquireCADescrambler(path, current_service_rec[path]))
2280  {
2281  /* The NIT, CAT and BAT need to be reported to the CA system, but
2282  * in some cases they're received before the CA descrambler has been
2283  * acquired, so the filters are reset to ensure they're received
2284  * again and can be reported */
2285  if (nit_filter[path] != NULL)
2286  {
2287  STB_SIRestartTableRequest(nit_filter[path]);
2288  }
2289  if (cat_filter[path] != NULL)
2290  {
2291  STB_SIRestartTableRequest(cat_filter[path]);
2292  }
2293  if (bat_filter[path] != NULL)
2294  {
2295  STB_SIRestartTableRequest(bat_filter[path]);
2296  }
2297  }
2298 
2299  /* PMT for current service has been received or updated,
2300  * start or restart monitoring the RCT */
2301  if (rct_filter[path] != NULL)
2302  {
2303 #ifdef DEBUG_SI_RCT
2304  AP_SI_PRINT(("Cancelling RCT request"));
2305 #endif
2306  STB_SICancelTableRequest(rct_filter[path]);
2307  rct_filter[path] = NULL;
2308  }
2309 
2310  if (current_service_rec[path]->rct_pid != 0)
2311  {
2312 #ifdef DEBUG_SI_RCT
2313  AP_SI_PRINT(("Requesting RCT for service 0x%04x on PID %u",
2314  serv_id, current_service_rec[path]->rct_pid));
2315 #endif
2316  rct_filter[path] = STB_SIRequestRct(path, CONTINUOUS_REQUEST,
2317  current_service_rec[path]->rct_pid, ReceiveSiTable, APP_SI_RCT_RECEIVED);
2318  }
2319 
2320 #ifdef INTEGRATE_HBBTV
2321  if (ait_filter[path] != NULL)
2322  {
2323  AP_SI_PRINT(("Cancelling AIT request"));
2324  STB_SICancelTableRequest(ait_filter[path]);
2325  ait_filter[path] = NULL;
2326  }
2327 
2328  if (current_service_rec[path]->ait_pid != 0)
2329  {
2330  ait_filter[path] = STB_SIRequestAit(path, CONTINUOUS_REQUEST,
2331  current_service_rec[path]->ait_pid, ReceiveSiTable, APP_SI_AIT_RECEIVED);
2332  }
2333 #endif
2334  }
2335 
2336 #ifdef INTEGRATE_HBBTV
2337  if ((ait_filter[path] == NULL) && (current_service_rec[path]->ait_pid != 0))
2338  {
2339  ait_filter[path] = STB_SIRequestAit(path, CONTINUOUS_REQUEST,
2340  current_service_rec[path]->ait_pid, ReceiveSiTable, APP_SI_AIT_RECEIVED);
2341  }
2342 #endif
2343 
2344  first_pmt = FALSE;
2345  pmt_update_timestamp[path] = STB_OSGetClockMilliseconds();
2346  pmt_update_period_ms[path] = PMT_UPDATE_MS;
2347  }
2348  else
2349  {
2350  #ifdef DEBUG_SI_UPDATE
2351  if (event == APP_SI_PMT_TIMEOUT)
2352  {
2353  AP_SI_PRINT(("Update(%d): PMT timeout (sid 0x%04x)", path,
2354  pmt_list[path][pmt_list_id[path]].serv_id));
2355  }
2356  #endif
2357 
2358  // move on to next pmt, wrap from last to first...
2359  if (pmt_list[path] != NULL)
2360  {
2361  if (pmt_filter[path] == NULL)
2362  {
2363  // restart pmt filtering for the new current service
2364  pmt_list_id[path] = 0;
2365  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
2366  }
2367  else
2368  {
2369  // move on to the next pmt
2370  if (pmt_request_mode[path] == PMT_REQUEST_CURRENT)
2371  {
2372  STB_OSSemaphoreWait(si_pmt_list_sem);
2373 
2374  if (pmt_priority_list[0] != INVALID_SERVICE_ID)
2375  {
2376  pmt_request_mode[path] = PMT_REQUEST_PRIORITY;
2377  }
2378  else
2379  {
2380  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
2381 
2382  pmt_list_id[path]++;
2383  if (pmt_list_id[path] >= num_pmt_list_entries[path])
2384  {
2385  pmt_list_id[path] = 0;
2386  }
2387  }
2388 
2389  STB_OSSemaphoreSignal(si_pmt_list_sem);
2390  }
2391  else if (pmt_request_mode[path] == PMT_REQUEST_PRIORITY)
2392  {
2393  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
2394 
2395  pmt_list_id[path]++;
2396  if (pmt_list_id[path] >= num_pmt_list_entries[path])
2397  {
2398  pmt_list_id[path] = 0;
2399  }
2400  }
2401  else
2402  {
2403  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
2404  }
2405  }
2406  MakeNewPmtRequest(path);
2407  }
2408  else
2409  {
2410  pmt_start_timestamp[path] = 0;
2411  pmt_update_timestamp[path] = 0;
2412  }
2413  }
2414  break;
2415  }
2416 
2417  case APP_SI_NIT_RECEIVED:
2418  {
2419  #ifdef DEBUG_SI_UPDATE
2420  AP_SI_PRINT(("Update(%u): NIT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
2421  #endif
2422  if (ProcessNitTable(table_rec, DB_ACCESS_UPDATE, TRUE, transport_changed))
2423  {
2424  /* The NIT has changed so restart collection of the SDTs to get any updates */
2425  #ifdef DEBUG_SI_UPDATE
2426  AP_SI_PRINT(("Update(%u): NIT changed; restarting SDT collection", path));
2427  #endif
2428  ASI_RestartSdtFilter(path);
2429  }
2430  break;
2431  }
2432 
2433  case APP_SI_SDT_RECEIVED:
2434  {
2435  #ifdef DEBUG_SI_UPDATE
2436  AP_SI_PRINT(("Update(%d): SDT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
2437  #endif
2438  sdt_changed = ProcessSdtTable(table_rec, DB_ACCESS_UPDATE, CHECK_VERSION, EIT_LIST_NOT_REQD);
2439  if (sdt_changed)
2440  {
2441  // restart the sdt filter - if the transport id has changed the filter will have more
2442  // than one table record. Calling Restart will clear out the filter records and start
2443  // again. It will mean we recieve the current table again but ProcessSdtTable checks
2444  // for version so next time sdt_changed will be false
2445  STB_SIRestartTableRequest(sdt_filter[path]);
2446  }
2447  break;
2448  }
2449 
2450  case APP_SI_EIT_RECEIVED:
2451  {
2452  #ifdef DEBUG_SI_UPDATE
2453  AP_SI_PRINT(("Update(%d): EIT received (sid 0x%04x)", path, table_rec->xtid));
2454  #endif
2455  ProcessEitTable(table_rec, CHECK_VERSION, DB_ACCESS_UPDATE, FALSE);
2456  break;
2457  }
2458 
2459  case APP_SI_TDT_RECEIVED:
2460  {
2461  #ifdef DEBUG_SI_UPDATE
2462  AP_SI_PRINT(("Update(%d): TDT received", path));
2463  #endif
2464 
2465  ASI_ProcessTdtTable(table_rec);
2466 
2467  // finished with the filter - release it and flag tdt complete
2468  STB_SICancelTableRequest(tdt_filter[path]);
2469  tdt_filter[path] = NULL;
2470  tdt_start_timestamp[path] = 0;
2471  break;
2472  }
2473 
2474  case APP_SI_TOT_RECEIVED:
2475  {
2476  // this is only used in DTG test
2477  #ifdef DEBUG_SI_UPDATE
2478  AP_SI_PRINT(("Update(%d): TOT received", path));
2479  #endif
2480  ASI_ProcessTotTable(table_rec);
2481  break;
2482  }
2483 
2484  case APP_SI_CAT_RECEIVED:
2485  case APP_SI_CAT_TIMEOUT:
2486  {
2487  if (event == APP_SI_CAT_RECEIVED)
2488  {
2489  // process the cat (if new version or transport - and report to other parties)
2490  #ifdef DEBUG_SI_UPDATE
2491  AP_SI_PRINT(("Update(%d): CAT received", path));
2492  #endif
2493  ProcessCatTable(path, table_rec, REPORT_CAT, transport_changed);
2494  }
2495  #ifdef DEBUG_SI_UPDATE
2496  else
2497  {
2498  AP_SI_PRINT(("Update(%d): CAT timeout", path));
2499  }
2500  #endif
2501  break;
2502  }
2503 
2504  case APP_SI_RCT_RECEIVED:
2505  {
2506 #ifdef DEBUG_SI_RCT
2507  AP_SI_PRINT(("Update(%u): RCT received", path));
2508 #endif
2509  ProcessRctTable(table_rec);
2510  break;
2511  }
2512 
2513  case APP_SI_SCHED_TIMEOUT:
2514  {
2515  /* EIT schedule filter needs to be restarted to force events to be re-received */
2516  STB_SICancelTableRequest(sched_filter[path]);
2517  sched_filter[path] = NULL;
2518  sched_start_timestamp[path] = 0;
2519  StartEITScheduleFilter(path);
2520  break;
2521  }
2522 
2523  case APP_SI_BAT_RECEIVED:
2524  {
2525  #ifdef DEBUG_SI_UPDATE
2526  AP_SI_PRINT(("Update(%u): BAT received (bouquet id 0x%04x, v%d)", path, table_rec->xtid, table_rec->version));
2527  #endif
2528  if (ProcessBatTable(table_rec, DB_ACCESS_UPDATE, TRUE))
2529  {
2530  /* The BAT has changed so restart collection of the SDTs to get any updates */
2531  #ifdef DEBUG_SI_UPDATE
2532  AP_SI_PRINT(("Update(%u): BAT changed; restarting SDT collection", path));
2533  #endif
2534  ASI_RestartSdtFilter(path);
2535  }
2536  break;
2537  }
2538 #ifdef INTEGRATE_HBBTV
2539  case APP_SI_AIT_RECEIVED:
2540  {
2541  U16BIT i;
2542  SI_SECTION_RECORD *section;
2543 
2544  #ifdef DEBUG_SI_UPDATE
2545  AP_SI_PRINT(("Update(%u): AIT received (test:%d,type:0x%04x, v%d)", path,
2546  table_rec->xtid >> 15, table_rec->xtid & 0x7F, table_rec->version));
2547  #endif
2548 
2549  section = table_rec->section_list;
2550  for (i = 0; (i < table_rec->num_sect) && (section != NULL); i++)
2551  {
2552  HBBTV_ProcessAitSection(current_service_rec[path]->serv_id, &(section->data_start), section->data_len);
2553  section = section->next;
2554  }
2555  break;
2556  }
2557 #endif
2558  }
2559 
2560  FUNCTION_FINISH(ManageUpdate);
2561 
2562  return(finished);
2563 }
2564 
2565 static void StartEITScheduleFilter(U8BIT path)
2566 {
2567  E_SI_SCHED_TABLE_REQ sched_table_req;
2568 
2569  if ((eit_schedule_limit == 0) || (eit_schedule_limit >= 8 * 24))
2570  {
2571  #ifdef DEBUG_SI_UPDATE
2572  AP_SI_PRINT(("Update(%d): requesting SCHED all", path));
2573  #endif
2574  sched_table_req = EIT_SCHED_ALL;
2575  sched_start_timestamp[path] = 0;
2576  sched_timeout_ms[path] = 0;
2577  }
2578  else if (eit_schedule_limit < 4 * 24)
2579  {
2580  #ifdef DEBUG_SI_UPDATE
2581  AP_SI_PRINT(("Update(%d): requesting SCHED 4 day", path));
2582  #endif
2583  sched_table_req = EIT_SCHED_ALL_4DAY;
2584  sched_start_timestamp[path] = STB_OSGetClockMilliseconds();
2585  sched_timeout_ms[path] = SCHED_TIMEOUT_MS;
2586  }
2587  else
2588  {
2589  #ifdef DEBUG_SI_UPDATE
2590  AP_SI_PRINT(("Update(%d): requesting SCHED 8 day", path));
2591  #endif
2592  sched_table_req = EIT_SCHED_ALL_8DAY;
2593  sched_start_timestamp[path] = STB_OSGetClockMilliseconds();
2594  sched_timeout_ms[path] = SCHED_TIMEOUT_MS;
2595  }
2596 
2597  /* Start search for eits on all transports, no timeout */
2598  sched_filter[path] = STB_SIRequestSched(path, CONTINUOUS_REQUEST, sched_table_req,
2599  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
2600 }
2601 
2615 static BOOLEAN ManageUpdatePlayback(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
2616 {
2617  BOOLEAN finished;
2618  BOOLEAN pmt_list_changed;
2619  BOOLEAN service_updated;
2620  U8BIT *pmt_data;
2621  U16BIT pmt_data_len;
2622  U16BIT *ca_ids;
2623  U16BIT num_ca_ids;
2624 
2625  FUNCTION_START(ManageUpdatePlayback);
2626 
2627  finished = FALSE;
2628  switch (event)
2629  {
2630  case APP_SI_START_MANAGER:
2631  {
2632  current_service_rec[path] = APVR_GetPlaybackService();
2633 
2634  /* Reset the table versions */
2635  last_playback_pmt_version = -1;
2636  last_playback_pat_version = -1;
2637 
2638  #ifdef DEBUG_SI_PLAYBACK
2639  AP_SI_PRINT(("UpdatePlayback(%d): start (playback service = %p)", path, current_service_rec[path]));
2640  #endif
2641 
2642  pat_rcvd_on_this_trnsprt[path] = FALSE;
2643  pmt_service_changed[path] = TRUE;
2644  report_pmt_allowed[path] = TRUE;
2645  pmt_reported[path] = FALSE;
2646  si_update_delay_timestamp[path] = 0;
2647 
2648  /* Start search for CAT, no timeout */
2649  cat_start_timestamp[path] = 0;
2650  cat_filter[path] = STB_SIRequestCat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_CAT_RECEIVED);
2651 
2652  /* Start search for PAT, no timeout */
2653  pmt_filter_pid[path] = 0;
2654  pat_start_timestamp[path] = 0;
2655  pat_filter[path] = STB_SIRequestPat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_PAT_RECEIVED);
2656 
2657  /* Start search for eits on all transports, no timeout */
2658  eit_start_timestamp[path] = 0;
2659  eit_filter[path] = STB_SIRequestEit(path, CONTINUOUS_REQUEST, EIT_NOW_NEXT_ACT,
2660  current_service_rec[path]->serv_id, 0xffff, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
2661  break;
2662  }
2663 
2664  case APP_SI_STOP_MANAGER:
2665  {
2666  #ifdef DEBUG_SI_PLAYBACK
2667  AP_SI_PRINT(("UpdatePlayback(%d): stop", path));
2668  #endif
2669  CancelTableRequests(path, FALSE);
2670  finished = TRUE;
2671  break;
2672  }
2673 
2674  case APP_SI_STOP_PMT_REPORTING:
2675  {
2676  #ifdef DEBUG_SI_PLAYBACK
2677  AP_SI_PRINT(("UpdatePlayback(%d): Stop pmt reporting", path));
2678  #endif
2679 
2680  // stop getting pmts
2681  if (pmt_filter[path] != NULL)
2682  {
2683  STB_SICancelTableRequest(pmt_filter[path]);
2684  pmt_filter[path] = NULL;
2685  pmt_start_timestamp[path] = 0;
2686  pmt_update_timestamp[path] = 0;
2687  }
2688  break;
2689  }
2690 
2691  case APP_SI_PAT_RECEIVED:
2692  {
2693  #ifdef DEBUG_SI_PLAYBACK
2694  AP_SI_PRINT(("UpdatePlayback(%d): PAT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
2695  #endif
2696 
2697  // process the pat table to build the new pmt list
2698  pmt_list_changed = ProcessPatTablePlayback(table_rec);
2699  if (pmt_list_changed == TRUE)
2700  {
2701  if (pmt_filter[path] != NULL)
2702  {
2703  STB_SICancelTableRequest(pmt_filter[path]);
2704  pmt_filter[path] = NULL;
2705  }
2706 
2707  /* ProcessPatTablePlayback has saved the pmt pid we're interested in */
2708  pmt_filter[path] = STB_SIRequestPmt(path, CONTINUOUS_REQUEST, pmt_filter_pid[path],
2709  current_service_rec[path]->serv_id, 0xffff, 0xffff, ReceiveSiTable, APP_SI_PMT_RECEIVED);
2710 
2711  // restart the pat filter - if the transport id has changed the filter will have more
2712  // than one table record. Calling Restart will clear out the filter records and start
2713  // again. It will mean we recieve the current table again but ProcessPatTable checks
2714  // for version so next time pmt_list_changed will be false
2715  STB_SIRestartTableRequest(pat_filter[path]);
2716  }
2717  break;
2718  }
2719 
2720  case APP_SI_PMT_RECEIVED:
2721  case APP_SI_PMT_TIMEOUT:
2722  case APP_SI_PMT_UPDATE:
2723  {
2724  if (event == APP_SI_PMT_RECEIVED)
2725  {
2726  // process the pmt (if new version and report to other parties)
2727  #ifdef DEBUG_SI_PLAYBACK
2728  AP_SI_PRINT(("UpdatePlayback(%d): PMT received", path));
2729  #endif
2730 
2731  service_updated = ProcessPmtTable(table_rec, CHECK_VERSION, REPORT_PMT, NULL, DB_ACCESS_PLAYBACK);
2732  if (service_updated && (current_service_rec[path] != NULL))
2733  {
2734  if ((pmt_data = ADB_GetServicePMTData(current_service_rec[path], &pmt_data_len)) != NULL)
2735  {
2736  /* Get the CA system IDs from the PMT */
2737  if ((num_ca_ids = STB_SIGetPmtCaIdDescArray(pmt_data, &ca_ids)) != 0)
2738  {
2739  /* Check whether the CA system needs to be involved in the playback */
2740  if (STB_CADescramblerRequiredForPlayback(ca_ids, num_ca_ids))
2741  {
2742  /* Acquire a CA descrambler if needed */
2743  if (ACA_AcquireCADescrambler(path, current_service_rec[path]))
2744  {
2745  /* The NIT, CAT and BAT need to be reported to the CA system, but in
2746  * some cases they're received before the CA descrambler has been
2747  * acquired, so the filters are reset to ensure they're received
2748  * again and can be reported */
2749  STB_SIRestartTableRequest(nit_filter[path]);
2750  STB_SIRestartTableRequest(cat_filter[path]);
2751  if (bat_filter[path] != NULL)
2752  {
2753  STB_SIRestartTableRequest(bat_filter[path]);
2754  }
2755  }
2756  }
2757 
2758  STB_SIReleaseCaIdDescArray(ca_ids, (U8BIT)num_ca_ids);
2759  }
2760  }
2761  }
2762 
2763  pmt_update_timestamp[path] = 0;
2764  }
2765  else
2766  {
2767  #ifdef DEBUG_SI_PLAYBACK
2768  if (event == APP_SI_PMT_TIMEOUT)
2769  {
2770  AP_SI_PRINT(("UpdatePlayback(%d): PMT timeout", path));
2771  }
2772  else
2773  {
2774  AP_SI_PRINT(("UpdatePlayback(%d): #1# PMT update", path));
2775  }
2776  #endif
2777  }
2778  break;
2779  }
2780 
2781  case APP_SI_EIT_RECEIVED:
2782  {
2783  #ifdef DEBUG_SI_PLAYBACK
2784  AP_SI_PRINT(("UpdatePlayback(%d): EIT received (sid 0x%04x)", path, table_rec->xtid));
2785  #endif
2786  ProcessEitTable(table_rec, CHECK_VERSION, DB_ACCESS_UPDATE, TRUE);
2787  break;
2788  }
2789 
2790  case APP_SI_CAT_RECEIVED:
2791  case APP_SI_CAT_TIMEOUT:
2792  {
2793  if (event == APP_SI_CAT_RECEIVED)
2794  {
2795  // process the cat (if new version or transport - and report to other parties)
2796  #ifdef DEBUG_SI_PLAYBACK
2797  AP_SI_PRINT(("UpdatePlayback(%d): CAT received", path));
2798  #endif
2799  ProcessCatTable(path, table_rec, REPORT_CAT, FALSE);
2800  }
2801  #ifdef DEBUG_SI_PLAYBACK
2802  else
2803  {
2804  AP_SI_PRINT(("UpdatePlayback(%d): CAT timeout", path));
2805  }
2806  #endif
2807 
2808  break;
2809  }
2810  }
2811 
2812  FUNCTION_FINISH(ManageUpdatePlayback);
2813  return(finished);
2814 }
2815 
2816 #ifdef COMMON_INTERFACE
2817 /*!**************************************************************************
2818  * @brief Manages the CI+ search for the SDT using secure routing - i.e. not through
2819  * the CAM if it isn't a CI+ CAM - and then proceeds to the normal
2820  * update search when the SDT is received or times out.
2821  * @param path - decode path
2822  * @param event - event code
2823  * @param table_rec - SI table record to go with the event, may be NULL
2824  * @return TRUE if the search has finished, FALSE otherwise
2825  ****************************************************************************/
2826 static BOOLEAN ManageCIPlusUpdate(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
2827 {
2828  BOOLEAN finished;
2829  BOOLEAN acquired;
2830  SI_SECTION_RECORD *section_rec;
2831  U8BIT *data_ptr;
2832 
2833  FUNCTION_START(ManageCIPlusUpdate);
2834 
2835  finished = FALSE;
2836 
2837  switch (event)
2838  {
2839  case APP_SI_START_MANAGER:
2840  {
2841  current_service_rec[path] = ADB_GetTunedService(path);
2842  current_transport_rec[path] = ADB_GetTunedTransport(path);
2843 
2844  #ifdef DEBUG_CI_SI_UPDATE
2845  AP_SI_PRINT(("CI+ update(%u): start for sid 0x%04x", path, current_service_rec[path]->serv_id));
2846  #endif
2847 
2848  if (ACI_SetSecureRouting(path))
2849  {
2850  /* Can now request the SDT for the service */
2851  #ifdef DEBUG_CI_SI_UPDATE
2852  AP_SI_PRINT(("CI+ update(%u): Requesting SDT for tid 0x%04x", path,
2853  current_transport_rec[path]->tran_id));
2854  #endif
2855 
2857  sdt_start_timestamp[path] = STB_OSGetClockMilliseconds();
2858  sdt_filter[path] = STB_SIRequestSdt(path, CONTINUOUS_REQUEST, TRUE, FALSE,
2859  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 1, ReceiveSiTable, APP_SI_SDT_RECEIVED);
2860  }
2861  break;
2862  }
2863 
2864  case APP_SI_STOP_MANAGER:
2865  {
2866  #ifdef DEBUG_CI_SI_UPDATE
2867  AP_SI_PRINT(("CI+ update(%u): stop", path));
2868  #endif
2869  CancelTableRequests(path, FALSE);
2870  finished = TRUE;
2871  break;
2872  }
2873 
2874  case APP_SI_SDT_RECEIVED:
2875  {
2876  #ifdef DEBUG_CI_SI_UPDATE
2877  AP_SI_PRINT(("CI+ update(%u): SDT received (tid 0x%04x v%d)", path, table_rec->xtid,
2878  table_rec->version));
2879  #endif
2880 
2881  if (!current_transport_rec[path]->sdt_received)
2882  {
2884  DBA_LockDatabase();
2885 
2886  /* New transport added by a CICAM+ tuning command, update IDs before parsing the table */
2887  current_transport_rec[path]->tran_id = table_rec->xtid;
2888  DBA_SetFieldValue(current_transport_rec[path]->dba_rec, DBA_FIELD_TRANSPORT_ID,
2889  current_transport_rec[path]->tran_id);
2890 
2891  section_rec = table_rec->section_list;
2892  data_ptr = &(section_rec->data_start) + 8;
2893  current_transport_rec[path]->orig_net_id = (data_ptr[0] << 8) | data_ptr[1];
2894  DBA_SetFieldValue(current_transport_rec[path]->dba_rec, DBA_FIELD_ORIG_NET_ID,
2895  current_transport_rec[path]->orig_net_id);
2896 
2897  current_transport_rec[path]->sdt_received = TRUE;
2898 
2899  DBA_SaveRecord(current_transport_rec[path]->dba_rec);
2900  DBA_SaveDatabase();
2901 
2904  }
2905 
2906  ProcessSdtTable(table_rec, DB_ACCESS_UPDATE, IGNORE_VERSION, EIT_LIST_NOT_REQD);
2908 
2909  /* Check whether the SDT for the current service has now been received */
2910  if (ADB_GetServiceSDTReceived(current_service_rec[path]))
2911  {
2912  STB_SICancelTableRequest(sdt_filter[path]);
2913  sdt_filter[path] = NULL;
2914  sdt_start_timestamp[path] = 0;
2915 
2916  /* Now need to re-evaluate the CAM requirements for the path */
2917  acquired = ACI_AcquireCISlot(path, current_service_rec[path]);
2918 
2919  if (!acquired)
2920  {
2921  /* Acquire a CA descrambler if needed */
2922  if (ACA_AcquireCADescrambler(path, current_service_rec[path]))
2923  {
2924  /* The NIT, CAT and BAT need to be reported to the CA system, but in
2925  * some cases they're received before the CA descrambler has been
2926  * acquired, so the filters are reset to ensure they're received
2927  * again and can be reported */
2928  STB_SIRestartTableRequest(nit_filter[path]);
2929  STB_SIRestartTableRequest(cat_filter[path]);
2930  if (bat_filter[path] != NULL)
2931  {
2932  STB_SIRestartTableRequest(bat_filter[path]);
2933  }
2934  }
2935  }
2936 
2937  /* Now continue with normal update manager */
2938  #ifdef DEBUG_CI_SI_UPDATE
2939  AP_SI_PRINT(("CI+ update(%u): start update", path));
2940  #endif
2941  current_manager[path] = ManageUpdate;
2942  finished = ManageUpdate(path, APP_SI_START_MANAGER, NULL);
2943  if (finished)
2944  {
2945  current_manager[path] = NULL;
2946  STB_SISearchComplete(path, TRUE, NULL, 0);
2947  }
2948  }
2949  #ifdef DEBUG_CI_SI_UPDATE
2950  else
2951  {
2952  AP_SI_PRINT(("CI+ update(%u): required SDT not yet received, continue", path));
2953  }
2954  #endif
2955  break;
2956  }
2957 
2958  case APP_SI_SDT_TIMEOUT:
2959  {
2960  #ifdef DEBUG_CI_SI_UPDATE
2961  AP_SI_PRINT(("CI+ update(%u): SDT timeout", path));
2962  #endif
2963 
2965 
2966  STB_SICancelTableRequest(sdt_filter[path]);
2967  sdt_filter[path] = NULL;
2968  sdt_start_timestamp[path] = 0;
2969 
2970  /* Failed to receive the SDT, in which case the service can still be presented,
2971  * so now need to re-evaluate the CAM requirements for the path */
2972  acquired = ACI_AcquireCISlot(path, current_service_rec[path]);
2973 
2974  if (!acquired)
2975  {
2976  /* Acquire a CA descrambler if needed */
2977  if (ACA_AcquireCADescrambler(path, current_service_rec[path]))
2978  {
2979  /* The NIT, CAT and BAT need to be reported to the CA system, but in
2980  * some cases they're received before the CA descrambler has been
2981  * acquired, so the filters are reset to ensure they're received
2982  * again and can be reported */
2983  STB_SIRestartTableRequest(nit_filter[path]);
2984  STB_SIRestartTableRequest(cat_filter[path]);
2985  if (bat_filter[path] != NULL)
2986  {
2987  STB_SIRestartTableRequest(bat_filter[path]);
2988  }
2989  }
2990  }
2991 
2992  /* Now continue with normal update manager */
2993  #ifdef DEBUG_CI_SI_UPDATE
2994  AP_SI_PRINT(("CI+ update(%u): start update", path));
2995  #endif
2996  current_manager[path] = ManageUpdate;
2997  finished = ManageUpdate(path, APP_SI_START_MANAGER, NULL);
2998  if (finished)
2999  {
3000  current_manager[path] = NULL;
3001  STB_SISearchComplete(path, FALSE, NULL, 0);
3002  }
3003  break;
3004  }
3005  }
3006 
3007  FUNCTION_FINISH(ManageCIPlusUpdate);
3008 
3009  return(finished);
3010 }
3011 
3012 /*!**************************************************************************
3013  * @brief Manages the CI+ search where the SDT has to be acquired using secure routing
3014  * and then monitors other SI tables but without PAT and PMT
3015  * @param path - decode path
3016  * @param event - event code
3017  * @param table_rec - SI table record to go with the event, may be NULL
3018  * @return TRUE if the search has finished, FALSE otherwise
3019  ****************************************************************************/
3020 static BOOLEAN ManageCIPlusNoPatPmt(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
3021 {
3022  BOOLEAN finished;
3023  BOOLEAN acquired;
3024 
3025  FUNCTION_START(ManageCIPlusNoPatPmt);
3026 
3027  finished = FALSE;
3028 
3029  switch (event)
3030  {
3031  case APP_SI_START_MANAGER:
3032  {
3033  current_service_rec[path] = ADB_GetTunedService(path);
3034  current_transport_rec[path] = ADB_GetTunedTransport(path);
3035 
3036  #ifdef DEBUG_CI_SI_UPDATE
3037  AP_SI_PRINT(("CI+ no PAT/PMT(%u): start for sid 0x%04x", path, current_service_rec[path]->serv_id));
3038  #endif
3039 
3040  if (ACI_SetSecureRouting(path))
3041  {
3042  /* Can now request the SDT for the service */
3043  #ifdef DEBUG_CI_SI_UPDATE
3044  AP_SI_PRINT(("CI+ no PAT/PMT(%u): Requesting SDT for tid 0x%04x", path,
3045  current_transport_rec[path]->tran_id));
3046  #endif
3047 
3048  sdt_start_timestamp[path] = STB_OSGetClockMilliseconds();
3049  sdt_filter[path] = STB_SIRequestSdt(path, CONTINUOUS_REQUEST, TRUE, FALSE,
3050  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 1, ReceiveSiTable, APP_SI_SDT_RECEIVED);
3051  }
3052  break;
3053  }
3054 
3055  case APP_SI_STOP_MANAGER:
3056  {
3057  #ifdef DEBUG_CI_SI_UPDATE
3058  AP_SI_PRINT(("CI+ no PAT/PMT(%u): stop", path));
3059  #endif
3060  CancelTableRequests(path, FALSE);
3061  finished = TRUE;
3062  break;
3063  }
3064 
3065  case APP_SI_SDT_RECEIVED:
3066  case APP_SI_SDT_TIMEOUT:
3067  {
3068  if (event == APP_SI_SDT_RECEIVED)
3069  {
3070  #ifdef DEBUG_CI_SI_UPDATE
3071  AP_SI_PRINT(("CI+ no PAT/PMT(%u): SDT received (tid 0x%04x v%d)", path, table_rec->xtid,
3072  table_rec->version));
3073  #endif
3074 
3075  ProcessSdtTable(table_rec, DB_ACCESS_UPDATE, IGNORE_VERSION, EIT_LIST_NOT_REQD);
3076 
3077  /* Check whether the SDT for the current service has now been received */
3078  if (!ADB_GetServiceSDTReceived(current_service_rec[path]))
3079  {
3080  #ifdef DEBUG_CI_SI_UPDATE
3081  AP_SI_PRINT(("CI+ no PAT/PMT(%u): required SDT not yet received, continue search", path));
3082  #endif
3083  break;
3084  }
3085  }
3086  #ifdef DEBUG_CI_SI_UPDATE
3087  else /* APP_SI_SDT_TIMEOUT */
3088  {
3089  AP_SI_PRINT(("CI+ no PAT/PMT(%u): SDT timeout", path));
3090  }
3091  #endif
3092 
3093  STB_SICancelTableRequest(sdt_filter[path]);
3094  sdt_filter[path] = NULL;
3095  sdt_start_timestamp[path] = 0;
3096 
3097  /* Now need to re-evaluate the CAM requirements for the path */
3098  acquired = ACI_AcquireCISlot(path, current_service_rec[path]);
3099 
3100  if (!acquired)
3101  {
3102  /* Acquire a CA descrambler if needed */
3103  if (ACA_AcquireCADescrambler(path, current_service_rec[path]))
3104  {
3105  /* The NIT, CAT and BAT need to be reported to the CA system, but in
3106  * some cases they're received before the CA descrambler has been
3107  * acquired, so the filters are reset to ensure they're received
3108  * again and can be reported */
3109  STB_SIRestartTableRequest(nit_filter[path]);
3110  STB_SIRestartTableRequest(cat_filter[path]);
3111  if (bat_filter[path] != NULL)
3112  {
3113  STB_SIRestartTableRequest(bat_filter[path]);
3114  }
3115  }
3116  }
3117 
3118  /* Notify that the CI+ tune has completed successfully */
3119  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_CIPLUS_TUNE_COMPLETED, &path, sizeof(path));
3120 
3121  /* Now start monitoring other SI tables */
3122  #ifdef DEBUG_CI_SI_UPDATE
3123  AP_SI_PRINT(("CI+ no PAT/PMT(%u): starting other tables", path));
3124  #endif
3125 
3126  /* Start search for TDT and TOT, no timeout */
3127  tdt_start_timestamp[path] = 0;
3128  tdt_filter[path] = STB_SIRequestTdt(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TDT_RECEIVED);
3129  tot_start_timestamp[path] = 0;
3130  tot_filter[path] = STB_SIRequestTot(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
3131  break;
3132  }
3133 
3134  case APP_SI_TDT_RECEIVED:
3135  {
3136  #ifdef DEBUG_CI_SI_UPDATE
3137  AP_SI_PRINT(("CI+ no PAT/PMT(%d): TDT received", path));
3138  #endif
3139 
3140  ASI_ProcessTdtTable(table_rec);
3141 
3142  /* Finished with the filter so release it */
3143  STB_SICancelTableRequest(tdt_filter[path]);
3144  tdt_filter[path] = NULL;
3145  tdt_start_timestamp[path] = 0;
3146  break;
3147  }
3148 
3149  case APP_SI_TOT_RECEIVED:
3150  {
3151  #ifdef DEBUG_CI_SI_UPDATE
3152  AP_SI_PRINT(("CI+ no PAT/PMT(%d): TOT received", path));
3153  #endif
3154  ASI_ProcessTotTable(table_rec);
3155  break;
3156  }
3157  }
3158 
3159  FUNCTION_FINISH(ManageCIPlusNoPatPmt);
3160 
3161  return(finished);
3162 }
3163 
3164 #endif
3165 
3179 static BOOLEAN ManageRecording(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
3180 {
3181  BOOLEAN finished;
3182  U16BIT eit_pid;
3183 
3184  FUNCTION_START(ManageRecording);
3185 
3186  finished = FALSE;
3187 
3188  switch (event)
3189  {
3190  case APP_SI_START_MANAGER:
3191  {
3192  current_service_rec[path] = ADB_GetTunedService(path);
3193  current_transport_rec[path] = ADB_GetTunedTransport(path);
3194  if (current_transport_rec[path] != NULL)
3195  {
3196 #ifdef DEBUG_SI_RECORDING
3197  AP_SI_PRINT(("Recording(%u): start on transport %p (tid 0x%04x)", path,
3198  current_transport_rec[path], current_transport_rec[path]->tran_id));
3199 #endif
3200 
3201  pat_rcvd_on_this_trnsprt[path] = FALSE;
3202 
3203  // start search for CAT, no timeout
3204  cat_start_timestamp[path] = 0;
3205  cat_filter[path] = STB_SIRequestCat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_CAT_RECEIVED);
3206 
3207  /* Start search for PAT */
3208  pat_start_timestamp[path] = 0;
3209  pat_filter[path] = STB_SIRequestPat(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_PAT_RECEIVED);
3210 
3211  /* Start search for eit now/next just on this transport */
3212  if (ADB_IsFreesatService(current_service_rec[path]))
3213  {
3214  eit_pid = 0;
3215  if (current_service_rec[path]->eit_pf_plus_pid != 0)
3216  {
3217  eit_pid = current_service_rec[path]->eit_pf_plus_pid;
3218  }
3219  else if (current_service_rec[path]->eit_pf_pid != 0)
3220  {
3221  eit_pid = current_service_rec[path]->eit_pf_pid;
3222  }
3223 
3224  if (eit_pid != 0)
3225  {
3226  #ifdef DEBUG_SI_RECORDING
3227  AP_SI_PRINT(("Recording(%u): requesting EIT on PID %u", path, eit_pid));
3228  #endif
3229  eit_start_timestamp[path] = 0;
3230  eit_filter[path] = STB_SIRequestEitFromPid(path, eit_pid, CONTINUOUS_REQUEST, EIT_PF_PLUS,
3231  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
3232  }
3233  }
3234  else
3235  {
3236  eit_filter[path] = STB_SIRequestEit(path, CONTINUOUS_REQUEST, EIT_NOW_NEXT_ACT, DONT_CARE_ID_MATCH,
3237  DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
3238  }
3239  }
3240  break;
3241  }
3242 
3243  case APP_SI_STOP_MANAGER:
3244  {
3245 #ifdef DEBUG_SI_RECORDING
3246  AP_SI_PRINT(("Recording(%d): stop", path));
3247 #endif
3248  CancelTableRequests(path, FALSE);
3249  finished = TRUE;
3250  break;
3251  }
3252 
3253  case APP_SI_CAT_RECEIVED:
3254  case APP_SI_CAT_TIMEOUT:
3255  {
3256  if (event == APP_SI_CAT_RECEIVED)
3257  {
3258  // process the cat (if new version or transport - and report to other parties)
3259  #ifdef DEBUG_SI_RECORDING
3260  AP_SI_PRINT(("Recording(%d): CAT received", path));
3261  #endif
3262  ProcessCatTable(path, table_rec, REPORT_CAT, FALSE);
3263  }
3264  #ifdef DEBUG_SI_RECORDING
3265  else
3266  {
3267  AP_SI_PRINT(("recording(%d): CAT timeout", path));
3268  }
3269  #endif
3270  break;
3271  }
3272 
3273  case APP_SI_PAT_RECEIVED:
3274  {
3275  /* Check it is the right PAT */
3276  if (table_rec->xtid != current_transport_rec[path]->tran_id)
3277  {
3278 #ifdef DEBUG_SI_RECORDING
3279  AP_SI_PRINT(("Recording(%d): Wrong PAT (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
3280 #endif
3281  STB_SIRestartTableRequest(pat_filter[path]);
3282  }
3283  else
3284  {
3285 #ifdef DEBUG_SI_RECORDING
3286  AP_SI_PRINT(("Recording(%d): PAT received (tid 0x%04x v%d)", path, table_rec->xtid, table_rec->version));
3287 #endif
3288 
3289  /* Process the PAT table to build the new PMT list */
3290  if (ProcessPatTable(table_rec))
3291  {
3292  if (pmt_list[path] != NULL)
3293  {
3294  /* Find the current service in the pmt list and start pmt gathering from that service */
3295  pmt_list_id[path] = 0;
3296  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
3297  MakeNewPmtRequest(path);
3298  }
3299  else
3300  {
3301  /* No list anymore - cancel existing pmt filter */
3302  if (pmt_filter[path] != NULL)
3303  {
3304  STB_SICancelTableRequest(pmt_filter[path]);
3305  pmt_filter[path] = NULL;
3306  pmt_start_timestamp[path] = 0;
3307  }
3308  }
3309 
3310  /* Restart the pat filter - if the transport id has changed the filter will have more
3311  * than one table record. Calling Restart will clear out the filter records and start
3312  * again. It will mean we receive the current table again but ProcessPatTable checks
3313  * for version so next time pmt_list_changed will be false */
3314  STB_SIRestartTableRequest(pat_filter[path]);
3315  }
3316  }
3317  break;
3318  }
3319 
3320  case APP_SI_PMT_RECEIVED:
3321  case APP_SI_PMT_TIMEOUT:
3322  case APP_SI_PMT_UPDATE:
3323  {
3324  if (event == APP_SI_PMT_RECEIVED)
3325  {
3326  /* Process the pmt */
3327 #ifdef DEBUG_SI_RECORDING
3328  AP_SI_PRINT(("Recording(%d): PMT received (sid 0x%04x)", path, table_rec->xtid));
3329 #endif
3330  ProcessPmtTable(table_rec, CHECK_VERSION, DONT_REPORT_PMT, NULL, DB_ACCESS_UPDATE);
3331  pmt_update_timestamp[path] = STB_OSGetClockMilliseconds();
3332  pmt_update_period_ms[path] = PMT_UPDATE_MS;
3333  }
3334  else
3335  {
3336 #ifdef DEBUG_SI_RECORDING
3337  if (event == APP_SI_PMT_TIMEOUT)
3338  {
3339  AP_SI_PRINT(("Recording(%d): PMT timeout (sid 0x%04x)", path,
3340  pmt_list[path][pmt_list_id[path]].serv_id));
3341  }
3342  else
3343  {
3344  AP_SI_PRINT(("Recording(%d): PMT update", path));
3345  }
3346 #endif
3347 
3348  /* Move on to next pmt, wrap from last to first */
3349  if (pmt_list[path] != NULL)
3350  {
3351  if (pmt_filter[path] == NULL)
3352  {
3353  // restart pmt filtering for the new current service
3354  pmt_list_id[path] = 0;
3355  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
3356  }
3357  else
3358  {
3359  // move on to the next pmt
3360  if (pmt_request_mode[path] == PMT_REQUEST_CURRENT)
3361  {
3362  STB_OSSemaphoreWait(si_pmt_list_sem);
3363 
3364  if (pmt_priority_list[0] != INVALID_SERVICE_ID)
3365  {
3366  pmt_request_mode[path] = PMT_REQUEST_PRIORITY;
3367  }
3368  else
3369  {
3370  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
3371 
3372  pmt_list_id[path]++;
3373  if (pmt_list_id[path] >= num_pmt_list_entries[path])
3374  {
3375  pmt_list_id[path] = 0;
3376  }
3377  }
3378 
3379  STB_OSSemaphoreSignal(si_pmt_list_sem);
3380  }
3381  else if (pmt_request_mode[path] == PMT_REQUEST_PRIORITY)
3382  {
3383  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
3384 
3385  pmt_list_id[path]++;
3386  if (pmt_list_id[path] >= num_pmt_list_entries[path])
3387  {
3388  pmt_list_id[path] = 0;
3389  }
3390  }
3391  else
3392  {
3393  pmt_request_mode[path] = PMT_REQUEST_CURRENT;
3394  }
3395  }
3396  MakeNewPmtRequest(path);
3397  }
3398  else
3399  {
3400  pmt_start_timestamp[path] = 0;
3401  pmt_update_timestamp[path] = 0;
3402  }
3403  }
3404  break;
3405  }
3406 
3407  case APP_SI_EIT_RECEIVED:
3408  {
3409 #ifdef DEBUG_SI_RECORDING
3410  AP_SI_PRINT(("Recording(%d): EIT received (sid 0x%04x)", path, table_rec->xtid));
3411 #endif
3412  ProcessEitTable(table_rec, CHECK_VERSION, DB_ACCESS_UPDATE, FALSE);
3413  break;
3414  }
3415  }
3416 
3417  FUNCTION_FINISH(ManageRecording);
3418 
3419  return(finished);
3420 }
3421 
3422 
3423 static BOOLEAN ValidServiceType(ADB_SERVICE_TYPE serv_type, BOOLEAN all_streams_free)
3424 {
3425  BOOLEAN valid_service;
3426 
3427  FUNCTION_START(ValidServiceType);
3428 
3429  valid_service = FALSE;
3430 
3431  if (((serv_type == ADB_SERVICE_TYPE_TV) ||
3432  (serv_type == ADB_SERVICE_TYPE_RADIO) ||
3433  (serv_type == ADB_SERVICE_TYPE_DATA) ||
3434  (((serv_type == ADB_SERVICE_TYPE_AVC_RADIO) ||
3435  (serv_type == ADB_SERVICE_TYPE_AVC_SD_TV)) &&
3436  ((required_service_type & SEARCH_SERVICE_TYPE_ADVANCED_CODEC) != 0)) ||
3437  (((serv_type == ADB_SERVICE_TYPE_HD_TV) ||
3438  (serv_type == ADB_SERVICE_TYPE_MPEG2_HD)) &&
3439  ((required_service_type & SEARCH_SERVICE_TYPE_HD) != 0)) ||
3440  ((serv_type == ADB_SERVICE_TYPE_UHD_TV) &&
3441  ((required_service_type & SEARCH_SERVICE_TYPE_HEVC) != 0))))
3442  {
3443  if ((((required_service_type & SEARCH_SERVICE_TYPE_FREE_TO_AIR) != 0) && all_streams_free) ||
3444  (((required_service_type & SEARCH_SERVICE_TYPE_ENCRYPTED) != 0) && !all_streams_free))
3445  {
3446  valid_service = TRUE;
3447  }
3448  }
3449 
3450  FUNCTION_FINISH(ValidServiceType);
3451 
3452  return(valid_service);
3453 }
3454 
3468 static BOOLEAN ProcessSdtTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode,
3469  BOOLEAN ignore_version, BOOLEAN eit_list_reqd)
3470 {
3471  BOOLEAN retval;
3472  SI_SDT_TABLE *sdt_table;
3473  SI_SDT_SERVICE_ENTRY *sdt_entry;
3474  SI_STRING_DESC *str_desc;
3475  SI_MULTILING_SERV_NAME_DESC *mlsn_desc_ptr;
3476  SI_MULTILING_SHORT_NAME_DESC *short_name_desc_ptr;
3477  SI_PREFERRED_NAME_DESC *pref_name_desc_ptr;
3478  SI_LINKAGE_DESC_ENTRY *linkage_desc_ptr;
3479  ADB_ALT_SERV_REC *alt_serv_rec;
3480  ADB_ALT_SERV_REC **last_alt_serv_rec_next_ptr;
3481  ADB_SERVICE_REC *s_ptr;
3482  ADB_SERVICE_REC *next_s_ptr;
3483  ADB_TRANSPORT_REC *t_ptr;
3484  BOOLEAN changed;
3485  U16BIT i;
3486  U16BIT j;
3487  U8BIT lang_id;
3488  U8BIT name_id;
3489  U16BIT eit_list_id;
3490  U8BIT path;
3491  BOOLEAN serv_scrambled;
3492  BOOLEAN serv_not_running;
3493  BOOLEAN service_updated;
3494  U8BIT serv_running_status;
3495  U32BIT ca_handle;
3496 
3497  FUNCTION_START(ProcessSdtTable);
3498 
3499  retval = FALSE;
3500  path = table_rec->path;
3501  eit_list_id = 0;
3502 
3503  sdt_table = STB_SIParseSdtTable(table_rec);
3504  if (sdt_table != NULL)
3505  {
3506  t_ptr = NULL;
3507 
3508  if (mode == DB_ACCESS_SEARCH)
3509  {
3510  t_ptr = current_transport_rec[path];
3511 
3512  if (t_ptr->sig_type != SIGNAL_COFDM)
3513  {
3514  if ((t_ptr = ADB_GetTransportFromIds(ADB_INVALID_DVB_ID, sdt_table->orig_net_id,
3515  sdt_table->tran_id)) == NULL)
3516  {
3517  /* A transport with these IDs doesn't exist so use current transport */
3518  t_ptr = current_transport_rec[path];
3519  }
3520  else
3521  {
3522  if (t_ptr != current_transport_rec[path])
3523  {
3524  /* A transport for this SDT has previously been created, but the tuning params
3525  * weren't known at the time (i.e. it may have been created when processing a BAT,
3526  * in which case it may also have service's associated with it), so the parent
3527  * transport of any services that have the current transport as a parent are updated
3528  * to point to the transport that's just been found, after which the old transport
3529  * record can be deleted */
3531 
3532  s_ptr = DBDEF_GetNextServiceRec(NULL);
3533  while (s_ptr != NULL)
3534  {
3535  if (s_ptr->transport == current_transport_rec[path])
3536  {
3537  /* Change the parent transport record of this service */
3538  s_ptr->transport = t_ptr;
3539  DBA_SetRecordParent(s_ptr->dba_rec, t_ptr->dba_rec);
3540  DBA_SaveRecord(s_ptr->dba_rec);
3541  }
3542 
3543  s_ptr = DBDEF_GetNextServiceRec(s_ptr);
3544  }
3545 
3546  DBDEF_DeleteTransportRec(current_transport_rec[path]);
3548 
3549  current_transport_rec[path] = t_ptr;
3550  ADB_SetTunedTransport(path, t_ptr);
3551  }
3552  }
3553  }
3554  }
3555  else if (sdt_table->num_services > 0)
3556  {
3557  /* Find the transport for this SDT. This may not be found if this is an SDTother where
3558  * cross-carriage is used and the transport wasn't found when doing a service search */
3559  t_ptr = ADB_GetTransportFromIds(ADB_INVALID_DVB_ID, sdt_table->orig_net_id, sdt_table->tran_id);
3560  }
3561 
3562  if ((t_ptr != NULL) && ((t_ptr->network == NULL) || (t_ptr->network->profile_type != ADB_PROFILE_TYPE_CIPLUS)))
3563  {
3564  #ifdef DEBUG_SI_SDT
3565  if (mode == DB_ACCESS_SEARCH)
3566  {
3567  AP_SI_PRINT(("SDT Table: tran_id 0x%04x onet_id 0x%04x v%d %d services",
3568  sdt_table->tran_id, sdt_table->orig_net_id, sdt_table->version,
3569  sdt_table->num_services));
3570  }
3571  else
3572  {
3573  if ((t_ptr->sdt_version != sdt_table->version) || (ignore_version == TRUE))
3574  {
3575  AP_SI_PRINT(("SDT Table: tran_id 0x%04x onet_id 0x%04x v%d %d services - new",
3576  sdt_table->tran_id, sdt_table->orig_net_id, sdt_table->version,
3577  sdt_table->num_services));
3578  }
3579  else
3580  {
3581  AP_SI_PRINT(("SDT Table: tran_id 0x%04x onet_id 0x%04x v%d %d services - same",
3582  sdt_table->tran_id, sdt_table->orig_net_id, sdt_table->version,
3583  sdt_table->num_services));
3584  }
3585  }
3586  #endif
3587 
3588  if (eit_list_reqd == TRUE)
3589  {
3590  // make space for the eit_list
3591  if (eit_list[path] != NULL)
3592  {
3593  STB_AppFreeMemory(eit_list[path]);
3594  }
3595  num_eit_list_entries[path] = sdt_table->num_services;
3596  eit_list[path] = STB_AppGetMemory(num_eit_list_entries[path] * sizeof(EIT_LIST_ENTRY));
3597  eit_list_id = 0;
3598  memset(eit_list[path], 0, num_eit_list_entries[path] * sizeof(EIT_LIST_ENTRY));
3599  }
3600 
3601  // only process the table if we are in search mode, or the sdt version has changed
3602  if ((mode == DB_ACCESS_SEARCH) || (ignore_version == TRUE) || !t_ptr->sdt_received ||
3603  (t_ptr->sdt_version != sdt_table->version))
3604  {
3605  retval = TRUE;
3606  changed = FALSE;
3607 
3608  // save sdt data to the database...
3609  // get access to the database (may suspend)
3611 
3612  t_ptr->sdt_received = TRUE;
3613 
3614  if (t_ptr->sdt_version != sdt_table->version)
3615  {
3616  // save version in transport record
3617  t_ptr->sdt_version = sdt_table->version;
3618 
3619  /* Save the latest version of the SDT */
3620  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_VERSION, t_ptr->sdt_version);
3621  changed = TRUE;
3622 
3623  if (mode != DB_ACCESS_SEARCH)
3624  {
3625  t_ptr->sdt_version_changed = TRUE;
3626  }
3627  }
3628 
3629  if (mode == DB_ACCESS_SEARCH)
3630  {
3631  /* Now doing a search, so version no longer changed */
3632  t_ptr->sdt_version_changed = FALSE;
3633 
3634  /* Save transport and onet ids in the transport record */
3635  if (t_ptr->tran_id != sdt_table->tran_id)
3636  {
3637  t_ptr->tran_id = sdt_table->tran_id;
3638  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRANSPORT_ID, t_ptr->tran_id);
3639  changed = TRUE;
3640  }
3641 
3642  /* Only set the onet id if it hasn't been set yet */
3643  if (t_ptr->orig_net_id == 0)
3644  {
3645  t_ptr->orig_net_id = sdt_table->orig_net_id;
3646  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_ORIG_NET_ID, t_ptr->orig_net_id);
3647  changed = TRUE;
3648  }
3649 
3650  if (changed)
3651  {
3652  DBA_SaveRecord(t_ptr->dba_rec);
3653  }
3654  }
3655 
3656  // mark all services on this transport as unavailable - all services listed in the sdt will
3657  // be marked available in the following loop, leaving those services which are no longer in
3658  // the sdt marked unavailable
3659  s_ptr = DBDEF_GetNextServiceOnTransport(NULL, t_ptr);
3660  while (s_ptr != NULL)
3661  {
3662  s_ptr->unavailable = TRUE;
3663  s_ptr = DBDEF_GetNextServiceOnTransport(s_ptr, t_ptr);
3664  }
3665 
3666  // examine each entry in the sdt...
3667  sdt_entry = sdt_table->service_list;
3668  while (sdt_entry != NULL)
3669  {
3670  /* Find service in database */
3671  if (mode == DB_ACCESS_SEARCH)
3672  {
3673  s_ptr = DBDEF_FindServiceRec(sdt_entry->serv_id, t_ptr);
3674  }
3675  else
3676  {
3677  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, t_ptr->orig_net_id,
3678  t_ptr->tran_id, sdt_entry->serv_id);
3679  }
3680 
3681  if ((s_ptr == NULL) && ValidServiceType(sdt_entry->serv_type, sdt_entry->all_streams_free))
3682  {
3683  if (mode == DB_ACCESS_SEARCH)
3684  {
3685  #ifdef DEBUG_SI_SDT
3686  AP_SI_PRINT((" add service sid 0x%04x", sdt_entry->serv_id));
3687  #endif
3688  s_ptr = DBDEF_AddServiceRec(sdt_entry->serv_id, t_ptr);
3689  if (s_ptr != NULL)
3690  {
3691  s_ptr->new_service = TRUE;
3692  }
3693  }
3694  else if ((mode == DB_ACCESS_UPDATE) && ASI_DatabaseUpdatesAllowed(t_ptr->sig_type) &&
3695  ACFG_GetDynamicSIUpdate(t_ptr->sig_type, t_ptr->orig_net_id, ACFG_DYNAMIC_SI_UPDATE_SERVICE_ADD) &&
3696  (dynamic_update_head != NULL))
3697  {
3698  #ifdef DEBUG_SI_SDT
3699  AP_SI_PRINT((" add service sid 0x%04x", sdt_entry->serv_id));
3700  #endif
3701  s_ptr = DBDEF_AddServiceRec(sdt_entry->serv_id, t_ptr);
3702  if (s_ptr != NULL)
3703  {
3704  s_ptr->new_service = TRUE;
3705 
3706  DynamicUpdateAddService(t_ptr, s_ptr,
3707  ACFG_GetDynamicSIUpdate(t_ptr->sig_type, t_ptr->orig_net_id, ACFG_DYNAMIC_SI_UPDATE_SERVICE_MOVE));
3708 
3709  /* The target region data may be needed for the allocation of LCNs so it's
3710  * kept until after the dynamic update process has completed, when it will
3711  * be freed */
3712  s_ptr->target_region_list = sdt_entry->target_region_list;
3713  sdt_entry->target_region_list = NULL;
3714  }
3715  }
3716  }
3717 
3718  while (s_ptr != NULL)
3719  {
3720  #ifdef DEBUG_SI_SDT
3721  AP_SI_PRINT((" Service 0x%04x", sdt_entry->serv_id));
3722  if (s_ptr->name_str != NULL)
3723  {
3724  AP_SI_PRINT((" name \"%s\"", s_ptr->name_str->str_ptr));
3725  }
3726  #endif
3727 
3728  service_updated = FALSE;
3729  s_ptr->found = TRUE;
3730 
3731  /* Save the scambled state of the service to handle the change to/from FTA services */
3732  serv_scrambled = s_ptr->scrambled;
3733 
3734  if ((eit_list_reqd == TRUE) && (eit_list[path] != NULL))
3735  {
3736  // add service to eit list
3737  if (eit_list_id < num_eit_list_entries[path])
3738  {
3739  eit_list[path][eit_list_id].serv_id = sdt_entry->serv_id;
3740  eit_list_id++;
3741  }
3742  }
3743 
3744  //--------------------------------------------------------------------------
3745  // first store data in service record that is saved in nvm...
3746  // (remember to free old data first if changed)
3747 
3748  if (ASI_DatabaseUpdatesAllowed(t_ptr->sig_type))
3749  {
3750  // update service type
3751  if (DBDEF_SetServiceType(s_ptr, sdt_entry->serv_type))
3752  {
3753  service_updated = TRUE;
3754  }
3755 
3756  // update service name
3757  if (sdt_entry->name_str != NULL)
3758  {
3759  if (DBDEF_SetServiceName(s_ptr, sdt_entry->name_str->str_ptr))
3760  {
3761  #ifdef DEBUG_SI_SDT
3762  AP_SI_PRINT((" new name \"%s\"", sdt_entry->name_str->str_ptr));
3763  #endif
3764  service_updated = TRUE;
3765  }
3766  }
3767  else
3768  {
3769  if (DBDEF_SetServiceName(s_ptr, NULL))
3770  {
3771  #ifdef DEBUG_SI_SDT
3772  AP_SI_PRINT((" new NULL name"));
3773  #endif
3774  service_updated = TRUE;
3775  }
3776  }
3777  }
3778 
3779  //--------------------------------------------------------------------------
3780  // now store data in service record that is NOT saved in nvm...
3781  // (remember to free old data first if appropriate)
3782  s_ptr->unavailable = FALSE;
3783  s_ptr->scrambled = (sdt_entry->all_streams_free == FALSE);
3784  serv_running_status = s_ptr->running_status;
3785  s_ptr->running_status = sdt_entry->running_status;
3786  serv_not_running = s_ptr->not_running;
3787 
3788  /* Check the running status of the service */
3789  if ((sdt_entry->running_status == RUN_STATE_NOT_RUNNING) ||
3790  (sdt_entry->running_status == RUN_STATE_STARTS_SOON) ||
3791  (sdt_entry->running_status == RUN_STATE_OFF_AIR))
3792  {
3793  s_ptr->not_running = TRUE;
3794  }
3795  else
3796  {
3797  s_ptr->not_running = FALSE;
3798  }
3799 
3800  if (sdt_entry->fta_content_desc != NULL)
3801  {
3802  s_ptr->has_fta_desc = TRUE;
3803  s_ptr->do_not_scramble = sdt_entry->fta_content_desc->do_not_scramble;
3804  }
3805 
3806  if (ASI_DatabaseUpdatesAllowed(t_ptr->sig_type))
3807  {
3808  // transfer provider string from sdt entry (not stored in nvm)
3809  if (sdt_entry->provider_str != NULL)
3810  {
3811  DBDEF_SetServiceProviderName(s_ptr, sdt_entry->provider_str->str_ptr);
3812  }
3813  else
3814  {
3815  if (DBDEF_SetServiceProviderName(s_ptr, NULL))
3816  {
3817  service_updated = TRUE;
3818  }
3819  }
3820 
3821  if (sdt_entry->short_name_str != NULL)
3822  {
3823  if (DBDEF_SetServiceShortName(s_ptr, sdt_entry->short_name_str->str_ptr))
3824  {
3825  service_updated = TRUE;
3826  }
3827  }
3828  else
3829  {
3830  if (DBDEF_SetServiceShortName(s_ptr, NULL))
3831  {
3832  service_updated = TRUE;
3833  }
3834  }
3835 
3836  // release all old multilingual and preferred names
3837  for (i = 0; i < ACFG_NUM_DB_LANGUAGES; i++)
3838  {
3839  if (s_ptr->short_name_array[i] != NULL)
3840  {
3841  DBDEF_ReleaseString(s_ptr->short_name_array[i]);
3842  s_ptr->short_name_array[i] = NULL;
3843  }
3844  if (s_ptr->provider_array[i] != NULL)
3845  {
3846  DBDEF_ReleaseString(s_ptr->provider_array[i]);
3847  s_ptr->provider_array[i] = NULL;
3848  }
3849  for (j = 0; j < ADB_NUM_SERV_NAME_IDS; j++)
3850  {
3851  if (s_ptr->name_array[i][j] != NULL)
3852  {
3853  DBDEF_ReleaseString(s_ptr->name_array[i][j]);
3854  s_ptr->name_array[i][j] = NULL;
3855  }
3856  }
3857  }
3858 
3859  /* Extract multilingual short service names */
3860  short_name_desc_ptr = sdt_entry->multiling_short_name_array;
3861  for (i = 0; i < sdt_entry->num_multiling_short_names; i++, short_name_desc_ptr++)
3862  {
3863  lang_id = ACFG_ConvertLangCodeToId(short_name_desc_ptr->lang_code);
3864  if (lang_id != ACFG_INVALID_DB_LANG)
3865  {
3866  if (short_name_desc_ptr->name_str != NULL)
3867  {
3868  if (s_ptr->short_name_array[lang_id] == NULL)
3869  {
3870  str_desc = short_name_desc_ptr->name_str;
3871  s_ptr->short_name_array[lang_id] = DBDEF_MakeString(
3872  short_name_desc_ptr->lang_code, str_desc->str_ptr, str_desc->nbytes);
3873  }
3874  }
3875  }
3876  }
3877 
3878  // extract multilingual service names
3879  mlsn_desc_ptr = sdt_entry->multiling_name_desc_array;
3880  for (i = 0; i < sdt_entry->num_multiling_names; i++, mlsn_desc_ptr++)
3881  {
3882  lang_id = ACFG_ConvertLangCodeToId(mlsn_desc_ptr->lang_code);
3883  if (lang_id != ACFG_INVALID_DB_LANG)
3884  {
3885  // if mulitlingual service name is defined transfer it to appropriate
3886  // language entry for name_id=0 in names array
3887  if (mlsn_desc_ptr->name_str != NULL)
3888  {
3889  if (s_ptr->name_array[lang_id][0] == NULL)
3890  {
3891  str_desc = mlsn_desc_ptr->name_str;
3892  s_ptr->name_array[lang_id][0] = DBDEF_MakeString(
3893  mlsn_desc_ptr->lang_code, str_desc->str_ptr, str_desc->nbytes);
3894  }
3895  }
3896 
3897  // if mulitlingual provider name is defined transfer it to appropriate
3898  // language entry in the provider array
3899  if (mlsn_desc_ptr->provider_str != NULL)
3900  {
3901  if (s_ptr->provider_array[lang_id] == NULL)
3902  {
3903  str_desc = mlsn_desc_ptr->provider_str;
3904  s_ptr->provider_array[lang_id] = DBDEF_MakeString(
3905  mlsn_desc_ptr->lang_code, str_desc->str_ptr, str_desc->nbytes);
3906  }
3907  }
3908  }
3909  }
3910 
3911  // now transfer preferred names to name array
3912  pref_name_desc_ptr = sdt_entry->preferred_name_desc_array;
3913  for (i = 0; i < sdt_entry->num_preferred_names; i++, pref_name_desc_ptr++)
3914  {
3915  if (pref_name_desc_ptr->name_str != NULL)
3916  {
3917  lang_id = ACFG_ConvertLangCodeToId(pref_name_desc_ptr->lang_code);
3918  if (lang_id != ACFG_INVALID_DB_LANG)
3919  {
3920  if (pref_name_desc_ptr->name_id < ADB_NUM_SERV_NAME_IDS)
3921  {
3922  name_id = pref_name_desc_ptr->name_id;
3923  if (s_ptr->name_array[lang_id][name_id] == NULL)
3924  {
3925  str_desc = pref_name_desc_ptr->name_str;
3926  s_ptr->name_array[lang_id][name_id] = DBDEF_MakeString(
3927  pref_name_desc_ptr->lang_code, str_desc->str_ptr, str_desc->nbytes);
3928  }
3929  }
3930  }
3931  }
3932  }
3933  }
3934 
3935  if ((sdt_entry->guidance != NULL) &&
3936  ((sdt_entry->guidance->guidance_type == 0) || (sdt_entry->guidance->guidance_type == 1)))
3937  {
3938  for (i = 0; i < sdt_entry->guidance->num_langs; i++)
3939  {
3940  lang_id = ACFG_ConvertLangCodeToId(sdt_entry->guidance->lang_codes[i]);
3941  if (lang_id != ACFG_INVALID_DB_LANG)
3942  {
3943  if (s_ptr->guidance[lang_id].text != NULL)
3944  {
3945  DBDEF_ReleaseString(s_ptr->guidance[lang_id].text);
3946  s_ptr->guidance[lang_id].text = NULL;
3947  }
3948 
3949  s_ptr->guidance[lang_id].type = sdt_entry->guidance->guidance_type;
3950  s_ptr->guidance[lang_id].mode = sdt_entry->guidance->guidance_mode;
3951 
3952  s_ptr->guidance[lang_id].text = DBDEF_MakeString(
3953  sdt_entry->guidance->lang_codes[i],
3954  sdt_entry->guidance->strings[i]->str_ptr,
3955  sdt_entry->guidance->strings[i]->nbytes);
3956  }
3957  }
3958  }
3959  else if (s_ptr->guidance != NULL)
3960  {
3961  for (i = 0; i < ACFG_NUM_DB_LANGUAGES; i++)
3962  {
3963  if (s_ptr->guidance[i].text != NULL)
3964  {
3965  DBDEF_ReleaseString(s_ptr->guidance[i].text);
3966  s_ptr->guidance[i].text = NULL;
3967  }
3968  }
3969  }
3970 
3971  // look for linkage descriptor defining alternative services
3972  DBDEF_DeleteAltServList(s_ptr->alt_serv_list);
3973  s_ptr->alt_serv_list = NULL;
3974  last_alt_serv_rec_next_ptr = &(s_ptr->alt_serv_list);
3975 
3976  linkage_desc_ptr = sdt_entry->linkage_desc_list;
3977  while (linkage_desc_ptr != NULL)
3978  {
3979  if ((linkage_desc_ptr->link_type == LINK_TYPE_SERVICE_REPLACEMENT) ||
3980  (linkage_desc_ptr->link_type == LINK_TYPE_CA_REPLACEMENT_SERVICE))
3981  {
3982  alt_serv_rec = STB_AppGetMemory(sizeof(ADB_ALT_SERV_REC));
3983  if (alt_serv_rec != NULL)
3984  {
3985  alt_serv_rec->onet_id = linkage_desc_ptr->orig_net_id;
3986  alt_serv_rec->tran_id = linkage_desc_ptr->tran_id;
3987  alt_serv_rec->serv_id = linkage_desc_ptr->serv_id;
3988  alt_serv_rec->link_type = linkage_desc_ptr->link_type;
3989  alt_serv_rec->next = NULL;
3990  *last_alt_serv_rec_next_ptr = alt_serv_rec;
3991  last_alt_serv_rec_next_ptr = &(alt_serv_rec->next);
3992  #ifdef DEBUG_SI_SDT
3993  AP_SI_PRINT((" add alt service type=0x%02x, 0x%04x/0x%04x/0x%04x",
3994  alt_serv_rec->link_type, alt_serv_rec->onet_id, alt_serv_rec->tran_id,
3995  alt_serv_rec->serv_id));
3996  #endif
3997  }
3998  }
3999  linkage_desc_ptr = linkage_desc_ptr->next;
4000  }
4001 
4002  if (sdt_entry->def_authority != NULL)
4003  {
4004  changed = TRUE;
4005 
4006  if (s_ptr->def_authority != NULL)
4007  {
4008  /* Check whether the default authority has changed */
4009  if (sdt_entry->def_authority->nbytes == s_ptr->def_authority->nbytes)
4010  {
4011  if (memcmp(s_ptr->def_authority->str_ptr, sdt_entry->def_authority->str_ptr,
4012  s_ptr->def_authority->nbytes) == 0)
4013  {
4014  /* The names are the same */
4015  changed = FALSE;
4016  }
4017  }
4018  }
4019 
4020  if (changed)
4021  {
4022  /* Free the old authority string */
4023  if (s_ptr->def_authority != NULL)
4024  {
4025  STB_AppFreeMemory(s_ptr->def_authority);
4026  s_ptr->def_authority = NULL;
4027  }
4028 
4029  /* Add the new authority string */
4030  s_ptr->def_authority = DBDEF_MakeString(0,
4031  sdt_entry->def_authority->str_ptr, sdt_entry->def_authority->nbytes);
4032  #ifdef DEBUG_SI_SDT
4033  AP_SI_PRINT((" SDT \"%s\" has default authority \"%s\"", s_ptr->name_str->str_ptr,
4034  s_ptr->def_authority->str_ptr));
4035  #endif
4036  }
4037  }
4038 
4039  if ((current_service_rec[path] == s_ptr) &&
4040  (s_ptr->running_status != serv_running_status) &&
4041  STB_DPGetPathCADescrambler(path, &ca_handle))
4042  {
4043  /* Notify the CA system that the running status has changed */
4044  STB_CANotifyRunningStatus(ca_handle, s_ptr->running_status);
4045  }
4046 
4047  if (s_ptr->not_running != serv_not_running)
4048  {
4049  /* There has been a change in the running status of the service */
4050  if ((current_service_rec[path] == s_ptr) && s_ptr->not_running)
4051  {
4052  /* The current service is no longer running */
4053  #ifdef DEBUG_SI_SDT
4054  AP_SI_PRINT((" sid 0x%04x report service not running", s_ptr->serv_id));
4055  #endif
4056  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION,
4057  EV_SERVICE_NOT_RUNNING, &path, sizeof(U8BIT));
4058  STB_SIReportCurrentPmt(s_ptr->serv_id, NULL, FALSE, FALSE);
4059  }
4060  else if ((s_ptr->not_running == FALSE) &&
4061  ((s_ptr->video_pid != 0) || (s_ptr->audio_pid != 0) ||
4062  (t_ptr != current_transport_rec[path])))
4063  {
4064  /* A service that was previously not running is now running */
4065  #ifdef DEBUG_SI_SDT
4066  AP_SI_PRINT((" sid 0x%04x report service running", s_ptr->serv_id));
4067  #endif
4068  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_RUNNING,
4069  &s_ptr, sizeof(s_ptr));
4070  }
4071  }
4072  else
4073  {
4074  if (s_ptr->scrambled != serv_scrambled)
4075  {
4076  /* The service has changed to/from FTA.
4077  * The service this change relates to needs to be known by whatever handles
4078  * the event, but there isn't a way to send this info with the event as it
4079  * would require too many bits and there are only 8 bits available (the top
4080  * 8 bits of the class). So the service record is stored in a table and the
4081  * index into that table is sent with the event, instead of the path. The
4082  * event's handler must query this data, after which the table entry will
4083  * be released so that it can be reused. */
4084  #ifdef DEBUG_SI_SDT
4085  AP_SI_PRINT((" sid 0x%04x report scramble change", s_ptr->serv_id));
4086  #endif
4087  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION,
4088  EV_SERVICE_SCRAMBLE_CHANGE, &s_ptr, sizeof(s_ptr));
4089  }
4090  }
4091 
4092  if (mode == DB_ACCESS_SEARCH)
4093  {
4094  /* The target region data will only be kept until after the search has completed
4095  * and all of the info gathered may be needed so just keep the lot and ensure it
4096  * isn't deleted when the table gets deleted. */
4097  s_ptr->target_region_list = sdt_entry->target_region_list;
4098  sdt_entry->target_region_list = NULL;
4099  }
4100 
4101  if (service_updated)
4102  {
4103  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION,
4104  EV_SERVICE_UPDATED, &s_ptr, sizeof(s_ptr));
4105  }
4106 
4107  /* See if there's another service with the same IDs */
4108  s_ptr = DBDEF_FindServiceRecByIds(s_ptr, ADB_INVALID_DVB_ID, t_ptr->orig_net_id,
4109  t_ptr->tran_id, sdt_entry->serv_id);
4110  }
4111 
4112  if ((s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, t_ptr->orig_net_id,
4113  t_ptr->tran_id, sdt_entry->serv_id)) != NULL)
4114  {
4115  /* Delete the linkage array for repopulation */
4116  DeleteLinkageDescripterArray(s_ptr->linkage_desc_list);
4117  s_ptr->last_linkage_entry = NULL;
4118  s_ptr->num_linkage_entries = 0;
4119  s_ptr->linkage_desc_list = NULL;
4120 
4121  linkage_desc_ptr = sdt_entry->linkage_desc_list;
4122  while (linkage_desc_ptr != NULL)
4123  {
4124  /* Copy the linkage descripter to the service */
4125  CopyLinkageDesc(linkage_desc_ptr,
4126  &s_ptr->linkage_desc_list,
4127  &s_ptr->last_linkage_entry,
4128  &s_ptr->num_linkage_entries);
4129 
4130  linkage_desc_ptr = linkage_desc_ptr->next;
4131  }
4132 
4133 #ifdef COMMON_INTERFACE
4134  /* The CI protection desc should only be updated if the SDT has come
4135  * from a trusted source */
4136  if (ACI_IsTrustedPath(path) && (mode != DB_ACCESS_SEARCH))
4137  {
4138  s_ptr->sdt_received = TRUE;
4139 
4140  if (s_ptr->ci_protection_desc != NULL)
4141  {
4142  STB_FreeMemory(s_ptr->ci_protection_desc);
4143  s_ptr->ci_protection_desc = NULL;
4144  }
4145 
4146  /* Check whether the ci_protection_descriptor for the service needs to be updated */
4147  if (sdt_entry->ci_protection_desc != NULL)
4148  {
4149  /* Save the raw desc data and clear the reference to it from the SDT service
4150  * entry to ensure it isn't freed */
4151  s_ptr->ci_protection_desc = sdt_entry->ci_protection_desc;
4152  sdt_entry->ci_protection_desc = NULL;
4153 
4154  /* Save the update time of the descriptor */
4155  s_ptr->ci_prot_last_update = STB_OSGetClockRTC();
4156  }
4157  }
4158  else
4159  {
4160  s_ptr->sdt_received = FALSE;
4161  }
4162 #endif
4163  }
4164 
4165  sdt_entry = sdt_entry->next;
4166  }
4167 
4168  /* For Nordig go through all services and delete the ones that are no longer available */
4169  if ((mode == DB_ACCESS_SEARCH) && ACFG_IsNordigCountry())
4170  {
4171  s_ptr = DBDEF_GetNextServiceOnTransport(NULL, t_ptr);
4172  while (s_ptr != NULL)
4173  {
4174  next_s_ptr = DBDEF_GetNextServiceOnTransport(s_ptr, t_ptr);
4175 
4176  if (s_ptr->unavailable)
4177  {
4178  #ifdef DEBUG_SI_SDT
4179  AP_SI_PRINT((" sid 0x%04x deleted as not available", s_ptr->serv_id));
4180  #endif
4181  DBDEF_DeleteServiceRec(s_ptr);
4182  }
4183 
4184  s_ptr = next_s_ptr;
4185  }
4186  }
4187  else if ((mode == DB_ACCESS_UPDATE) && ASI_DatabaseUpdatesAllowed(t_ptr->sig_type) &&
4188  ACFG_GetDynamicSIUpdate(t_ptr->sig_type, t_ptr->orig_net_id, ACFG_DYNAMIC_SI_UPDATE_SERVICE_REMOVE) &&
4189  (dynamic_update_head != NULL))
4190  {
4191  /* Services that are no longer available should be deleted, if possible */
4192  for (s_ptr = DBDEF_GetNextServiceOnTransport(NULL, t_ptr); s_ptr != NULL; s_ptr = next_s_ptr)
4193  {
4194  next_s_ptr = DBDEF_GetNextServiceOnTransport(s_ptr, t_ptr);
4195 
4196  if (s_ptr->unavailable)
4197  {
4198  /* If moving of a service is supported then the deletion has to be delayed
4199  * until all SDTs have been received to check whether this service is being
4200  * moved or deleted. If it's being deleted then this will be done later */
4201  if (ACFG_GetDynamicSIUpdate(t_ptr->sig_type, t_ptr->orig_net_id, ACFG_DYNAMIC_SI_UPDATE_SERVICE_MOVE))
4202  {
4203  DynamicUpdateDeleteService(t_ptr, s_ptr, TRUE);
4204  }
4205  else
4206  {
4207  /* The service can only be deleted if it isn't the current service */
4208  if (current_service_rec[path] != s_ptr)
4209  {
4210  /* The service can be deleted */
4211  #ifdef DEBUG_SI_SDT
4212  AP_SI_PRINT((" sid 0x%04x deleted", s_ptr->serv_id));
4213  #endif
4214  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_DELETED,
4215  &s_ptr, sizeof(s_ptr));
4216 
4217  DBDEF_DeleteServiceRec(s_ptr);
4218  }
4219  else
4220  {
4221  /* The service can't be deleted so an event is sent to ask the
4222  * controlling code to delete it */
4223  #ifdef DEBUG_SI_SDT
4224  AP_SI_PRINT((" sid 0x%04x needs to be deleted", s_ptr->serv_id));
4225  #endif
4226  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_DELETE_SERVICE,
4227  &s_ptr, sizeof(s_ptr));
4228  }
4229  }
4230  }
4231  }
4232  }
4233 
4234  if ((current_service_rec[path] != NULL) && (t_ptr == current_transport_rec[path]))
4235  {
4236  if (current_service_rec[path]->unavailable)
4237  {
4238  #ifdef DEBUG_SI_SDT
4239  AP_SI_PRINT((" sid 0x%04x report not running", current_service_rec[path]->serv_id));
4240  #endif
4241  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_NOT_RUNNING,
4242  &path, sizeof(U8BIT));
4243  STB_SIReportCurrentPmt(current_service_rec[path]->serv_id, NULL, FALSE, FALSE);
4244  }
4245  }
4246 
4247  // release database access
4249  }
4250  }
4251 
4252  ApplyDynamicUpdates(path);
4253 
4254  if (update_sdt_func != NULL)
4255  {
4256  /* Call the function that's been registered to handle additional SDT processing */
4257  (*update_sdt_func)(path, sdt_table, table_rec);
4258  }
4259 
4260 #ifdef INTEGRATE_HBBTV
4261  if ((mode != DB_ACCESS_SEARCH) && retval)
4262  {
4264  }
4265 #endif
4266 
4267  // release the table
4268  STB_SIReleaseSdtTable(sdt_table);
4269  }
4270 
4271  STB_SIReleaseTableRecord(table_rec);
4272 
4273  FUNCTION_FINISH(ProcessSdtTable);
4274  return(retval);
4275 }
4276 
4288 static BOOLEAN ProcessPatTable(SI_TABLE_RECORD *table_rec)
4289 {
4290  BOOLEAN retval;
4291  SI_PAT_TABLE *pat_table;
4292  SI_PAT_SERVICE_ENTRY *pat_entry;
4293  ADB_SERVICE_REC *s_ptr;
4294  U16BIT i;
4295  BOOLEAN found;
4296  U8BIT path;
4297  ADB_PMT_VERSION_REC *pmt_ver_rec;
4298  ADB_PMT_VERSION_REC *prev_ver_rec;
4299 
4300  FUNCTION_START(ProcessPatTable);
4301 
4302  retval = FALSE;
4303 
4304  // convert table_rec to pat_table
4305  pat_table = STB_SIParsePatTable(table_rec);
4306 
4307  path = table_rec->path;
4308 
4309  STB_SIReleaseTableRecord(table_rec);
4310 
4311  if (pat_table != NULL)
4312  {
4313  #ifdef DEBUG_SI_PAT
4314  if (pmt_list[path] == NULL)
4315  {
4316  AP_SI_PRINT(("PAT Table: tran_id 0x%04x v%d %d services",
4317  pat_table->tran_id, pat_table->version, pat_table->num_services));
4318  }
4319  else
4320  {
4321  if (current_transport_rec[path]->pat_version != pat_table->version)
4322  {
4323  AP_SI_PRINT(("PAT Table: tran_id 0x%04x v%d %d services - new",
4324  pat_table->tran_id, pat_table->version, pat_table->num_services));
4325  }
4326  else
4327  {
4328  AP_SI_PRINT(("PAT Table: tran_id 0x%04x v%d %d services - same",
4329  pat_table->tran_id, pat_table->version, pat_table->num_services));
4330  }
4331  }
4332  #endif
4333 
4334  if ((pat_rcvd_on_this_trnsprt[path] == FALSE) || (current_transport_rec[path]->pat_version != pat_table->version))
4335  {
4336  retval = TRUE;
4337  current_transport_rec[path]->pat_version = pat_table->version;
4338  pat_rcvd_on_this_trnsprt[path] = TRUE;
4339 
4340  // delete old list if one exists
4341  if (pmt_list[path] != NULL)
4342  {
4343  STB_AppFreeMemory(pmt_list[path]);
4344  }
4345 
4346  // create new pmt list from entries in PAT
4347  num_pmt_list_entries[path] = pat_table->num_services;
4348  pmt_list[path] = STB_AppGetMemory(num_pmt_list_entries[path] * sizeof(PMT_LIST_ENTRY));
4349  pmt_list_id[path] = 0;
4350  if (pmt_list[path] != NULL)
4351  {
4352  pat_entry = pat_table->service_list;
4353  for (i = 0; ((i < num_pmt_list_entries[path]) && (pat_entry != NULL)); i++)
4354  {
4355  #ifdef DEBUG_SI_PAT
4356  AP_SI_PRINT((" sid 0x%04x pmt 0x%04x", pat_entry->serv_id, pat_entry->pmt_pid));
4357  #endif
4358  pmt_list[path][i].serv_id = pat_entry->serv_id;
4359  pmt_list[path][i].ts_id = ADB_GetTransportTid(current_transport_rec[path]);
4360  pmt_list[path][i].on_id = ADB_GetTransportOriginalNetworkId(current_transport_rec[path]);
4361  pmt_list[path][i].pid = pat_entry->pmt_pid;
4362 
4363  pat_entry = pat_entry->next;
4364  }
4365  // confirm num_pmt_list_entries in case the loop exited with pat_entry == NULL
4366  num_pmt_list_entries[path] = i;
4367  }
4368 
4369  // save pat data to the database...
4371 
4372  // search through all services on the current transport (if any) - if the service is not
4373  // listed in the pat table then mark it not running
4374  s_ptr = DBDEF_GetNextServiceOnTransport(NULL, current_transport_rec[path]);
4375  while (s_ptr != NULL)
4376  {
4377  found = FALSE;
4378  for (i = 0; i < num_pmt_list_entries[path]; i++)
4379  {
4380  if (pmt_list[path][i].serv_id == s_ptr->serv_id)
4381  {
4382  found = TRUE;
4383  break;
4384  }
4385  }
4386 
4387  if (found == FALSE)
4388  {
4389  if (s_ptr->not_running == FALSE)
4390  {
4391  #ifdef DEBUG_SI_PAT
4392  AP_SI_PRINT((" sid 0x%04x marked not running", s_ptr->serv_id));
4393  #endif
4394  // service not listed in PAT - mark it not running and clear the details in the
4395  // service that normally come from the pmt
4396  s_ptr->not_running = TRUE;
4397  DBDEF_DeleteStreamList(s_ptr->stream_list);
4398  s_ptr->stream_list = NULL;
4399  s_ptr->video_pid = 0;
4400  s_ptr->audio_pid = 0;
4401  s_ptr->subtitle_pid = 0;
4402  s_ptr->pcr_pid = 0;
4403 
4404  /* Delete the service's PMT version rec from the transport list */
4405  pmt_ver_rec = current_transport_rec[path]->pmt_version_list;
4406  prev_ver_rec = NULL;
4407  while (pmt_ver_rec != NULL)
4408  {
4409  if (pmt_ver_rec->serv_id == s_ptr->serv_id)
4410  {
4411  /* Found the entry for this service.
4412  * Check whether it's first in the list and remove it */
4413  if (prev_ver_rec == NULL)
4414  {
4415  current_transport_rec[path]->pmt_version_list = pmt_ver_rec->next;
4416  }
4417  else
4418  {
4419  prev_ver_rec->next = pmt_ver_rec->next;
4420  }
4421 
4422  STB_AppFreeMemory(pmt_ver_rec);
4423  pmt_ver_rec = NULL;
4424  }
4425  else
4426  {
4427  prev_ver_rec = pmt_ver_rec;
4428  pmt_ver_rec = pmt_ver_rec->next;
4429  }
4430  }
4431 
4432  /* If it's the current service tell the application it's no longer running */
4433  if (s_ptr == current_service_rec[path])
4434  {
4435  #ifdef DEBUG_SI_PAT
4436  AP_SI_PRINT((" sid 0x%04x report not running", s_ptr->serv_id));
4437  #endif
4438  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_NOT_RUNNING,
4439  &path, sizeof(U8BIT));
4440  STB_SIReportCurrentPmt(s_ptr->serv_id, NULL, FALSE, FALSE);
4441  }
4442  }
4443  }
4444  else
4445  {
4446  /* A PMT is present for this service, save it in the service structure */
4447  DBDEF_SetServicePmtPid(s_ptr, pmt_list[path][i].pid);
4448  }
4449  s_ptr = DBDEF_GetNextServiceOnTransport(s_ptr, current_transport_rec[path]);
4450  }
4451 
4452  // release database access
4454  }
4455  // release the table
4456  STB_SIReleasePatTable(pat_table);
4457  }
4458 
4459  FUNCTION_FINISH(ProcessPatTable);
4460  return(retval);
4461 }
4462 
4474 static BOOLEAN ProcessPatTablePlayback(SI_TABLE_RECORD *table_rec)
4475 {
4476  BOOLEAN retval;
4477  SI_PAT_TABLE *pat_table;
4478  SI_PAT_SERVICE_ENTRY *pat_entry;
4479  U16BIT i;
4480  U8BIT path;
4481 
4482  FUNCTION_START(ProcessPatTablePlayback);
4483 
4484  retval = FALSE;
4485 
4486  // convert table_rec to pat_table
4487  pat_table = STB_SIParsePatTable(table_rec);
4488 
4489  path = table_rec->path;
4490 
4491  STB_SIReleaseTableRecord(table_rec);
4492 
4493  if (pat_table != NULL)
4494  {
4495  if ((pat_rcvd_on_this_trnsprt[path] == FALSE) || (last_playback_pat_version != pat_table->version))
4496  {
4497  retval = TRUE;
4498  pat_rcvd_on_this_trnsprt[path] = TRUE;
4499  last_playback_pat_version = pat_table->version;
4500 
4501  pat_entry = pat_table->service_list;
4502  for (i = 0; ((i < pat_table->num_services) && (pat_entry != NULL)); i++)
4503  {
4504  if ((pat_entry->serv_id == current_service_rec[path]->serv_id) ||
4505  (current_service_rec[path]->serv_id == 0))
4506  {
4507  #ifdef DEBUG_SI_PAT_PLAYBACK
4508  AP_SI_PRINT(("ProcessPatTablePlayback: path=%u found sid 0x%04x pmt 0x%04x", path, pat_entry->serv_id, pat_entry->pmt_pid));
4509  #endif
4510 
4511  pmt_filter_pid[path] = pat_entry->pmt_pid;
4512 
4513  /* If serv_id == 0 in the current service, it means we were expecting a single service PAT.
4514  * Use the serv_id in the PAT to set the serv_id of the current service record */
4515  if (current_service_rec[path]->serv_id == 0)
4516  {
4517  current_service_rec[path]->serv_id = pat_entry->serv_id;
4518  }
4519  break;
4520  }
4521 
4522  pat_entry = pat_entry->next;
4523  }
4524  }
4525  // release the table
4526  STB_SIReleasePatTable(pat_table);
4527  }
4528 
4529  FUNCTION_FINISH(ProcessPatTablePlayback);
4530 
4531  return(retval);
4532 }
4533 
4552 static BOOLEAN ProcessPmtTable(SI_TABLE_RECORD *table_rec, BOOLEAN ignore_version, BOOLEAN report_pmt,
4553  U16BIT *service_id, E_DB_ACCESS_MODE mode)
4554 {
4555  ADB_PMT_VERSION_REC *pmt_ver_rec;
4556  BOOLEAN pmt_ver_changed;
4557  ADB_SERVICE_REC *s_ptr;
4558  U8BIT path;
4559  BOOLEAN service_updated;
4560  BOOLEAN pmt_received = FALSE;
4561 #ifdef COMMON_INTERFACE
4562  void *owner_data;
4563  U32BIT data_size;
4564 #endif
4565 
4566  FUNCTION_START(ProcessPmtTable);
4567 
4568  path = table_rec->path;
4569 
4570  // get access to the database (may suspend)
4572 
4573  if (mode == DB_ACCESS_PLAYBACK)
4574  {
4575  if (last_playback_pmt_version != table_rec->version)
4576  {
4577  pmt_ver_changed = TRUE;
4578  last_playback_pmt_version = table_rec->version;
4579  #ifdef DEBUG_SI_PMT_PLAYBACK
4580  AP_SI_PRINT(("Playback, PMT table: serv_id 0x%04x v%d - update",
4581  table_rec->xtid, table_rec->version));
4582  #endif
4583  }
4584  else
4585  {
4586  pmt_ver_changed = FALSE;
4587  #ifdef DEBUG_SI_PMT_PLAYBACK
4588  if (ignore_version == TRUE)
4589  {
4590  AP_SI_PRINT(("Playback, PMT table: serv_id 0x%04x v%d - same",
4591  table_rec->xtid, table_rec->version));
4592  }
4593  #endif
4594  }
4595  }
4596  else
4597  {
4598  // find or add entry in the pmt history list
4599  pmt_ver_changed = TRUE;
4600  pmt_ver_rec = current_transport_rec[path]->pmt_version_list;
4601  while (pmt_ver_rec != NULL)
4602  {
4603  if (pmt_ver_rec->serv_id == table_rec->xtid)
4604  {
4605  // found entry - check if the version has changed
4606  if (pmt_ver_rec->version != table_rec->version)
4607  {
4608  pmt_ver_rec->version = table_rec->version;
4609  #ifdef DEBUG_SI_PMT
4610  AP_SI_PRINT(("PMT table: serv_id 0x%04x v%d - update",
4611  table_rec->xtid, table_rec->version));
4612  #endif
4613  }
4614  else
4615  {
4616  pmt_ver_changed = FALSE;
4617  #ifdef DEBUG_SI_PMT
4618  if (ignore_version == TRUE)
4619  {
4620  AP_SI_PRINT(("PMT table: serv_id 0x%04x v%d - same",
4621  table_rec->xtid, table_rec->version));
4622  }
4623  #endif
4624  }
4625  break;
4626  }
4627  pmt_ver_rec = pmt_ver_rec->next;
4628  }
4629  if (pmt_ver_rec == NULL)
4630  {
4631  // no history entry - add one
4632  pmt_ver_rec = STB_AppGetMemory(sizeof(ADB_PMT_VERSION_REC));
4633  if (pmt_ver_rec != NULL)
4634  {
4635  pmt_ver_rec->serv_id = table_rec->xtid;
4636  pmt_ver_rec->version = table_rec->version;
4637  pmt_ver_rec->next = current_transport_rec[path]->pmt_version_list;
4638  current_transport_rec[path]->pmt_version_list = pmt_ver_rec;
4639  #ifdef DEBUG_SI_PMT
4640  AP_SI_PRINT(("PMT table: serv_id 0x%04x v%d - new",
4641  table_rec->xtid, table_rec->version));
4642  #endif
4643  }
4644  }
4645  }
4646 
4647  if (service_id != NULL)
4648  {
4649  *service_id = table_rec->xtid;
4650  }
4651 
4652  service_updated = FALSE;
4653 
4654  if (mode == DB_ACCESS_PLAYBACK)
4655  {
4656  s_ptr = current_service_rec[path];
4657  }
4658  else
4659  {
4660  // find the service matching this pmt (should be one because it would have been added by
4661  // the SDT, if there isn't then skip this pmt)
4662  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID,
4663  current_transport_rec[path]->orig_net_id, current_transport_rec[path]->tran_id,
4664  table_rec->xtid);
4665  }
4666 
4667 #ifdef DEBUG_SI_PMT
4668  AP_SI_PRINT(("PMT table, service = %p, ignore_version=%u, pmt_ver_changed=%u", s_ptr,
4669  ignore_version, pmt_ver_changed));
4670 #endif
4671 
4672  if (s_ptr != NULL)
4673  {
4674  /* Remember whether the PMT for the service had already been received, because after
4675  * being processed the flag will be TRUE */
4676  pmt_received = s_ptr->pmt_received;
4677 
4678  // if the service is marked not running, or we don't care about the version, or the version
4679  // has changed, or we don't yet have valid PIDs, then process the pmt
4680  if ((ignore_version == TRUE) || (pmt_ver_changed == TRUE))
4681  {
4682  service_updated = InternalProcessPmtTable(path, s_ptr, table_rec,
4683  ((mode == DB_ACCESS_PLAYBACK) ? FALSE : TRUE), mode);
4684  }
4685  }
4686  else
4687  {
4688  if (update_pmt_func != NULL)
4689  {
4690  /* Call the function that's been registered to handle additional PMT processing */
4691  (*update_pmt_func)(path, NULL, table_rec, NULL);
4692  }
4693  }
4694 
4695  // release database access
4697 
4698  if (pmt_service_changed[path] && STB_DPIsLivePath(path) &&
4699  (s_ptr == current_service_rec[path]) && !pmt_received)
4700  {
4701  /* Service for live path has changed, inform the UI */
4702  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_CHANGED, &s_ptr, sizeof(void *));
4703  }
4704 
4705  // check if pmt needs reporting to other applications (e.g. ca systems or MHEG)
4706  if (report_pmt == TRUE)
4707  {
4708  if (report_pmt_allowed[path] == TRUE)
4709  {
4710  #ifdef DEBUG_SI_PMT
4711  AP_SI_PRINT(("Report pmt: serv_id 0x%04x v%d", table_rec->xtid, table_rec->version));
4712  #endif
4713 
4714 #ifdef COMMON_INTERFACE
4715  if (pmt_service_changed[path] && STB_DPIsOwnedBy(path, RES_OWNER_CIPLUS))
4716  {
4717  /* The service has changed and the path is owned by CI+,
4718  * so inform it that the tune operation has completed */
4719  if ((owner_data = STB_DPGetOwnerData(path, &data_size)) != NULL)
4720  {
4721  if (table_rec->xtid == current_service_rec[path]->serv_id)
4722  {
4723  ACI_TuneReply(path, *(U32BIT *)owner_data, CIP_TUNER_LOCKED);
4724  }
4725  else
4726  {
4727  ACI_TuneReply(path, *(U32BIT *)owner_data, CIP_TUNER_SERVICE_NOT_FOUND);
4728  }
4729  }
4730  }
4731 #endif
4732 
4733  if ((current_service_rec[path] != NULL) &&
4734  (table_rec->xtid == current_service_rec[path]->serv_id) &&
4735  (table_rec->version != last_reported_pmt_version[path]))
4736  {
4737  pmt_ver_changed = TRUE;
4738  last_reported_pmt_version[path] = table_rec->version;
4739  }
4740  else
4741  {
4742  pmt_ver_changed = FALSE;
4743  }
4744 
4745  STB_SIReportCurrentPmt(table_rec->xtid, table_rec, pmt_service_changed[path], pmt_ver_changed);
4746 
4747 #ifdef COMMON_INTERFACE
4748  if (table_rec->section_list != NULL)
4749  {
4750  ACI_ProgramMapTableChanged(&(table_rec->section_list->data_start));
4751  }
4752 #endif
4753 
4754  pmt_reported[path] = TRUE;
4755  pmt_service_changed[path] = FALSE;
4756  }
4757  }
4758 
4759  // free up the table record
4760  STB_SIReleaseTableRecord(table_rec);
4761 
4762  FUNCTION_FINISH(ProcessPmtTable);
4763 
4764  return(service_updated);
4765 }
4766 
4767 /*!**************************************************************************
4768  * @brief Internal function to process a PMT table and update the database
4769  * @param path - decode path the table was received from
4770  * @param s_ptr - first service that the PMT is for
4771  * @param table_rec - pointer to the SI table data
4772  * @param db_services - TRUE if the database is to be searched for additional
4773  * identical services that the PMT is to be used for
4774  * @return TRUE if a service is updated, FALSE otherwise
4775  ****************************************************************************/
4776 static BOOLEAN InternalProcessPmtTable(U8BIT path, ADB_SERVICE_REC *s_ptr, SI_TABLE_RECORD *table_rec,
4777  BOOLEAN db_services, E_DB_ACCESS_MODE mode)
4778 {
4779  SI_PMT_TABLE *pmt_table;
4780  ADB_STREAM_REC **last_stream_rec_next_ptr;
4781  SI_PMT_STREAM_ENTRY *pmt_entry;
4782  ADB_STREAM_REC *stream_rec = NULL;
4783  ADB_STREAM_REC *srec;
4784  ADB_STREAM_REC *old_stream_list;
4785  U16BIT i;
4786  U16BIT subt_pid;
4787  U16BIT subt_cpage;
4788  U16BIT subt_apage;
4789  BOOLEAN prev_not_running;
4790  BOOLEAN match_found;
4791  E_STB_DP_AUDIO_MODE audio_mode;
4792  ADB_STREAM_TYPE audio_type;
4793  ADB_STREAM_TYPE adesc_type;
4794  ADB_STREAM_TYPE video_type;
4795  U16BIT video_pid;
4796  U16BIT audio_pid;
4797  U16BIT adesc_pid;
4798  BOOLEAN service_updated;
4799  U16BIT ttxt_pid;
4800  U8BIT ttxt_mag;
4801  U8BIT ttxt_page;
4802 #if defined(DEBUG_SI_PMT_AUDIO) || defined(DEBUG_SI_PMT_VIDEO)
4803  U8BIT tag_count;
4804 #endif
4805 #ifdef COMMON_INTERFACE
4806  U8BIT slot_id;
4807 #endif
4808 
4809  FUNCTION_START(InternalProcessPmtTable);
4810 
4811  service_updated = FALSE;
4812 
4813  pmt_table = STB_SIParsePmtTable(table_rec);
4814  if (pmt_table != NULL)
4815  {
4816  /* The same service may have multiple LCNs (e.g. Finnish Nordig spec), which is handled by
4817  * having multiple copies of the same service, so the PMT may apply to more than one service */
4818  while (s_ptr != NULL)
4819  {
4820  if (s_ptr->pmt_data != NULL)
4821  {
4822  STB_AppFreeMemory(s_ptr->pmt_data);
4823  s_ptr->pmt_data = NULL;
4824  s_ptr->pmt_data_len = 0;
4825  }
4826 
4827  /* Store the PMT with the service for use by CI+ and other CA systems */
4828  s_ptr->pmt_data = STB_AppGetMemory(table_rec->section_list->data_len);
4829  if (s_ptr->pmt_data != NULL)
4830  {
4831  memcpy(s_ptr->pmt_data, &(table_rec->section_list->data_start),
4832  table_rec->section_list->data_len);
4833  s_ptr->pmt_data_len = table_rec->section_list->data_len;
4834  }
4835 
4836 #ifdef COMMON_INTERFACE
4837  if ((slot_id = STB_DPGetPathCISlot(path)) != INVALID_RES_ID)
4838  {
4839  /* Re-evaluate state even if service is not scrambled */
4840  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_URI_UPDATED, &slot_id, sizeof(slot_id));
4841  }
4842 #endif
4843  service_updated = TRUE;
4844  s_ptr->pmt_received = TRUE;
4845 
4846  /* Save the current PIDs and type so we can check whether they are changed */
4847  adesc_pid = DBDEF_GetReqdADPid(s_ptr, &audio_mode, &adesc_type, &match_found);
4848  video_pid = s_ptr->video_pid;
4849  audio_pid = s_ptr->audio_pid;
4850  video_type = s_ptr->video_type;
4851  audio_type = s_ptr->audio_type;
4852 
4853  DBDEF_GetReqdSubtitleParams(s_ptr, &subt_pid, &subt_cpage, &subt_apage);
4854  DBDEF_GetReqdTtextPid(s_ptr, TRUE, &ttxt_pid, &ttxt_mag, &ttxt_page);
4855 
4856  // extract the data from the pmt and add to the service record
4857  // all data from the pmt is stored in ram only so no need to update nvm. Remember to
4858  // free old data before the new data is added.
4859 
4860  /* Save the service's current stream list so it can be checked
4861  * to see if any have changed */
4862  old_stream_list = s_ptr->stream_list;
4863 
4864  s_ptr->stream_list = NULL;
4865  s_ptr->video_pid = 0;
4866  s_ptr->audio_pid = 0;
4867  s_ptr->subtitle_pid = 0;
4868  s_ptr->pcr_pid = pmt_table->pcr_pid;
4869  s_ptr->rct_pid = 0;
4870 
4871  prev_not_running = s_ptr->not_running;
4872  s_ptr->not_running = FALSE;
4873 
4874  if (pmt_table->ca_desc_array == NULL)
4875  {
4876  s_ptr->has_ca_descriptor = FALSE;
4877  }
4878  else
4879  {
4880  s_ptr->has_ca_descriptor = TRUE;
4881  }
4882 
4883  /* Save the content protection level with the service so it can be used when content
4884  * protection is applied */
4885  s_ptr->content_protection_level = pmt_table->content_protection_level;
4886 
4887 #ifdef INTEGRATE_HBBTV
4888  s_ptr->ait_pid = 0;
4889 #endif
4890 
4891  // copy pmt data to service.
4892  last_stream_rec_next_ptr = &(s_ptr->stream_list);
4893  pmt_entry = pmt_table->stream_list;
4894  while (pmt_entry != NULL)
4895  {
4896  switch (pmt_entry->type)
4897  {
4898  case SI_STREAM_TYPE_VIDEO1:
4899  case SI_STREAM_TYPE_VIDEO2:
4900  case SI_STREAM_TYPE_H264:
4901  case SI_STREAM_TYPE_H265:
4902  {
4903  // make new stream entry and add to end of list
4904  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
4905  if (stream_rec != NULL)
4906  {
4907  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
4908  /* Now copying all tags as there may be multiple */
4909  CopyComponentTagArray(stream_rec, pmt_entry);
4910  stream_rec->pid = pmt_entry->pid;
4911  if (pmt_entry->type == SI_STREAM_TYPE_H264)
4912  {
4913  stream_rec->type = ADB_H264_VIDEO_STREAM;
4914  }
4915  else if (pmt_entry->type == SI_STREAM_TYPE_H265)
4916  {
4917  stream_rec->type = ADB_H265_VIDEO_STREAM;
4918  }
4919  else
4920  {
4921  stream_rec->type = ADB_VIDEO_STREAM;
4922  }
4923  stream_rec->next = NULL;
4924  *last_stream_rec_next_ptr = stream_rec;
4925  last_stream_rec_next_ptr = &(stream_rec->next);
4926 
4927  #ifdef DEBUG_SI_PMT_VIDEO
4928  AP_SI_PRINT((" video stream: pid 0x%04x", pmt_entry->pid));
4929  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
4930  {
4931  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
4932  }
4933  #endif
4934  }
4935  break;
4936  }
4937 
4938  case SI_STREAM_TYPE_AUDIO1:
4939  case SI_STREAM_TYPE_AUDIO2:
4940  case SI_STREAM_TYPE_AAC:
4941  case SI_STREAM_TYPE_HEAAC:
4942  {
4943  if (pmt_entry->num_iso_lang_entries == 0)
4944  {
4945  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
4946  if (stream_rec != NULL)
4947  {
4948  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
4949  /* Now copying all tags as there may be multiple */
4950  CopyComponentTagArray(stream_rec, pmt_entry);
4951  stream_rec->pid = pmt_entry->pid;
4952  if (pmt_entry->type == SI_STREAM_TYPE_AAC)
4953  {
4954  if (pmt_entry->aac_descriptor != NULL)
4955  {
4956  switch (pmt_entry->aac_descriptor->profile_level)
4957  {
4958  case 0x58:
4959  case 0x59:
4960  case 0x5a:
4961  case 0x5b:
4962  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
4963  break;
4964 
4965  case 0x60:
4966  case 0x61:
4967  case 0x62:
4968  case 0x63:
4969  stream_rec->type = ADB_HEAACv2_AUDIO_STREAM;
4970  break;
4971 
4972  default:
4973  stream_rec->type = ADB_AAC_AUDIO_STREAM;
4974  break;
4975  }
4976 
4977  if (pmt_entry->aac_descriptor->type_present)
4978  {
4979  switch (pmt_entry->aac_descriptor->aac_type)
4980  {
4981  case 0x01:
4982  stream_rec->data.audio.mode = AUDIO_MONO;
4983  break;
4984 
4985  case 0x05:
4986  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
4987  break;
4988 
4989  case 0x03:
4990  case 0x43:
4991  default:
4992  stream_rec->data.audio.mode = AUDIO_STEREO;
4993  break;
4994  }
4995  }
4996  else
4997  {
4998  /* Default to stereo */
4999  stream_rec->data.audio.mode = AUDIO_STEREO;
5000  }
5001  }
5002  else
5003  {
5004  /* Default to AAC stereo */
5005  stream_rec->type = ADB_AAC_AUDIO_STREAM;
5006  stream_rec->data.audio.mode = AUDIO_STEREO;
5007  }
5008  }
5009  else if (pmt_entry->type == SI_STREAM_TYPE_HEAAC)
5010  {
5011  if (pmt_entry->aac_descriptor != NULL)
5012  {
5013  switch (pmt_entry->aac_descriptor->profile_level)
5014  {
5015  case 0x60:
5016  case 0x61:
5017  case 0x62:
5018  case 0x63:
5019  stream_rec->type = ADB_HEAACv2_AUDIO_STREAM;
5020  break;
5021 
5022  default:
5023  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
5024  break;
5025  }
5026 
5027  if (pmt_entry->aac_descriptor->type_present)
5028  {
5029  switch (pmt_entry->aac_descriptor->aac_type)
5030  {
5031  case 0x01:
5032  stream_rec->data.audio.mode = AUDIO_MONO;
5033  break;
5034 
5035  case 0x05:
5036  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5037  break;
5038 
5039  case 0x03:
5040  case 0x43:
5041  default:
5042  stream_rec->data.audio.mode = AUDIO_STEREO;
5043  break;
5044  }
5045  }
5046  else
5047  {
5048  /* Default to stereo */
5049  stream_rec->data.audio.mode = AUDIO_STEREO;
5050  }
5051  }
5052  else
5053  {
5054  /* Default to HE-AAC stereo */
5055  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
5056  stream_rec->data.audio.mode = AUDIO_STEREO;
5057  }
5058  }
5059  else
5060  {
5061  stream_rec->type = ADB_AUDIO_STREAM;
5062  stream_rec->data.audio.mode = AUDIO_UNDEF;
5063  }
5064  stream_rec->data.audio.lang_code = ACFG_UNDEFINED_DB_LANG_CODE;
5065  stream_rec->data.audio.type = ADB_AUDIO_TYPE_UNDEFINED;
5066 
5067  stream_rec->next = NULL;
5068  *last_stream_rec_next_ptr = stream_rec;
5069  last_stream_rec_next_ptr = &(stream_rec->next);
5070 
5071  #ifdef DEBUG_SI_PMT_AUDIO
5072  AP_SI_PRINT((" %s audio stream: pid 0x%04x, type %u, mode %u",
5073  ((stream_rec->type == ADB_HEAACv2_AUDIO_STREAM) ? "HE-AACv2" :
5074  ((stream_rec->type == ADB_HEAAC_AUDIO_STREAM) ? "HE-AACv1" :
5075  ((stream_rec->type == ADB_AAC_AUDIO_STREAM) ? "AAC" : "MPEG"))),
5076  pmt_entry->pid,
5077  stream_rec->data.audio.type,
5078  stream_rec->data.audio.mode));
5079  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5080  {
5081  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5082  }
5083  #endif
5084  }
5085  }
5086  else
5087  {
5088  // make new stream entry and add to end of list. Add an entry for each iso
5089  // lang desc with same tag and pid.
5090  for (i = 0; i < pmt_entry->num_iso_lang_entries; i++)
5091  {
5092  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5093  if (stream_rec != NULL)
5094  {
5095  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5096  /* Now copying all tags as there may be multiple */
5097  CopyComponentTagArray(stream_rec, pmt_entry);
5098  stream_rec->pid = pmt_entry->pid;
5099  if (pmt_entry->type == SI_STREAM_TYPE_AAC)
5100  {
5101  if (pmt_entry->aac_descriptor != NULL)
5102  {
5103  switch (pmt_entry->aac_descriptor->profile_level)
5104  {
5105  case 0x58:
5106  case 0x59:
5107  case 0x5a:
5108  case 0x5b:
5109  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
5110  break;
5111 
5112  case 0x60:
5113  case 0x61:
5114  case 0x62:
5115  case 0x63:
5116  stream_rec->type = ADB_HEAACv2_AUDIO_STREAM;
5117  break;
5118 
5119  default:
5120  stream_rec->type = ADB_AAC_AUDIO_STREAM;
5121  break;
5122  }
5123 
5124  if (pmt_entry->aac_descriptor->type_present)
5125  {
5126  switch (pmt_entry->aac_descriptor->aac_type)
5127  {
5128  case 0x01:
5129  stream_rec->data.audio.mode = AUDIO_MONO;
5130  break;
5131 
5132  case 0x05:
5133  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5134  break;
5135 
5136  case 0x03:
5137  case 0x43:
5138  default:
5139  stream_rec->data.audio.mode = AUDIO_STEREO;
5140  break;
5141  }
5142  }
5143  else
5144  {
5145  /* Default to stereo */
5146  stream_rec->data.audio.mode = AUDIO_STEREO;
5147  }
5148  }
5149  else
5150  {
5151  /* Default to AAC stereo */
5152  stream_rec->type = ADB_AAC_AUDIO_STREAM;
5153  stream_rec->data.audio.mode = AUDIO_STEREO;
5154  }
5155  }
5156  else if (pmt_entry->type == SI_STREAM_TYPE_HEAAC)
5157  {
5158  if (pmt_entry->aac_descriptor != NULL)
5159  {
5160  switch (pmt_entry->aac_descriptor->profile_level)
5161  {
5162  case 0x60:
5163  case 0x61:
5164  case 0x62:
5165  case 0x63:
5166  stream_rec->type = ADB_HEAACv2_AUDIO_STREAM;
5167  break;
5168 
5169  default:
5170  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
5171  break;
5172  }
5173 
5174  if (pmt_entry->aac_descriptor->type_present)
5175  {
5176  switch (pmt_entry->aac_descriptor->aac_type)
5177  {
5178  case 0x01:
5179  stream_rec->data.audio.mode = AUDIO_MONO;
5180  break;
5181 
5182  case 0x05:
5183  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5184  break;
5185 
5186  case 0x03:
5187  case 0x43:
5188  default:
5189  stream_rec->data.audio.mode = AUDIO_STEREO;
5190  break;
5191  }
5192  }
5193  else
5194  {
5195  /* Default to stereo */
5196  stream_rec->data.audio.mode = AUDIO_STEREO;
5197  }
5198  }
5199  else
5200  {
5201  /* Default to HE-AAC stereo */
5202  stream_rec->type = ADB_HEAAC_AUDIO_STREAM;
5203  stream_rec->data.audio.mode = AUDIO_STEREO;
5204  }
5205  }
5206  else
5207  {
5208  stream_rec->type = ADB_AUDIO_STREAM;
5209  stream_rec->data.audio.mode = AUDIO_UNDEF;
5210  }
5211  stream_rec->data.audio.lang_code =
5212  pmt_entry->iso_lang_desc_array[i].lang_code;
5213  stream_rec->data.audio.type =
5214  pmt_entry->iso_lang_desc_array[i].audio_type;
5215 
5216  stream_rec->next = NULL;
5217  *last_stream_rec_next_ptr = stream_rec;
5218  last_stream_rec_next_ptr = &(stream_rec->next);
5219 
5220  #ifdef DEBUG_SI_PMT_AUDIO
5221  AP_SI_PRINT((" %s audio stream: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5222  ((stream_rec->type == ADB_HEAACv2_AUDIO_STREAM) ? "HE-AACv2" :
5223  ((stream_rec->type == ADB_HEAAC_AUDIO_STREAM) ? "HE-AACv1" :
5224  ((stream_rec->type == ADB_AAC_AUDIO_STREAM) ? "AAC" : "MPEG"))),
5225  pmt_entry->pid,
5226  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5227  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5228  (stream_rec->data.audio.lang_code & 0xff),
5229  stream_rec->data.audio.type,
5230  stream_rec->data.audio.mode));
5231  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5232  {
5233  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5234  }
5235  #endif
5236  }
5237  }
5238  }
5239  break;
5240  }
5241 
5242  case SI_STREAM_TYPE_PES_PKT:
5243  {
5244  if ((pmt_entry->ac3_descriptor != NULL) &&
5245  ((pmt_entry->ac3_descriptor->dtag == AC3_DESC_DTAG) ||
5246  (pmt_entry->ac3_descriptor->dtag == EAC3_DESC_DTAG)))
5247  {
5248  if (pmt_entry->num_iso_lang_entries == 0)
5249  {
5250  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5251  if (stream_rec != NULL)
5252  {
5253  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5254 
5255  /* Now copying all tags as there may be multiple */
5256  CopyComponentTagArray(stream_rec, pmt_entry);
5257 
5258  stream_rec->pid = pmt_entry->pid;
5259  stream_rec->data.audio.type = ADB_AUDIO_TYPE_UNDEFINED;
5260 
5261  if (pmt_entry->ac3_descriptor->dtag == AC3_DESC_DTAG)
5262  {
5263  stream_rec->type = ADB_AC3_AUDIO_STREAM;
5264 
5265  if (pmt_entry->ac3_descriptor->component_type_flag)
5266  {
5267  if ((pmt_entry->ac3_descriptor->component_type & 0x40) == 0)
5268  {
5269  /* This is a full service audio stream */
5270  stream_rec->data.audio.type = ADB_AUDIO_TYPE_CLEAN_EFFECTS;
5271  }
5272  else
5273  {
5274  switch ((pmt_entry->ac3_descriptor->component_type >> 3) & 0x07)
5275  {
5276  case 2:
5277  stream_rec->data.audio.type = ADB_AUDIO_TYPE_FOR_VISUALLY_IMPAIRED;
5278  break;
5279  case 3:
5280  stream_rec->data.audio.type = ADB_AUDIO_TYPE_FOR_HEARING_IMPAIRED;
5281  break;
5282  default:
5283  /* Default is undefined, which is already set */
5284  break;
5285  }
5286  }
5287 
5288  switch(pmt_entry->ac3_descriptor->component_type & 0x07)
5289  {
5290  case 0: /* Mono audio */
5291  case 1: /* 1+1 mode - dual mono */
5292  stream_rec->data.audio.mode = AUDIO_MONO;
5293  break;
5294  case 2: /* 2 channel stereo */
5295  case 3: /* 2 channel surround stereo */
5296  stream_rec->data.audio.mode = AUDIO_STEREO;
5297  break;
5298  case 4: /* More than 2 channels */
5299  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5300  break;
5301  default: /* All other values are invalid for AC-3 */
5302  stream_rec->data.audio.mode = AUDIO_STEREO;
5303  break;
5304  }
5305  }
5306  else
5307  {
5308  /* Assume stereo audio in absense of definition */
5309  stream_rec->data.audio.mode = AUDIO_STEREO;
5310  }
5311  }
5312  else
5313  {
5314  stream_rec->type = ADB_EAC3_AUDIO_STREAM;
5315 
5316  if (pmt_entry->ac3_descriptor->component_type_flag)
5317  {
5318  if ((pmt_entry->ac3_descriptor->component_type & 0x40) == 0)
5319  {
5320  /* This is a full service audio stream */
5321  stream_rec->data.audio.type = ADB_AUDIO_TYPE_CLEAN_EFFECTS;
5322  }
5323  else
5324  {
5325  switch ((pmt_entry->ac3_descriptor->component_type >> 3) & 0x07)
5326  {
5327  case 2:
5328  stream_rec->data.audio.type = ADB_AUDIO_TYPE_FOR_VISUALLY_IMPAIRED;
5329  break;
5330  case 3:
5331  stream_rec->data.audio.type = ADB_AUDIO_TYPE_FOR_HEARING_IMPAIRED;
5332  break;
5333  default:
5334  /* Default is undefined, which is already set */
5335  break;
5336  }
5337  }
5338 
5339  switch(pmt_entry->ac3_descriptor->component_type & 0x07)
5340  {
5341  case 0: /* Mono audio */
5342  case 1: /* 1+1 mode - dual mono */
5343  stream_rec->data.audio.mode = AUDIO_MONO;
5344  break;
5345  case 2: /* 2 channel stereo */
5346  case 3: /* 2 channel surround stereo */
5347  stream_rec->data.audio.mode = AUDIO_STEREO;
5348  break;
5349  case 4: /* More than 2 channels */
5350  case 5: /* More than 5.1 channels */
5351  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5352  break;
5353  default: /* All other values are invalid for AC-3 */
5354  stream_rec->data.audio.mode = AUDIO_STEREO;
5355  break;
5356  }
5357  }
5358  else
5359  {
5360  /* Assume multi-channel audio in absense of definition */
5361  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5362  }
5363  }
5364 
5365  stream_rec->data.audio.lang_code = ACFG_UNDEFINED_DB_LANG_CODE;
5366 
5367  stream_rec->next = NULL;
5368  *last_stream_rec_next_ptr = stream_rec;
5369  last_stream_rec_next_ptr = &(stream_rec->next);
5370 
5371  #ifdef DEBUG_SI_PMT_AUDIO
5372  AP_SI_PRINT((" %s audio stream: pid 0x%04x, type %u, mode %u",
5373  ((stream_rec->type == ADB_EAC3_AUDIO_STREAM) ? "E-AC3" : "AC3"),
5374  pmt_entry->pid,
5375  stream_rec->data.audio.type,
5376  stream_rec->data.audio.mode));
5377  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5378  {
5379  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5380  }
5381  #endif
5382  }
5383  }
5384  else
5385  {
5386  /* make new stream entry and add to end of list. Add an entry for each
5387  * iso lang desc with same tag and pid. */
5388  for (i = 0; i < pmt_entry->num_iso_lang_entries; i++)
5389  {
5390  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5391  if (stream_rec != NULL)
5392  {
5393  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5394 
5395  /* Now copying all tags as there may be multiple */
5396  CopyComponentTagArray(stream_rec, pmt_entry);
5397 
5398  stream_rec->pid = pmt_entry->pid;
5399 
5400  if (pmt_entry->ac3_descriptor->dtag == AC3_DESC_DTAG)
5401  {
5402  stream_rec->type = ADB_AC3_AUDIO_STREAM;
5403 
5404  if (pmt_entry->ac3_descriptor->component_type_flag)
5405  {
5406  switch(pmt_entry->ac3_descriptor->component_type & 0x07)
5407  {
5408  case 0: /* Mono audio */
5409  case 1: /* 1+1 mode - dual mono */
5410  stream_rec->data.audio.mode = AUDIO_MONO;
5411  break;
5412  case 2: /* 2 channel stereo */
5413  case 3: /* 2 channel surround stereo */
5414  stream_rec->data.audio.mode = AUDIO_STEREO;
5415  break;
5416  case 4: /* More than 2 channels */
5417  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5418  break;
5419  default: /* All other values are invalid for AC-3 */
5420  stream_rec->data.audio.mode = AUDIO_STEREO;
5421  break;
5422  }
5423  }
5424  else
5425  {
5426  /* Assume stereo audio in absense of definition */
5427  stream_rec->data.audio.mode = AUDIO_STEREO;
5428  }
5429  }
5430  else
5431  {
5432  stream_rec->type = ADB_EAC3_AUDIO_STREAM;
5433 
5434  if (pmt_entry->ac3_descriptor->component_type_flag)
5435  {
5436  switch(pmt_entry->ac3_descriptor->component_type & 0x07)
5437  {
5438  case 0: /* Mono audio */
5439  case 1: /* 1+1 mode - dual mono */
5440  stream_rec->data.audio.mode = AUDIO_MONO;
5441  break;
5442  case 2: /* 2 channel stereo */
5443  case 3: /* 2 channel surround stereo */
5444  stream_rec->data.audio.mode = AUDIO_STEREO;
5445  break;
5446  case 4: /* More than 2 channels */
5447  case 5: /* More than 5.1 channels */
5448  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5449  break;
5450  default: /* All other values are invalid for AC-3 */
5451  stream_rec->data.audio.mode = AUDIO_STEREO;
5452  break;
5453  }
5454  }
5455  else
5456  {
5457  /* Assume multi-channel audio in absense of definition */
5458  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5459  }
5460  }
5461 
5462  stream_rec->data.audio.lang_code =
5463  pmt_entry->iso_lang_desc_array[i].lang_code;
5464  stream_rec->data.audio.type =
5465  pmt_entry->iso_lang_desc_array[i].audio_type;
5466 
5467  stream_rec->next = NULL;
5468  *last_stream_rec_next_ptr = stream_rec;
5469  last_stream_rec_next_ptr = &(stream_rec->next);
5470 
5471  #ifdef DEBUG_SI_PMT_AUDIO
5472  AP_SI_PRINT((" %s audio stream: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5473  ((stream_rec->type == ADB_EAC3_AUDIO_STREAM) ? "E-AC3" : "AC3"),
5474  pmt_entry->pid,
5475  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5476  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5477  (stream_rec->data.audio.lang_code & 0xff),
5478  stream_rec->data.audio.type,
5479  stream_rec->data.audio.mode));
5480  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5481  {
5482  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5483  }
5484  #endif
5485  }
5486  }
5487  }
5488  }
5489  else
5490  {
5491  if (pmt_entry->subtitle_desc_array != NULL)
5492  {
5493  #ifdef DEBUG_SI_PMT
5494  AP_SI_PRINT(("PMT: %d subtitle entries, PID = %d", pmt_entry->num_subtitle_entries,
5495  pmt_entry->pid));
5496  #endif
5497 
5498  // subtitle streams - make new stream entry for each subtitle descriptor
5499  // and add to end of list
5500  for (i = 0; i < pmt_entry->num_subtitle_entries; i++)
5501  {
5502  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5503  if (stream_rec != NULL)
5504  {
5505  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5506  /* Now copying all tags as there may be multiple */
5507  CopyComponentTagArray(stream_rec, pmt_entry);
5508  stream_rec->pid = pmt_entry->pid;
5509  stream_rec->type = ADB_SUBTITLE_STREAM;
5510  stream_rec->data.subtitle.lang_code =
5511  pmt_entry->subtitle_desc_array[i].lang_code;
5512  stream_rec->data.subtitle.type =
5513  pmt_entry->subtitle_desc_array[i].type;
5514  stream_rec->data.subtitle.composition_page =
5515  pmt_entry->subtitle_desc_array[i].composition_page;
5516  stream_rec->data.subtitle.ancillary_page =
5517  pmt_entry->subtitle_desc_array[i].ancillary_page;
5518 
5519  stream_rec->next = NULL;
5520  *last_stream_rec_next_ptr = stream_rec;
5521  last_stream_rec_next_ptr = &(stream_rec->next);
5522  }
5523  }
5524  }
5525  else
5526  {
5527  // teletext
5528  if (pmt_entry->teletext_desc_array != NULL)
5529  {
5530  #ifdef DEBUG_SI_PMT
5531  AP_SI_PRINT(("PMT: %d teletext entries, PID=%d", pmt_entry->num_teletext_entries,
5532  pmt_entry->pid));
5533  #endif
5534 
5535  // ttext streams - make new stream entry for each ttext descriptor
5536  // and add to end of list
5537  for (i = 0; i < pmt_entry->num_teletext_entries; i++)
5538  {
5539  #ifdef DEBUG_SI_PMT
5540  AP_SI_PRINT((" lang_code=0x%x, type=%d, magazine=%d, page=%d",
5541  pmt_entry->teletext_desc_array[i].lang_code,
5542  pmt_entry->teletext_desc_array[i].type,
5543  pmt_entry->teletext_desc_array[i].magazine,
5544  pmt_entry->teletext_desc_array[i].page));
5545  #endif
5546 
5547  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5548  if (stream_rec != NULL)
5549  {
5550  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5551  /* Now copying all tags as there may be multiple */
5552  CopyComponentTagArray(stream_rec, pmt_entry);
5553  stream_rec->pid = pmt_entry->pid;
5554  stream_rec->type = ADB_TTEXT_STREAM;
5555  stream_rec->data.ttext.lang_code =
5556  pmt_entry->teletext_desc_array[i].lang_code;
5557  stream_rec->data.ttext.type =
5558  pmt_entry->teletext_desc_array[i].type;
5559  stream_rec->data.ttext.magazine =
5560  pmt_entry->teletext_desc_array[i].magazine;
5561  stream_rec->data.ttext.page =
5562  pmt_entry->teletext_desc_array[i].page;
5563 
5564  stream_rec->next = NULL;
5565  *last_stream_rec_next_ptr = stream_rec;
5566  last_stream_rec_next_ptr = &(stream_rec->next);
5567  }
5568  }
5569  }
5570  else
5571  {
5572  #ifdef DEBUG_SI_PMT
5573  AP_SI_PRINT(("PMT: data stream, PID=%d", pmt_entry->pid));
5574  #endif
5575 
5576  // not a subtitle stream - define it as a data stream
5577  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5578  if (stream_rec != NULL)
5579  {
5580  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5581  /* Now copying all tags as there may be multiple */
5582  CopyComponentTagArray(stream_rec, pmt_entry);
5583  stream_rec->pid = pmt_entry->pid;
5584  stream_rec->type = ADB_DATA_STREAM;
5585 
5586  stream_rec->next = NULL;
5587  *last_stream_rec_next_ptr = stream_rec;
5588  last_stream_rec_next_ptr = &(stream_rec->next);
5589  }
5590  }
5591  }
5592  }
5593  break;
5594  }
5595 
5596  case SI_STREAM_TYPE_AC3:
5597  {
5598  if (pmt_entry->num_iso_lang_entries == 0)
5599  {
5600  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5601  if (stream_rec != NULL)
5602  {
5603  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5604  /* Now copying all tags as there may be multiple */
5605  CopyComponentTagArray(stream_rec, pmt_entry);
5606  stream_rec->pid = pmt_entry->pid;
5607  stream_rec->type = ADB_AC3_AUDIO_STREAM;
5608  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5609 
5610  stream_rec->data.audio.lang_code = ACFG_UNDEFINED_DB_LANG_CODE;
5611  stream_rec->data.audio.type = ADB_AUDIO_TYPE_UNDEFINED;
5612 
5613  stream_rec->next = NULL;
5614  *last_stream_rec_next_ptr = stream_rec;
5615  last_stream_rec_next_ptr = &(stream_rec->next);
5616 
5617  #ifdef DEBUG_SI_PMT_AUDIO
5618  AP_SI_PRINT((" AC3 audio stream: pid 0x%04x, type %u, mode %u",
5619  pmt_entry->pid,
5620  stream_rec->data.audio.type,
5621  stream_rec->data.audio.mode));
5622  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5623  {
5624  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5625  }
5626  #endif
5627  }
5628  }
5629  else
5630  {
5631  /* make new stream entry and add to end of list. Add an entry for each
5632  * iso lang desc with same tag and pid. */
5633  for (i = 0; i < pmt_entry->num_iso_lang_entries; i++)
5634  {
5635  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5636  if (stream_rec != NULL)
5637  {
5638  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5639  /* Now copying all tags as there may be multiple */
5640  CopyComponentTagArray(stream_rec, pmt_entry);
5641  stream_rec->pid = pmt_entry->pid;
5642  stream_rec->type = ADB_AC3_AUDIO_STREAM;
5643  stream_rec->data.audio.mode = AUDIO_MULTICHANNEL;
5644 
5645  stream_rec->data.audio.lang_code =
5646  pmt_entry->iso_lang_desc_array[i].lang_code;
5647  stream_rec->data.audio.type =
5648  pmt_entry->iso_lang_desc_array[i].audio_type;
5649 
5650  stream_rec->next = NULL;
5651  *last_stream_rec_next_ptr = stream_rec;
5652  last_stream_rec_next_ptr = &(stream_rec->next);
5653 
5654  #ifdef DEBUG_SI_PMT_AUDIO
5655  AP_SI_PRINT((" AC3 audio stream: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5656  pmt_entry->pid,
5657  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5658  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5659  (stream_rec->data.audio.lang_code & 0xff),
5660  stream_rec->data.audio.type,
5661  stream_rec->data.audio.mode));
5662  for (tag_count = 0; tag_count < pmt_entry->num_tag_entries; tag_count++)
5663  {
5664  AP_SI_PRINT((" tag: %x", pmt_entry->tag_array_ptr[tag_count]));
5665  }
5666  #endif
5667  }
5668  }
5669  }
5670  break;
5671  }
5672 
5673  case SI_STREAM_TYPE_PRIVATE:
5674  {
5675  if (pmt_entry->has_rct)
5676  {
5677  /* Save the PID to be used by this service for collecting the RCT */
5678  s_ptr->rct_pid = pmt_entry->pid;
5679 
5680  /* No need to create a record for this stream */
5681  break;
5682  }
5683 
5684 #ifdef INTEGRATE_HBBTV
5685  #ifdef DEBUG_SI_PMT
5686  AP_SI_PRINT(("PMT: has AIT: %s, num application signalling descriptors %d",
5687  pmt_entry->has_ait ? "TRUE" : "FALSE", pmt_entry->num_app_sig_entries));
5688  #endif
5689  if (pmt_entry->has_ait)
5690  {
5691  /* "If more than one stream is signalled in the PMT for a service with an
5692  application_signalling_descriptor, then the
5693  application_signalling_descriptor for the stream containing the AIT for
5694  the HbbTV application shall include the HbbTV application_type (0x0010)."
5695  TS102796 section 7.2.3.1 */
5696  if (s_ptr->ait_pid == 0)
5697  {
5698  /* Always take the first one, it will be overwritten by the next ones if they are valid */
5699  s_ptr->ait_pid = pmt_entry->pid;
5700  }
5701  else if (pmt_entry->num_app_sig_entries > 0)
5702  {
5703  for (i = 0; i < pmt_entry->num_app_sig_entries; i++)
5704  {
5705  #ifdef DEBUG_SI_PMT
5706  AP_SI_PRINT(("PMT: app_type=0x%x", pmt_entry->app_sig_desc_array[i].app_type));
5707  #endif
5708  if (pmt_entry->app_sig_desc_array[i].app_type == 0x0010)
5709  {
5710  s_ptr->ait_pid = pmt_entry->pid;
5711  }
5712  }
5713  }
5714  }
5715  #ifdef DEBUG_SI_PMT
5716  else
5717  {
5718  AP_SI_PRINT(("PMT: num application signalling descriptors %d but app_sig_desc_array is NULL ",
5719  pmt_entry->num_app_sig_entries));
5720  }
5721  #endif
5722 #endif
5723 
5724  /* Allow to fall through if the stream isn't marked as defining an RCT PID */
5725  }
5726 
5727  default:
5728  {
5729  // make new stream entry and add to end of list
5730  stream_rec = STB_AppGetMemory(sizeof(ADB_STREAM_REC));
5731  if (stream_rec != NULL)
5732  {
5733  memset(stream_rec, 0, sizeof(ADB_STREAM_REC));
5734  /* Now copying all tags as there may be multiple */
5735  CopyComponentTagArray(stream_rec, pmt_entry);
5736  stream_rec->pid = pmt_entry->pid;
5737  stream_rec->type = ADB_DATA_STREAM;
5738 
5739  stream_rec->next = NULL;
5740  *last_stream_rec_next_ptr = stream_rec;
5741  last_stream_rec_next_ptr = &(stream_rec->next);
5742  }
5743  break;
5744  }
5745  }
5746 
5747  if (stream_rec != NULL)
5748  {
5749  if (pmt_entry->ca_desc_array == NULL)
5750  {
5751  stream_rec->has_ca_descriptor = FALSE;
5752  }
5753  else
5754  {
5755  stream_rec->has_ca_descriptor = TRUE;
5756  }
5757  }
5758 
5759  pmt_entry = pmt_entry->next;
5760  }
5761 
5762  /* Set the audio channel setting for each audio stream */
5763  stream_rec = s_ptr->stream_list;
5764  while (stream_rec != NULL)
5765  {
5766  if (((stream_rec->type == ADB_AUDIO_STREAM) ||
5767  (stream_rec->type == ADB_AAC_AUDIO_STREAM) ||
5768  (stream_rec->type == ADB_HEAAC_AUDIO_STREAM) ||
5769  (stream_rec->type == ADB_AC3_AUDIO_STREAM) ||
5770  (stream_rec->type == ADB_EAC3_AUDIO_STREAM)) &&
5771  (stream_rec->pid != 0) && (stream_rec->data.audio.mode == AUDIO_UNDEF))
5772  {
5773  if (stream_rec->data.audio.type == ADB_AUDIO_TYPE_FOR_VISUALLY_IMPAIRED)
5774  {
5775  stream_rec->data.audio.mode = AUDIO_MONO;
5776  }
5777  else
5778  {
5779  /* Search for another audio stream with the same PID and audio type */
5780  srec = stream_rec->next;
5781  match_found = FALSE;
5782 
5783  while ((srec != NULL) && !match_found)
5784  {
5785  if ((srec->type == stream_rec->type) && (srec->pid == stream_rec->pid) &&
5786  (srec->data.audio.type != ADB_AUDIO_TYPE_FOR_VISUALLY_IMPAIRED))
5787  {
5788  /* Found another audio stream on the same PID,
5789  * check whether the language is the same */
5790  match_found = TRUE;
5791 
5792  if (stream_rec->data.audio.lang_code == srec->data.audio.lang_code)
5793  {
5794  if (stream_rec->data.audio.type == srec->data.audio.type)
5795  {
5796  /* Left and right channels have the same language & type
5797  * so mark them as stereo */
5798  stream_rec->data.audio.mode = AUDIO_STEREO;
5799  srec->data.audio.mode = AUDIO_STEREO;
5800 
5801  #ifdef DEBUG_SI_PMT_AUDIO
5802  AP_SI_PRINT((" Stereo left/right audio stream: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5803  stream_rec->pid,
5804  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5805  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5806  (stream_rec->data.audio.lang_code & 0xff),
5807  stream_rec->data.audio.type,
5808  stream_rec->data.audio.mode));
5809  #endif
5810  }
5811  else
5812  {
5813  /* Left and right channels are different */
5814  stream_rec->data.audio.mode = AUDIO_LEFT;
5815  srec->data.audio.mode = AUDIO_RIGHT;
5816 
5817  #ifdef DEBUG_SI_PMT_AUDIO
5818  AP_SI_PRINT((" Left/right audio stream with diff types: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5819  stream_rec->pid,
5820  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5821  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5822  (stream_rec->data.audio.lang_code & 0xff),
5823  stream_rec->data.audio.type,
5824  stream_rec->data.audio.mode));
5825  #endif
5826  }
5827  }
5828  else
5829  {
5830  /* Left and right channels are different */
5831  stream_rec->data.audio.mode = AUDIO_LEFT;
5832  srec->data.audio.mode = AUDIO_RIGHT;
5833 
5834  #ifdef DEBUG_SI_PMT_AUDIO
5835  AP_SI_PRINT((" Left/right audio stream with diff langs: pid 0x%04x, lang %c%c%c, type %u, mode %u",
5836  stream_rec->pid,
5837  ((stream_rec->data.audio.lang_code >> 16) & 0xff),
5838  ((stream_rec->data.audio.lang_code >> 8) & 0xff),
5839  (stream_rec->data.audio.lang_code & 0xff),
5840  stream_rec->data.audio.type,
5841  stream_rec->data.audio.mode));
5842  #endif
5843  }
5844  }
5845 
5846  srec = srec->next;
5847  }
5848 
5849  if (!match_found)
5850  {
5851  /* Single language code means the audio comes from the left channel but is stereo */
5852  stream_rec->data.audio.mode = AUDIO_LEFT;
5853  }
5854  }
5855  }
5856 
5857  stream_rec = stream_rec->next;
5858  }
5859 
5860  /* Now we have all the stream details, we can see if there are any changes from
5861  * the service's previous set of streams */
5862  if ((HaveStreamsChanged(old_stream_list, s_ptr->stream_list) == TRUE) && (mode != DB_ACCESS_SEARCH))
5863  {
5864  #ifdef DEBUG_SI_PMT
5865  AP_SI_PRINT(("PMT: streams changed for service %p (id=0x%04x)", s_ptr, s_ptr->serv_id));
5866  #endif
5867  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_STREAMS_CHANGED,
5868  &s_ptr, sizeof(s_ptr));
5869  }
5870 
5871  /* The old list of streams can now be deleted */
5872  DBDEF_DeleteStreamList(old_stream_list);
5873 
5874  /* Now we have all the stream details we can get the correct pids
5875  * and subtitle details */
5876  s_ptr->audio_pid = DBDEF_GetReqdAudioPid(s_ptr, &audio_mode, &s_ptr->audio_type);
5877 
5878  DBDEF_GetReqdSubtitleParams(s_ptr, &(s_ptr->subtitle_pid), &(s_ptr->subtitle_cpage),
5879  &(s_ptr->subtitle_apage));
5880 
5881  DBDEF_GetReqdTtextPid(s_ptr, TRUE, &(s_ptr->ttext_pid), &(s_ptr->ttext_mag),
5882  &(s_ptr->ttext_page));
5883 
5884  s_ptr->video_pid = DBDEF_GetReqdVideoPid(s_ptr, &s_ptr->video_type);
5885 
5886  /* If any of the PIDs have changed or the service was previously not running
5887  * then send a message informing about the PID update */
5888  if (((video_pid != s_ptr->video_pid) || prev_not_running) && (mode != DB_ACCESS_SEARCH))
5889  {
5890  #ifdef DEBUG_SI_PMT
5891  AP_SI_PRINT(("PMT: report video PID update for service %p (id=0x%04x)", s_ptr, s_ptr->serv_id));
5892  #endif
5893  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_VIDEO_PID_UPDATE,
5894  &s_ptr, sizeof(s_ptr));
5895  }
5896 
5897  if ((mode != DB_ACCESS_SEARCH) &&
5898  ((audio_pid != s_ptr->audio_pid) || prev_not_running ||
5899  (adesc_pid != DBDEF_GetReqdADPid(s_ptr, &audio_mode, &adesc_type, &match_found))))
5900  {
5901  #ifdef DEBUG_SI_PMT_AUDIO
5902  AP_SI_PRINT(("PMT: report audio PID update for service %p (id=0x%04x) pid=%x", s_ptr, s_ptr->serv_id,s_ptr->audio_pid));
5903  #endif
5904  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_AUDIO_PID_UPDATE,
5905  &s_ptr, sizeof(s_ptr));
5906  }
5907 
5908  /* check whether the video type changed, if so, notify the application */
5909  if ((video_type != s_ptr->video_type) && (mode != DB_ACCESS_SEARCH))
5910  {
5911  #ifdef DEBUG_SI_PMT
5912  AP_SI_PRINT(("PMT: report video codec changed for service %p (id=0x%04x)", s_ptr, s_ptr->serv_id));
5913  #endif
5914  /* send an video codec changed event*/
5915  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_VIDEO_CODEC_CHANGED,
5916  &s_ptr, sizeof(s_ptr));
5917  }
5918 
5919  /* check whether the audio type changed, if so, notify the application */
5920  if ((audio_type != s_ptr->audio_type) && (mode != DB_ACCESS_SEARCH))
5921  {
5922  #ifdef DEBUG_SI_PMT
5923  AP_SI_PRINT(("PMT: report audio codec changed for service %p (id=0x%04x)", s_ptr, s_ptr->serv_id));
5924  #endif
5925  /* send an video codec changed event*/
5926  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_AUDIO_CODEC_CHANGED,
5927  &s_ptr, sizeof(s_ptr));
5928  }
5929 
5930  if (s_ptr == current_service_rec[path])
5931  {
5933  {
5934  /* Check if parameters have changed */
5935  if (((subt_pid != s_ptr->subtitle_pid) ||
5936  (subt_cpage != s_ptr->subtitle_cpage) ||
5937  (subt_apage != s_ptr->subtitle_apage) ||
5938  (ttxt_pid != s_ptr->ttext_pid) ||
5939  (ttxt_mag != s_ptr->ttext_mag) ||
5940  (ttxt_page != s_ptr->ttext_page)) &&
5941  (mode != DB_ACCESS_SEARCH))
5942  {
5943  #ifdef DEBUG_SI_PMT
5944  AP_SI_PRINT(("PMT: report subtitle update for service %p (id=0x%04x)", s_ptr, s_ptr->serv_id));
5945  #endif
5946  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_SUBTITLE_UPDATE,
5947  &s_ptr, sizeof(s_ptr));
5948  }
5949  }
5950  }
5951 
5952  if (update_pmt_func != NULL)
5953  {
5954  /* Call the function that's been registered to handle additional PMT processing */
5955  (*update_pmt_func)(path, pmt_table, table_rec, s_ptr);
5956  }
5957 
5958  if (db_services)
5959  {
5960  /* See if there's a duplicate service that this PMT also applies to */
5961  s_ptr = DBDEF_FindServiceRecByIds(s_ptr, ADB_INVALID_DVB_ID,
5962  current_transport_rec[path]->orig_net_id, current_transport_rec[path]->tran_id,
5963  s_ptr->serv_id);
5964  }
5965  else
5966  {
5967  s_ptr = NULL;
5968  }
5969  }
5970 
5971  // release pmt table
5972  STB_SIReleasePmtTable(pmt_table);
5973  }
5974 
5975  FUNCTION_FINISH(InternalProcessPmtTable);
5976 
5977  return(service_updated);
5978 }
5979 
5980 /*!**************************************************************************
5981  * @brief Allocates and copies the tag array from the PMT stream to the service stream
5982  * @param stream_rec - service stream the tag array is to be copied into
5983  * @param pmt_entry - PMT stream the tag array is to be copied from
5984  ****************************************************************************/
5985 static void CopyComponentTagArray(ADB_STREAM_REC *stream_rec, SI_PMT_STREAM_ENTRY *pmt_entry)
5986 {
5987  U8BIT i;
5988 
5989  FUNCTION_START(CopyComponentTagArray);
5990 
5991  if (pmt_entry->tag_array_ptr != NULL)
5992  {
5993  stream_rec->tag_array = STB_AppGetMemory(pmt_entry->num_tag_entries);
5994  if (stream_rec->tag_array != NULL)
5995  {
5996  for (i = 0; i < pmt_entry->num_tag_entries; i++)
5997  {
5998  stream_rec->tag_array[i] = pmt_entry->tag_array_ptr[i];
5999  }
6000  stream_rec->num_tags = pmt_entry->num_tag_entries;
6001  }
6002  }
6003 
6004  FUNCTION_FINISH(CopyComponentTagArray);
6005 }
6006 
6007 /*!**************************************************************************
6008  * @brief Compares the two stream lists to determine if they contain the same PIDs, ignoring differences in order
6009  * @param slist1 - stream list 1
6010  * @param slist2 - stream list 2
6011  * @return TRUE if the PIDs are different or the number of streams is different, FALSE otherwise
6012  ****************************************************************************/
6013 static BOOLEAN HaveStreamsChanged(ADB_STREAM_REC *slist1, ADB_STREAM_REC *slist2)
6014 {
6015  BOOLEAN changed;
6016  ADB_STREAM_REC *srec1;
6017  ADB_STREAM_REC *srec2;
6018 
6019  FUNCTION_START(HaveStreamsChanged);
6020 
6021  changed = FALSE;
6022 
6023  if (DBDEF_NumStreamsInList(slist1) != DBDEF_NumStreamsInList(slist2))
6024  {
6025  changed = TRUE;
6026  }
6027  else
6028  {
6029  /* Need to check whether streams in one list are the same as streams in the other */
6030  srec1 = slist1;
6031  while ((srec1 != NULL) && !changed)
6032  {
6033  srec2 = slist2;
6034  while ((srec2 != NULL) && (srec2->pid != srec1->pid))
6035  {
6036  srec2 = srec2->next;
6037  }
6038 
6039  if (srec2 == NULL)
6040  {
6041  /* PID wasn't found so streams have changed */
6042  changed = TRUE;
6043  }
6044 
6045  srec1 = srec1->next;
6046  }
6047  }
6048 
6049  FUNCTION_FINISH(HaveStreamsChanged);
6050 
6051  return(changed);
6052 }
6053 
6065 static BOOLEAN ProcessNitTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode, BOOLEAN report_nit,
6066  BOOLEAN transport_changed)
6067 {
6068  SI_NIT_TABLE *nit_table;
6069  SI_NIT_TRANSPORT_ENTRY *nit_entry;
6070  ADB_SERVICE_REC *s_ptr;
6071  ADB_SERVICE_REC *s2_ptr;
6072  U8BIT i, j;
6073  BOOLEAN changed;
6074  U16BIT reqd_lcn;
6075  U8BIT path;
6076  ADB_TRANSPORT_REC *t_ptr;
6077  SI_MULTILING_NET_NAME_DESC *mlnn_desc_ptr;
6078  SI_STRING_DESC *str_desc;
6079  U8BIT lang_id;
6080  ADB_NETWORK_REC *n_ptr;
6081  SI_LINKAGE_DESC_ENTRY *linkage_desc_ptr;
6082  void *sat_ptr;
6083  BOOLEAN restart_sdts;
6084  SI_NIT_FREQUENCY_LIST_DESC *freq_list_ptr;
6085 
6086  FUNCTION_START(ProcessNitTable);
6087 
6088  restart_sdts = FALSE;
6089 
6090  path = table_rec->path;
6091 
6092  nit_table = STB_SIParseNitTable(table_rec);
6093  if (nit_table != NULL)
6094  {
6095  #ifdef DEBUG_SI_NIT
6096  AP_SI_PRINT(("NIT Table: net_id 0x%04x v%d",
6097  nit_table->net_id, nit_table->version));
6098  #endif
6099 
6100  sat_ptr = ACTL_GetCurrentSatellite(path);
6101 
6102  // get access to the database (may suspend)
6104 
6105  // get network record
6106  n_ptr = DBDEF_FindNetworkRec(nit_table->net_id, sat_ptr);
6107  if (n_ptr != NULL)
6108  {
6109  if (n_ptr->profile_type == ADB_PROFILE_TYPE_CIPLUS)
6110  {
6111  /* Don't change CI+ profiles */
6112  while (n_ptr != NULL)
6113  {
6114  n_ptr = DBDEF_GetNextNetworkRec(n_ptr);
6115  if ((n_ptr != NULL) && (n_ptr->net_id == nit_table->net_id) &&
6116  (n_ptr->satellite == sat_ptr) && (n_ptr->profile_type != ADB_PROFILE_TYPE_CIPLUS))
6117  {
6118  /* Found a matching non CI+ network, use it */
6119  break;
6120  }
6121  }
6122  }
6123 
6124  if (n_ptr != NULL)
6125  {
6126  if (n_ptr->nit_version != nit_table->version)
6127  {
6128  // save version in network record
6129  n_ptr->nit_version = nit_table->version;
6130 
6131  if (mode != DB_ACCESS_SEARCH)
6132  {
6133  n_ptr->nit_version_changed = TRUE;
6134 
6135  DBA_SetFieldValue(n_ptr->dba_rec, DBA_FIELD_VERSION, n_ptr->nit_version);
6136  DBA_SaveRecord(n_ptr->dba_rec);
6137  }
6138  }
6139  else
6140  {
6141  n_ptr->nit_version_changed = FALSE;
6142  }
6143  }
6144  }
6145 
6146  if (mode == DB_ACCESS_SEARCH)
6147  {
6148  if (n_ptr == NULL)
6149  {
6150  n_ptr = DBDEF_AddNetworkRec(nit_table->net_id, sat_ptr);
6151  }
6152 
6153  if (n_ptr != NULL)
6154  {
6155  //save this network as the tuned network
6156  DBDEF_SetTunedNetwork(path, n_ptr);
6157  current_network_rec[path] = n_ptr;
6158 
6159  if (current_transport_rec[path]->network != n_ptr)
6160  {
6161  // link the current transport to the network
6162  current_transport_rec[path]->network = n_ptr;
6163  DBA_SetRecordParent(current_transport_rec[path]->dba_rec, n_ptr->dba_rec);
6164  DBA_SaveRecord(current_transport_rec[path]->dba_rec);
6165  }
6166 
6167  /* Save version in network record */
6168  n_ptr->nit_version = nit_table->version;
6169  DBA_SetFieldValue(n_ptr->dba_rec, DBA_FIELD_VERSION, n_ptr->nit_version);
6170 
6171  /* Now doing a search, so version no longer changed */
6172  n_ptr->nit_version_changed = FALSE;
6173 
6174  if (n_ptr->satellite != sat_ptr)
6175  {
6176  if ((n_ptr->satellite = sat_ptr) != NULL)
6177  {
6178  DBA_SetRecordParent(n_ptr->dba_rec, n_ptr->satellite->dba_rec);
6179  }
6180  else
6181  {
6182  DBA_SetRecordParent(n_ptr->dba_rec, NULL);
6183  }
6184  }
6185 
6186  DBA_SaveRecord(n_ptr->dba_rec);
6187 
6188  /* The target region data will only be kept until after the search has completed
6189  * and all of the info gathered may be needed so just keep the lot and ensure it
6190  * isn't deleted when the table gets deleted. */
6191  n_ptr->target_region_name_list = nit_table->target_region_name_list;
6192  nit_table->target_region_name_list = NULL;
6193 
6194  n_ptr->target_region_list = nit_table->target_region_list;
6195  nit_table->target_region_list = NULL;
6196  }
6197 
6198  /* If the NIT contains linkage descriptors types 0xB or 0xC, then this transport is not DVB C/T/S */
6199  linkage_desc_ptr = nit_table->linkage_desc_list;
6200  s_ptr = NULL;
6201  while (linkage_desc_ptr != NULL)
6202  {
6203  if ((linkage_desc_ptr->link_type == DVB_DVBH1_LINKAGE_TYPE) ||
6204  (linkage_desc_ptr->link_type == DVB_DVBH2_LINKAGE_TYPE))
6205  {
6206 #ifdef DEBUG_SI_NIT
6207  AP_SI_PRINT((" linkage_type=0x%x (DVB-H) onid=0x%x tran_id=0x%x", linkage_desc_ptr->link_type,
6208  linkage_desc_ptr->orig_net_id, linkage_desc_ptr->tran_id));
6209 #endif
6210  /* Delete all the services on this transport that might have been added */
6211  s_ptr = DBDEF_FindServiceRecByIds(s_ptr, ADB_INVALID_DVB_ID,
6212  linkage_desc_ptr->orig_net_id, linkage_desc_ptr->tran_id, ADB_INVALID_DVB_ID);
6213  while (s_ptr != NULL)
6214  {
6215  s2_ptr = DBDEF_FindServiceRecByIds(s_ptr, ADB_INVALID_DVB_ID,
6216  linkage_desc_ptr->orig_net_id, linkage_desc_ptr->tran_id, ADB_INVALID_DVB_ID);
6217 #ifdef DEBUG_SI_NIT
6218  AP_SI_PRINT((" deleting non DVB-T/C/S sid=0x%x", s_ptr->serv_id));
6219 #endif
6220  /* Ignore services that are part of a CI+ profile */
6221  if ((s_ptr->transport == NULL) ||
6222  (s_ptr->transport->network == NULL) ||
6223  (s_ptr->transport->network->profile_type != ADB_PROFILE_TYPE_CIPLUS))
6224  {
6225  DBDEF_DeleteServiceRec(s_ptr);
6226  }
6227  s_ptr = s2_ptr;
6228  }
6229  }
6230  linkage_desc_ptr = linkage_desc_ptr->next;
6231  }
6232 
6233  // extract logical channel numbers for the current transport only
6234  nit_entry = nit_table->transport_list;
6235  while (nit_entry != NULL)
6236  {
6237  /* Ignore transports that are part of a CI+ profile */
6238  if ((nit_entry->tran_id == current_transport_rec[path]->tran_id) &&
6239  ((current_transport_rec[path]->network == NULL) ||
6240  current_transport_rec[path]->network->profile_type != ADB_PROFILE_TYPE_CIPLUS))
6241  {
6242  if (current_transport_rec[path]->orig_net_id != nit_entry->orig_net_id)
6243  {
6244  current_transport_rec[path]->orig_net_id = nit_entry->orig_net_id;
6245  DBA_SetFieldValue(current_transport_rec[path]->dba_rec, DBA_FIELD_ORIG_NET_ID,
6246  current_transport_rec[path]->orig_net_id);
6247  }
6248 
6249  /* Check for nordig version two LCN descripter, if this doesn't exsist then use normal lcn descripter*/
6250  if (nit_entry->nordig_lcn_desc_array != NULL)
6251  {
6252  /* Mark all services as unavailable */
6253  s_ptr = DBDEF_GetNextServiceOnTransport(NULL, current_transport_rec[path]);
6254  while (s_ptr != NULL)
6255  {
6256  if (s_ptr->serv_lcn != 0)
6257  {
6258  s_ptr->unavailable = TRUE;
6259  }
6260  s_ptr = DBDEF_GetNextServiceOnTransport(s_ptr, current_transport_rec[path]);
6261  }
6262 
6263  for (j = 0; j < nit_entry->num_nordig_lcn_entries; j++)
6264  {
6265  for (i = 0; i < nit_entry->nordig_lcn_desc_array[j].num_services; i++)
6266  {
6267  s_ptr = DBDEF_FindServiceRec(nit_entry->nordig_lcn_desc_array[j].serv_array[i].serv_id,
6268  current_transport_rec[path]);
6269 
6270  if (s_ptr != NULL)
6271  {
6272  reqd_lcn = nit_entry->nordig_lcn_desc_array[j].serv_array[i].serv_lcn;
6273 
6274  /* Set service hidden attribute for Nordig LCN descriptor version 2, a hidden service still
6275  need to be selectable, so it's aways TRUE in this case, for other countries such as UK,
6276  service attribute may be overwritten by service attribute descriptor */
6277  s_ptr->hidden = !nit_entry->nordig_lcn_desc_array[j].serv_array[i].visible;
6278  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_HIDDEN, s_ptr->hidden);
6279 
6280  s_ptr->selectable = TRUE;
6281  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_SELECTABLE, s_ptr->selectable);
6282 
6283  if (reqd_lcn != s_ptr->serv_lcn)
6284  {
6285  if (s_ptr->serv_lcn == 0)
6286  {
6287  s_ptr->unavailable = FALSE;
6288 
6289  /* First time the LCN for this service has been set */
6290  s_ptr->serv_lcn = reqd_lcn;
6291  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_REQ_LCN, s_ptr->serv_lcn);
6292 #ifdef DEBUG_SI_NIT
6293  AP_SI_PRINT((" LCN for 0x%04x, %u, hidden=%u", s_ptr->serv_id,
6294  reqd_lcn, s_ptr->hidden));
6295 #endif
6296  }
6297  else
6298  {
6299  /* The same service is being allocated a different LCN.
6300  * Check whether this LCN is already assigned to another service */
6301  s2_ptr = DBDEF_FindServiceRecByLcn(reqd_lcn, current_transport_rec[path], FALSE);
6302  if (s2_ptr == NULL)
6303  {
6304  /* Add a new duplicate service with this LCN */
6305 #ifdef DEBUG_SI_NIT
6306  AP_SI_PRINT((" copy service sid 0x%04x, lcn %u, new lcn %u",
6307  s_ptr->serv_id, s_ptr->serv_lcn, reqd_lcn));
6308 #endif
6309  s2_ptr = DBDEF_CopyServiceRec(s_ptr);
6310  if (s2_ptr != NULL)
6311  {
6312  s2_ptr->unavailable = FALSE;
6313 
6314  s2_ptr->new_service = TRUE;
6315  s2_ptr->serv_lcn = reqd_lcn;
6316  DBA_SetFieldValue(s2_ptr->dba_rec, DBA_FIELD_SERV_REQ_LCN,
6317  s2_ptr->serv_lcn);
6318  DBA_SaveRecord(s2_ptr->dba_rec);
6319  }
6320  }
6321  }
6322  }
6323  else
6324  {
6325  s_ptr->unavailable = FALSE;
6326  }
6327  DBA_SaveRecord(s_ptr->dba_rec);
6328  }
6329  }
6330  }
6331  }
6332  else
6333  {
6334  for (i = 0; i < nit_entry->num_lcn_entries; i++)
6335  {
6336  s_ptr = DBDEF_FindServiceRec(nit_entry->lcn_desc_array[i].serv_id,
6337  current_transport_rec[path]);
6338 
6339  if (s_ptr != NULL)
6340  {
6341  reqd_lcn = nit_entry->lcn_desc_array[i].serv_lcn;
6342 
6343  /* Set service hidden attribute for Nordig LCN descriptor version 1, a hidden service still
6344  need to be selectable, so it's aways TRUE in this case */
6345  s_ptr->hidden = !nit_entry->lcn_desc_array[i].visible;
6346  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_HIDDEN, s_ptr->hidden);
6347 
6348  s_ptr->selectable = TRUE;
6349  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_SELECTABLE, s_ptr->selectable);
6350 
6351  if (reqd_lcn != s_ptr->serv_lcn)
6352  {
6353  s_ptr->serv_lcn = reqd_lcn;
6354  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_REQ_LCN, s_ptr->serv_lcn);
6355 #ifdef DEBUG_SI_NIT
6356  AP_SI_PRINT((" LCN for 0x%04x, %u, hidden=%u", s_ptr->serv_id, reqd_lcn,
6357  s_ptr->hidden));
6358 #endif
6359  }
6360  DBA_SaveRecord(s_ptr->dba_rec);
6361  }
6362  }
6363  }
6364 
6365  /* Extract the service attributes - hidden/selectable flags */
6366  for (i = 0; i < nit_entry->num_serv_attr_entries; i++)
6367  {
6368  s_ptr = DBDEF_FindServiceRec(nit_entry->serv_attr_array[i].serv_id,
6369  current_transport_rec[path]);
6370 
6371  if (s_ptr != NULL)
6372  {
6373  s_ptr->hidden = !nit_entry->serv_attr_array[i].service_visible;
6374  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_HIDDEN, s_ptr->hidden);
6375 
6376  s_ptr->selectable = nit_entry->serv_attr_array[i].service_selectable;
6377  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_SELECTABLE, s_ptr->selectable);
6378 
6379  DBA_SaveRecord(s_ptr->dba_rec);
6380  }
6381  }
6382 
6383  /* Now take into account any HD LCN assignments */
6384  for (i = 0; i < nit_entry->num_hd_lcn_entries; i++)
6385  {
6386  s_ptr = DBDEF_FindServiceRec(nit_entry->hd_lcn_desc_array[i].serv_id,
6387  current_transport_rec[path]);
6388 
6389  if ((s_ptr != NULL) && (s_ptr->old_allocated_lcn == 0))
6390  {
6391  /* The HD LCN descriptor will be used at the end of the scan
6392  * after the LCN conflicts and duplicated services have been
6393  * dealt with. hd_lcn_desc will be freed by
6394  * ADB_ReleaseDatabaseSearchData() */
6395  s_ptr->hd_lcn_desc = STB_GetMemory(sizeof(SI_LCN_DESC));
6396  memcpy(s_ptr->hd_lcn_desc, &nit_entry->hd_lcn_desc_array[i],
6397  sizeof(SI_LCN_DESC));
6398  }
6399  }
6400  }
6401 
6402  t_ptr = DBDEF_FindTransportRecByIds(NULL, ADB_INVALID_DVB_ID,
6403  nit_entry->orig_net_id, nit_entry->tran_id);
6404  if ((t_ptr != NULL) && (t_ptr->network != NULL) &&
6405  (t_ptr->network->profile_type == ADB_PROFILE_TYPE_CIPLUS))
6406  {
6407  /* Ignore transports that are part of a CI+ profile */
6408  t_ptr = NULL;
6409  }
6410 
6411  if (nit_entry->del_sys_desc != NULL)
6412  {
6413  if (t_ptr == NULL)
6414  {
6415  /* Add a new transport based on the system delivery descriptor */
6416  switch (nit_entry->del_sys_desc_type)
6417  {
6418  case SI_DEL_SYS_DESC_TYPE_TERR:
6419  if (current_transport_rec[path]->sig_type == SIGNAL_COFDM)
6420  {
6421  if (nit_entry->del_sys_desc->terr.is_t2)
6422  {
6423  if ((nit_entry->del_sys_desc->terr.u.t2.num_cells > 0) &&
6424  (nit_entry->del_sys_desc->terr.u.t2.cell[0].num_freqs > 0))
6425  {
6426  if ((t_ptr = DBDEF_FindTerrestrialTransportRec(
6427  nit_entry->del_sys_desc->terr.u.t2.cell[0].freq_hz[0],
6428  nit_entry->del_sys_desc->terr.u.t2.plp_id)) == NULL)
6429  {
6430  #ifdef DEBUG_SI_NIT
6431  AP_SI_PRINT((" Adding terr transport for %lu Hz, PLP %u",
6432  nit_entry->del_sys_desc->terr.u.t2.cell[0].freq_hz[0],
6433  nit_entry->del_sys_desc->terr.u.t2.plp_id));
6434  #endif
6436  nit_entry->del_sys_desc->terr.u.t2.cell[0].freq_hz[0],
6437  nit_entry->del_sys_desc->terr.u.t2.plp_id, n_ptr);
6438  }
6439  }
6440  }
6441  else
6442  {
6443  if ((t_ptr = DBDEF_FindTerrestrialTransportRec(nit_entry->del_sys_desc->terr.u.t1.freq_hz, 0)) == NULL)
6444  {
6445  #ifdef DEBUG_SI_NIT
6446  AP_SI_PRINT((" Adding terr transport for %lu Hz",
6447  nit_entry->del_sys_desc->terr.u.t1.freq_hz));
6448  #endif
6449  t_ptr = DBDEF_AddTerrestrialTransportRec(nit_entry->del_sys_desc->terr.u.t1.freq_hz,
6450  0, n_ptr);
6451  }
6452  }
6453  }
6454  break;
6455  case SI_DEL_SYS_DESC_TYPE_CABLE:
6456  if (current_transport_rec[path]->sig_type == SIGNAL_QAM)
6457  {
6458  if ((t_ptr = DBDEF_FindCableTransportRec(nit_entry->del_sys_desc->cable.freq_hz,
6459  nit_entry->del_sys_desc->cable.symbol_rate)) == NULL)
6460  {
6461  #ifdef DEBUG_SI_NIT
6462  AP_SI_PRINT((" Adding cable transport for %lu Hz, symbol rate %u Kbits",
6463  nit_entry->del_sys_desc->cable.freq_hz,
6464  nit_entry->del_sys_desc->cable.symbol_rate));
6465  #endif
6466  t_ptr = DBDEF_AddCableTransportRec(nit_entry->del_sys_desc->cable.freq_hz,
6467  nit_entry->del_sys_desc->cable.symbol_rate, n_ptr);
6468  }
6469  else
6470  {
6471  /* Symbol rate read from a tuner isn't very accurate, so use the setting
6472  * from the delivery descriptor */
6473  t_ptr->u.cab.symbol_rate = (U16BIT)nit_entry->del_sys_desc->cable.symbol_rate;
6474  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRAN_SRATE, t_ptr->u.cab.symbol_rate);
6475  }
6476  }
6477  break;
6478  case SI_DEL_SYS_DESC_TYPE_SAT:
6479  if (current_transport_rec[path]->sig_type == SIGNAL_QPSK)
6480  {
6481  if ((t_ptr = DBDEF_FindSatTransportRec(nit_entry->del_sys_desc->sat.freq_hz,
6482  nit_entry->del_sys_desc->sat.sym_rate,
6483  nit_entry->del_sys_desc->sat.polarity,
6484  nit_entry->del_sys_desc->sat.dvb_s2,
6485  nit_entry->del_sys_desc->sat.modulation, sat_ptr)) == NULL)
6486  {
6487  #ifdef DEBUG_SI_NIT
6488  AP_SI_PRINT((" Adding sat transport for %lu Hz, symrate %u, polarity %u, DVB-S2 %u, modulation %u",
6489  nit_entry->del_sys_desc->sat.freq_hz,
6490  nit_entry->del_sys_desc->sat.sym_rate,
6491  nit_entry->del_sys_desc->sat.polarity,
6492  nit_entry->del_sys_desc->sat.dvb_s2,
6493  nit_entry->del_sys_desc->sat.modulation));
6494  #endif
6495  t_ptr = DBDEF_AddSatTransportRec(nit_entry->del_sys_desc->sat.freq_hz,
6496  nit_entry->del_sys_desc->sat.sym_rate,
6497  nit_entry->del_sys_desc->sat.polarity,
6498  nit_entry->del_sys_desc->sat.dvb_s2,
6499  nit_entry->del_sys_desc->sat.modulation, n_ptr);
6500  }
6501  }
6502  break;
6503  default:
6504  break;
6505  }
6506  if (t_ptr != NULL)
6507  {
6508  DBDEF_SetTransportOrigNetworkId(t_ptr, nit_entry->orig_net_id);
6509  DBDEF_SetTransportTransportId(t_ptr, nit_entry->tran_id);
6510  }
6511  }
6512  else
6513  {
6514  /* Set transport settings from the delivery descriptor */
6515  switch (nit_entry->del_sys_desc_type)
6516  {
6517  case SI_DEL_SYS_DESC_TYPE_TERR:
6518  break;
6519  case SI_DEL_SYS_DESC_TYPE_CABLE:
6520  /* Only set the symbol rate if the transport is DVB-C */
6521  if (t_ptr->sig_type == SIGNAL_QAM)
6522  {
6523  /* Symbol rate read from a tuner isn't very accurate, so use the setting
6524  * from the delivery descriptor */
6525  t_ptr->u.cab.symbol_rate = (U16BIT)nit_entry->del_sys_desc->cable.symbol_rate;
6526  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRAN_SRATE, t_ptr->u.cab.symbol_rate);
6527  }
6528  break;
6529  case SI_DEL_SYS_DESC_TYPE_SAT:
6530  break;
6531  default:
6532  break;
6533  }
6534  }
6535 
6536  if (t_ptr != NULL)
6537  {
6538  DBDEF_SetTransportOrigNetworkId(t_ptr, nit_entry->orig_net_id);
6539  }
6540  }
6541 
6542  if (t_ptr != NULL)
6543  {
6544  if (nit_entry->target_region_list != NULL)
6545  {
6546  /* The target region data will only be kept until after the search has completed
6547  * and all of the info gathered may be needed so just keep the lot and ensure it
6548  * isn't deleted when the table gets deleted. */
6549  t_ptr->u.terr.target_region_list = nit_entry->target_region_list;
6550  nit_entry->target_region_list = NULL;
6551  }
6552  }
6553 
6554  nit_entry = nit_entry->next;
6555  }
6556  }
6557  else if ((mode == DB_ACCESS_UPDATE) && (n_ptr != NULL) && n_ptr->nit_version_changed)
6558  {
6559  nit_entry = nit_table->transport_list;
6560  while (nit_entry != NULL)
6561  {
6562  t_ptr = DBDEF_FindTransportRecByIds(NULL, ADB_INVALID_DVB_ID,
6563  nit_entry->orig_net_id, nit_entry->tran_id);
6564  if (t_ptr != NULL)
6565  {
6566  if (ASI_DatabaseUpdatesAllowed(t_ptr->sig_type) &&
6567  ACFG_GetDynamicSIUpdate(t_ptr->sig_type, nit_entry->orig_net_id,
6568  (ACFG_DYNAMIC_SI_UPDATE_LCNS |
6569  ACFG_DYNAMIC_SI_UPDATE_SERVICE_ADD |
6570  ACFG_DYNAMIC_SI_UPDATE_SERVICE_REMOVE)))
6571  {
6572  /* Service addition or deletion means LCNs may change so LCN descriptors need to
6573  * be saved so they can be applied following any changes to the service line up */
6574  if (DynamicUpdateAddTransport(t_ptr,
6575  nit_entry->num_lcn_entries, nit_entry->lcn_desc_array,
6576  nit_entry->num_hd_lcn_entries, nit_entry->hd_lcn_desc_array,
6577  nit_entry->num_nordig_lcn_entries, nit_entry->nordig_lcn_desc_array))
6578  {
6579  /* The structure for the Nordig LCNs isn't a simple array structure, so the
6580  * LCN array from the transport will have been used directly and will be freed
6581  * later, so the array is set to NULL to ensure it isn't freed with the NIT */
6582  nit_entry->num_nordig_lcn_entries = 0;
6583  nit_entry->nordig_lcn_desc_array = NULL;
6584 
6585  /* The target region data may be needed for the allocation of LCNs so it's
6586  * kept until after the dynamic update process has completed, when it will
6587  * be freed */
6588  t_ptr->u.terr.target_region_list = nit_entry->target_region_list;
6589  nit_entry->target_region_list = NULL;
6590 
6591  /* The SDT for this transport needs to be processed again, so mark it as not
6592  * having been received yet so we can tell when it has been */
6593  t_ptr->sdt_received = FALSE;
6594 
6595  restart_sdts = TRUE;
6596  }
6597  }
6598  }
6599 
6600  nit_entry = nit_entry->next;
6601  }
6602  }
6603 
6604  if (n_ptr != NULL)
6605  {
6607  {
6608  if (nit_table->name_str != NULL)
6609  {
6610  DBDEF_SetNetworkName(n_ptr, nit_table->name_str->str_ptr);
6611  }
6612  else
6613  {
6614  DBDEF_SetNetworkName(n_ptr, NULL);
6615  }
6616 
6617  // now multilingual network names (not stored in nvm)
6618  // free old entries
6619  for (i = 0; i < ACFG_NUM_DB_LANGUAGES; i++)
6620  {
6621  if (n_ptr->name_array[i] != NULL)
6622  {
6623  STB_AppFreeMemory(n_ptr->name_array[i]);
6624  n_ptr->name_array[i] = NULL;
6625  }
6626  }
6627 
6628  // populate new entries
6629  mlnn_desc_ptr = nit_table->multiling_net_name_desc_array;
6630  for (i = 0; i < nit_table->num_multiling_net_names; i++, mlnn_desc_ptr++)
6631  {
6632  if (mlnn_desc_ptr->name_str != NULL)
6633  {
6634  lang_id = ACFG_ConvertLangCodeToId(mlnn_desc_ptr->lang_code);
6635  if (lang_id != ACFG_INVALID_DB_LANG)
6636  {
6637  if (n_ptr->name_array[lang_id] == NULL)
6638  {
6639  str_desc = mlnn_desc_ptr->name_str;
6640  n_ptr->name_array[lang_id] = DBDEF_MakeString(mlnn_desc_ptr->lang_code,
6641  str_desc->str_ptr, str_desc->nbytes);
6642  }
6643  }
6644  }
6645  }
6646  }
6647 
6648  if (nit_table->def_authority != NULL)
6649  {
6650  changed = TRUE;
6651 
6652  if (n_ptr->def_authority != NULL)
6653  {
6654  /* Check whether the default authority has changed */
6655  if (nit_table->def_authority->nbytes == n_ptr->def_authority->nbytes)
6656  {
6657  if (memcmp(n_ptr->def_authority->str_ptr, nit_table->def_authority->str_ptr,
6658  n_ptr->def_authority->nbytes) == 0)
6659  {
6660  /* The names are the same */
6661  changed = FALSE;
6662  }
6663  }
6664  }
6665 
6666  if (changed)
6667  {
6668  /* Free the old authority string */
6669  if (n_ptr->def_authority != NULL)
6670  {
6671  STB_AppFreeMemory(n_ptr->def_authority);
6672  n_ptr->def_authority = NULL;
6673  }
6674 
6675  /* Add the new authority string */
6676  n_ptr->def_authority = DBDEF_MakeString(0, nit_table->def_authority->str_ptr,
6677  nit_table->def_authority->nbytes);
6678 #ifdef DEBUG_SI_NIT
6679  AP_SI_PRINT((" Network \"%s\" has default authority \"%s\"", n_ptr->name_str->str_ptr,
6680  n_ptr->def_authority->str_ptr));
6681 #endif
6682  }
6683  }
6684 
6685  if (nit_table->fta_content_desc != NULL)
6686  {
6687  n_ptr->has_fta_desc = TRUE;
6688  n_ptr->do_not_scramble = nit_table->fta_content_desc->do_not_scramble;
6689  }
6690  }
6691 
6692  nit_entry = nit_table->transport_list;
6693  while (nit_entry != NULL)
6694  {
6695  t_ptr = DBDEF_FindTransportRecByIds(NULL, nit_table->net_id, nit_entry->orig_net_id,
6696  nit_entry->tran_id);
6697  if ((t_ptr != NULL) && (t_ptr->network != NULL) &&
6698  (t_ptr->network->profile_type == ADB_PROFILE_TYPE_CIPLUS))
6699  {
6700  /* Ignore transports that are part of a CI+ profile */
6701  t_ptr = NULL;
6702  }
6703 
6704  if (t_ptr != NULL)
6705  {
6706  if (nit_entry->fta_content_desc != NULL)
6707  {
6708  t_ptr->has_fta_desc = TRUE;
6709  t_ptr->do_not_scramble = nit_entry->fta_content_desc->do_not_scramble;
6710  }
6711 
6712  if (nit_entry->def_authority != NULL)
6713  {
6714  changed = TRUE;
6715 
6716  if (t_ptr->def_authority != NULL)
6717  {
6718  /* Check whether the default authority has changed */
6719  if (nit_entry->def_authority->nbytes == t_ptr->def_authority->nbytes)
6720  {
6721  if (memcmp(t_ptr->def_authority->str_ptr, nit_entry->def_authority->str_ptr,
6722  t_ptr->def_authority->nbytes) == 0)
6723  {
6724  /* The names are the same */
6725  changed = FALSE;
6726  }
6727  }
6728  }
6729 
6730  if (changed)
6731  {
6732  /* Free the old authority string */
6733  if (t_ptr->def_authority != NULL)
6734  {
6735  STB_AppFreeMemory(t_ptr->def_authority);
6736  t_ptr->def_authority = NULL;
6737  }
6738 
6739  /* Add the new authority string */
6740  t_ptr->def_authority = DBDEF_MakeString(0, nit_entry->def_authority->str_ptr,
6741  nit_entry->def_authority->nbytes);
6742 #ifdef DEBUG_SI_NIT
6743  AP_SI_PRINT((" Transport 0x%x has default authority \"%s\"", t_ptr->tran_id,
6744  t_ptr->def_authority->str_ptr));
6745 #endif
6746  }
6747  }
6748 
6749  if (nit_entry->freq_list != NULL)
6750  {
6751  if (t_ptr->additional_frequencies != NULL)
6752  {
6753  STB_AppFreeMemory(t_ptr->additional_frequencies);
6754  t_ptr->additional_frequencies = NULL;
6755  t_ptr->num_additional_frequencies = 0;
6756  }
6757 
6758  /* See if a list of additional frequencies exists for this transport based on its signal type */
6759  for (freq_list_ptr = nit_entry->freq_list; freq_list_ptr != NULL; freq_list_ptr = freq_list_ptr->next)
6760  {
6761  if (((t_ptr->sig_type == SIGNAL_QPSK) &&
6762  (freq_list_ptr->coding_type == FREQ_LIST_CODING_TYPE_SATELLITE)) ||
6763  ((t_ptr->sig_type == SIGNAL_QAM) &&
6764  (freq_list_ptr->coding_type == FREQ_LIST_CODING_TYPE_CABLE)) ||
6765  ((t_ptr->sig_type == SIGNAL_COFDM) &&
6766  (freq_list_ptr->coding_type == FREQ_LIST_CODING_TYPE_TERRESTRIAL)))
6767  {
6768  /* This is a list of additional frequencies for this transport.
6769  * Save the frequencies with the transport so they can be used, if needed,
6770  * the next time there's an attempt to tune to it */
6771  t_ptr->additional_frequencies = STB_AppGetMemory(freq_list_ptr->num_frequencies * sizeof(U32BIT));
6772  if (t_ptr->additional_frequencies != NULL)
6773  {
6774  memcpy(t_ptr->additional_frequencies, freq_list_ptr->frequency_array,
6775  freq_list_ptr->num_frequencies * sizeof(U32BIT));
6776  t_ptr->num_additional_frequencies = freq_list_ptr->num_frequencies;
6777  }
6778  break;
6779  }
6780  }
6781  }
6782  }
6783 
6784  nit_entry = nit_entry->next;
6785  }
6786 
6787  if (n_ptr != NULL)
6788  {
6789  if (mode == DB_ACCESS_UPDATE)
6790  {
6791  /* Delete the linkage array for repopulation */
6792  DeleteLinkageDescripterArray(n_ptr->linkage_desc_list);
6793  n_ptr->last_linkage_entry = NULL;
6794  n_ptr->num_linkage_entries = 0;
6795  n_ptr->linkage_desc_list = NULL;
6796 
6797  /* Copy all network linkage descripters */
6798  linkage_desc_ptr = nit_table->linkage_desc_list;
6799  while (linkage_desc_ptr != NULL)
6800  {
6801  CopyLinkageDesc(linkage_desc_ptr,
6802  &n_ptr->linkage_desc_list,
6803  &n_ptr->last_linkage_entry,
6804  &n_ptr->num_linkage_entries);
6805 
6806  linkage_desc_ptr = linkage_desc_ptr->next;
6807  }
6808  }
6809  }
6810 
6811  // release database access
6813 
6814  if (update_nit_func != NULL)
6815  {
6816  /* Call the function that's been registered to handle additional NIT processing */
6817  (*update_nit_func)(path, nit_table, table_rec);
6818  }
6819 
6820  // release the table - don't need it anymore
6821  STB_SIReleaseNitTable(nit_table);
6822  }
6823 
6824  if (report_nit && (transport_changed || (table_rec->version != last_reported_nit_version[path])))
6825  {
6826  #ifdef DEBUG_SI_NIT
6827  AP_SI_PRINT(("%s: reporting NIT 0x%04x, ver=%u", __FUNCTION__, table_rec->xtid, table_rec->version));
6828  #endif
6829 
6830  if (STB_SIReportNit(table_rec))
6831  {
6832  last_reported_nit_version[path] = table_rec->version;
6833  }
6834  }
6835 
6836  STB_SIReleaseTableRecord(table_rec);
6837 
6838  FUNCTION_FINISH(ProcessNitTable);
6839 
6840  return(restart_sdts);
6841 }
6842 
6861 static void ProcessCatTable(U8BIT path, SI_TABLE_RECORD *table_rec, BOOLEAN report_cat, BOOLEAN transport_changed)
6862 {
6863  FUNCTION_START(ProcessCatTable);
6864 
6865 #ifdef DEBUG_SI_CAT
6866  AP_SI_PRINT(("%s(%u, report_cat=%u, transport_changed=%u): table_rec->version=%d last version=%d",
6867  __FUNCTION__, path, report_cat, transport_changed, table_rec->version, last_reported_cat_version[path]));
6868 #endif
6869 
6870  // check if CAT needs reporting to other applications (e.g. ca systems)
6871  if (report_cat && (transport_changed || (table_rec->version != last_reported_cat_version[path])))
6872  {
6873  #ifdef DEBUG_SI_CAT
6874  AP_SI_PRINT(("Reporting cat: version=%d num_sects=%d", table_rec->version, table_rec->num_sect));
6875  #endif
6876 
6877  if (STB_SIReportCat(table_rec))
6878  {
6879  last_reported_cat_version[path] = table_rec->version;
6880  }
6881  }
6882 
6883  STB_SIReleaseTableRecord(table_rec);
6884 
6885  FUNCTION_FINISH(ProcessCatTable);
6886 }
6887 
6888 /*!**************************************************************************
6889  * @brief Processes the related content table (RCT) to provide trailer booking functionality.
6890  * It's assumed that only the RCT for the current service will have been requested.
6891  * @param table_rec - pointer to the SI table data
6892  ****************************************************************************/
6893 static void ProcessRctTable(SI_TABLE_RECORD *table_rec)
6894 {
6895  SI_RCT_TABLE *rct_table;
6896  SI_RCT_SUBTABLE *subtable;
6897  SI_RCT_SUBTABLE_DATA *subdata;
6898  SI_RCT_LINK_INFO *link_info;
6899  SI_RCT_PROMO_TEXT *promo_text;
6900  U8BIT path;
6901  U8BIT i, link;
6902  BOOLEAN valid_link;
6903  ADB_RCT_LINK_INFO *adb_link;
6904  ADB_IMAGE_ICON *icon_ptr;
6905  U8BIT lang_id;
6906  BOOLEAN links_cleared;
6907  BOOLEAN service_links_updated;
6908 
6909  FUNCTION_START(ProcessRctTable);
6910 
6911  path = table_rec->path;
6912  service_links_updated = FALSE;
6913 
6914  rct_table = STB_SIParseRctTable(table_rec);
6915  STB_SIReleaseTableRecord(table_rec);
6916 
6917  if (rct_table != NULL)
6918  {
6919  links_cleared = FALSE;
6920 
6921  /* Look for any RCT subtables that are for the current service */
6922  subtable = rct_table->subtables;
6923  while (subtable != NULL)
6924  {
6925  /* A service ID of 0 means the service defined by the PMT that defined the PID containing the RCT */
6926  if ((subtable->service_id == 0) || (subtable->service_id == current_service_rec[path]->serv_id))
6927  {
6928  if (!links_cleared)
6929  {
6930 #ifdef DEBUG_SI_RCT
6931  AP_SI_PRINT(("Clearing RCT links for service 0x%04x", current_service_rec[path]->serv_id));
6932 #endif
6933  /* Clear the existing links for the current service */
6934  ADB_ServiceReleaseRCTLinks(current_service_rec[path]);
6935  links_cleared = TRUE;
6936  service_links_updated = TRUE;
6937  }
6938 
6939  subdata = subtable->data;
6940  while (subdata != NULL)
6941  {
6942  /* Process the links */
6943  for (link = 0; link < subdata->link_count; link++)
6944  {
6945  link_info = &subdata->link_array[link];
6946 
6947  /* Check that this is a valid link as defined by D-Book 6.2.1 */
6948  if ((link_info->link_type == RCT_LINK_TYPE_URI) &&
6949  (link_info->how_related == RCT_HOW_RELATED_TVA_2007) &&
6950  (link_info->uri_string != NULL))
6951  {
6952  switch (link_info->term_id)
6953  {
6954  case RCT_TERMID_IS_TRAILER_OF:
6955 #ifdef DEBUG_SI_RCT
6956  AP_SI_PRINT(("ProcessRctTable: Found TRAILER_OF link with uri \"%s\"",
6957  link_info->uri_string));
6958 #endif
6959  valid_link = TRUE;
6960  break;
6961 
6962  case RCT_TERMID_IS_GROUP_TRAILER_OF:
6963 #ifdef DEBUG_SI_RCT
6964  AP_SI_PRINT(("ProcessRctTable: Found GROUP_TRAILER_OF link with uri \"%s\"",
6965  link_info->uri_string));
6966 #endif
6967  valid_link = TRUE;
6968  break;
6969 
6970  default:
6971  valid_link = FALSE;
6972  break;
6973  }
6974 
6975  if (valid_link)
6976  {
6977  adb_link = (ADB_RCT_LINK_INFO *)STB_AppGetMemory(sizeof(ADB_RCT_LINK_INFO));
6978  if (adb_link != NULL)
6979  {
6980  memset(adb_link, 0, sizeof(ADB_RCT_LINK_INFO));
6981 
6982  if (link_info->term_id == RCT_TERMID_IS_GROUP_TRAILER_OF)
6983  {
6984  adb_link->is_group_trailer = TRUE;
6985  }
6986 
6987  adb_link->uri_string = (U8BIT *)STB_AppGetMemory(strlen((char *)link_info->uri_string) + 1);
6988  if (adb_link->uri_string != NULL)
6989  {
6990  strncpy((char *)adb_link->uri_string, (char *)link_info->uri_string, strlen((char *)link_info->uri_string) + 1);
6991 
6992  adb_link->can_use_default_icon = link_info->can_use_default_icon;
6993  adb_link->icon_id = link_info->icon_id;
6994 
6995  if ((link_info->event_desc != NULL) && (link_info->event_desc->name_str != NULL))
6996  {
6997  adb_link->event_name = DBDEF_MakeString(link_info->event_desc->lang_code,
6998  link_info->event_desc->name_str->str_ptr,
6999  link_info->event_desc->name_str->nbytes);
7000  }
7001 
7002  /* Store promotional text strings for each defined language */
7003  for (i = 0; i < link_info->num_items; i++)
7004  {
7005  promo_text = &link_info->promo_text_array[i];
7006 
7007  if (promo_text->string != NULL)
7008  {
7009  lang_id = ACFG_ConvertLangCodeToId(promo_text->lang_code);
7010  if (lang_id == ACFG_INVALID_DB_LANG)
7011  {
7012  lang_id = 0;
7013  }
7014 
7015  if (adb_link->promo_text[lang_id] == NULL)
7016  {
7017  adb_link->promo_text[lang_id] = DBDEF_MakeString(promo_text->lang_code,
7018  promo_text->string->str_ptr, promo_text->string->nbytes);
7019  }
7020  }
7021  }
7022 
7023 #ifdef DEBUG_SI_RCT
7024  AP_SI_PRINT(("ProcessRctTable: \"%s\" can_use_default=%u",
7025  adb_link->uri_string, adb_link->can_use_default_icon));
7026 #endif
7027  ADB_ServiceAddRCTLink(current_service_rec[path], adb_link);
7028  service_links_updated = TRUE;
7029 
7030  /* Save any icons defined in this link */
7031  for (i = 0; i < link_info->num_icons; i++)
7032  {
7033  if ((icon_ptr = ProcessImageIcon(&link_info->icon_array[i])) != NULL)
7034  {
7035  if (ADB_ServiceAddImageIcon(current_service_rec[path], icon_ptr))
7036  {
7037  #if defined(INCLUDE_DSMCC_FILE_REQUEST)
7038  IconFileRequest(icon_ptr,path);
7039  #endif
7040  }
7041  }
7042  }
7043  }
7044  else
7045  {
7046  /* Out of memory! */
7047  STB_AppFreeMemory(adb_link);
7048  }
7049  }
7050  }
7051  }
7052  }
7053 
7054  /* Add any icons defined by this subtable to the current service */
7055  for (i = 0; i < subdata->num_icons; i++)
7056  {
7057  if ((icon_ptr = ProcessImageIcon(&subdata->icon_array[i])) != NULL)
7058  {
7059  if (ADB_ServiceAddImageIcon(current_service_rec[path], icon_ptr))
7060  {
7061  #if defined(INCLUDE_DSMCC_FILE_REQUEST)
7062  IconFileRequest(icon_ptr,path);
7063  #endif
7064  }
7065  }
7066  }
7067 
7068  subdata = subdata->next;
7069  }
7070  }
7071 
7072  subtable = subtable->next;
7073  }
7074 
7075  STB_SIReleaseRctTable(rct_table);
7076 
7077  if (service_links_updated)
7078  {
7079 #ifdef DEBUG_SI_RCT
7080  AP_SI_PRINT(("ProcessRctTable: Sending PROMO_LINK_CHANGE event"));
7081 #endif
7082  /* Send an event to the app to info it that RCT link info for the current service has changed */
7083  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_MHEG, EV_TYPE_MHEG_PROMO_LINK_CHANGE, NULL, 0);
7084  }
7085  }
7086 
7087  FUNCTION_FINISH(ProcessRctTable);
7088 }
7089 
7090 /*!**************************************************************************
7091  * @brief Processes the bouquet association table (BAT)
7092  * @param table_rec - pointer to the SI table data
7093  * @param mode - mode in which the table is being processsed, SEARCH or UPDATE
7094  * @param report_bat - TRUE if the BAT can be reported to other modules, FALSE otherwise
7095  * @return TRUE if the SDT collection needs to be restarted, FALSE otherwise
7096  ****************************************************************************/
7097 static BOOLEAN ProcessBatTable(SI_TABLE_RECORD *table_rec, E_DB_ACCESS_MODE mode, BOOLEAN report_bat)
7098 {
7099  BOOLEAN process;
7100  SI_BAT_TABLE *bat_table;
7101  ADB_BAT_VERSION_REC *bat_version_rec;
7102  U8BIT list_id;
7103  U8BIT *name;
7104  U16BIT nchar;
7105  SI_BAT_TRANSPORT_ENTRY *trans_entry;
7106  ADB_TRANSPORT_REC *t_ptr;
7107  ADB_SATELLITE_REC *sat_ptr;
7108  SI_SERV_LIST_DESC *serv_desc;
7109  ADB_SERVICE_REC *s_ptr;
7110  BOOLEAN changed;
7111  U8BIT path;
7112  U16BIT i;
7113  BOOLEAN restart_sdts;
7114 
7115  FUNCTION_START(ProcessBatTable);
7116 
7117  restart_sdts = FALSE;
7118 
7119  /* Check whether this BAT needs to be processed */
7120  if (active_bouquet_ids != NULL)
7121  {
7122  process = FALSE;
7123 
7124  for (i = 0; i < num_active_bouquet_ids; i++)
7125  {
7126  if (active_bouquet_ids[i].bouquet_id == table_rec->xtid)
7127  {
7128  active_bouquet_ids[i].received = TRUE;
7129  process = TRUE;
7130  break;
7131  }
7132  }
7133  }
7134  else
7135  {
7136  /* All BATs are to be processed */
7137  process = TRUE;
7138  }
7139 
7140  if (process)
7141  {
7142  bat_table = STB_SIParseBatTable(table_rec);
7143  if (bat_table != NULL)
7144  {
7145  #ifdef DEBUG_SI_BAT
7146  AP_SI_PRINT(("BAT received: id=%u, num_trans=%u", bat_table->bouquet_id, bat_table->num_transports));
7147 
7148  if (bat_table->bouquet_name != NULL)
7149  {
7150  AP_SI_PRINT((" name=\"%s\"", bat_table->bouquet_name->str_ptr));
7151  }
7152  #endif
7153 
7154  path = table_rec->path;
7155 
7156  if ((sat_ptr = (ADB_SATELLITE_REC *)ACTL_GetCurrentSatellite(path)) != NULL)
7157  {
7158  /* Check the table version */
7159  bat_version_rec = sat_ptr->bat_version_list;
7160  while (bat_version_rec != NULL)
7161  {
7162  if (bat_version_rec->bouquet_id == bat_table->bouquet_id)
7163  {
7164  if (bat_version_rec->version == bat_table->version)
7165  {
7166  /* Version hasn't changed so doesn't need to be processed */
7167 #ifdef DEBUG_SI_BAT
7168  AP_SI_PRINT((" existing BAT version %u", bat_table->version));
7169 #endif
7170  process = FALSE;
7171  }
7172  break;
7173  }
7174 
7175  bat_version_rec = bat_version_rec->next;
7176  }
7177 
7178  if (bat_version_rec == NULL)
7179  {
7180  /* No version record for this BAT yet, so add one */
7181 #ifdef DEBUG_SI_BAT
7182  AP_SI_PRINT((" new BAT version %u", bat_table->version));
7183 #endif
7184  bat_version_rec = (ADB_BAT_VERSION_REC *)STB_AppGetMemory(sizeof(ADB_BAT_VERSION_REC));
7185  if (bat_version_rec != NULL)
7186  {
7187  bat_version_rec->bouquet_id = bat_table->bouquet_id;
7188  bat_version_rec->next = sat_ptr->bat_version_list;
7189  sat_ptr->bat_version_list = bat_version_rec;
7190  }
7191  }
7192 
7193  if (process && (bat_version_rec != NULL))
7194  {
7195  bat_version_rec->version = bat_table->version;
7196  }
7197  }
7198 
7199  if (process)
7200  {
7201  if (mode == DB_ACCESS_SEARCH)
7202  {
7203  /* No point creating a favourite list if the bouquet doesn't have a name */
7204  if (bat_table->bouquet_name != NULL)
7205  {
7206  /* Create a favourite list for this bouquet */
7207  if ((name = STB_ConvertStringToUTF8(bat_table->bouquet_name->str_ptr, &nchar, TRUE, 0)) != NULL)
7208  {
7209  if (ADB_AddFavouriteList(name, bat_table->bouquet_id, -1, &list_id))
7210  {
7212 
7213  /* Go through each transport adding transports and services, as necessary, so
7214  * the services can be added to the favourite list in the order they're defined
7215  * in the BAT */
7216  for (trans_entry = bat_table->transport_list; trans_entry != NULL;
7217  trans_entry = trans_entry->next)
7218  {
7219  t_ptr = DBDEF_FindTransportRecByIds(NULL, ADB_INVALID_DVB_ID,
7220  trans_entry->orig_net_id, trans_entry->tran_id);
7221 
7222  if ((trans_entry->num_serv_list_entries > 0) &&
7223  (trans_entry->serv_list_desc_array != NULL))
7224  {
7225  if (t_ptr == NULL)
7226  {
7227  #ifdef DEBUG_SI_BAT
7228  AP_SI_PRINT((" New transport 0x%04x/0x%04x", trans_entry->orig_net_id,
7229  trans_entry->tran_id));
7230  #endif
7231 
7232  /* Create an empty transport record so the services can be added to it */
7233  switch (current_transport_rec[path]->sig_type)
7234  {
7235  case SIGNAL_COFDM:
7236  t_ptr = DBDEF_AddTerrestrialTransportRec(0, 0, NULL);
7237  break;
7238 
7239  case SIGNAL_QAM:
7240  t_ptr = DBDEF_AddCableTransportRec(0, 0, NULL);
7241  break;
7242 
7243  case SIGNAL_QPSK:
7244  t_ptr = DBDEF_AddSatTransportRec(0, 0, POLARITY_HORIZONTAL,
7245  FALSE, MOD_AUTO, NULL);
7246  break;
7247 
7248  default:
7249  break;
7250  }
7251 
7252  if (t_ptr != NULL)
7253  {
7254  DBDEF_SetTransportTransportId(t_ptr, trans_entry->tran_id);
7255  DBDEF_SetTransportOrigNetworkId(t_ptr, trans_entry->orig_net_id);
7256  }
7257  #ifdef DEBUG_SI_BAT
7258  else
7259  {
7260  AP_SI_PRINT((" Failed to create transport!", __FUNCTION__));
7261  }
7262  #endif
7263  }
7264  #ifdef DEBUG_SI_BAT
7265  else
7266  {
7267  AP_SI_PRINT((" Existing transport 0x%04x/0x%04x", trans_entry->orig_net_id,
7268  trans_entry->tran_id));
7269  }
7270  #endif
7271 
7272  if (t_ptr != NULL)
7273  {
7274  for (i = 0; i < trans_entry->num_serv_list_entries; i++)
7275  {
7276  serv_desc = &trans_entry->serv_list_desc_array[i];
7277  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID,
7278  t_ptr->orig_net_id, t_ptr->tran_id, serv_desc->serv_id);
7279  if (s_ptr == NULL)
7280  {
7281  #ifdef DEBUG_SI_BAT
7282  AP_SI_PRINT((" New service 0x%04x", serv_desc->serv_id));
7283  #endif
7284 
7285  /* Create a new service */
7286  if ((s_ptr = DBDEF_AddServiceRec(serv_desc->serv_id, t_ptr)) != NULL)
7287  {
7288  s_ptr->found = FALSE;
7289  s_ptr->unavailable = TRUE;
7290 
7291  s_ptr->serv_type = serv_desc->serv_type;
7292  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_TYPE, s_ptr->serv_type);
7293 
7294  DBA_SaveRecord(s_ptr->dba_rec);
7295  }
7296  #ifdef DEBUG_SI_BAT
7297  else
7298  {
7299  AP_SI_PRINT((" Failed to create service!", __FUNCTION__));
7300  }
7301  #endif
7302  }
7303  #ifdef DEBUG_SI_BAT
7304  else
7305  {
7306  AP_SI_PRINT((" Existing service 0x%04x", serv_desc->serv_id));
7307  }
7308  #endif
7309 
7310  if (s_ptr != NULL)
7311  {
7312  /* Add the service to the end of the bouquet's favourite list */
7313  changed = ADB_AddServiceToFavouriteList(list_id, s_ptr, -1);
7314  #ifdef DEBUG_SI_BAT
7315  if (!changed)
7316  {
7317  AP_SI_PRINT((" Failed to add service to fav list 0x%02x", list_id));
7318  }
7319  #endif
7320  }
7321  }
7322  }
7323  }
7324  }
7325 
7327 
7328  if (ADB_GetNumServicesInList(ADB_LIST_TYPE_FROM_FAVLIST(list_id), TRUE) == 0)
7329  {
7330  #ifdef DEBUG_SI_BAT
7331  AP_SI_PRINT(("%s: Deleting empty bouquet favourite list", __FUNCTION__));
7332  #endif
7333 
7334  /* No services have been added to the list so it can be deleted */
7335  ADB_DeleteFavouriteList(list_id);
7336  }
7337  }
7338 
7340  }
7341  }
7342  }
7343  else if (mode == DB_ACCESS_UPDATE)
7344  {
7345  /* To support dynamic addition and deletion of services, info from the transports
7346  * needs to be saved so it can be applied when all relevant SDTs have been received */
7347  trans_entry = bat_table->transport_list;
7348  while (trans_entry != NULL)
7349  {
7350  t_ptr = DBDEF_FindTransportRecByIds(NULL, ADB_INVALID_DVB_ID,
7351  trans_entry->orig_net_id, trans_entry->tran_id);
7352  if (t_ptr != NULL)
7353  {
7354  if (ASI_DatabaseUpdatesAllowed(t_ptr->sig_type) &&
7355  ACFG_GetDynamicSIUpdate(t_ptr->sig_type, trans_entry->orig_net_id,
7356  (ACFG_DYNAMIC_SI_UPDATE_LCNS |
7357  ACFG_DYNAMIC_SI_UPDATE_SERVICE_ADD |
7358  ACFG_DYNAMIC_SI_UPDATE_SERVICE_REMOVE)))
7359  {
7360  /* Service addition or deletion means LCNs may change so LCN descriptors need to
7361  * be saved so they can be applied following any changes to the service line up */
7362  if (DynamicUpdateAddTransport(t_ptr,
7363  trans_entry->num_lcn_entries, trans_entry->lcn_desc_array, 0, NULL, 0, NULL))
7364  {
7365  /* The SDT for this transport needs to be processed again, so mark it as not
7366  * having been received yet so we can tell when it has been */
7367  t_ptr->sdt_received = FALSE;
7368 
7369  restart_sdts = TRUE;
7370  }
7371  }
7372  }
7373 
7374  trans_entry = trans_entry->next;
7375  }
7376  }
7377 
7378  if (sat_ptr != NULL)
7379  {
7380  if (bat_table->fta_content_desc != NULL)
7381  {
7382  sat_ptr->has_fta_desc = TRUE;
7383  sat_ptr->do_not_scramble = bat_table->fta_content_desc->do_not_scramble;
7384  }
7385 
7386  if (bat_table->def_authority != NULL)
7387  {
7388  changed = TRUE;
7389 
7390  if (sat_ptr->def_authority != NULL)
7391  {
7392  if (bat_table->def_authority->nbytes == sat_ptr->def_authority->nbytes)
7393  {
7394  /* String are the same length, check they're the same */
7395  if (memcmp(bat_table->def_authority->str_ptr, sat_ptr->def_authority->str_ptr,
7396  bat_table->def_authority->nbytes) == 0)
7397  {
7398  /* Strings are the same */
7399  changed = FALSE;
7400  }
7401  }
7402  }
7403 
7404  if (changed)
7405  {
7406  if (sat_ptr->def_authority != NULL)
7407  {
7408  DBDEF_ReleaseString(sat_ptr->def_authority);
7409  }
7410 
7411  sat_ptr->def_authority = DBDEF_MakeString(0, bat_table->def_authority->str_ptr,
7412  bat_table->def_authority->nbytes);
7413 #ifdef DEBUG_SI_BAT
7414  AP_SI_PRINT((" Satellite has default authority \"%s\"",
7415  sat_ptr->def_authority->str_ptr));
7416 #endif
7417  }
7418  }
7419  else if (sat_ptr->def_authority != NULL)
7420  {
7421  /* Default authority has disappeared from the BAT, so delete it from the satellite */
7422  DBDEF_ReleaseString(sat_ptr->def_authority);
7423  sat_ptr->def_authority = NULL;
7424  }
7425 
7426  for (trans_entry = bat_table->transport_list; trans_entry != NULL;
7427  trans_entry = trans_entry->next)
7428  {
7429  t_ptr = DBDEF_FindTransportRecByIds(NULL, ADB_INVALID_DVB_ID,
7430  trans_entry->orig_net_id, trans_entry->tran_id);
7431  if (t_ptr != NULL)
7432  {
7433  if (trans_entry->def_authority != NULL)
7434  {
7435  changed = TRUE;
7436 
7437  if (t_ptr->def_authority != NULL)
7438  {
7439  if (trans_entry->def_authority->nbytes == t_ptr->def_authority->nbytes)
7440  {
7441  /* String are the same length, check they're the same */
7442  if (memcmp(trans_entry->def_authority->str_ptr,
7443  t_ptr->def_authority->str_ptr,
7444  trans_entry->def_authority->nbytes) == 0)
7445  {
7446  /* Strings are the same */
7447  changed = FALSE;
7448  }
7449  }
7450  }
7451 
7452  if (changed)
7453  {
7454  if (t_ptr->def_authority != NULL)
7455  {
7456  DBDEF_ReleaseString(t_ptr->def_authority);
7457  }
7458 
7459  t_ptr->def_authority = DBDEF_MakeString(0,
7460  trans_entry->def_authority->str_ptr,
7461  trans_entry->def_authority->nbytes);
7462 #ifdef DEBUG_SI_BAT
7463  AP_SI_PRINT((" Transport 0x%04x has default authority \"%s\"",
7464  t_ptr->tran_id, t_ptr->def_authority->str_ptr));
7465 #endif
7466  }
7467  }
7468  else if (t_ptr->def_authority != NULL)
7469  {
7470  /* Default authority has disappeared from the BAT, so delete it from the transport */
7471  DBDEF_ReleaseString(t_ptr->def_authority);
7472  t_ptr->def_authority = NULL;
7473  }
7474  }
7475  }
7476  }
7477  }
7478 
7479  if (update_bat_func != NULL)
7480  {
7481  /* Call the function that's been registered to handle additional BAT processing */
7482  (*update_bat_func)(path, bat_table, table_rec);
7483  }
7484 
7485  STB_SIReleaseBatTable(bat_table);
7486  }
7487 
7488  if (report_bat)
7489  {
7490  #ifdef DEBUG_SI_BAT
7491  AP_SI_PRINT(("%s: reporting BAT 0x%04x, ver=%u", __FUNCTION__, table_rec->xtid, table_rec->version));
7492  #endif
7493 
7494  STB_SIReportBat(table_rec);
7495  }
7496  }
7497 
7498  STB_SIReleaseTableRecord(table_rec);
7499 
7500  FUNCTION_FINISH(ProcessBatTable);
7501 
7502  return(restart_sdts);
7503 }
7504 
7505 /*!**************************************************************************
7506  * @brief Processes an image icon descriptor, storing the info for use by the app
7507  * @param si_icon - pointer to the SI icon structure
7508  * @return a pointer to a newly allocated app image icon
7509  ****************************************************************************/
7510 static ADB_IMAGE_ICON* ProcessImageIcon(SI_IMAGE_ICON_DESC *si_icon)
7511 {
7512  ADB_IMAGE_ICON *icon_ptr;
7513 
7514  FUNCTION_START(ProcessImageIcon);
7515 
7516  icon_ptr = NULL;
7517 
7518  if (((si_icon->transport_mode == ICON_TRANS_LOCAL) || (si_icon->transport_mode == ICON_TRANS_URL)) &&
7519  (si_icon->icon_type != NULL) && (si_icon->data_len > 0) && (si_icon->icon_data != NULL))
7520  {
7521  /* Check the icon is a known type */
7522  if ((STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"image/png") == 0) ||
7523  (STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"/png") == 0) ||
7524  (STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"image/jpeg") == 0) ||
7525  (STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"/jpeg") == 0))
7526  {
7527  /* Create a structure for the new icon */
7528  icon_ptr = (ADB_IMAGE_ICON *)STB_AppGetMemory(sizeof(ADB_IMAGE_ICON));
7529  if (icon_ptr != NULL)
7530  {
7531  memset(icon_ptr, 0, sizeof(ADB_IMAGE_ICON));
7532 
7533  icon_ptr->icon_id = si_icon->icon_id;
7534  icon_ptr->transport_mode = si_icon->transport_mode;
7535 
7536  if ((STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"image/png") == 0) ||
7537  (STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"/png") == 0))
7538  {
7539  icon_ptr->icon_type = ICON_TYPE_PNG;
7540  }
7541  else if ((STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"image/jpeg") == 0) ||
7542  (STB_CompareStringsIgnoreCase(si_icon->icon_type, (U8BIT *)"/jpeg") == 0))
7543  {
7544  icon_ptr->icon_type = ICON_TYPE_JPEG;
7545  }
7546 
7547  /* Set the default coordinate system which may be overridden below */
7548  icon_ptr->coord_system = ICON_COORDS_576;
7549 
7550  icon_ptr->position_defined = si_icon->position_defined;
7551  if (icon_ptr->position_defined)
7552  {
7553  /* Check for valid coord system and positions, otherwise allow app to use its
7554  * default pos. The specified position is scaled to output being used */
7555  switch (si_icon->coord_system)
7556  {
7557  case ICON_COORDS_576:
7558  if ((si_icon->x_pos < 720) && (si_icon->y_pos < 576))
7559  {
7560  icon_ptr->coord_system = si_icon->coord_system;
7561  icon_ptr->x_pos = si_icon->x_pos;
7562  icon_ptr->y_pos = si_icon->y_pos;
7563  }
7564  else
7565  {
7566  icon_ptr->position_defined = FALSE;
7567  }
7568  break;
7569 
7570  case ICON_COORDS_720:
7571  if ((si_icon->x_pos < 1280) && (si_icon->y_pos < 720))
7572  {
7573  icon_ptr->coord_system = si_icon->coord_system;
7574  icon_ptr->x_pos = si_icon->x_pos;
7575  icon_ptr->y_pos = si_icon->y_pos;
7576  }
7577  else
7578  {
7579  icon_ptr->position_defined = FALSE;
7580  }
7581  break;
7582 
7583  case ICON_COORDS_1080:
7584  if ((si_icon->x_pos < 1920) && (si_icon->y_pos < 1080))
7585  {
7586  icon_ptr->coord_system = si_icon->coord_system;
7587  icon_ptr->x_pos = si_icon->x_pos;
7588  icon_ptr->y_pos = si_icon->y_pos;
7589  }
7590  else
7591  {
7592  icon_ptr->position_defined = FALSE;
7593  }
7594  break;
7595 
7596  default:
7597  icon_ptr->position_defined = FALSE;
7598  break;
7599  }
7600  }
7601 
7602  if (si_icon->transport_mode == ICON_TRANS_URL)
7603  {
7604  /* Store the icon's uri so it can be retrieved from the MHEG carousel */
7605  icon_ptr->icon_url = (U8BIT *)STB_AppGetMemory(si_icon->data_len);
7606  if (icon_ptr->icon_url != NULL)
7607  {
7608  memcpy(icon_ptr->icon_url, si_icon->icon_data, si_icon->data_len);
7609  }
7610  }
7611  else
7612  {
7613  /* The icon data is contained in the SI data. Convert the file to an image
7614  * that can be displayed */
7615  if (icon_ptr->icon_type == ICON_TYPE_PNG)
7616  {
7617 #ifdef DEBUG_SI_RCT
7618  AP_SI_PRINT(("ProcessImageIcon: Inline PNG icon @ (%u, %u), size %u x %u",
7619  icon_ptr->x_pos, icon_ptr->y_pos, icon_ptr->width, icon_ptr->height));
7620 #endif
7621  /* Interpret the data as a PNG image */
7622  if (!STB_IMGConvertPNG(si_icon->icon_data, si_icon->data_len,
7623  &icon_ptr->icon_data, &icon_ptr->data_len, &icon_ptr->width, &icon_ptr->height))
7624  {
7625 #ifdef DEBUG_SI_RCT
7626  AP_SI_PRINT(("ProcessImageIcon: Failed to process PNG icon"));
7627 #endif
7628  DBDEF_DeleteImageIcons(icon_ptr);
7629  icon_ptr = NULL;
7630  }
7631  }
7632  else
7633  {
7634 #ifdef DEBUG_SI_RCT
7635  AP_SI_PRINT(("ProcessImageIcon: Inline JPEG icon @ (%u, %u), size %u x %u",
7636  icon_ptr->x_pos, icon_ptr->y_pos, icon_ptr->width, icon_ptr->height));
7637 #endif
7638  /* Interpret the data as a JPEG image */
7639  if (!STB_IMGConvertJPEG(si_icon->icon_data, si_icon->data_len,
7640  &icon_ptr->icon_data, &icon_ptr->data_len, &icon_ptr->width, &icon_ptr->height))
7641  {
7642 #ifdef DEBUG_SI_RCT
7643  AP_SI_PRINT(("ProcessImageIcon: Failed to process JPEG icon"));
7644 #endif
7645  DBDEF_DeleteImageIcons(icon_ptr);
7646  icon_ptr = NULL;
7647  }
7648  }
7649  }
7650  }
7651  }
7652  }
7653 
7654  FUNCTION_FINISH(ProcessImageIcon);
7655 
7656  return(icon_ptr);
7657 }
7658 
7659 #if defined(INCLUDE_DSMCC_FILE_REQUEST)
7660 /*!**************************************************************************
7661  * @brief Callback function for icons, passed to DSM file request, that processes
7662  * an icon image when it's been received from the DSM carousel.
7663  * @param user_data - pointer to the icon that this data is for
7664  * @param file_data - data received from DSM-CC
7665  * @param data_size - number of bytes received from DSM-CC
7666  ****************************************************************************/
7667 static void IconFileReceived(E_FsStatus status, S_CONTENT *pContent)
7668 {
7669  ADB_IMAGE_ICON *icon_ptr;
7670 
7671  FUNCTION_START(IconFileReceived);
7672  ASSERT( pContent != NULL );
7673 
7674  icon_ptr = (ADB_IMAGE_ICON *)pContent->user_data;
7675  if (status == FS_STATUS_OK)
7676  {
7677  ASSERT((pContent->data != NULL) && (pContent->size > 0));
7678  /* Process the image received based on the type of icon */
7679  if (icon_ptr->icon_type == ICON_TYPE_PNG)
7680  {
7681 #ifdef DEBUG_SI_RCT
7682  AP_SI_PRINT(("IconFileReceived: PNG icon \"%s\" received", icon_ptr->icon_url));
7683 #endif
7684  /* Interpret the data as a PNG image */
7685  if (!STB_IMGConvertPNG(pContent->data, pContent->size, &icon_ptr->icon_data,
7686  &icon_ptr->data_len, &icon_ptr->width, &icon_ptr->height))
7687  {
7688 #ifdef DEBUG_SI_RCT
7689  AP_SI_PRINT(("IconFileReceived: Failed to process PNG icon"));
7690 #endif
7691  }
7692  }
7693  else
7694  {
7695 #ifdef DEBUG_SI_RCT
7696  AP_SI_PRINT(("IconFileReceived: JPEG icon \"%s\" received", icon_ptr->icon_url));
7697 #endif
7698  /* Interpret the data as a JPEG image */
7699  if (!STB_IMGConvertJPEG(pContent->data, pContent->size, &icon_ptr->icon_data,
7700  &icon_ptr->data_len, &icon_ptr->width, &icon_ptr->height))
7701  {
7702 #ifdef DEBUG_SI_RCT
7703  AP_SI_PRINT(("IconFileReceived: Failed to process JPEG icon"));
7704 #endif
7705  }
7706  }
7707  ASSERT( pContent->destroy != NULL );
7708  pContent->destroy( pContent->fs_handle );
7709  icon_ptr->destroy_func = NULL;
7710  icon_ptr->dsm_handle = NULL;
7711  }
7712 #ifdef DEBUG_SI_RCT
7713  else
7714  {
7715  AP_SI_PRINT(("IconFileReceived: Failed to obtain icon file \"%s\", status %u",
7716  icon_ptr->icon_url, status));
7717  }
7718 #endif
7719 
7720  FUNCTION_FINISH(IconFileReceived);
7721 }
7722 
7723 static void IconFileRequest(ADB_IMAGE_ICON *icon_ptr,U8BIT path)
7724 {
7725  E_FsStatus status;
7726  H_DsmControl dsmctrl;
7727  S_CONTENT dsm;
7728 
7729  FUNCTION_START(IconFileRequest);
7730 
7731  /* If the icon is signalled as being available from the MHEG
7732  * carousel, request the file from MHEG */
7733  if ((icon_ptr->transport_mode == ICON_TRANS_URL) &&
7734  (icon_ptr->icon_url != NULL))
7735  {
7736 #ifdef DEBUG_SI_RCT
7737  AP_SI_PRINT(("IconFileRequest: Requesting icon file \"%s\"", icon_ptr->icon_url));
7738 #endif
7739  dsm.user_data = icon_ptr;
7740  dsmctrl = DSMCC_FindInstance(current_service_rec[path]->serv_id,STB_DPGetPathDemux(path));
7741  if (dsmctrl != NULL)
7742  {
7743  status = DSMCC_ClientLoadObject(dsmctrl, icon_ptr->icon_url,
7744  LOAD_FLAGS_DEFAULT, IconFileReceived, &dsm);
7745  if (status == FS_STATUS_PENDING)
7746  {
7747  icon_ptr->destroy_func = dsm.destroy;
7748  icon_ptr->dsm_handle = dsm.fs_handle;
7749  }
7750  else if (status == FS_STATUS_OK)
7751  {
7752  if (icon_ptr->icon_type == ICON_TYPE_PNG)
7753  {
7754  #ifdef DEBUG_SI_RCT
7755  AP_SI_PRINT(("IconFileRequest: PNG icon received"));
7756  #endif
7757  /* Interpret the data as a PNG image */
7758  STB_IMGConvertPNG(dsm.data, dsm.size, &icon_ptr->icon_data, &icon_ptr->data_len,
7759  &icon_ptr->width, &icon_ptr->height);
7760  }
7761  else
7762  {
7763  #ifdef DEBUG_SI_RCT
7764  AP_SI_PRINT(("IconFileRequest: JPEG icon received"));
7765  #endif
7766  /* Interpret the data as a JPEG image */
7767  STB_IMGConvertJPEG(dsm.data, dsm.size, &icon_ptr->icon_data, &icon_ptr->data_len,
7768  &icon_ptr->width, &icon_ptr->height);
7769  }
7770  ASSERT( dsm.destroy != NULL );
7771  dsm.destroy( dsm.fs_handle );
7772  }
7773  }
7774  }
7775 
7776  FUNCTION_FINISH(IconFileRequest);
7777 }
7778 
7779 #endif /*INCLUDE_DSMCC_FILE_REQUEST*/
7780 
7781 static void ProcessEitTable(SI_TABLE_RECORD *table_rec, BOOLEAN ignore_version,
7782  E_DB_ACCESS_MODE mode, BOOLEAN playback)
7783 {
7784  U8BIT table_id;
7785  U8BIT version;
7786  U16BIT serv_id;
7787  U16BIT tran_id;
7788  U16BIT orig_net_id;
7789  SI_SECTION_RECORD *section_rec;
7790  U8BIT *data_ptr;
7791  U8BIT *data_end;
7792  U16BIT dloop_len;
7793  U8BIT *dloop_end;
7794  U16BIT dlen;
7795  U32BIT priv_data_code;
7796  ADB_SERVICE_REC *s_ptr;
7797  ADB_SERVICE_REC *s2_ptr;
7798  ADB_EVENT_REC *e_ptr;
7799  ADB_EVENT_DESC *event_desc;
7800  U16BIT i;
7801  U8BIT path;
7802  BOOLEAN abort;
7803  BOOLEAN now_next_updated;
7804  BOOLEAN sched_updated;
7805  U32DHMS gmt;
7806  U32DHMS start_date_time;
7807  U32DHMS limit_date_time;
7808  U8BIT sect_num, seg_last_sect_num, segment;
7809  SI_SECTION_RECORD *section_ptr;
7810  BOOLEAN complete_segment;
7811  U16BIT offset_hours;
7812  U32DHMS segment_start;
7813 
7814  FUNCTION_START(ProcessEitTable);
7815 
7816  if (table_rec != NULL)
7817  {
7818  now_next_updated = FALSE;
7819  sched_updated = FALSE;
7820  s_ptr = NULL;
7821 
7822  table_id = table_rec->tid;
7823  if ((table_id == EITPF_ACTUAL_TID) || (table_id == EITPF_PLUS_TID) ||
7824  ((playback == FALSE) && ((table_id == EITPF_OTHER_TID) ||
7825  ((table_id & 0xf0) == EITSC_ACTUAL_TID) || ((table_id & 0xf0) == EITSC_OTHER_TID))))
7826  {
7827  path = table_rec->path;
7828 
7829  version = table_rec->version;
7830  serv_id = table_rec->xtid;
7831 
7832 #ifdef DEBUG_SI_EIT
7833  AP_SI_PRINT(("EIT: tid=0x%02x, serv=0x%04x, version=%u", table_id, serv_id, version));
7834 #endif
7835 
7836  /* Get the transport and network IDs from the first section */
7837  section_rec = table_rec->section_list;
7838  if (section_rec != NULL)
7839  {
7840  /* Get pointer to start of section data */
7841  data_ptr = &(section_rec->data_start);
7842 
7843  /* Read transport id, original network id and last table id. If there is more than
7844  * one section all sections should contain the same value. */
7845  tran_id = (data_ptr[8] << 8) | data_ptr[9];
7846  orig_net_id = (data_ptr[10] << 8) | data_ptr[11];
7847 
7848  /* Get access to the database (may suspend) */
7850 
7851  if (playback == TRUE)
7852  {
7853  s_ptr = current_service_rec[path];
7854  }
7855  else
7856  {
7857  /* Find service this event table refers to */
7858  if (mode == DB_ACCESS_SEARCH)
7859  {
7860  /* EIT actual table only so restrict search to current transport */
7861  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID,
7862  current_transport_rec[path]->orig_net_id, current_transport_rec[path]->tran_id,
7863  serv_id);
7864  }
7865  else
7866  {
7867  /* Actual and other tables - find service by ids.
7868  * IMPORTANT NOTE - in a multi-network system there may be more than one service
7869  * matching the ids - must copy the events to all of them */
7870  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, orig_net_id,
7871  tran_id, serv_id);
7872  }
7873  }
7874 
7875  if (s_ptr != NULL)
7876  {
7877  /* If EIT events have been limited, calculate the limit */
7878  if (eit_schedule_limit == 0)
7879  {
7880  limit_date_time = 0;
7881  }
7882  else
7883  {
7884  gmt = STB_GCNowDHMSGmt();
7885 
7886  if (gmt == 0)
7887  {
7888  /* System date/time not yet known so can't calculate the limit */
7889  limit_date_time = 0;
7890  }
7891  else
7892  {
7893  limit_date_time = STB_GCCalculateDHMS(gmt,
7894  DHMS_CREATE(0, eit_schedule_limit, 0, 0), CALC_ADD);
7895  }
7896  }
7897 
7898  /* Delete any events that are out of date */
7899  if (DeleteOutOfDateEvents(s_ptr))
7900  {
7901  sched_updated = TRUE;
7902  }
7903 
7904  /* Loop through all sections in the list - they will be in section order */
7905  abort = FALSE;
7906  section_rec = table_rec->section_list;
7907  while ((section_rec != NULL) && !abort)
7908  {
7909  /* Get pointer to section data */
7910  data_ptr = &(section_rec->data_start);
7911 
7912  /* If a complete segment has arrived, then any existing events covered by the
7913  * period it represents can be deleted because the new events will replace them */
7914  sect_num = data_ptr[6];
7915 
7916  if (((sect_num % 8) == 0) &&
7917  (((table_id & 0xf0) == EITSC_ACTUAL_TID) || ((table_id & 0xf0) == EITSC_OTHER_TID)))
7918  {
7919  /* Start of a segment, check whether the rest of the sections making up the
7920  * segment are present */
7921  segment = sect_num / 8;
7922  seg_last_sect_num = data_ptr[12];
7923  complete_segment = FALSE;
7924 
7925  if (sect_num == seg_last_sect_num)
7926  {
7927  complete_segment = TRUE;
7928  }
7929  else
7930  {
7931  section_ptr = section_rec->next;
7932  sect_num++;
7933 
7934  /* Check the rest of the sections to see if the segment is complete */
7935  while (!complete_segment && (section_ptr != NULL))
7936  {
7937  data_ptr = &(section_ptr->data_start);
7938 
7939  /* Check this is the next expected section number */
7940  if (data_ptr[6] == sect_num)
7941  {
7942  if (data_ptr[6] == seg_last_sect_num)
7943  {
7944  /* Last section in the segment */
7945  complete_segment = TRUE;
7946  }
7947  else
7948  {
7949  /* More sections in the segment, set the next section number */
7950  sect_num++;
7951  section_ptr = section_ptr->next;
7952  }
7953  }
7954  else
7955  {
7956  /* The number of the next section isn't the expected one,
7957  * so the sections provided don't make up a segment */
7958  section_ptr = NULL;
7959  }
7960  }
7961  }
7962 
7963  if (complete_segment)
7964  {
7965  /* A complete segment is available, so the appropriate events can be
7966  * deleted because they're about to be updated.
7967  * Each segment represents a 3 hour time slot, with 32 segments
7968  * per sub-table, which is 4 days of events, so calculate the offset
7969  * to the start of the segment in hours */
7970  if ((table_id & 0xf0) == EITSC_ACTUAL_TID)
7971  {
7972  offset_hours = ((table_id - EITSC_ACTUAL_TID) * 32 + segment) * 3;
7973  }
7974  else
7975  {
7976  offset_hours = ((table_id - EITSC_OTHER_TID) * 32 + segment) * 3;
7977  }
7978 
7979  /* The schedule starts from midnight today */
7980  segment_start = STB_GCCalculateDHMS(STB_GCCreateDHMS(STB_GCGetGMTDate(), 0, 0, 0),
7981  STB_GCCreateDHMS(offset_hours / 24, offset_hours % 24, 0, 0), CALC_ADD);
7982 
7983  /* Delete the events for the 3 hour period represented by this segment */
7984  if (DeleteEventsForPeriod(s_ptr, segment_start,
7985  STB_GCCalculateDHMS(segment_start, STB_GCCreateDHMS(0, 3, 0, 0), CALC_ADD)))
7986  {
7987  sched_updated = TRUE;
7988  }
7989  }
7990  }
7991 
7992  /* Get pointer to section data and end of section */
7993  data_ptr = &(section_rec->data_start);
7994  data_end = data_ptr + section_rec->data_len - 4; // -4 for crc
7995 
7996  /* Skip section header and IDs already read */
7997  data_ptr += 14;
7998 
7999  /* Read entry for each event */
8000  while ((data_ptr < data_end) && !abort)
8001  {
8002  start_date_time = ReadEventStart(data_ptr);
8003 
8004  if ((limit_date_time == 0) || (start_date_time <= limit_date_time))
8005  {
8006  e_ptr = STB_AppGetMemory(sizeof(ADB_EVENT_REC));
8007  if (e_ptr != NULL)
8008  {
8009  memset(e_ptr, 0, sizeof(ADB_EVENT_REC));
8010 
8011  e_ptr->event_id = (data_ptr[0] << 8) | data_ptr[1];
8012  e_ptr->start = ReadEventStart(data_ptr);
8013  e_ptr->duration = ReadEventDuration(data_ptr);
8014  e_ptr->running_status = data_ptr[10] >> 5;
8015  e_ptr->free_to_air = ((data_ptr[10] & 0x10) == 0);
8016  e_ptr->version = version;
8017 
8018  dloop_len = ((data_ptr[10] & 0x0f) << 8) | data_ptr[11];
8019  data_ptr += 12;
8020 
8021 #ifdef DEBUG_SI_EIT
8022  AP_SI_PRINT((" event_id=%u, start=%u, duration=%u, len=%u",
8023  e_ptr->event_id, e_ptr->start, e_ptr->duration, dloop_len));
8024 #endif
8025 
8026  priv_data_code = 0;
8027  dloop_end = data_ptr + dloop_len;
8028  while (data_ptr < dloop_end)
8029  {
8030 #ifdef DEBUG_SI_EIT
8031  AP_SI_PRINT((" dtag=0x%02x, dlen=%u", data_ptr[0], data_ptr[1]));
8032 #endif
8033  dlen = data_ptr[1];
8034 
8035  /* Parse any descriptors here that contain data needed by DVBCore */
8036  if (data_ptr[0] == PRIVATE_DATA_SPEC_DTAG)
8037  {
8038  /* Keep track of the private data specifier so it can be passed
8039  * to the EIT parsing callback function */
8040  if (dlen == 4)
8041  {
8042  priv_data_code = (data_ptr[2] << 24) | (data_ptr[3] << 16) |
8043  (data_ptr[4] << 8) | data_ptr[5];
8044  }
8045  }
8046  else if (data_ptr[0] == FTA_CONTENT_DESC_DTAG)
8047  {
8048  if (dlen == 1)
8049  {
8050  e_ptr->has_content_management_desc = TRUE;
8051  if ((data_ptr[2] & 0x08) != 0)
8052  {
8053  e_ptr->do_not_scramble = TRUE;
8054  }
8055  else
8056  {
8057  e_ptr->do_not_scramble = FALSE;
8058  }
8059  }
8060  }
8061  else
8062  {
8063  /* Pass the descriptor to the registered callback function
8064  * so it can pull out any info it needs to */
8065  if (eit_parser_func != NULL)
8066  {
8067  (*eit_parser_func)(data_ptr[0], (U8BIT)dlen, data_ptr + 2, priv_data_code, e_ptr);
8068  }
8069  }
8070 
8071  /* Length is +2 for dtag and dlen */
8072  dlen += 2;
8073 
8074  event_desc = (ADB_EVENT_DESC *)STB_AppGetMemory(sizeof(ADB_EVENT_DESC) + dlen);
8075  if (event_desc != NULL)
8076  {
8077  event_desc->desc_data = (U8BIT *)event_desc + sizeof(ADB_EVENT_DESC);
8078  if (event_desc->desc_data != NULL)
8079  {
8080  memcpy(event_desc->desc_data, data_ptr, dlen);
8081 
8082  event_desc->next = NULL;
8083 
8084  if (e_ptr->desc_list_head == NULL)
8085  {
8086  e_ptr->desc_list_head = event_desc;
8087  }
8088  else
8089  {
8090  e_ptr->desc_list_tail->next = event_desc;
8091  }
8092 
8093  e_ptr->desc_list_tail = event_desc;
8094  }
8095  else
8096  {
8097  STB_AppFreeMemory(event_desc);
8098  }
8099  }
8100 
8101  data_ptr += dlen;
8102  }
8103 
8104  /* Add the event into the event list */
8105  if ((table_id == EITPF_ACTUAL_TID) || (table_id == EITPF_OTHER_TID) ||
8106  (table_id == EITPF_PLUS_TID))
8107  {
8108  if (section_rec->sect_num == 0)
8109  {
8110  if (ignore_version || (s_ptr->now_event == NULL) ||
8111  ((s_ptr->now_event != NULL) &&
8112  ((s_ptr->now_event->event_id != e_ptr->event_id) ||
8113  (s_ptr->now_event->version != version))))
8114  {
8115  /* Now event */
8116  if (s_ptr->now_event != NULL)
8117  {
8118  DBDEF_DeleteEventList(s_ptr->now_event);
8119  }
8120 
8121  s_ptr->now_event = e_ptr;
8122  e_ptr = NULL;
8123  now_next_updated = TRUE;
8124  }
8125  }
8126  else if (section_rec->sect_num == 1)
8127  {
8128  if (ignore_version || (s_ptr->next_event == NULL) ||
8129  ((s_ptr->next_event != NULL) &&
8130  ((s_ptr->next_event->event_id != e_ptr->event_id) ||
8131  (s_ptr->next_event->version != version))))
8132  {
8133  /* Next event */
8134  if (s_ptr->next_event != NULL)
8135  {
8136  DBDEF_DeleteEventList(s_ptr->next_event);
8137  s_ptr->next_event = NULL;
8138  }
8139 
8140  s_ptr->next_event = e_ptr;
8141  e_ptr = NULL;
8142  now_next_updated = TRUE;
8143  }
8144  }
8145  else if (table_id == EITPF_PLUS_TID)
8146  {
8147  /* Freesat EITpf++ can have more than just the now/next events
8148  * in the pf++ table, so use it to update the schedule */
8149  if (UpdateEvents(e_ptr, s_ptr, TRUE))
8150  {
8151  e_ptr = NULL;
8152  sched_updated = TRUE;
8153  }
8154  }
8155  }
8156  else
8157  {
8158  /* Insert this event into the event list */
8159  if (UpdateEvents(e_ptr, s_ptr, FALSE))
8160  {
8161  e_ptr = NULL;
8162  sched_updated = TRUE;
8163  }
8164  }
8165 
8166  if (e_ptr != NULL)
8167  {
8168  /* The event hasn't been used so needs to be deleted */
8169  DBDEF_DeleteEventList(e_ptr);
8170  e_ptr = NULL;
8171  }
8172 
8173  /* In the update case check if there are any other services matching the same ids */
8174  if ((mode == DB_ACCESS_UPDATE) && !playback)
8175  {
8176  s2_ptr = DBDEF_FindServiceRecByIds(s_ptr, ADB_INVALID_DVB_ID,
8177  orig_net_id, tran_id, serv_id);
8178 
8179  while (s2_ptr != NULL)
8180  {
8181  s2_ptr->now_event = s_ptr->now_event;
8182  s2_ptr->next_event = s_ptr->next_event;
8183  s2_ptr->event_schedule = s_ptr->event_schedule;
8184 
8185  /* Any more services? */
8186  s2_ptr = DBDEF_FindServiceRecByIds(s2_ptr, ADB_INVALID_DVB_ID,
8187  orig_net_id, tran_id, serv_id);
8188  }
8189  }
8190  }
8191  else
8192  {
8193  /* Failed to allocate memory so abort */
8194  abort = TRUE;
8195  }
8196  }
8197  else
8198  {
8199  /* Events are broadcast in chronological order, so any remaining events
8200  * will also be outside the limit and can be skipped */
8201  data_ptr = data_end;
8202  }
8203  }
8204 
8205  /* Move on to next section */
8206  section_rec = section_rec->next;
8207  }
8208  }
8209 
8210  /* If eit list is in use find entry corresponding to this service and mark it as done */
8211  if ((mode == DB_ACCESS_SEARCH) && (eit_list[path] != NULL) && (playback == FALSE))
8212  {
8213  for (i = 0; i < num_eit_list_entries[path]; i++)
8214  {
8215  if (eit_list[path][i].serv_id == serv_id)
8216  {
8217  eit_list[path][i].got_eit = TRUE;
8218  break;
8219  }
8220  }
8221  }
8222 
8223  // release database access
8225  }
8226 
8227  if (update_eit_func != NULL)
8228  {
8229  /* Call the function that's been registered to handle additional EIT processing */
8230  (*update_eit_func)(path, table_rec);
8231  }
8232  }
8233 
8234  // release eit table
8235  STB_SIReleaseTableRecord(table_rec);
8236 
8237  if (now_next_updated && (s_ptr->now_event != NULL))
8238  {
8239 #ifdef NOW_EVENTS_LATCHED
8240  /* Send this event as a latched event. This means that if this type of event has already
8241  * been sent but it hasn't been dealt with then this one won't be queued. This prevents
8242  * the queue being flooded with events of this type, which can happen after startup. */
8243  STB_ERSendEvent(TRUE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_EIT_NOW_UPDATE, NULL, 0);
8244 #else
8245  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_EIT_NOW_UPDATE,
8246  &s_ptr, sizeof(s_ptr));
8247 #endif
8248 
8249 #ifdef INTEGRATE_HBBTV
8250  if (s_ptr == current_service_rec[path])
8251  {
8253  }
8254 #endif
8255  }
8256 
8257  if (sched_updated)
8258  {
8259  /* Send this event as a latched event. This means that if this type of event has already
8260  * been sent but it hasn't been dealt with then this one won't be queued. This prevents
8261  * the queue being flooded with events of this type, which can happen after startup. */
8262  STB_ERSendEvent(TRUE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_EIT_SCHED_UPDATE, NULL, 0);
8263  }
8264  }
8265 
8266  FUNCTION_FINISH(ProcessEitTable);
8267 }
8268 
8269 static U32DHMS ReadEventStart(U8BIT *data_ptr)
8270 {
8271  U16BIT date;
8272  U8BIT hrs, mns, scs;
8273 
8274  FUNCTION_START(ReadEventStart);
8275 
8276  date = (data_ptr[2] << 8) | data_ptr[3];
8277  hrs = ((data_ptr[4] >> 4) * 10) + (data_ptr[4] & 0x0f);
8278  mns = ((data_ptr[5] >> 4) * 10) + (data_ptr[5] & 0x0f);
8279  scs = ((data_ptr[6] >> 4) * 10) + (data_ptr[6] & 0x0f);
8280 
8281  FUNCTION_FINISH(ReadEventStart);
8282 
8283  return DHMS_CREATE(date, hrs, mns, scs);
8284 }
8285 
8286 static U32DHMS ReadEventDuration(U8BIT *data_ptr)
8287 {
8288  U32BIT days;
8289  U8BIT hrs, mns, scs;
8290 
8291  FUNCTION_START(ReadEventDuration);
8292 
8293  hrs = ((data_ptr[7] >> 4) * 10) + (data_ptr[7] & 0x0f);
8294  mns = ((data_ptr[8] >> 4) * 10) + (data_ptr[8] & 0x0f);
8295  scs = ((data_ptr[9] >> 4) * 10) + (data_ptr[9] & 0x0f);
8296  if (hrs > 23)
8297  {
8298  days = hrs / 24;
8299  hrs = hrs % 24;
8300  }
8301  else
8302  {
8303  days = 0;
8304  }
8305 
8306  FUNCTION_FINISH(ReadEventDuration);
8307 
8308  return DHMS_CREATE(days, hrs, mns, scs);
8309 }
8310 
8311 static BOOLEAN DeleteOutOfDateEvents(ADB_SERVICE_REC *s_ptr)
8312 {
8313  ADB_EVENT_REC *e_ptr;
8314  ADB_EVENT_REC *prev_e_ptr;
8315  ADB_EVENT_REC *expired_e_ptr;
8316  U32DHMS now;
8317  U32DHMS end_date_time;
8318  BOOLEAN sched_updated = FALSE;
8319 
8320  /* Delete any events that are out of date */
8321  if (s_ptr->event_schedule != NULL)
8322  {
8323  prev_e_ptr = NULL;
8324  e_ptr = s_ptr->event_schedule;
8325 
8326  now = STB_GCNowDHMSGmt();
8327 
8328  do
8329  {
8330  end_date_time = STB_GCCalculateDHMS(e_ptr->start, e_ptr->duration, CALC_ADD);
8331 
8332  if (end_date_time < now)
8333  {
8334  /* Event has expired so test the next event */
8335  prev_e_ptr = e_ptr;
8336  e_ptr = e_ptr->next;
8337  s_ptr->num_events_in_schedule--;
8338  sched_updated = TRUE;
8339  }
8340  else
8341  {
8342  break;
8343  }
8344  }
8345  while (e_ptr != NULL);
8346 
8347  if (prev_e_ptr != NULL)
8348  {
8349  /* At this point, prev_e_ptr is pointing at the last event to be deleted
8350  * from the event list, so the list is terminated to delete these events */
8351  prev_e_ptr->next = NULL;
8352 
8353  /* keep the pointer to the expired part of the list */
8354  expired_e_ptr = s_ptr->event_schedule;
8355 
8356  /* e_ptr is the first event that hasn't expired so this now becomes the
8357  * first event in the schedule */
8358  s_ptr->event_schedule = e_ptr;
8359 
8360  /* notify about the expired events */
8361  e_ptr = expired_e_ptr;
8362  while (e_ptr)
8363  {
8364 #ifdef DEBUG_SI_EIT
8365  AP_SI_PRINT(("[-] EIT %d v%d for LCN %d: deleting (expire)",
8366  (int)e_ptr->event_id, (int)e_ptr->version,
8367  (int)s_ptr->serv_lcn));
8368 #endif
8369  ASI_NotifyEitSchedUpdate(s_ptr, e_ptr->event_id,
8370  APP_SI_EIT_JOURNAL_TYPE_EXPIRE);
8371  e_ptr = e_ptr->next;
8372  }
8373 
8374  /* delete expired events */
8375  DBDEF_DeleteEventList(expired_e_ptr);
8376  }
8377  }
8378  return sched_updated;
8379 }
8380 
8381 static inline U32DHMS start(const ADB_EVENT_REC *e)
8382 {
8383  return e->start;
8384 }
8385 
8386 static inline U32DHMS end(const ADB_EVENT_REC *e)
8387 {
8388  return STB_GCCalculateDHMS(e->start, e->duration, CALC_ADD);
8389 }
8390 
8391 static inline BOOLEAN before(const ADB_EVENT_REC *e1, const ADB_EVENT_REC *e2)
8392 {
8393  return start(e1) <= start(e2);
8394 }
8395 
8396 static inline BOOLEAN after(const ADB_EVENT_REC *e1, const ADB_EVENT_REC *e2)
8397 {
8398  return before(e2, e1);
8399 }
8400 
8401 static inline void push(ADB_EVENT_REC **list, ADB_EVENT_REC *event)
8402 {
8403  event->next = *list;
8404  *list = event;
8405 }
8406 
8407 static inline ADB_EVENT_REC *pop(ADB_EVENT_REC **list)
8408 {
8409  ADB_EVENT_REC *event = *list;
8410  if (event) {
8411  *list = event->next;
8412  event->next = NULL;
8413  }
8414  /* else *list is already NULL because the last event->next was NULL
8415  * or *list was NULL to start with
8416  */
8417 
8418  return event;
8419 }
8420 
8421 static BOOLEAN DeleteEventsForPeriod(ADB_SERVICE_REC *s_ptr, U32DHMS start_time, U32DHMS end_time)
8422 {
8423  ADB_EVENT_REC *e_ptr;
8424  ADB_EVENT_REC *prev_ptr;
8425  ADB_EVENT_REC *delete_ptr;
8426  ADB_EVENT_REC *prev_delete_ptr;
8427  BOOLEAN events_deleted;
8428 
8429  events_deleted = FALSE;
8430  prev_ptr = NULL;
8431 
8432 #ifdef DEBUG_SI_EIT
8433  AP_SI_PRINT(("%s(%u): %u@%02u:%02u - %u@%02u:%02u", __FUNCTION__, s_ptr->serv_lcn,
8434  DHMS_DATE(start_time), DHMS_HOUR(start_time), DHMS_MINS(start_time),
8435  DHMS_DATE(end_time), DHMS_HOUR(end_time), DHMS_MINS(end_time)));
8436 #endif
8437  e_ptr = s_ptr->event_schedule;
8438  while (e_ptr != NULL)
8439  {
8440  if (start(e_ptr) >= end_time)
8441  {
8442  /* No more events to delete */
8443  e_ptr = NULL;
8444  }
8445  else if (start(e_ptr) < start_time)
8446  {
8447  /* Event precedes the events to be deleted */
8448  prev_ptr = e_ptr;
8449  e_ptr = e_ptr->next;
8450  }
8451  else
8452  {
8453  /* Found the first event to be deleted.
8454  * Find the last event so they can all be deleted together */
8455  delete_ptr = e_ptr;
8456  if (prev_ptr != NULL)
8457  {
8458  prev_delete_ptr = prev_ptr;
8459  }
8460  else
8461  {
8462  prev_delete_ptr = NULL;
8463  }
8464 
8465  while ((e_ptr != NULL) && (start(e_ptr) < end_time))
8466  {
8467 #ifdef DEBUG_SI_EIT
8468  AP_SI_PRINT(("[-] EIT %u v%u for LCN %u, %u@%02u:%02u - deleting",
8469  e_ptr->event_id, e_ptr->version, s_ptr->serv_lcn,
8470  DHMS_DATE(e_ptr->start), DHMS_HOUR(e_ptr->start), DHMS_MINS(e_ptr->start)));
8471 #endif
8472  /* Notify that this event is going to be deleted */
8473  ASI_NotifyEitSchedUpdate(s_ptr, e_ptr->event_id, APP_SI_EIT_JOURNAL_TYPE_DELETE);
8474 
8475  prev_ptr = e_ptr;
8476  e_ptr = e_ptr->next;
8477  }
8478 
8479  /* Terminate the list of events to be deleted */
8480  prev_ptr->next = NULL;
8481 
8482  if (prev_delete_ptr == NULL)
8483  {
8484  s_ptr->event_schedule = e_ptr;
8485  }
8486  else
8487  {
8488  prev_delete_ptr->next = e_ptr;
8489  }
8490 
8491  DBDEF_DeleteEventList(delete_ptr);
8492  events_deleted = TRUE;
8493  e_ptr = NULL;
8494  }
8495  }
8496 
8497  return(events_deleted);
8498 }
8499 
8500 static ADB_EVENT_REC ** PruneEvents(ADB_EVENT_REC *event_ptr,
8501  ADB_SERVICE_REC *s_ptr, BOOLEAN update_only, BOOLEAN *is_update)
8502 {
8503  ADB_EVENT_REC **walk_ptr = &(s_ptr->event_schedule);
8504  ADB_EVENT_REC **add_ptr = walk_ptr;
8505  ADB_EVENT_REC *prev_ptr;
8506  ADB_EVENT_REC * temp;
8507  BOOLEAN past_event = FALSE;
8508  BOOLEAN found_match = FALSE;
8509  BOOLEAN old_version;
8510  BOOLEAN overlap;
8511 
8512  FUNCTION_START(PruneEvents);
8513 
8514  /* walk through the event list and:
8515  * 1. find insertion point for this event
8516  * 2. delete all colliding items, including the old version, if present
8517  * The walk ends when we've found and deleted all overlapping items
8518  * (i.e. we past the end time of the event) and we've found and deleted
8519  * the old version of this event or we reached the end of the list.
8520  */
8521  prev_ptr = NULL;
8522 
8523  while ((*walk_ptr != NULL) && !(found_match && past_event))
8524  {
8525 #if 0
8526  AP_SI_PRINT(("Found EIT event %d v%d, (%u-%u)",
8527  (int)(*walk_ptr)->event_id, (int)(*walk_ptr)->version,
8528  (unsigned)start(*walk_ptr), (unsigned)end(*walk_ptr)));
8529 #endif
8530 
8531  /* we need to search the entire list for the original instance
8532  * of the event because the update can change the time and/or duration.
8533  */
8534  old_version = FALSE;
8535  if (!found_match && ((*walk_ptr)->event_id == event_ptr->event_id))
8536  {
8537  found_match = TRUE;
8538  if ((*walk_ptr)->version == event_ptr->version)
8539  {
8540 #ifdef DEBUG_SI_EIT
8541  AP_SI_PRINT(("EIT event %d v%d is a duplicate",
8542  (int)event_ptr->event_id, (int)event_ptr->version));
8543 #endif
8544  add_ptr = NULL; /* don't add this event - we've got it already */
8545  break; /* stop the search */
8546  }
8547  else
8548  {
8549 #ifdef DEBUG_SI_EIT
8550  AP_SI_PRINT(("EIT event update %d: v%d->v%d, (%u-%u)->(%u-%u)",
8551  (int)event_ptr->event_id,
8552  (int)(*walk_ptr)->version, (int)event_ptr->version,
8553  (unsigned)start(event_ptr), (unsigned)end(event_ptr),
8554  (unsigned)start(*walk_ptr), (unsigned)end(*walk_ptr)
8555  ));
8556 #endif
8557  old_version = TRUE;
8558  }
8559  }
8560 
8561  /* check event time overlap and delete overlapping items;
8562  * this is sorted list so once we passed the end time of the event
8563  * all subsequent items are also after the event and no further
8564  * checks are needed because they can't overlap with received event.
8565  */
8566  overlap = FALSE;
8567  if (!past_event)
8568  {
8569  if (before(*walk_ptr, event_ptr))
8570  {
8571  /* possible insertion point after this item */
8572  add_ptr = &((*walk_ptr)->next);
8573  }
8574  else /* possible collision - time overlaps */
8575  {
8576  past_event = after(*walk_ptr, event_ptr);
8577  }
8578  }
8579  /* else we're past the end time of the event - no overlap possible */
8580 
8581  /* delete unwanted item */
8582  if (old_version || (overlap && !update_only))
8583  {
8584  /* delete this item from the list */
8585  temp = pop(walk_ptr);
8586 #ifdef DEBUG_SI_EIT
8587  AP_SI_PRINT(("[-] EIT %d v%d for LCN %d: deleting %s",
8588  (int)temp->event_id, (int)temp->version,
8589  (int)s_ptr->serv_lcn,
8590  found_match ? "(update)" : "(overlap)"));
8591 #endif
8592 
8593  if (!found_match)
8594  {
8595  ASI_NotifyEitSchedUpdate(s_ptr, temp->event_id,
8596  APP_SI_EIT_JOURNAL_TYPE_DELETE);
8597  }
8598  /* else send a single "update" instead of "del", "add" */
8599 
8600  DBDEF_DeleteEventList(temp);
8601  s_ptr->num_events_in_schedule--;
8602 
8603  if (prev_ptr != NULL)
8604  {
8605  add_ptr = &(prev_ptr->next);
8606  }
8607  else
8608  {
8609  add_ptr = &(s_ptr->event_schedule);
8610  }
8611  }
8612  else /* skip over this item and keep going */
8613  {
8614  prev_ptr = *walk_ptr;
8615  walk_ptr = &((*walk_ptr)->next);
8616  }
8617  }
8618  *is_update = found_match;
8619 
8620  FUNCTION_FINISH(PruneEvents);
8621 
8622  return add_ptr;
8623 }
8624 
8625 static BOOLEAN UpdateEvents(ADB_EVENT_REC *event_ptr, ADB_SERVICE_REC *s_ptr, BOOLEAN update_only)
8626 {
8627  BOOLEAN event_used;
8628  ADB_EVENT_REC **add_ptr = NULL;
8629  BOOLEAN is_update = FALSE;
8630 
8631  FUNCTION_START(UpdateEvents);
8632 
8633  event_used = FALSE;
8634 
8635 #ifdef DEBUG_SI_EIT
8636  AP_SI_PRINT(("EIT received event %u v%u for service %u,%u,%u LCN %u, (%u@%02u:%02u - %u@%02u:%02u)",
8637  event_ptr->event_id, event_ptr->version,
8638  s_ptr->transport->orig_net_id, s_ptr->transport->tran_id,
8639  s_ptr->serv_id, s_ptr->serv_lcn,
8640  DHMS_DATE(event_ptr->start), DHMS_HOUR(event_ptr->start), DHMS_MINS(event_ptr->start),
8641  DHMS_DATE(end(event_ptr)), DHMS_HOUR(end(event_ptr)), DHMS_MINS(end(event_ptr))));
8642 #endif
8643 
8644  if (end(event_ptr) > STB_GCNowDHMSGmt())
8645  {
8646  add_ptr = PruneEvents(event_ptr, s_ptr, update_only, &is_update);
8647  if (add_ptr != NULL)
8648  {
8649 #ifdef DEBUG_SI_EIT
8650  AP_SI_PRINT(("[+] EIT %u v%u for LCN %u: adding %s",
8651  event_ptr->event_id, event_ptr->version,
8652  s_ptr->serv_lcn,
8653  is_update ? "(update)" : "(new)"));
8654 #endif
8655  push(add_ptr, event_ptr);
8656  s_ptr->num_events_in_schedule++;
8657 
8658  ASI_NotifyEitSchedUpdate(s_ptr, event_ptr->event_id, is_update ?
8659  APP_SI_EIT_JOURNAL_TYPE_UPDATE :
8660  APP_SI_EIT_JOURNAL_TYPE_ADD);
8661 
8662  event_used = TRUE;
8663  }
8664 #ifdef DEBUG_SI_EIT
8665  else
8666  {
8667  AP_SI_PRINT(("[ ] EIT %u v%u for LCN %u: discarding, duplicate",
8668  event_ptr->event_id, event_ptr->version, s_ptr->serv_lcn));
8669  }
8670 #endif
8671  }
8672 #ifdef DEBUG_SI_EIT
8673  else
8674  {
8675  AP_SI_PRINT(("[ ] EIT %u v%u for LCN %u: discarding, ends in the past (%lu now)",
8676  event_ptr->event_id, event_ptr->version, s_ptr->serv_lcn,
8677  STB_GCNowDHMSGmt()));
8678  }
8679 #endif
8680  FUNCTION_FINISH(UpdateEvents);
8681 
8682  return(event_used);
8683 }
8684 
8698 static BOOLEAN MakeNewPmtRequest(U8BIT path)
8699 {
8700  BOOLEAN service_found;
8701  U16BIT list_id;
8702  U16BIT i;
8703 
8704  FUNCTION_START(MakeNewPmtRequest);
8705 
8706  service_found = FALSE;
8707 
8708  if ((pmt_request_mode[path] == PMT_REQUEST_CURRENT) && (current_service_rec[path] != NULL))
8709  {
8710  list_id = 0;
8711  for (i = 0; i < num_pmt_list_entries[path]; i++)
8712  {
8713  if (pmt_list[path][i].serv_id == current_service_rec[path]->serv_id)
8714  {
8715  list_id = i;
8716  service_found = TRUE;
8717  break;
8718  }
8719  }
8720  }
8721  else if (pmt_request_mode[path] == PMT_REQUEST_PRIORITY)
8722  {
8723  list_id = GetPriorityListId(path);
8724  }
8725  else
8726  {
8727  list_id = pmt_list_id[path];
8728  }
8729 
8730  if ((pmt_filter[path] != NULL) && (pmt_filter_pid[path] == pmt_list[path][list_id].pid))
8731  {
8732  #ifdef DEBUG_SI_UPDATE
8733  AP_SI_PRINT(("Update(%u): PMT request (sid 0x%04x)", path, pmt_list[path][list_id].serv_id));
8734  #endif
8735  // filter exists with same pid - modify filter
8736  STB_SIModifyPmtRequest(pmt_filter[path], pmt_list[path][list_id].serv_id, 0xffff, 1);
8737  pmt_start_timestamp[path] = STB_OSGetClockMilliseconds();
8738  pmt_update_timestamp[path] = 0;
8739  }
8740  else
8741  {
8742  /* Different pid or filter doesn't exist yet - either way we need a new filter.
8743  * If a filter exists, cancel it, then request the new filter */
8744  if (pmt_filter[path] != NULL)
8745  {
8746  STB_SICancelTableRequest(pmt_filter[path]);
8747  pmt_filter[path] = NULL;
8748  }
8749 
8750  #ifdef DEBUG_SI_UPDATE
8751  AP_SI_PRINT(("Update(%u): PMT request (sid 0x%04x)", path, pmt_list[path][list_id].serv_id));
8752  #endif
8753  pmt_filter_pid[path] = pmt_list[path][list_id].pid;
8754  pmt_start_timestamp[path] = STB_OSGetClockMilliseconds();
8755  pmt_update_timestamp[path] = 0;
8756  pmt_filter[path] = STB_SIRequestPmt(path, ONE_SHOT_REQUEST, pmt_filter_pid[path],
8757  pmt_list[path][list_id].serv_id, 0xffff, 1, ReceiveSiTable, APP_SI_PMT_RECEIVED);
8758  }
8759 
8760  FUNCTION_FINISH(MakeNewPmtRequest);
8761 
8762  return(service_found);
8763 }
8764 
8765 static U16BIT GetPriorityListId(U8BIT path)
8766 {
8767  U16BIT i, index;
8768  U16BIT list_id;
8769  U16BIT service_id;
8770 
8771  FUNCTION_START(GetPriorityListId);
8772 
8773  list_id = pmt_list_id[path];
8774 
8775  STB_OSSemaphoreWait(si_pmt_list_sem);
8776 
8777  if (pmt_priority_list[0] != INVALID_SERVICE_ID)
8778  {
8779  /* Find service in pmt_list */
8780  for (i = 0; i < num_pmt_list_entries[path]; i++)
8781  {
8782  if (pmt_list[path][i].serv_id == pmt_priority_list[0])
8783  {
8784  list_id = i;
8785  break;
8786  }
8787  }
8788 
8789  /* Rotate priority services, whether we found it or not */
8790  index = MAX_PMT_PRIORITY_LIST - 1;
8791  for (i = 1; i < MAX_PMT_PRIORITY_LIST; i++)
8792  {
8793  if (pmt_priority_list[i] == INVALID_SERVICE_ID)
8794  {
8795  index = i - 1;
8796  break;
8797  }
8798  }
8799 
8800  service_id = (U16BIT)pmt_priority_list[0];
8801  for (i = 0; i < index; i++)
8802  {
8803  pmt_priority_list[i] = pmt_priority_list[i + 1];
8804  }
8805 
8806  pmt_priority_list[index] = service_id;
8807  }
8808 
8809  STB_OSSemaphoreSignal(si_pmt_list_sem);
8810 
8811  FUNCTION_FINISH(GetPriorityListId);
8812 
8813  return list_id;
8814 }
8815 
8827 static void UpdateTransportParameters(U8BIT path)
8828 {
8829  U8BIT tuner;
8830  U8BIT sig_quality;
8831  U8BIT sig_strength;
8832  ADB_TRANSPORT_REC *t_ptr;
8833  E_STB_DP_TMODE tmode;
8834  E_STB_DP_TBWIDTH bwidth;
8835  E_STB_DP_TTYPE terr_type;
8836  E_STB_DP_CMODE cmode;
8837  U32BIT srate;
8838 
8839  FUNCTION_START(UpdateTransportParameters);
8840 
8841  tuner = STB_DPGetPathTuner(path);
8842  if (tuner != INVALID_RES_ID)
8843  {
8844  if ((t_ptr = current_transport_rec[path]) != NULL)
8845  {
8847 
8848  switch (t_ptr->sig_type)
8849  {
8850  case SIGNAL_COFDM:
8851  {
8852  switch (STB_TuneGetActualTerrMode(tuner))
8853  {
8854  case TUNE_MODE_COFDM_1K: {tmode = MODE_COFDM_1K; break; }
8855  case TUNE_MODE_COFDM_2K: {tmode = MODE_COFDM_2K; break; }
8856  case TUNE_MODE_COFDM_4K: {tmode = MODE_COFDM_4K; break; }
8857  case TUNE_MODE_COFDM_8K: {tmode = MODE_COFDM_8K; break; }
8858  case TUNE_MODE_COFDM_16K: {tmode = MODE_COFDM_16K; break; }
8859  case TUNE_MODE_COFDM_32K: {tmode = MODE_COFDM_32K; break; }
8860  default: {tmode = MODE_COFDM_UNDEFINED; break; }
8861  }
8862  if (t_ptr->u.terr.tmode != tmode)
8863  {
8864  t_ptr->u.terr.tmode = tmode;
8865  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TTRAN_MODE, tmode);
8866  }
8867 
8868  switch (STB_TuneGetActualTerrBwidth(tuner))
8869  {
8870  case TUNE_TBWIDTH_8MHZ: {bwidth = TBWIDTH_8MHZ; break; }
8871  case TUNE_TBWIDTH_7MHZ: {bwidth = TBWIDTH_7MHZ; break; }
8872  case TUNE_TBWIDTH_6MHZ: {bwidth = TBWIDTH_6MHZ; break; }
8873  default: {bwidth = 0; break; }
8874  }
8875  if (t_ptr->u.terr.bwidth != bwidth)
8876  {
8877  t_ptr->u.terr.bwidth = bwidth;
8878  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TTRAN_BWIDTH, bwidth);
8879  }
8880 
8881  switch (STB_TuneGetSystemType(tuner))
8882  {
8883  case TUNE_SYSTEM_TYPE_DVBT2: {terr_type = TERR_TYPE_DVBT2; break; }
8884  case TUNE_SYSTEM_TYPE_DVBT: {terr_type = TERR_TYPE_DVBT; break; }
8885  default: {terr_type = TERR_TYPE_UNKNOWN; break; }
8886  }
8887 
8888  if (t_ptr->u.terr.terr_type != terr_type)
8889  {
8890  t_ptr->u.terr.terr_type = terr_type;
8891  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TTRAN_TERR_TYPE, terr_type);
8892  }
8893  break;
8894  }
8895  case SIGNAL_QAM:
8896  {
8897  /* Symbol rate is stored in Ksym/sec */
8898  if ((srate = STB_TuneGetActualSymbolRate(tuner)) != SYMBOL_RATE_AUTO)
8899  {
8900  srate = srate / 1000;
8901  DBDEF_SetCableTransportSymbolRate(t_ptr, (U16BIT)srate);
8902  }
8903 
8904  switch (STB_TuneGetActualCableMode(tuner))
8905  {
8906  case TUNE_MODE_QAM_4: {cmode = MODE_QAM_4; break; }
8907  case TUNE_MODE_QAM_8: {cmode = MODE_QAM_8; break; }
8908  case TUNE_MODE_QAM_16: {cmode = MODE_QAM_16; break; }
8909  case TUNE_MODE_QAM_32: {cmode = MODE_QAM_32; break; }
8910  case TUNE_MODE_QAM_64: {cmode = MODE_QAM_64; break; }
8911  case TUNE_MODE_QAM_128: {cmode = MODE_QAM_128; break; }
8912  case TUNE_MODE_QAM_256: {cmode = MODE_QAM_256; break; }
8913  default: {cmode = MODE_QAM_AUTO; break; }
8914  }
8915 
8916  DBDEF_SetCableTransportMode(t_ptr, cmode);
8917  break;
8918  }
8919  case SIGNAL_QPSK:
8920  {
8921  /* Symbol rate is stored in Ksym/sec */
8922  if ((srate = STB_TuneGetActualSymbolRate(tuner)) != SYMBOL_RATE_AUTO)
8923  {
8924  srate = srate / 1000;
8925 
8926  if (t_ptr->u.sat.symbol_rate != srate)
8927  {
8928  t_ptr->u.sat.symbol_rate = (U16BIT)srate;
8929  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRAN_SRATE, srate);
8930  }
8931  }
8932  break;
8933  }
8934  default:
8935  {
8936  break;
8937  }
8938  }
8939 
8940  /* Get signal quality in a scale 0 to 10 */
8941  sig_quality = STB_TuneGetDataIntegrity(tuner);
8942  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRAN_SIGNAL_QUALITY, sig_quality);
8943 
8944  /* Get signal strength in a scale 0 to 10 */
8945  sig_strength = STB_TuneGetSignalStrength(tuner);
8946  DBA_SetFieldValue(t_ptr->dba_rec, DBA_FIELD_TRAN_SIGNAL_STRENGTH, sig_strength);
8947 
8948  /* Combine quality and strength into 1 byte in a system so that signals
8949  * of equal quality can be compared by strength. */
8950  current_transport_rec[path]->signal_level_at_search = GET_SIGNAL_STATUS(sig_quality, sig_strength);
8951 
8952  current_transport_rec[path]->available = TRUE;
8953 
8954  DBA_SaveRecord(t_ptr->dba_rec);
8956  }
8957  }
8958 
8959  FUNCTION_FINISH(UpdateTransportParameters);
8960 }
8961 
8973 static void CancelTableRequests(U8BIT path, BOOLEAN this_path_only)
8974 {
8975  if (!this_path_only && (rct_filter[path] != NULL))
8976  {
8977  STB_SICancelTableRequest(rct_filter[path]);
8978  rct_filter[path] = NULL;
8979 
8980  if (current_service_rec[path] != NULL)
8981  {
8982  ADB_ServiceReleaseRCTLinks(current_service_rec[path]);
8983  }
8984  }
8985  if (!this_path_only && (cat_filter[path] != NULL))
8986  {
8987  STB_SICancelTableRequest(cat_filter[path]);
8988  cat_filter[path] = NULL;
8989  cat_start_timestamp[path] = 0;
8990  }
8991  if (pat_filter[path] != NULL)
8992  {
8993  STB_SICancelTableRequest(pat_filter[path]);
8994  pat_filter[path] = NULL;
8995  pat_start_timestamp[path] = 0;
8996  }
8997  if (pmt_filter[path] != NULL)
8998  {
8999  STB_SICancelTableRequest(pmt_filter[path]);
9000  pmt_filter[path] = NULL;
9001  pmt_start_timestamp[path] = 0;
9002  }
9003  if (pmt_list[path] != NULL)
9004  {
9005  STB_AppFreeMemory(pmt_list[path]);
9006  pmt_list[path] = NULL;
9007  num_pmt_list_entries[path] = 0;
9008  }
9009  if (!this_path_only && (nit_filter[path] != NULL))
9010  {
9011  STB_SICancelTableRequest(nit_filter[path]);
9012  nit_filter[path] = NULL;
9013  nit_start_timestamp[path] = 0;
9014  }
9015  if (!this_path_only && (sdt_filter[path] != NULL))
9016  {
9017  STB_SICancelTableRequest(sdt_filter[path]);
9018  sdt_filter[path] = NULL;
9019  sdt_start_timestamp[path] = 0;
9020  }
9021  if (!this_path_only && (eit_list[path] != NULL))
9022  {
9023  STB_AppFreeMemory(eit_list[path]);
9024  eit_list[path] = NULL;
9025  num_eit_list_entries[path] = 0;
9026  }
9027  if (eit_filter[path] != NULL)
9028  {
9029  STB_SICancelTableRequest(eit_filter[path]);
9030  eit_filter[path] = NULL;
9031  eit_start_timestamp[path] = 0;
9032  }
9033  if (!this_path_only && (sched_filter[path] != NULL))
9034  {
9035  STB_SICancelTableRequest(sched_filter[path]);
9036  sched_filter[path] = NULL;
9037  sched_start_timestamp[path] = 0;
9038  }
9039  if (!this_path_only && (tot_filter[path] != NULL))
9040  {
9041  STB_SICancelTableRequest(tot_filter[path]);
9042  tot_filter[path] = NULL;
9043  tot_start_timestamp[path] = 0;
9044  }
9045  if (!this_path_only && (tdt_filter[path] != NULL))
9046  {
9047  STB_SICancelTableRequest(tdt_filter[path]);
9048  tdt_filter[path] = NULL;
9049  tdt_start_timestamp[path] = 0;
9050  }
9051  if (bat_filter[path] != NULL)
9052  {
9053  STB_SICancelTableRequest(bat_filter[path]);
9054  bat_filter[path] = NULL;
9055  bat_start_timestamp[path] = 0;
9056  }
9057  if (ait_filter[path] != NULL)
9058  {
9059  STB_SICancelTableRequest(ait_filter[path]);
9060  ait_filter[path] = NULL;
9061  }
9062 
9063  if (!this_path_only)
9064  {
9065  // clear flags
9066  report_pmt_allowed[path] = FALSE;
9067  pmt_reported[path] = FALSE;
9068  si_update_delay_timestamp[path] = 0;
9069  }
9070 
9071  pmt_update_timestamp[path] = 0;
9072 }
9073 
9087 static BOOLEAN ManageDvbSsuSearch(U8BIT path, U32BIT event, SI_TABLE_RECORD *table_rec)
9088 {
9089  BOOLEAN finished;
9090  U16BIT onet_id, tran_id, serv_id;
9091 
9092  FUNCTION_START(ManageDvbSsuSearch);
9093 
9094  finished = FALSE;
9095  if (event == APP_SI_START_MANAGER)
9096  {
9097  // first ensure there is a transport record for the transport we are tuned to and set
9098  // current transport accordingly
9099  current_transport_rec[path] = DBDEF_GetTunedTransport(path);
9100  if (current_transport_rec[path] != NULL)
9101  {
9102  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9103  AP_SI_PRINT(("DVB SSU search: start (%s)",
9104  ACTL_GetRfNameFromFreq(current_transport_rec[path]->sig_type, current_transport_rec[path]->frequency)));
9105  #endif
9106 
9107  // update transport fields
9108  current_network_rec[path] = current_transport_rec[path]->network;
9109  current_service_rec[path] = NULL;
9110 
9111  // start search for NIT
9112  nit_start_timestamp[path] = STB_OSGetClockMilliseconds();
9113 
9114  if (active_network_id == 0)
9115  {
9116  nit_filter[path] = STB_SIRequestNit(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_NIT_RECEIVED);
9117  }
9118  else
9119  {
9120  nit_filter[path] = STB_SIRequestNitWithId(path, active_network_id, ONE_SHOT_REQUEST,
9121  ReceiveSiTable, APP_SI_NIT_RECEIVED);
9122  }
9123  }
9124  else
9125  {
9126  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9127  AP_SI_PRINT(("DVB SSU search: start - failed, no transport"));
9128  #endif
9129  // report end of search
9130  STB_SISearchComplete(path, TRUE, NULL, 0);
9131  finished = TRUE;
9132  }
9133  }
9134  else if (event == APP_SI_STOP_MANAGER)
9135  {
9136  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9137  AP_SI_PRINT(("DVB SSU search: stop"));
9138  #endif
9139  CancelTableRequests(path, FALSE);
9140  finished = TRUE;
9141  }
9142  else
9143  {
9144  switch (event)
9145  {
9146  case APP_SI_NIT_RECEIVED:
9147  {
9148  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9149  AP_SI_PRINT(("DVB SSU search: NIT received (nid 0x%04x)", table_rec->xtid));
9150  #endif
9151 
9152  ProcessNitTable(table_rec, DB_ACCESS_UPDATE, TRUE, TRUE);
9153 
9154  // finished with the filter - release it
9155  STB_SICancelTableRequest(nit_filter[path]);
9156  nit_filter[path] = NULL;
9157  nit_start_timestamp[path] = 0;
9158 
9159  // report end of search
9160  CancelTableRequests(path, FALSE);
9161 
9162  if (ASI_GetNextOTALocation(current_network_rec[path], NULL, &onet_id, &tran_id,
9163  &serv_id) != NULL)
9164  {
9165  /* Possible OTA update found */
9166  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9167  AP_SI_PRINT(("DVB SSU search: possible OTA update found, search succeeded"));
9168  #endif
9169  STB_SISearchComplete(path, TRUE, &current_transport_rec[path], sizeof(void *));
9170  }
9171  else
9172  {
9173  /* No OTA found */
9174  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9175  AP_SI_PRINT(("DVB SSU search: no OTA update found, search failed"));
9176  #endif
9177  STB_SISearchComplete(path, FALSE, &current_transport_rec[path], sizeof(void *));
9178  }
9179  finished = TRUE;
9180  break;
9181  }
9182  case APP_SI_NIT_TIMEOUT:
9183  {
9184  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9185  AP_SI_PRINT(("DVB_SSU search: NIT timeout"));
9186  #endif
9187 
9188  // finished with the filter - release it
9189  STB_SICancelTableRequest(nit_filter[path]);
9190  nit_filter[path] = NULL;
9191  nit_start_timestamp[path] = 0;
9192 
9193  // report end of search
9194  #ifdef DEBUG_SI_DVB_SSU_SEARCH
9195  AP_SI_PRINT(("DVB SSU search: search failed"));
9196  #endif
9197 
9198  CancelTableRequests(path, FALSE);
9199  STB_SISearchComplete(path, FALSE, &current_transport_rec[path], sizeof(void *));
9200  finished = TRUE;
9201  break;
9202  }
9203  }
9204  }
9205 
9206  FUNCTION_FINISH(ManageDvbSsuSearch);
9207  return(finished);
9208 }
9209 
9222 static void CopyLinkageDesc(SI_LINKAGE_DESC_ENTRY *new_list_ptr, SI_LINKAGE_DESC_ENTRY **list_ptr,
9223  SI_LINKAGE_DESC_ENTRY **last_entry_ptr, U16BIT *num_linkage_desc)
9224 {
9225  SI_LINKAGE_DESC_ENTRY *desc_ptr;
9226 
9227  FUNCTION_START(CopyLinkageDesc);
9228 
9229  desc_ptr = (SI_LINKAGE_DESC_ENTRY *)STB_GetMemory(sizeof(SI_LINKAGE_DESC_ENTRY) + new_list_ptr->data_length);
9230  if (desc_ptr != NULL)
9231  {
9232  desc_ptr->next = NULL;
9233  desc_ptr->tran_id = new_list_ptr->tran_id;
9234  desc_ptr->orig_net_id = new_list_ptr->orig_net_id;
9235  desc_ptr->serv_id = new_list_ptr->serv_id;
9236  desc_ptr->link_type = new_list_ptr->link_type;
9237  desc_ptr->data_length = new_list_ptr->data_length;
9238 
9239  if (new_list_ptr->data_length != 0)
9240  {
9241  memcpy(&(desc_ptr->data), &(new_list_ptr->data), new_list_ptr->data_length);
9242  }
9243 
9244  // now add descriptor to linked list
9245  if (*last_entry_ptr == NULL)
9246  {
9247  // first entry in the list
9248  *list_ptr = desc_ptr;
9249  }
9250  else
9251  {
9252  // not the first entry
9253  (*last_entry_ptr)->next = desc_ptr;
9254  }
9255  *last_entry_ptr = desc_ptr;
9256  (*num_linkage_desc)++;
9257 
9258  #ifdef DEBUG_SI_SDT
9259  AP_SI_PRINT((" AP_SI---- Linkage desc: tid=0x%04x, onid=0x%04x, sid=0x%04x, type=%d, dlen=%d",
9260  desc_ptr->tran_id, desc_ptr->orig_net_id, desc_ptr->serv_id,
9261  desc_ptr->link_type, desc_ptr->data_length));
9262  #endif
9263  }
9264 
9265  FUNCTION_FINISH(CopyLinkageDesc);
9266 }
9267 
9268 /*!**************************************************************************
9269  * @brief Deletes a linkage descripter rray
9270  * @param list_ptr - array to delete
9271  ****************************************************************************/
9272 static void DeleteLinkageDescripterArray(SI_LINKAGE_DESC_ENTRY *list_ptr)
9273 {
9274  SI_LINKAGE_DESC_ENTRY *desc_ptr;
9275  SI_LINKAGE_DESC_ENTRY *tmp_ptr;
9276 
9277  FUNCTION_START(DeleteLinkageDescripterArray);
9278 
9279  desc_ptr = list_ptr;
9280  while (desc_ptr != NULL)
9281  {
9282  tmp_ptr = desc_ptr->next;
9283  STB_FreeMemory(desc_ptr);
9284  desc_ptr = tmp_ptr;
9285  }
9286 
9287  FUNCTION_FINISH(DeleteLinkageDescripterArray);
9288 }
9289 
9304 static BOOLEAN CheckSsuLinkageDescForUpgrade(SI_LINKAGE_DESC_ENTRY *desc_ptr, U16BIT *onid_ptr,
9305  U16BIT *tid_ptr, U16BIT *sid_ptr)
9306 {
9307  BOOLEAN retval;
9308  U8BIT *data_ptr;
9309  U8BIT oui_loop_len;
9310  U8BIT *oui_loop_end;
9311  U8BIT oui[3];
9312  U8BIT selector_len;
9313 
9314  FUNCTION_START(CheckSsuLinkageDescForUpgrade);
9315 
9316  ASSERT(desc_ptr != NULL);
9317  ASSERT(onid_ptr != NULL);
9318  ASSERT(tid_ptr != NULL);
9319  ASSERT(sid_ptr != NULL);
9320 
9321  #ifdef DEBUG_DVB_SSU
9322  AP_SI_PRINT((" DVB SSU link desc 0x%04x/0x%04x/0x%04x len %d",
9323  desc_ptr->orig_net_id, desc_ptr->tran_id, desc_ptr->serv_id, desc_ptr->data_length));
9324  #endif
9325 
9326  retval = FALSE;
9327 
9328  // check data to see if upgrade applies to us
9329  data_ptr = &(desc_ptr->data);
9330  oui_loop_len = data_ptr[0];
9331  data_ptr++;
9332  oui_loop_end = data_ptr + oui_loop_len;
9333  while (data_ptr < oui_loop_end)
9334  {
9335  memcpy(oui, data_ptr, 3);
9336  selector_len = data_ptr[3];
9337  data_ptr += 4;
9338  #ifdef DEBUG_DVB_SSU
9339  AP_SI_PRINT((" OUI=0x%02x%02x%02x", oui[0], oui[1], oui[2]));
9340  #endif
9341  if ((memcmp(oui, dvb_oui, 3) == 0) ||
9342  ((STB_HWGetOUI() != NULL) && (memcmp(oui, STB_HWGetOUI(), 3) == 0)))
9343  {
9344  *onid_ptr = desc_ptr->orig_net_id;
9345  *tid_ptr = desc_ptr->tran_id;
9346  *sid_ptr = desc_ptr->serv_id;
9347 #ifdef DEBUG_DVB_SSU
9348  AP_SI_PRINT((" DVB SSU: upgrade service detected, onid=0x%x, tid=0x%x, sid=0x%x",
9349  *onid_ptr, *tid_ptr, *sid_ptr));
9350 #endif
9351  retval = TRUE;
9352  break;
9353  }
9354 
9355  data_ptr += selector_len;
9356  }
9357 
9358  FUNCTION_FINISH(CheckSsuLinkageDescForUpgrade);
9359  return(retval);
9360 }
9361 
9362 //--------------------------------------------------------------------------------------------------
9363 // global function definitions
9364 //--------------------------------------------------------------------------------------------------
9365 
9370 {
9371  U8BIT path, num_paths;
9372 
9373  FUNCTION_START(ASI_InitialiseAppSi);
9374 
9375  /* Allocate arrays for each path */
9376  num_paths = STB_DPGetNumPaths();
9377 
9378  current_manager = (F_SIManager *)STB_AppGetMemory(sizeof(F_SIManager) * num_paths);
9379  required_si_mode = (E_APP_SI_MODE *)STB_AppGetMemory(sizeof(E_APP_SI_MODE) * num_paths);
9380 
9381  current_network_rec = (ADB_NETWORK_REC **)STB_AppGetMemory(sizeof(ADB_NETWORK_REC *) * num_paths);
9382  current_transport_rec = (ADB_TRANSPORT_REC **)STB_AppGetMemory(sizeof(ADB_TRANSPORT_REC *) * num_paths);
9383  current_service_rec = (ADB_SERVICE_REC **)STB_AppGetMemory(sizeof(ADB_SERVICE_REC *) * num_paths);
9384  last_transport_rec = (ADB_TRANSPORT_REC **)STB_AppGetMemory(sizeof(ADB_TRANSPORT_REC *) * num_paths);
9385 
9386  sched_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9387  eit_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9388  pat_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9389  pmt_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9390  nit_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9391  sdt_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9392  bat_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9393  tot_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9394  tdt_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9395  cat_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9396  rct_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9397  ait_filter = (void **)STB_AppGetMemory(sizeof(void *) * num_paths);
9398 
9399  pat_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9400  pmt_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9401  nit_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9402  sdt_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9403  bat_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9404  eit_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9405  sched_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9406  sched_timeout_ms = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9407  tot_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9408  tdt_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9409  si_update_delay_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9410  pmt_update_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9411  cat_start_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9412 
9413  pmt_update_period_ms = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9414  last_timestamp = (U32BIT *)STB_AppGetMemory(sizeof(U32BIT) * num_paths);
9415 
9416  pmt_list_id = (U16BIT *)STB_AppGetMemory(sizeof(U16BIT) * num_paths);
9417 
9418  sdt_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9419  bat_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9420  nit_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9421  pmts_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9422  eits_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9423  tot_complete = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9424 
9425  tot_already_received = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9426  pat_rcvd_on_this_trnsprt = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9427  pmt_list = (PMT_LIST_ENTRY **)STB_AppGetMemory(sizeof(PMT_LIST_ENTRY *) * num_paths);
9428  num_pmt_list_entries = (U16BIT *)STB_AppGetMemory(sizeof(U16BIT) * num_paths);
9429  pmt_filter_pid = (U16BIT *)STB_AppGetMemory(sizeof(U16BIT) * num_paths);
9430  pmt_service_changed = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9431  report_pmt_allowed = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9432  pmt_reported = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9433  stop_pmt_reporting = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9434  pmt_request_mode = (E_PMT_REQUEST_MODE *)STB_AppGetMemory(sizeof(E_PMT_REQUEST_MODE) * num_paths);
9435  eit_list = (EIT_LIST_ENTRY **)STB_AppGetMemory(sizeof(EIT_LIST_ENTRY *) * num_paths);
9436  num_eit_list_entries = (U16BIT *)STB_AppGetMemory(sizeof(U16BIT) * num_paths);
9437 
9438  service_list_ready = (BOOLEAN *)STB_AppGetMemory(sizeof(BOOLEAN) * num_paths);
9439  last_reported_cat_version = (S16BIT *)STB_AppGetMemory(sizeof(S16BIT) * num_paths);
9440  last_reported_nit_version = (S16BIT *)STB_AppGetMemory(sizeof(S16BIT) * num_paths);
9441  last_reported_pmt_version = (U8BIT *)STB_AppGetMemory(sizeof(U8BIT) * num_paths);
9442 
9443  for (path = 0; path < num_paths; path++)
9444  {
9445  current_manager[path] = NULL;
9446  required_si_mode[path] = STOP_SI;
9447  current_network_rec[path] = NULL;
9448  current_transport_rec[path] = NULL;
9449  current_service_rec[path] = NULL;
9450  last_transport_rec[path] = NULL;
9451 
9452  sched_filter[path] = NULL;
9453  eit_filter[path] = NULL;
9454  pat_filter[path] = NULL;
9455  pmt_filter[path] = NULL;
9456  nit_filter[path] = NULL;
9457  sdt_filter[path] = NULL;
9458  bat_filter[path] = NULL;
9459  tot_filter[path] = NULL;
9460  tdt_filter[path] = NULL;
9461  cat_filter[path] = NULL;
9462  rct_filter[path] = NULL;
9463  ait_filter[path] = NULL;
9464 
9465  pat_start_timestamp[path] = 0;
9466  pmt_start_timestamp[path] = 0;
9467  nit_start_timestamp[path] = 0;
9468  sdt_start_timestamp[path] = 0;
9469  bat_start_timestamp[path] = 0;
9470  eit_start_timestamp[path] = 0;
9471  sched_start_timestamp[path] = 0;
9472  sched_timeout_ms[path] = 0;
9473  tot_start_timestamp[path] = 0;
9474  tdt_start_timestamp[path] = 0;
9475  si_update_delay_timestamp[path] = 0;
9476  pmt_update_timestamp[path] = 0;
9477  cat_start_timestamp[path] = 0;
9478  pmt_update_period_ms[path] = 0;
9479  last_timestamp[path] = 0;
9480 
9481  pmt_list_id[path] = 0;
9482 
9483  sdt_complete[path] = FALSE;
9484  bat_complete[path] = FALSE;
9485  nit_complete[path] = FALSE;
9486  pmts_complete[path] = FALSE;
9487  eits_complete[path] = FALSE;
9488  tot_complete[path] = FALSE;
9489 
9490  tot_already_received[path] = FALSE;
9491  pat_rcvd_on_this_trnsprt[path] = FALSE;
9492  pmt_list[path] = NULL;
9493  num_pmt_list_entries[path] = 0;
9494  pmt_filter_pid[path] = 0;
9495  pmt_service_changed[path] = FALSE;
9496  report_pmt_allowed[path] = FALSE;
9497  pmt_reported[path] = FALSE;
9498  stop_pmt_reporting[path] = FALSE;
9499  pmt_request_mode[path] = PMT_REQUEST_MONITOR;
9500  eit_list[path] = NULL;
9501  num_eit_list_entries[path] = 0;
9502 
9503  service_list_ready[path] = FALSE;
9504  last_reported_cat_version[path] = -1;
9505  last_reported_nit_version[path] = -1;
9506  last_reported_pmt_version[path] = 0;
9507  }
9508 
9509  required_service_type = SEARCH_SERVICE_TYPE_ALL;
9510 
9511  STB_SIRegisterAppSiEventHandler(HandleSiEvent);
9512 
9513  eit_schedule_limit = (U16BIT)APP_NvmRead(EIT_SCHED_LIMIT_NVM);
9514 
9515  /* Create a semaphore to protect access to the PMT priority list */
9516  si_pmt_list_sem = STB_OSCreateSemaphore();
9517 
9518  ASI_ClearPmtList();
9519 
9520  use_bats_active = FALSE;
9521  active_bouquet_ids = NULL;
9522  num_active_bouquet_ids = 0;
9523 
9524  active_network_id = 0;
9525 
9526  FUNCTION_FINISH(ASI_InitialiseAppSi);
9527 }
9528 
9534 void ASI_SetAppSiMode(U8BIT path, E_APP_SI_MODE si_mode)
9535 {
9536  FUNCTION_START(APP_SetAppSiMode);
9537 
9538  if (path < STB_DPGetNumPaths())
9539  {
9540  required_si_mode[path] = si_mode;
9541  }
9542 
9543  FUNCTION_FINISH(APP_SetAppSiMode);
9544 }
9545 
9559 {
9560  FUNCTION_START(ASI_CheckServiceListReadyDuringSearch);
9561  FUNCTION_FINISH(ASI_CheckServiceListReadyDuringSearch);
9562  return(service_list_ready[path]);
9563 }
9564 
9572 U16BIT ASI_GetPmtPid(U16BIT serv_id, U16BIT ts_id, U16BIT on_id)
9573 {
9574  U16BIT i;
9575  U16BIT pid;
9576  U8BIT path;
9577 
9578  FUNCTION_START(ASI_GetPmtPid);
9579 
9580  pid = 0xffff;
9581  path = STB_DPGetLivePath();
9582  if (path != INVALID_RES_ID && pmt_list[path] != NULL)
9583  {
9584  for (i = 0; i < num_pmt_list_entries[path]; i++)
9585  {
9586  if ((pmt_list[path][i].serv_id == serv_id) &&
9587  ((ts_id == ADB_INVALID_DVB_ID) || (pmt_list[path][i].ts_id == ts_id)) &&
9588  ((on_id == ADB_INVALID_DVB_ID) || (pmt_list[path][i].on_id == on_id)))
9589  {
9590  pid = pmt_list[path][i].pid;
9591  break;
9592  }
9593  }
9594  }
9595 
9596  FUNCTION_FINISH(ASI_GetPmtPid);
9597 
9598  return pid;
9599 }
9600 
9604 void ASI_StopPmtReporting(U8BIT path)
9605 {
9606  FUNCTION_START(ASI_StopPmtReporting);
9607  // set flag - state is checked in timer handling section
9608  stop_pmt_reporting[path] = TRUE;
9609  FUNCTION_FINISH(ASI_StopPmtReporting);
9610 }
9611 
9617 BOOLEAN ASI_PmtReported(U8BIT path)
9618 {
9619  FUNCTION_START(ASI_PmtReported);
9620  FUNCTION_FINISH(ASI_PmtReported);
9621  return(pmt_reported[path]);
9622 }
9623 
9630 void ASI_SetStandbyState(BOOLEAN standby_state)
9631 {
9632  U8BIT i, num_paths;
9633 
9634  FUNCTION_START(ASI_SetStandbyState);
9635 
9636  // If we are going into standby then nullify the last transport record pointer. This will ensure
9637  // that, on exiting from standby, tables which are normally reported (to third parties) when a
9638  // transport changes (e.g. CAT) are re-reported.
9639  if (standby_state == TRUE)
9640  {
9641  num_paths = STB_DPGetNumPaths();
9642 
9643  for (i = 0; i < num_paths; i++)
9644  {
9645  last_transport_rec[i] = NULL;
9646  }
9647  }
9648 
9649  FUNCTION_FINISH(ASI_SetStandbyState);
9650 }
9651 
9664 void* ASI_GetNextOTALocation(void *network, void *prev_location, U16BIT *onid_ptr,
9665  U16BIT *tid_ptr, U16BIT *sid_ptr)
9666 {
9667  ADB_NETWORK_REC *n_ptr;
9668  SI_LINKAGE_DESC_ENTRY *desc_ptr;
9669  U16BIT onid, tsid, sid;
9670 
9671  FUNCTION_START(ASI_GetNextOTALocation);
9672 
9673  desc_ptr = NULL;
9674  if (network != NULL)
9675  {
9676  n_ptr = (ADB_NETWORK_REC*)network;
9677 
9679 
9680  if (prev_location != NULL)
9681  {
9682  /* Find the previous linkage descriptor in the network */
9683  for (desc_ptr = n_ptr->linkage_desc_list; desc_ptr != NULL; desc_ptr = desc_ptr->next)
9684  {
9685  if (desc_ptr == prev_location)
9686  {
9687  desc_ptr = desc_ptr->next;
9688  break;
9689  }
9690  }
9691  }
9692  else
9693  {
9694  /* Start the search from the first linkage descriptor in the network */
9695  desc_ptr = n_ptr->linkage_desc_list;
9696  }
9697 
9698  for ( ; desc_ptr != NULL; desc_ptr = desc_ptr->next)
9699  {
9700  if (CheckSsuLinkageDescForUpgrade(desc_ptr, &onid, &tsid, &sid))
9701  {
9702  *onid_ptr = onid;
9703  *tid_ptr = tsid;
9704  *sid_ptr = sid;
9705  break;
9706  }
9707  }
9708 
9710  }
9711 
9712  FUNCTION_FINISH(ASI_GetNextOTALocation);
9713 
9714  return(desc_ptr);
9715 }
9716 
9721 BOOLEAN ASI_SSURefused(void)
9722 {
9723  return ssu_refused;
9724 }
9725 
9730 void ASI_RefuseSSU(BOOLEAN refuse)
9731 {
9732  ssu_refused = refuse;
9733 }
9734 
9739 void ASI_SSUSetMandatory(BOOLEAN mandatory)
9740 {
9741  FUNCTION_START(ASI_SSUSetMandatory);
9742  dvb_ssu_mandatory = mandatory;
9743  FUNCTION_FINISH(ASI_SSUSetMandatory);
9744 }
9745 
9750 BOOLEAN ASI_SSUGetMandatory(void)
9751 {
9752  FUNCTION_START(ASI_SSUGetMandatory);
9753  FUNCTION_FINISH(ASI_SSUGetMandatory);
9754  return dvb_ssu_mandatory;
9755 }
9756 
9765 BOOLEAN ASI_CheckForServiceChange(E_STB_DP_SIGNAL_TYPE tuner_type)
9766 {
9767  BOOLEAN service_change;
9768  ADB_TRANSPORT_REC *t_ptr;
9769 
9770  FUNCTION_START(ASI_CheckForServiceChange);
9771 
9772  service_change = FALSE;
9773 
9775 
9776  /* Iterate through transports */
9777  t_ptr = DBDEF_GetNextTransportRec(NULL);
9778  while (!service_change && (t_ptr != NULL))
9779  {
9780  if ((tuner_type == SIGNAL_NONE) || (t_ptr->sig_type == tuner_type))
9781  {
9782  service_change = t_ptr->sdt_version_changed;
9783  if (!service_change && (t_ptr->network != NULL))
9784  {
9785  service_change = t_ptr->network->nit_version_changed;
9786  }
9787  }
9788 
9789  t_ptr = DBDEF_GetNextTransportRec(t_ptr);
9790  }
9791 
9793 
9794  FUNCTION_FINISH(ASI_CheckForServiceChange);
9795 
9796  return(service_change);
9797 }
9798 
9804 void ASI_RestartCatFilter(U8BIT path)
9805 {
9806  FUNCTION_START(ASI_RestartCatFilter);
9807 
9808  if (path < STB_DPGetNumPaths())
9809  {
9810  if (cat_filter[path] != NULL)
9811  {
9812  STB_SIRestartTableRequest(cat_filter[path]);
9813  }
9814 
9815  last_reported_cat_version[path] = -1;
9816  }
9817 
9818  FUNCTION_FINISH(ASI_RestartCatFilter);
9819 }
9820 
9826 void ASI_RestartNitFilter(U8BIT path)
9827 {
9828  FUNCTION_START(ASI_RestartNitFilter);
9829 
9830  if (path < STB_DPGetNumPaths())
9831  {
9832  if (nit_filter[path] != NULL)
9833  {
9834  STB_SIRestartTableRequest(nit_filter[path]);
9835  }
9836 
9837  last_reported_nit_version[path] = -1;
9838  }
9839 
9840  FUNCTION_FINISH(ASI_RestartNitFilter);
9841 }
9842 
9848 void ASI_RestartSdtFilter(U8BIT path)
9849 {
9850  FUNCTION_START(ASI_RestartSdtFilter);
9851 
9852  if (path < STB_DPGetNumPaths())
9853  {
9854  if (sdt_filter[path] != NULL)
9855  {
9856  STB_SIRestartTableRequest(sdt_filter[path]);
9857  }
9858  }
9859 
9860  FUNCTION_FINISH(ASI_RestartSdtFilter);
9861 }
9862 
9868 void ASI_RestartBatFilter(U8BIT path)
9869 {
9870  FUNCTION_START(ASI_RestartBatFilter);
9871 
9872  if (path < STB_DPGetNumPaths())
9873  {
9874  if (bat_filter[path] != NULL)
9875  {
9876  STB_SIRestartTableRequest(bat_filter[path]);
9877  }
9878  }
9879 
9880  FUNCTION_FINISH(ASI_RestartBatFilter);
9881 }
9882 
9888 void ASI_RestartTotFilter(U8BIT path)
9889 {
9890  FUNCTION_START(ASI_RestartTotFilter);
9891 
9892  if (path < STB_DPGetNumPaths())
9893  {
9894  if (tot_filter[path] != NULL)
9895  {
9896  STB_SIRestartTableRequest(tot_filter[path]);
9897  }
9898  }
9899 
9900  FUNCTION_FINISH(ASI_RestartTotFilter);
9901 }
9902 
9908 void ASI_RestartTdtFilter(U8BIT path)
9909 {
9910  FUNCTION_START(ASI_RestartTdtFilter);
9911 
9912  if (path < STB_DPGetNumPaths())
9913  {
9914  if (tdt_filter[path] != NULL)
9915  {
9916  STB_SIRestartTableRequest(tdt_filter[path]);
9917  }
9918  }
9919 
9920  FUNCTION_FINISH(ASI_RestartTdtFilter);
9921 }
9922 
9927 void ASI_SetSearchServiceType(E_SEARCH_SERVICE_TYPE service_type)
9928 {
9929  FUNCTION_START(ASI_SetSearchServiceType);
9930  required_service_type = service_type;
9931  FUNCTION_FINISH(ASI_SetSearchServiceType);
9932 }
9933 
9939 void ASI_AddServiceToPmtList(U16BIT service_id)
9940 {
9941  U8BIT i, index = MAX_PMT_PRIORITY_LIST - 1;
9942 
9943  FUNCTION_START(ASI_AddServiceToPmtList);
9944 
9945  STB_OSSemaphoreWait(si_pmt_list_sem);
9946 
9947  for (i = 0; i < MAX_PMT_PRIORITY_LIST; i++)
9948  {
9949  if (pmt_priority_list[i] == service_id)
9950  {
9951  /* Service is already in the list */
9952  index = i;
9953  break;
9954  }
9955  }
9956 
9957  /* Move existing entries up so the new one can be added at the start */
9958  for (i = index; i > 0; i--)
9959  {
9960  pmt_priority_list[i] = pmt_priority_list[i - 1];
9961  }
9962 
9963  pmt_priority_list[0] = service_id;
9964 
9965  STB_OSSemaphoreSignal(si_pmt_list_sem);
9966 
9967  FUNCTION_FINISH(ASI_AddServiceToPmtList);
9968 }
9969 
9974 void ASI_RemoveServiceFromPmtList(U16BIT service_id)
9975 {
9976  U8BIT i, index = MAX_PMT_PRIORITY_LIST;
9977 
9978  FUNCTION_START(ASI_RemoveServiceFromPmtList);
9979 
9980  STB_OSSemaphoreWait(si_pmt_list_sem);
9981 
9982  for (i = 0; i < MAX_PMT_PRIORITY_LIST; i++)
9983  {
9984  if (pmt_priority_list[i] == service_id)
9985  {
9986  index = i;
9987  break;
9988  }
9989  }
9990 
9991  if (index < MAX_PMT_PRIORITY_LIST)
9992  {
9993  for (i = index; i < MAX_PMT_PRIORITY_LIST - 1; i++)
9994  {
9995  pmt_priority_list[i] = pmt_priority_list[i + 1];
9996  }
9997 
9998  pmt_priority_list[MAX_PMT_PRIORITY_LIST - 1] = INVALID_SERVICE_ID;
9999  }
10000 
10001  STB_OSSemaphoreSignal(si_pmt_list_sem);
10002 
10003  FUNCTION_FINISH(ASI_RemoveServiceFromPmtList);
10004 }
10005 
10010 {
10011  U8BIT i;
10012 
10013  FUNCTION_START(ASI_ClearPmtList);
10014 
10015  STB_OSSemaphoreWait(si_pmt_list_sem);
10016 
10017  for (i = 0; i < MAX_PMT_PRIORITY_LIST; i++)
10018  {
10019  pmt_priority_list[i] = INVALID_SERVICE_ID;
10020  }
10021 
10022  STB_OSSemaphoreSignal(si_pmt_list_sem);
10023 
10024  FUNCTION_FINISH(ASI_ClearPmtList);
10025 }
10026 
10035 void ASI_ProcessPmt(U8BIT path, void *s_ptr, U8BIT *pmt_data)
10036 {
10037  SI_TABLE_RECORD table_rec;
10038  SI_SECTION_RECORD *sect;
10039  U16BIT pmt_size;
10040 
10041  FUNCTION_START(ASI_ProcessPmt);
10042 
10043  /* Need to populate a table_rec before parsing the PMT data */
10044  pmt_size = ((pmt_data[1] & 0x0f) << 8) + pmt_data[2];
10045 
10046  if ((sect = (SI_SECTION_RECORD *)STB_AppGetMemory(sizeof(SI_SECTION_RECORD) + pmt_size)) != NULL)
10047  {
10048  sect->next = NULL;
10049  sect->sect_num = 0;
10050  sect->data_len = pmt_size;
10051  memcpy(&sect->data_start, pmt_data, pmt_size);
10052 
10053  table_rec.path = path;
10054  table_rec.tid = pmt_data[0];
10055  table_rec.version = pmt_data[5] & 0x1f;
10056  table_rec.xtid = (pmt_data[3] << 8) + pmt_data[4];
10057  table_rec.num_sect = 1;
10058  table_rec.section_list = sect;
10059 
10060  /* Can now "inject" the PMT */
10062  InternalProcessPmtTable(path, (ADB_SERVICE_REC *)s_ptr, &table_rec, FALSE, DB_ACCESS_UPDATE);
10064 
10065  STB_SIReportCurrentPmt(table_rec.xtid, &table_rec, TRUE, TRUE);
10066 
10067 #ifdef COMMON_INTERFACE
10068  ACI_ProgramMapTableChanged(&(table_rec.section_list->data_start));
10069 #endif
10070 
10071  STB_AppFreeMemory(sect);
10072  }
10073 
10074  FUNCTION_FINISH(ASI_ProcessPmt);
10075 }
10076 
10083 void ASI_SetEITScheduleLimit(U16BIT limit_hours)
10084 {
10085  FUNCTION_START(ASI_SetEITScheduleLimit);
10086 
10087  eit_schedule_limit = limit_hours;
10088  APP_NvmSave(EIT_SCHED_LIMIT_NVM, eit_schedule_limit, TRUE);
10089 
10090  FUNCTION_FINISH(ASI_SetEITScheduleLimit);
10091 }
10092 
10098 {
10099  FUNCTION_START(ASI_GetEITScheduleLimit);
10100  FUNCTION_FINISH(ASI_GetEITScheduleLimit);
10101  return(eit_schedule_limit);
10102 }
10103 
10112 void ASI_EnableBatCollection(BOOLEAN use_bats, U16BIT *bouquet_ids, U16BIT num_ids)
10113 {
10114  U16BIT i;
10115 
10116  FUNCTION_START(ASI_EnableBatCollection);
10117 
10118  if (active_bouquet_ids != NULL)
10119  {
10120  /* Delete the current array of bouquet IDs */
10121  STB_AppFreeMemory(active_bouquet_ids);
10122  active_bouquet_ids = NULL;
10123  num_active_bouquet_ids = 0;
10124  }
10125 
10126  use_bats_active = use_bats;
10127 
10128  if (use_bats && (bouquet_ids != NULL) && (num_ids > 0))
10129  {
10130  /* Save the array of bouquet IDs to be collected */
10131  active_bouquet_ids = (S_ACTIVE_BOUQUET *)STB_AppGetMemory(sizeof(S_ACTIVE_BOUQUET) * num_ids);
10132  if (active_bouquet_ids != NULL)
10133  {
10134  num_active_bouquet_ids = num_ids;
10135  for (i = 0; i < num_ids; i++)
10136  {
10137  active_bouquet_ids[i].bouquet_id = bouquet_ids[i];
10138  active_bouquet_ids[i].received = FALSE;
10139  }
10140  }
10141  }
10142 
10143  FUNCTION_FINISH(ASI_EnableBatCollection);
10144 }
10145 
10154 void ASI_RestartSITables(U8BIT path, BOOLEAN use_standard_pids)
10155 {
10156  U16BIT eit_pid;
10157 
10158  FUNCTION_START(ASI_RestartSITables);
10159 
10160  #ifdef DEBUG_SI_UPDATE
10161  AP_SI_PRINT(("%s(%u, standard_pids=%u)", __FUNCTION__, path, use_standard_pids));
10162  #endif
10163 
10164  if ((path != INVALID_RES_ID) && (current_service_rec[path] != NULL))
10165  {
10166  if (sdt_filter[path] != NULL)
10167  {
10168  STB_SICancelTableRequest(sdt_filter[path]);
10169  sdt_filter[path] = NULL;
10170  sdt_start_timestamp[path] = 0;
10171  }
10172 
10173  if (use_standard_pids)
10174  {
10175  #ifdef DEBUG_SI_UPDATE
10176  AP_SI_PRINT(("Update(%d): requesting SDT", path));
10177  #endif
10178  sdt_start_timestamp[path] = 0;
10179  sdt_filter[path] = STB_SIRequestSdt(path, CONTINUOUS_REQUEST, TRUE, TRUE, DONT_CARE_ID_MATCH,
10180  DONT_CARE_ID_MASK, 1, ReceiveSiTable, APP_SI_SDT_RECEIVED);
10181  }
10182  else if (current_service_rec[path]->sdt_pid != 0)
10183  {
10184  #ifdef DEBUG_SI_UPDATE
10185  AP_SI_PRINT(("Update(%d): requesting SDT on PID %u", path, current_service_rec[path]->sdt_pid));
10186  #endif
10187  sdt_start_timestamp[path] = 0;
10188  sdt_filter[path] = STB_SIRequestSdtFromPid(path, current_service_rec[path]->sdt_pid,
10189  CONTINUOUS_REQUEST, TRUE, TRUE, DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 1,
10190  ReceiveSiTable, APP_SI_SDT_RECEIVED);
10191  }
10192 
10193  if (tdt_filter[path] != NULL)
10194  {
10195  STB_SICancelTableRequest(tdt_filter[path]);
10196  tdt_filter[path] = NULL;
10197  tdt_start_timestamp[path] = 0;
10198  }
10199 
10200  if (use_standard_pids)
10201  {
10202  #ifdef DEBUG_SI_UPDATE
10203  AP_SI_PRINT(("Update(%d): requesting TDT", path));
10204  #endif
10205  tdt_start_timestamp[path] = 0;
10206  tdt_filter[path] = STB_SIRequestTdt(path, ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TDT_RECEIVED);
10207  }
10208  else if (current_service_rec[path]->tdt_pid != 0)
10209  {
10210  #ifdef DEBUG_SI_UPDATE
10211  AP_SI_PRINT(("Update(%d): requesting TDT on PID %u", path, current_service_rec[path]->tdt_pid));
10212  #endif
10213  tdt_start_timestamp[path] = 0;
10214  tdt_filter[path] = STB_SIRequestTdtFromPid(path, current_service_rec[path]->tdt_pid,
10215  ONE_SHOT_REQUEST, ReceiveSiTable, APP_SI_TDT_RECEIVED);
10216  }
10217 
10218  if (tot_filter[path] != NULL)
10219  {
10220  STB_SICancelTableRequest(tot_filter[path]);
10221  tot_filter[path] = NULL;
10222  tot_start_timestamp[path] = 0;
10223  }
10224 
10225  if (use_standard_pids)
10226  {
10227  #ifdef DEBUG_SI_UPDATE
10228  AP_SI_PRINT(("Update(%d): requesting TOT", path));
10229  #endif
10230  tot_start_timestamp[path] = 0;
10231  tot_filter[path] = STB_SIRequestTot(path, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
10232  }
10233  else if (current_service_rec[path]->tot_pid != 0)
10234  {
10235  #ifdef DEBUG_SI_UPDATE
10236  AP_SI_PRINT(("Update(%d): requesting TOT on PID %u", path, current_service_rec[path]->tot_pid));
10237  #endif
10238  tot_start_timestamp[path] = 0;
10239  tot_filter[path] = STB_SIRequestTotFromPid(path, current_service_rec[path]->tot_pid,
10240  CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_TOT_RECEIVED);
10241  }
10242 
10243  if (nit_filter[path] != NULL)
10244  {
10245  STB_SICancelTableRequest(nit_filter[path]);
10246  nit_filter[path] = NULL;
10247  nit_start_timestamp[path] = 0;
10248  }
10249 
10250  if (use_standard_pids)
10251  {
10252  #ifdef DEBUG_SI_UPDATE
10253  AP_SI_PRINT(("Update(%d): requesting NIT", path));
10254  #endif
10255  nit_start_timestamp[path] = 0;
10256 
10257  if (active_network_id == 0)
10258  {
10259  nit_filter[path] = STB_SIRequestNit(path, CONTINUOUS_REQUEST, ReceiveSiTable,
10260  APP_SI_NIT_RECEIVED);
10261  }
10262  else
10263  {
10264  nit_filter[path] = STB_SIRequestNitWithId(path, active_network_id, CONTINUOUS_REQUEST,
10265  ReceiveSiTable, APP_SI_NIT_RECEIVED);
10266  }
10267  }
10268  else if (current_service_rec[path]->nit_pid != 0)
10269  {
10270  #ifdef DEBUG_SI_UPDATE
10271  AP_SI_PRINT(("Update(%d): requesting NIT on PID %u", path, current_service_rec[path]->nit_pid));
10272  #endif
10273  nit_start_timestamp[path] = 0;
10274  nit_filter[path] = STB_SIRequestNitFromPid(path, current_service_rec[path]->nit_pid,
10275  FALSE, CONTINUOUS_REQUEST, ReceiveSiTable, APP_SI_NIT_RECEIVED);
10276  }
10277 
10278  if (eit_filter[path] != NULL)
10279  {
10280  STB_SICancelTableRequest(eit_filter[path]);
10281  eit_filter[path] = NULL;
10282  eit_start_timestamp[path] = 0;
10283  }
10284 
10285  if (use_standard_pids)
10286  {
10287  #ifdef DEBUG_SI_UPDATE
10288  AP_SI_PRINT(("Update(%d): requesting EIT", path));
10289  #endif
10290  eit_start_timestamp[path] = 0;
10291  eit_filter[path] = STB_SIRequestEit(path, CONTINUOUS_REQUEST, EIT_NOW_NEXT_ALL,
10292  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
10293  }
10294  else
10295  {
10296  eit_pid = 0;
10297  if (current_service_rec[path]->eit_pf_plus_pid != 0)
10298  {
10299  eit_pid = current_service_rec[path]->eit_pf_plus_pid;
10300  }
10301  else if (current_service_rec[path]->eit_pf_pid != 0)
10302  {
10303  eit_pid = current_service_rec[path]->eit_pf_pid;
10304  }
10305 
10306  if (eit_pid != 0)
10307  {
10308  #ifdef DEBUG_SI_UPDATE
10309  AP_SI_PRINT(("Update(%d): requesting EIT on PID %u", path, eit_pid));
10310  #endif
10311  eit_start_timestamp[path] = 0;
10312  eit_filter[path] = STB_SIRequestEitFromPid(path, eit_pid, CONTINUOUS_REQUEST, EIT_PF_PLUS,
10313  DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_EIT_RECEIVED);
10314  }
10315  }
10316 
10317  if (sched_filter[path] != NULL)
10318  {
10319  STB_SICancelTableRequest(sched_filter[path]);
10320  sched_filter[path] = NULL;
10321  sched_start_timestamp[path] = 0;
10322  }
10323 
10324  if (use_standard_pids)
10325  {
10326  /* Start schedule filter based on EIT memory usage requirements */
10327  StartEITScheduleFilter(path);
10328  }
10329  else if (current_service_rec[path]->eit_sched_pid != 0)
10330  {
10331  #ifdef DEBUG_SI_UPDATE
10332  AP_SI_PRINT(("Update(%d): requesting SCHED on PID %u", path, current_service_rec[path]->eit_sched_pid));
10333  #endif
10334  sched_start_timestamp[path] = 0;
10335  sched_filter[path] = STB_SIRequestSchedFromPid(path, current_service_rec[path]->eit_sched_pid,
10336  CONTINUOUS_REQUEST, EIT_SCHED_ALL, DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff,
10337  ReceiveSiTable, APP_SI_EIT_RECEIVED);
10338  }
10339 
10340  if (bat_filter[path] != NULL)
10341  {
10342  STB_SICancelTableRequest(bat_filter[path]);
10343  bat_filter[path] = NULL;
10344  bat_start_timestamp[path] = 0;
10345  }
10346 
10347  if (use_bats_active)
10348  {
10349  if (use_standard_pids)
10350  {
10351  #ifdef DEBUG_SI_UPDATE
10352  AP_SI_PRINT(("Update(%d): requesting BAT", path));
10353  #endif
10354  bat_start_timestamp[path] = 0;
10355  bat_filter[path] = STB_SIRequestBat(path, CONTINUOUS_REQUEST, DONT_CARE_ID_MATCH,
10356  DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable, APP_SI_BAT_RECEIVED);
10357  }
10358  else if (current_service_rec[path]->bat_pid != 0)
10359  {
10360  #ifdef DEBUG_SI_UPDATE
10361  AP_SI_PRINT(("Update(%d): requesting BAT on PID %u", path, current_service_rec[path]->bat_pid));
10362  #endif
10363  bat_start_timestamp[path] = 0;
10364  bat_filter[path] = STB_SIRequestBatFromPid(path, current_service_rec[path]->bat_pid,
10365  CONTINUOUS_REQUEST, DONT_CARE_ID_MATCH, DONT_CARE_ID_MASK, 0xffff, ReceiveSiTable,
10366  APP_SI_BAT_RECEIVED);
10367  }
10368  }
10369  }
10370 
10371  FUNCTION_FINISH(ASI_RestartSITables);
10372 }
10373 
10379 void ASI_SetEITParserFunction(F_EitParser parser_func)
10380 {
10381  FUNCTION_START(ASI_SetEITParserFunction);
10382  eit_parser_func = parser_func;
10383  FUNCTION_FINISH(ASI_SetEITParserFunction);
10384 }
10385 
10390 void ASI_SetUpdateBatFunction(F_BatTableUpdate update_func)
10391 {
10392  FUNCTION_START(ASI_SetUpdateBatFunction);
10393  update_bat_func = update_func;
10394  FUNCTION_FINISH(ASI_SetUpdateBatFunction);
10395 }
10396 
10401 void ASI_SetUpdateEitFunction(F_EitTableUpdate update_func)
10402 {
10403  FUNCTION_START(ASI_SetUpdateEitFunction);
10404  update_eit_func = update_func;
10405  FUNCTION_FINISH(ASI_SetUpdateEitFunction);
10406 }
10407 
10412 void ASI_SetUpdateNitFunction(F_NitTableUpdate update_func)
10413 {
10414  FUNCTION_START(ASI_SetUpdateNitFunction);
10415  update_nit_func = update_func;
10416  FUNCTION_FINISH(ASI_SetUpdateNitFunction);
10417 }
10418 
10423 void ASI_SetUpdatePmtFunction(F_PmtTableUpdate update_func)
10424 {
10425  FUNCTION_START(ASI_SetUpdatePmtFunction);
10426  update_pmt_func = update_func;
10427  FUNCTION_FINISH(ASI_SetUpdatePmtFunction);
10428 }
10429 
10434 void ASI_SetUpdateSdtFunction(F_SdtTableUpdate update_func)
10435 {
10436  FUNCTION_START(ASI_SetUpdateSdtFunction);
10437  update_sdt_func = update_func;
10438  FUNCTION_FINISH(ASI_SetUpdateSdtFunction);
10439 }
10440 
10446 void ASI_ProcessEitTable(SI_TABLE_RECORD *table_rec, BOOLEAN playback)
10447 {
10448  FUNCTION_START(ASI_ProcessEitTable);
10449  ProcessEitTable(table_rec, TRUE, DB_ACCESS_UPDATE, playback);
10450  FUNCTION_FINISH(ASI_ProcessEitTable);
10451 }
10452 
10458 {
10459  SI_TIME_TABLE *tot_table;
10460  SI_LTO_DESC *lto_desc_ptr;
10461  U16BIT i;
10462  U32BIT reqd_country_code;
10463  BOOLEAN regions_exist;
10464  U8BIT reqd_region_code;
10465 
10466  FUNCTION_START(ASI_ProcessTotTable);
10467 
10468  tot_table = STB_SIParseTimeTable(table_rec);
10469  STB_SIReleaseTableRecord(table_rec);
10470  if (tot_table != NULL)
10471  {
10472  #ifdef DEBUG_SI_TOT
10473  AP_SI_PRINT(("TOT table: %02d:%02d:%02d on %d",
10474  tot_table->hrs, tot_table->mins, tot_table->secs, tot_table->date));
10475  #endif
10476 
10477  // set the time and date
10478  STB_GCSetGMTTime(tot_table->hrs, tot_table->mins, tot_table->secs);
10479  STB_GCSetGMTDate(tot_table->date);
10480 
10481  // check for time offset descriptor
10482  reqd_country_code = ACFG_GetCountry();
10483  regions_exist = ACFG_GetRegionCode(reqd_country_code, (U8BIT)APP_NvmRead(REGION_ID_NVM),
10484  &reqd_region_code);
10485 
10486  lto_desc_ptr = tot_table->lto_desc_array;
10487  for (i = 0; i < tot_table->num_lto_entries; i++, lto_desc_ptr++)
10488  {
10489  if (lto_desc_ptr->country_code == reqd_country_code)
10490  {
10491  if ((regions_exist == FALSE) ||
10492  ((regions_exist == TRUE) && (lto_desc_ptr->region == reqd_region_code)))
10493  {
10494  STB_GCSetLocalTimeChange(lto_desc_ptr->change_date,
10495  lto_desc_ptr->change_hrs,
10496  lto_desc_ptr->change_mins,
10497  lto_desc_ptr->change_secs,
10498  lto_desc_ptr->offset_hrs,
10499  lto_desc_ptr->offset_mins,
10500  lto_desc_ptr->next_offset_hrs,
10501  lto_desc_ptr->next_offset_mins,
10502  lto_desc_ptr->offset_negative);
10503  break;
10504  }
10505  }
10506  }
10507 
10508  STB_SIReleaseTimeTable(tot_table);
10509 
10510  /* Send event to the app indicating the time has been updated */
10511  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_TIME_CHANGED, NULL, 0);
10512  }
10513 
10514  FUNCTION_FINISH(ASI_ProcessTotTable);
10515 }
10516 
10522 {
10523  SI_TIME_TABLE *tdt_table;
10524 
10525  FUNCTION_START(ASI_ProcessTdtTable);
10526 
10527  tdt_table = STB_SIParseTimeTable(table_rec);
10528  STB_SIReleaseTableRecord(table_rec);
10529  if (tdt_table != NULL)
10530  {
10531  #ifdef DEBUG_SI_TDT
10532  AP_SI_PRINT(("TDT table: %02d:%02d:%02d on %d",
10533  tdt_table->hrs, tdt_table->mins, tdt_table->secs, tdt_table->date));
10534  #endif
10535 
10536  // set the time and date
10537  STB_GCSetGMTTime(tdt_table->hrs, tdt_table->mins, tdt_table->secs);
10538  STB_GCSetGMTDate(tdt_table->date);
10539 
10540  STB_SIReleaseTimeTable(tdt_table);
10541 
10542  /* Send event to the app indicating the time has been updated */
10543  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_TIME_CHANGED, NULL, 0);
10544  }
10545 
10546  FUNCTION_FINISH(ASI_ProcessTdtTable);
10547 }
10548 
10556 void ASI_RegisterEitSchedUpdateCallback(F_EitSchedUpdateCB sched_update_callback)
10557 {
10558  FUNCTION_START(ASI_RegisterEitSchedUpdateCallback);
10559 
10560  eit_sched_update_callback = sched_update_callback;
10561 
10562  FUNCTION_FINISH(ASI_RegisterEitSchedUpdateCallback);
10563 }
10564 
10572 void ASI_NotifyEitSchedUpdate(void *serv_ptr, U16BIT event_id, E_APP_SI_EIT_JOURNAL_TYPE type)
10573 {
10574  void *t_ptr;
10576 
10577  FUNCTION_START(ASI_NotifyEitSchedUpdate);
10578 
10579  if ((eit_sched_update_callback != NULL) && (serv_ptr != NULL))
10580  {
10581  if ((t_ptr = ADB_GetServiceTransportPtr(serv_ptr)) != NULL)
10582  {
10583  update.type = type;
10584  update.orig_net_id = ADB_GetTransportOriginalNetworkId(t_ptr);
10585  update.tran_id = ADB_GetTransportTid(t_ptr);
10586  update.serv_id = ADB_GetServiceId(serv_ptr);
10587  update.allocated_lcn = ADB_GetServiceLcn(serv_ptr);
10588  update.is_sched = TRUE;
10589  update.event_id = event_id;
10590 
10591  (*eit_sched_update_callback)(&update);
10592  }
10593  }
10594 
10595  FUNCTION_FINISH(ASI_NotifyEitSchedUpdate);
10596 }
10597 
10605 void ASI_SetActiveNetworkId(U16BIT network_id)
10606 {
10607  FUNCTION_START(ASI_SetActiveNetworkId);
10608 
10609  active_network_id = network_id;
10610 
10611  FUNCTION_FINISH(ASI_SetActiveNetworkId);
10612 }
10613 
10628 void ASI_AllowDatabaseUpdates(E_STB_DP_SIGNAL_TYPE signal_type, BOOLEAN allow)
10629 {
10630  FUNCTION_START(ASI_AllowDatabaseUpdates);
10631 
10632  if (signal_type == SIGNAL_NONE)
10633  {
10634  db_updates_allowed.terrestrial = allow;
10635  db_updates_allowed.cable = allow;
10636  db_updates_allowed.satellite = allow;
10637  }
10638  else if (signal_type == SIGNAL_COFDM)
10639  {
10640  db_updates_allowed.terrestrial = allow;
10641  }
10642  else if (signal_type == SIGNAL_QAM)
10643  {
10644  db_updates_allowed.cable = allow;
10645  }
10646  else if (signal_type == SIGNAL_QPSK)
10647  {
10648  db_updates_allowed.satellite = allow;
10649  }
10650 
10651  FUNCTION_FINISH(ASI_AllowDatabaseUpdates);
10652 }
10653 
10659 BOOLEAN ASI_DatabaseUpdatesAllowed(E_STB_DP_SIGNAL_TYPE signal_type)
10660 {
10661  BOOLEAN allowed;
10662 
10663  FUNCTION_START(ASI_DatabaseUpdatesAllowed);
10664 
10665  if (signal_type == SIGNAL_COFDM)
10666  {
10667  allowed = db_updates_allowed.terrestrial;
10668  }
10669  else if (signal_type == SIGNAL_QAM)
10670  {
10671  allowed = db_updates_allowed.cable;
10672  }
10673  else if (signal_type == SIGNAL_QPSK)
10674  {
10675  allowed = db_updates_allowed.satellite;
10676  }
10677  else
10678  {
10679  allowed = FALSE;
10680  }
10681 
10682  FUNCTION_FINISH(ASI_DatabaseUpdatesAllowed);
10683 
10684  return(allowed);
10685 }
10686 
10687 
10688 static BOOLEAN DynamicUpdateAddTransport(ADB_TRANSPORT_REC *transport, U16BIT num_lcns, SI_LCN_DESC * lcn_array,
10689  U16BIT num_hd_lcns, SI_LCN_DESC *hd_lcn_array, U16BIT num_nordig_lcns, SI_NORDIG_LCN_DESC *nordig_lcn_array)
10690 {
10691  BOOLEAN retval;
10692  S_DYNAMIC_UPDATE_TRANSPORT *dyn_ts_ptr;
10693 
10694  retval = FALSE;
10695 
10696 #ifdef DEBUG_DYNAMIC_UPDATE
10697  AP_SI_PRINT(("%s: tid 0x%04x, %u LCNs, %u HD LCNs, %u Nordig LCNs", __FUNCTION__, transport->tran_id,
10698  num_lcns, num_hd_lcns, num_nordig_lcns));
10699 #endif
10700 
10701  /* Create a new transport entry to be added to the list */
10703  num_lcns * sizeof(SI_LCN_DESC) + num_hd_lcns * sizeof(SI_LCN_DESC));
10704 
10705  if (dyn_ts_ptr != NULL)
10706  {
10707  memset(dyn_ts_ptr, 0, sizeof(S_DYNAMIC_UPDATE_TRANSPORT));
10708 
10709  dyn_ts_ptr->t_ptr = transport;
10710 
10711  dyn_ts_ptr->num_lcns = num_lcns;
10712  dyn_ts_ptr->lcn_array = (SI_LCN_DESC *)(dyn_ts_ptr + 1);
10713  if (num_lcns != 0)
10714  {
10715  memcpy(dyn_ts_ptr->lcn_array, lcn_array, num_lcns * sizeof(SI_LCN_DESC));
10716  }
10717 
10718  dyn_ts_ptr->num_hd_lcns = num_hd_lcns;
10719  dyn_ts_ptr->hd_lcn_array = dyn_ts_ptr->lcn_array + dyn_ts_ptr->num_lcns;
10720  if (num_hd_lcns != 0)
10721  {
10722  memcpy(dyn_ts_ptr->hd_lcn_array, hd_lcn_array, num_hd_lcns * sizeof(SI_LCN_DESC));
10723  }
10724 
10725  /* The Nordig LCN structure isn't a simple structure to copy,
10726  * so the array passed in is used directly */
10727  dyn_ts_ptr->num_nordig_lcns = num_nordig_lcns;
10728  dyn_ts_ptr->nordig_lcn_array = nordig_lcn_array;
10729 
10730  if (dynamic_update_head == NULL)
10731  {
10732  dynamic_update_head = dyn_ts_ptr;
10733  dynamic_update_tail = dyn_ts_ptr;
10734  }
10735  else
10736  {
10737  dynamic_update_tail->next = dyn_ts_ptr;
10738  dynamic_update_tail = dyn_ts_ptr;
10739  }
10740 
10741  retval = TRUE;
10742  }
10743 
10744  return(retval);
10745 }
10746 
10747 static void DynamicUpdateAddService(ADB_TRANSPORT_REC *transport, ADB_SERVICE_REC *service, BOOLEAN check_move)
10748 {
10749  S_DYNAMIC_UPDATE_TRANSPORT *dyn_ts_ptr;
10750  S_DYNAMIC_UPDATE_SERVICE *dyn_s_ptr;
10751 
10752 #ifdef DEBUG_DYNAMIC_UPDATE
10753  AP_SI_PRINT(("%s: tid 0x%04x, sid 0x%04x, %s", __FUNCTION__, transport->tran_id, service->serv_id,
10754  (check_move ? "check move" : "")));
10755 #endif
10756 
10757  if (check_move)
10758  {
10759  /* Check to see if there's been a service deleted with the same service ID
10760  * as the one being added. This will have been on a different transport so all
10761  * transports need to be checked. Without the support of a descriptor to define
10762  * the service move, the moved service can only be detected if it keeps the
10763  * same service ID */
10764  for (dyn_ts_ptr = dynamic_update_head, dyn_s_ptr = NULL; (dyn_ts_ptr != NULL) && (dyn_s_ptr == NULL);
10765  dyn_ts_ptr = dyn_ts_ptr->next)
10766  {
10767  for (dyn_s_ptr = dyn_ts_ptr->service_head; dyn_s_ptr != NULL; dyn_s_ptr = dyn_s_ptr->next)
10768  {
10769  if ((dyn_s_ptr->delete_s_ptr != NULL) && (dyn_s_ptr->delete_s_ptr->serv_id == service->serv_id))
10770  {
10771 #ifdef DEBUG_DYNAMIC_UPDATE
10772  AP_SI_PRINT(("%s: Found deleted service with the same service ID, tid 0x%04x",
10773  __FUNCTION__, dyn_s_ptr->delete_t_ptr->tran_id));
10774 #endif
10775  /* A service with the same service ID is being deleted.
10776  * Update this entry with the details of the service being added */
10777  dyn_s_ptr->add_s_ptr = service;
10778  dyn_s_ptr->add_t_ptr = transport;
10779  break;
10780  }
10781  }
10782 
10783  if (dyn_s_ptr != NULL)
10784  {
10785  break;
10786  }
10787  }
10788  }
10789  else
10790  {
10791  dyn_ts_ptr = NULL;
10792  }
10793 
10794  if (dyn_ts_ptr == NULL)
10795  {
10796  /* Look for the transport the service is being added to */
10797  dyn_ts_ptr = dynamic_update_head;
10798  while ((dyn_ts_ptr != NULL) && (dyn_ts_ptr->t_ptr != transport))
10799  {
10800  dyn_ts_ptr = dyn_ts_ptr->next;
10801  }
10802 
10803  if (dyn_ts_ptr != NULL)
10804  {
10805  /* Create a new entry for this service */
10807  if (dyn_s_ptr != NULL)
10808  {
10809  memset(dyn_s_ptr, 0, sizeof(S_DYNAMIC_UPDATE_SERVICE));
10810 
10811  dyn_s_ptr->add_s_ptr = service;
10812  dyn_s_ptr->add_t_ptr = transport;
10813 
10814  /* Add the service */
10815  if (dyn_ts_ptr->service_head == NULL)
10816  {
10817  dyn_ts_ptr->service_head = dyn_s_ptr;
10818  dyn_ts_ptr->service_tail = dyn_s_ptr;
10819  }
10820  else
10821  {
10822  dyn_ts_ptr->service_tail->next = dyn_s_ptr;
10823  dyn_ts_ptr->service_tail = dyn_s_ptr;
10824  }
10825 #ifdef DEBUG_DYNAMIC_UPDATE
10826  AP_SI_PRINT(("%s: New entry for service 0x%04x being added", __FUNCTION__, service->serv_id));
10827 #endif
10828  }
10829  }
10830  else
10831  {
10832 #ifdef DEBUG_DYNAMIC_UPDATE
10833  AP_SI_PRINT(("%s: Attempt to add service to a transport that isn't in the dynamic update list",
10834  __FUNCTION__));
10835 #endif
10836  }
10837  }
10838 }
10839 
10840 static void DynamicUpdateDeleteService(ADB_TRANSPORT_REC *transport, ADB_SERVICE_REC *service, BOOLEAN check_move)
10841 {
10842  S_DYNAMIC_UPDATE_TRANSPORT *dyn_ts_ptr;
10843  S_DYNAMIC_UPDATE_SERVICE *dyn_s_ptr;
10844 
10845 #ifdef DEBUG_DYNAMIC_UPDATE
10846  AP_SI_PRINT(("%s: tid 0x%04x, sid 0x%04x, %s", __FUNCTION__, transport->tran_id, service->serv_id,
10847  (check_move ? "check move" : "")));
10848 #endif
10849 
10850  if (check_move)
10851  {
10852  /* Check to see if there's been a service added with the same service ID
10853  * as the one being deleted. This will have been on a different transport so all
10854  * transports need to be checked. Without the support of a descriptor to define
10855  * the service move, the moved service can only be detected if it keeps the
10856  * same service ID */
10857  for (dyn_ts_ptr = dynamic_update_head, dyn_s_ptr = NULL; (dyn_ts_ptr != NULL) && (dyn_s_ptr == NULL);
10858  dyn_ts_ptr = dyn_ts_ptr->next)
10859  {
10860  for (dyn_s_ptr = dyn_ts_ptr->service_head; dyn_s_ptr != NULL; dyn_s_ptr = dyn_s_ptr->next)
10861  {
10862  if ((dyn_s_ptr->add_s_ptr != NULL) && (dyn_s_ptr->add_s_ptr->serv_id == service->serv_id))
10863  {
10864 #ifdef DEBUG_DYNAMIC_UPDATE
10865  AP_SI_PRINT(("%s: Found added service with the same service ID, tid 0x%04x",
10866  __FUNCTION__, dyn_s_ptr->add_t_ptr->tran_id));
10867 #endif
10868  /* A service with the same service ID has been added.
10869  * Update this entry with the details of the service being deleted */
10870  dyn_s_ptr->delete_s_ptr = service;
10871  dyn_s_ptr->delete_t_ptr = transport;
10872  break;
10873  }
10874  }
10875 
10876  if (dyn_s_ptr != NULL)
10877  {
10878  break;
10879  }
10880  }
10881  }
10882  else
10883  {
10884  dyn_ts_ptr = NULL;
10885  }
10886 
10887  if (dyn_ts_ptr == NULL)
10888  {
10889  /* Look for the transport the service is being added to */
10890  dyn_ts_ptr = dynamic_update_head;
10891  while ((dyn_ts_ptr != NULL) && (dyn_ts_ptr->t_ptr != transport))
10892  {
10893  dyn_ts_ptr = dyn_ts_ptr->next;
10894  }
10895 
10896  if (dyn_ts_ptr != NULL)
10897  {
10898  /* Create a new entry for this service */
10900  if (dyn_s_ptr != NULL)
10901  {
10902  memset(dyn_s_ptr, 0, sizeof(S_DYNAMIC_UPDATE_SERVICE));
10903 
10904  dyn_s_ptr->delete_s_ptr = service;
10905  dyn_s_ptr->delete_t_ptr = transport;
10906 
10907  /* Add the service */
10908  if (dyn_ts_ptr->service_head == NULL)
10909  {
10910  dyn_ts_ptr->service_head = dyn_s_ptr;
10911  dyn_ts_ptr->service_tail = dyn_s_ptr;
10912  }
10913  else
10914  {
10915  dyn_ts_ptr->service_tail->next = dyn_s_ptr;
10916  dyn_ts_ptr->service_tail = dyn_s_ptr;
10917  }
10918  }
10919  }
10920  else
10921  {
10922 #ifdef DEBUG_DYNAMIC_UPDATE
10923  AP_SI_PRINT(("%s: Attempt to delete service from a transport that isn't in the dynamic update list",
10924  __FUNCTION__));
10925 #endif
10926  }
10927  }
10928 }
10929 
10930 static void ApplyDynamicUpdates(U8BIT path)
10931 {
10932  BOOLEAN sdts_received;
10933  S_DYNAMIC_UPDATE_TRANSPORT *dyn_ts_ptr;
10934  S_DYNAMIC_UPDATE_SERVICE *dyn_s_ptr;
10935  ADB_SERVICE_REC *s_ptr;
10936  U16BIT reqd_lcn;
10937  U16BIT i, j;
10938 
10939  if (dynamic_update_head != NULL)
10940  {
10941  /* There are operations that may need to be applied; check that all SDTs have been received first */
10943 
10944  sdts_received = TRUE;
10945 
10946  for (dyn_ts_ptr = dynamic_update_head; (dyn_ts_ptr != NULL) && sdts_received;
10947  dyn_ts_ptr = dyn_ts_ptr->next)
10948  {
10949  sdts_received = dyn_ts_ptr->t_ptr->sdt_received;
10950  }
10951 
10953 
10954  if (sdts_received)
10955  {
10956  /* All SDTs have been received so the required operations can be performed */
10958 
10959  for (dyn_ts_ptr = dynamic_update_head; dyn_ts_ptr != NULL; dyn_ts_ptr = dyn_ts_ptr->next)
10960  {
10961 #ifdef DEBUG_DYNAMIC_UPDATE
10962  AP_SI_PRINT(("%s: Apply updates for transport 0x%04x", __FUNCTION__, dyn_ts_ptr->t_ptr->tran_id));
10963 #endif
10964  /* Iterate the service entries */
10965  for (dyn_s_ptr = dyn_ts_ptr->service_head; dyn_s_ptr != NULL; dyn_s_ptr = dyn_s_ptr->next)
10966  {
10967  /* Service addition will already have been performed, but an event needs to be sent */
10968  if ((dyn_s_ptr->add_s_ptr != NULL) && (dyn_s_ptr->delete_s_ptr == NULL))
10969  {
10970 #ifdef DEBUG_DYNAMIC_UPDATE
10971  AP_SI_PRINT(("%s: Added service 0x%04x to transport 0x%04x", __FUNCTION__,
10972  dyn_s_ptr->add_s_ptr->serv_id, dyn_s_ptr->add_t_ptr->tran_id));
10973 #endif
10974  /* Send notification of the service that's been added */
10975  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_ADDED,
10976  &dyn_s_ptr->add_s_ptr, sizeof(void *));
10977  }
10978  else if ((dyn_s_ptr->add_s_ptr != NULL) && (dyn_s_ptr->delete_s_ptr != NULL))
10979  {
10980  /* Service has been moved.
10981  * As the original service may be being referenced, the service to be deleted
10982  * is updated with info from the service that's been added and its transport
10983  * is changed, and the service that's been added is then deleted */
10984 #ifdef DEBUG_DYNAMIC_UPDATE
10985  AP_SI_PRINT(("%s: Move service 0x%04x (new sid 0x%04x) from 0x%04x to 0x%04x",
10986  __FUNCTION__,
10987  dyn_s_ptr->delete_s_ptr->serv_id, dyn_s_ptr->add_s_ptr->serv_id,
10988  dyn_s_ptr->delete_t_ptr->tran_id, dyn_s_ptr->add_t_ptr->tran_id));
10989 #endif
10990  dyn_s_ptr->delete_s_ptr->transport = dyn_s_ptr->add_t_ptr;
10991 
10992  if (dyn_s_ptr->delete_s_ptr->dba_rec != NULL)
10993  {
10994  DBA_SetRecordParent(dyn_s_ptr->delete_s_ptr->dba_rec, dyn_s_ptr->add_t_ptr->dba_rec);
10995 
10996  DBA_SaveRecord(dyn_s_ptr->delete_s_ptr->dba_rec);
10997  }
10998 
10999  DBDEF_DeleteServiceRec(dyn_s_ptr->add_s_ptr);
11000 
11001  if (ADB_GetTunedService(path) == dyn_s_ptr->delete_s_ptr)
11002  {
11003  /* Notify that the service has moved as a retune is required to stay on it */
11004  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_MOVED,
11005  &dyn_s_ptr->delete_s_ptr, sizeof(void *));
11006  }
11007  }
11008  else if (dyn_s_ptr->delete_s_ptr != NULL)
11009  {
11010  if (ADB_GetTunedService(path) != dyn_s_ptr->delete_s_ptr)
11011  {
11012 #ifdef DEBUG_DYNAMIC_UPDATE
11013  AP_SI_PRINT(("%s: Delete service 0x%04x from transport 0x%04x", __FUNCTION__,
11014  dyn_s_ptr->delete_s_ptr->serv_id, dyn_s_ptr->delete_t_ptr->tran_id));
11015 #endif
11016  /* Delete the service */
11017  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_SERVICE_DELETED,
11018  &dyn_s_ptr->delete_s_ptr, sizeof(dyn_s_ptr->delete_s_ptr));
11019 
11020  DBDEF_DeleteServiceRec(dyn_s_ptr->delete_s_ptr);
11021  }
11022  else
11023  {
11024  /* This is the currently tuned service so can't be deleted yet */
11025 #ifdef DEBUG_DYNAMIC_UPDATE
11026  AP_SI_PRINT(("%s: Service 0x%04x on transport 0x%04x is the current service, not deleting",
11027  __FUNCTION__, dyn_s_ptr->delete_s_ptr->serv_id, dyn_s_ptr->delete_t_ptr->tran_id));
11028 #endif
11029  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_DELETE_SERVICE,
11030  &dyn_s_ptr->delete_s_ptr, sizeof(dyn_s_ptr->delete_s_ptr));
11031  }
11032  }
11033  }
11034 
11035  /* Now apply any LCN changes */
11036  if ((dyn_ts_ptr->num_nordig_lcns != 0) && (dyn_ts_ptr->nordig_lcn_array != NULL))
11037  {
11038  for (i = 0; i < dyn_ts_ptr->num_nordig_lcns; i++)
11039  {
11040  for (j = 0; j < dyn_ts_ptr->nordig_lcn_array[i].num_services; j++)
11041  {
11042  s_ptr = DBDEF_FindServiceRec(dyn_ts_ptr->nordig_lcn_array[i].serv_array[j].serv_id,
11043  dyn_ts_ptr->t_ptr);
11044  if (s_ptr != NULL)
11045  {
11046  if (s_ptr->hidden != !dyn_ts_ptr->nordig_lcn_array[i].serv_array[j].visible)
11047  {
11048  s_ptr->hidden = !dyn_ts_ptr->nordig_lcn_array[i].serv_array[j].visible;
11049  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_HIDDEN, s_ptr->hidden);
11050 #ifdef DEBUG_DYNAMIC_UPDATE
11051  AP_SI_PRINT(("%s: service 0x%04x, hidden flag now %u", __FUNCTION__,
11052  s_ptr->serv_id, s_ptr->hidden));
11053 #endif
11054  }
11055 
11056  s_ptr->selectable = TRUE;
11057  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_SELECTABLE, s_ptr->selectable);
11058 
11059  reqd_lcn = dyn_ts_ptr->nordig_lcn_array[i].serv_array[j].serv_lcn;
11060  if (reqd_lcn != s_ptr->serv_lcn)
11061  {
11062  /* LCN is being changed so reset the one that's currently allocated
11063  * to this service so it's reassigned */
11064  s_ptr->allocated_lcn = 0;
11065  s_ptr->serv_lcn = reqd_lcn;
11066  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_REQ_LCN, s_ptr->serv_lcn);
11067 #ifdef DEBUG_DYNAMIC_UPDATE
11068  AP_SI_PRINT(("%s: service 0x%04x, LCN %u", __FUNCTION__, s_ptr->serv_id, reqd_lcn));
11069 #endif
11070  }
11071 
11072  DBA_SaveRecord(s_ptr->dba_rec);
11073  }
11074  }
11075  }
11076  }
11077  else
11078  {
11079  for (i = 0; i < dyn_ts_ptr->num_lcns; i++)
11080  {
11081  s_ptr = DBDEF_FindServiceRec(dyn_ts_ptr->lcn_array[i].serv_id, dyn_ts_ptr->t_ptr);
11082  if (s_ptr != NULL)
11083  {
11084  /* Set service hidden attribute from LCN descriptor */
11085  if (s_ptr->hidden != !dyn_ts_ptr->lcn_array[i].visible)
11086  {
11087  s_ptr->hidden = !dyn_ts_ptr->lcn_array[i].visible;
11088  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_HIDDEN, s_ptr->hidden);
11089 #ifdef DEBUG_DYNAMIC_UPDATE
11090  AP_SI_PRINT(("%s: service 0x%04x, hidden flag now %u", __FUNCTION__,
11091  s_ptr->serv_id, s_ptr->hidden));
11092 #endif
11093  }
11094 
11095  /* A hidden service still needs to be selectable, so it's aways TRUE in this case */
11096  s_ptr->selectable = TRUE;
11097  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_SELECTABLE, s_ptr->selectable);
11098 
11099  reqd_lcn = dyn_ts_ptr->lcn_array[i].serv_lcn;
11100  if (reqd_lcn != s_ptr->serv_lcn)
11101  {
11102  /* LCN is being changed so reset the one that's currently allocated
11103  * to this service so it's reassigned */
11104  s_ptr->allocated_lcn = 0;
11105  s_ptr->serv_lcn = reqd_lcn;
11106  DBA_SetFieldValue(s_ptr->dba_rec, DBA_FIELD_SERV_REQ_LCN, s_ptr->serv_lcn);
11107 #ifdef DEBUG_DYNAMIC_UPDATE
11108  AP_SI_PRINT(("%s: service 0x%04x, LCN %u", __FUNCTION__, s_ptr->serv_id, reqd_lcn));
11109 #endif
11110  }
11111 
11112  DBA_SaveRecord(s_ptr->dba_rec);
11113  }
11114  }
11115  }
11116 
11117  if (dyn_ts_ptr->num_hd_lcns != 0)
11118  {
11119  /* Now take into account any HD LCN assignments */
11120  for (i = 0; i < dyn_ts_ptr->num_hd_lcns; i++)
11121  {
11122  s_ptr = DBDEF_FindServiceRec(dyn_ts_ptr->hd_lcn_array[i].serv_id, dyn_ts_ptr->t_ptr);
11123 
11124  if ((s_ptr != NULL) && (s_ptr->old_allocated_lcn == 0))
11125  {
11126  /* The HD LCN descriptor will be used when allocating LCNs and will be freed
11127  * when ADB_ReleaseDatabaseSearchData is called */
11128  s_ptr->hd_lcn_desc = STB_GetMemory(sizeof(SI_LCN_DESC));
11129  memcpy(s_ptr->hd_lcn_desc, &dyn_ts_ptr->hd_lcn_array[i], sizeof(SI_LCN_DESC));
11130 #ifdef DEBUG_DYNAMIC_UPDATE
11131  AP_SI_PRINT(("%s: service 0x%04x has an HD LCN, %u", s_ptr->serv_id,
11132  s_ptr->hd_lcn_desc->serv_lcn));
11133 #endif
11134  }
11135  }
11136  }
11137  }
11138 
11139  /* The dynamic update list can now be freed */
11140  ClearDynamicUpdates();
11141 
11144 
11146 
11148 
11149  ADB_SaveDatabase();
11150  }
11151  }
11152 }
11153 
11154 static void ClearDynamicUpdates(void)
11155 {
11156  S_DYNAMIC_UPDATE_TRANSPORT *next_ts_ptr;
11157  S_DYNAMIC_UPDATE_SERVICE *next_s_ptr;
11158 
11159 #ifdef DEBUG_DYNAMIC_UPDATE
11160  AP_SI_PRINT(("%s", __FUNCTION__));
11161 #endif
11162 
11163  for ( ; dynamic_update_head != NULL; dynamic_update_head = next_ts_ptr)
11164  {
11165  next_ts_ptr = dynamic_update_head->next;
11166 
11167  for ( ; dynamic_update_head->service_head != NULL; dynamic_update_head->service_head = next_s_ptr)
11168  {
11169  next_s_ptr = dynamic_update_head->service_head->next;
11170 
11171  STB_FreeMemory(dynamic_update_head->service_head);
11172  }
11173 
11174  if (dynamic_update_head->nordig_lcn_array != NULL)
11175  {
11176  STB_SIReleaseNordigLcn2DescArray(dynamic_update_head->nordig_lcn_array,
11177  dynamic_update_head->num_nordig_lcns);
11178  }
11179 
11180  STB_FreeMemory(dynamic_update_head);
11181  }
11182 
11183  dynamic_update_tail = NULL;
11184 }
11185 
BOOLEAN STB_CADescramblerRequiredForPlayback(U16BIT *ca_ids, U16BIT num_ca_ids)
This function works out whether a CA descrambler is required to playback a recording with one of the ...
Definition: ca_glue.c:315
U16BIT DBDEF_GetReqdAudioPid(ADB_SERVICE_REC *s_ptr, E_STB_DP_AUDIO_MODE *audio_mode, ADB_STREAM_TYPE *audio_type)
Gets the appropriate audio pid - looks first for the pid matching exactly the required audio settings...
Definition: ap_dbdef.c:6298
void DBDEF_SetTunedTransport(U8BIT path, ADB_TRANSPORT_REC *t_ptr)
sets the currently tuned transport
Definition: ap_dbdef.c:8034
Application level CI control functions.
U32DHMS STB_GCCalculateDHMS(U32DHMS dhms, U32DHMS period, E_STB_GC_CALCTYPE calc)
Calculates the date/time when the period is added/subtracted to/from dhms.
Definition: stbgc.c:2136
BOOLEAN STB_SIReportCat(SI_TABLE_RECORD *table_rec)
Reports the CAT has been received so it can be passed on to other modules.
Definition: stbsiflt.c:2603
BOOLEAN ADB_AddServiceToFavouriteList(U8BIT list_id, void *serv_ptr, S16BIT index)
Adds the given service to the favourite list defined by list_id, with the service being optionally ad...
Definition: ap_dbacc.c:11032
void * APVR_GetPlaybackService(void)
A service instance is associated to the playback, this function returns its pointer. The handle can be used, for example, to call ADB_ServiceHasSubtitles as it&#39;s done for live channels.
Definition: ap_pvr.c:3607
void * STB_SIRequestNitWithId(U8BIT path, U16BIT network_id, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for NITactual and NITother for the given network ID.
Definition: stbsitab.c:7938
void * STB_SIRequestAit(U8BIT path, E_SI_REQUEST_TYPE req_type, U16BIT ait_pid, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for AIT on given PID.
Definition: stbsitab.c:13158
U8BIT STB_TuneGetDataIntegrity(U8BIT path)
Returns the current data integrity.
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void ADB_SaveDatabase(void)
Saves the database to non-volatile memory.
Definition: ap_dbacc.c:502
void DBDEF_DeleteEventList(ADB_EVENT_REC *elist)
Deletes all events in the given list.
Definition: ap_dbdef.c:3754
macros and function prototypes for public use
void ASI_InitialiseAppSi(void)
Initialises application SI handling.
Definition: ap_si.c:9369
void ASI_SetEITScheduleLimit(U16BIT limit_hours)
Sets the number of hours of EIT data that&#39;s kept for each service that hasn&#39;t its had EIT schedule di...
Definition: ap_si.c:10083
U8BIT STB_DPGetPathCISlot(U8BIT path)
Returns the CI slot id associated with the given path.
Definition: stbdpc.c:1082
U16BIT DBDEF_GetReqdADPid(ADB_SERVICE_REC *s_ptr, E_STB_DP_AUDIO_MODE *ad_mode, ADB_STREAM_TYPE *ad_type, BOOLEAN *broadcast_mix)
Gets the appropriate audio description pid - looks first for the pid matching exactly the required au...
Definition: ap_dbdef.c:6352
void STB_SIReleaseBatTable(SI_BAT_TABLE *bat_table)
Frees the memory used by the bat table.
Definition: stbsitab.c:11427
void * ADB_GetServiceTransportPtr(void *s_ptr)
Returns a pointer to the service&#39;s parent transport record.
Definition: ap_dbacc.c:5999
void * STB_SIRequestEitFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, E_SI_EIT_TABLE_REQ reqd_eit_tables, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for EIT.
Definition: stbsitab.c:8256
void ASI_RestartTotFilter(U8BIT path)
Forces the SI demux filter collecting the TOT tables to be reset, so a previously processed versions ...
Definition: ap_si.c:9888
BOOLEAN ACFG_GetDynamicSIUpdate(E_STB_DP_SIGNAL_TYPE signal_type, U16BIT onet_id, E_ACFG_DYNAMIC_SI_UPDATE_TYPE update_type)
Use to check whether a dynamic SI update is enabled for the currently configured country and given si...
Definition: ap_cfg.c:2092
U8BIT * STB_HWGetOUI(void)
Returns the number of smart card slots on the platorm.
BOOLEAN ACI_IsTrustedPath(U8BIT path)
The given decode path is only trusted if it doesn&#39;t include a CI slot or the CI slot contains a CI+ C...
Definition: ap_ci.c:1688
void STB_GCSetGMTDate(U16BIT code)
Sets current GMT date.
Definition: stbgc.c:1174
void * STB_SIRequestTotFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for TOT.
Definition: stbsitab.c:8508
BOOLEAN DBA_SaveDatabase(void)
Saves any changes made to the working database to non-volatile storage. If saving to a file...
Definition: dba_nvm.c:667
void * ASI_GetNextOTALocation(void *network, void *prev_location, U16BIT *onid_ptr, U16BIT *tid_ptr, U16BIT *sid_ptr)
Returns the DVB triplet for the next location containing a possible OTA update.
Definition: ap_si.c:9664
BOOLEAN STB_DPIsLivePath(U8BIT path)
Is the given decode path being used for live viewing.
Definition: stbdpc.c:1297
void STB_SIReleaseRctTable(SI_RCT_TABLE *rct_table)
Frees memory used by an RCT table.
Definition: stbsitab.c:11596
ADB_SERVICE_REC * DBDEF_FindServiceRecByLcn(U16BIT lcn, ADB_TRANSPORT_REC *t_ptr, BOOLEAN allocated_lcn)
Find the service with the given LCN, and optionally on the given transport.
Definition: ap_dbdef.c:6218
SI_NIT_TABLE * STB_SIParseNitTable(SI_TABLE_RECORD *table_rec)
Parses the Nit table supplied in TABLE_RECORD format to create a NIT_TABLE structure. Returns a pointer to the table. Application must call STB_SIReleaseNitTable to free the data.
Definition: stbsitab.c:9155
ADB_TRANSPORT_REC * DBDEF_FindSatTransportRec(U32BIT freq_hz, U16BIT symbol_rate, E_STB_DP_POLARITY polarity, BOOLEAN dvb_s2, E_STB_DP_MODULATION modulation, void *satellite)
Find the satellite transport record in the database matching the given params.
Definition: ap_dbdef.c:5170
BOOLEAN ACA_AcquireCADescrambler(U8BIT path, void *s_ptr)
Acquires a CA descrambler for the given path on the given service if needed. No CA descrambler is acq...
Definition: ap_ca.c:79
Application configuration.
U16BIT ADB_GetNumServicesInList(U32BIT list_type, BOOLEAN inc_hidden)
Returns the number of services in the database that would be returned with the given list type...
Definition: ap_dbacc.c:3200
Application database control.
U32DHMS STB_GCNowDHMSGmt(void)
Reads the current GMT date code and time.
Definition: stbgc.c:2264
E_STB_DP_TUNE_STATUS STB_DPGetTuneStatus(U8BIT path)
Reads the tuning status from decode path store.
Definition: stbdpc.c:3332
U32BIT STB_OSGetClockDiff(U32BIT timestamp)
Get Difference between Given Time and Current Time.
Header file - macros and function prototypes for public use.
void * STB_OSCreateSemaphore(void)
Create a Semaphore.
void * STB_SIRequestNitFromPid(U8BIT path, U16BIT pid, BOOLEAN actual, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Create an SI filter for an NIT table.
Definition: stbsitab.c:7899
U8BIT * ACTL_GetRfNameFromFreq(E_STB_DP_SIGNAL_TYPE tuner_type, U32BIT freq_hz)
Returns the rf name appropriate to the frequency specified.
Definition: ap_cntrl.c:1308
Header file for NVM data handling functions.
BOOLEAN DBDEF_SetServiceType(ADB_SERVICE_REC *s_ptr, ADB_SERVICE_TYPE serv_type)
Sets the service type for the given service record.
Definition: ap_dbdef.c:5969
BOOLEAN ADB_ServiceAddImageIcon(void *serv_ptr, void *icon_ptr)
Adds the given image icon to the end of the service&#39;s icon list. The icon id is checked and if it mat...
Definition: ap_dbacc.c:6468
SI_SDT_TABLE * STB_SIParseSdtTable(SI_TABLE_RECORD *table_rec)
Parses the Sdt table supplied in TABLE_RECORD format to create a SDT_TABLE structure. Returns a pointer to the table. Application must call STB_SIReleaseSdtTable to free the data.
Definition: stbsitab.c:9623
U16BIT ASI_GetPmtPid(U16BIT serv_id, U16BIT ts_id, U16BIT on_id)
Returns the PID for the pmt of a given service (on live path)
Definition: ap_si.c:9572
ADB_TRANSPORT_REC * DBDEF_FindTerrestrialTransportRec(U32BIT freq_hz, U8BIT plp_id)
Find the terrestrial transport record in the database matching the given params.
Definition: ap_dbdef.c:4952
void ASI_SetUpdateBatFunction(F_BatTableUpdate update_func)
Sets a function that will be called when a BAT table is received.
Definition: ap_si.c:10390
void * STB_AppGetMemory(U32BIT bytes)
Attempts to allocate memory from the application heap.
Definition: stbheap.c:651
void STB_GCSetLocalTimeChange(U16BIT code, U8BIT hour, U8BIT min, U8BIT secs, U8BIT ohour1, U8BIT omin1, U8BIT ohour2, U8BIT omin2, BOOLEAN neg)
Sets new and old local time offset from GMT.
Definition: stbgc.c:925
void ASI_SSUSetMandatory(BOOLEAN mandatory)
Sets the flag indicating whether the SSU can be refused by the user.
Definition: ap_si.c:9739
void STB_SIReleasePmtTable(SI_PMT_TABLE *pmt_table)
Frees the memory used by the pmt table.
Definition: stbsitab.c:11258
ADB_SERVICE_REC * DBDEF_FindServiceRecByIds(ADB_SERVICE_REC *servp, U32BIT net_id, U32BIT onet_id, U32BIT tran_id, U32BIT serv_id)
Search for a service with the given IDs.
Definition: ap_dbdef.c:6150
void DBDEF_SetTransportTransportId(ADB_TRANSPORT_REC *t_ptr, U16BIT tran_id)
Sets the transport ID of the given transport.
Definition: ap_dbdef.c:5368
void ADB_DeleteFavouriteList(U8BIT list_id)
Deletes the favourite list with the given list id.
Definition: ap_dbacc.c:11005
Application level CA control functions.
void DBA_SaveRecord(void *record)
Forces a record to be saved to non-volatile storage. Depending on the implementation, this function may not do anything if the data is updated to non-volatile storage as any records and/or fields are created or updated.
Definition: dba_nvm.c:1157
BOOLEAN DBDEF_SetServiceName(ADB_SERVICE_REC *s_ptr, U8BIT *name)
Set or change the name of a service.
Definition: ap_dbdef.c:5783
void STB_SIReleaseTimeTable(SI_TIME_TABLE *time_table)
Frees the memory used by the time table (tdt or tot)
Definition: stbsitab.c:11576
ADB_TRANSPORT_REC * DBDEF_AddSatTransportRec(U32BIT freq_hz, U16BIT symbol_rate, E_STB_DP_POLARITY polarity, BOOLEAN dvb_s2, E_STB_DP_MODULATION modulation, ADB_NETWORK_REC *network)
Adds a satellite transport record with the given frequency, symbol rate and polarity.
Definition: ap_dbdef.c:5102
void ADB_ServiceReleaseRCTLinks(void *serv_ptr)
Frees all RCT link info for the given service.
Definition: ap_dbacc.c:6152
void ASI_RegisterEitSchedUpdateCallback(F_EitSchedUpdateCB sched_update_callback)
Registers a function that will be called whenever an EIT event is added, updated, deleted or expires ...
Definition: ap_si.c:10556
Definition: stbsitab.h:732
U8BIT * STB_ConvertStringToUTF8(U8BIT *string, U16BIT *nchar, BOOLEAN strip_DVB_cntrl_char, U32BIT lang_code)
Converts the given DVB coded string into a UTF-8 unicode string. The returned string will be preceded...
Definition: stbuni.c:1508
void * STB_SIRequestCat(U8BIT path, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for CAT.
Definition: stbsitab.c:8541
E_STB_TUNE_TBWIDTH STB_TuneGetActualTerrBwidth(U8BIT path)
Returns the actual bandwidth of the current terrestrial signal.
Header file - Function prototypes for A/V control.
void ASI_ProcessPmt(U8BIT path, void *s_ptr, U8BIT *pmt_data)
Takes data for a raw PMT for the given service and processes it as if it had been received from the d...
Definition: ap_si.c:10035
void STB_OSSemaphoreSignal(void *semaphore)
Signal a Semaphore to Release it by decrementing its counter.
void DBDEF_ReleaseString(ADB_STRING *string)
Releases an ADB_STRING.
Definition: ap_dbdef.c:3983
void ASI_SetStandbyState(BOOLEAN standby_state)
Performs the neccessary actions for this module when entering/exiting standby according to the value ...
Definition: ap_si.c:9630
U8BIT STB_DPGetTerrPLP(U8BIT path)
Reads the terrestrial T2 PLP id from decode path store.
Definition: stbdpc.c:6709
BOOLEAN STB_IMGConvertPNG(U8BIT *image_data, U32BIT image_data_size, U8BIT **output_data, U32BIT *output_data_size, U16BIT *pixel_width, U16BIT *pixel_height)
Converts the given PNG image data to a bitmap image that can be displayed on-screen with the given bi...
Definition: image_png.c:98
Media image functions.
ADB_TRANSPORT_REC * DBDEF_AddTerrestrialTransportRec(U32BIT freq_hz, U8BIT plp_id, ADB_NETWORK_REC *network)
Adds a terrestrial transport record with the given frequency and PLP id.
Definition: ap_dbdef.c:4874
U32BIT APP_NvmRead(E_NVM_ITEMS nvm_item)
Returns the current value for the given DVB setting.
Definition: app_nvm.c:562
U32DHMS STB_GCCreateDHMS(U16BIT date, U8BIT hour, U8BIT mins, U8BIT secs)
Makes U32DHMS formated date/time from date code, hour, minutes, seconds.
Definition: stbgc.c:2080
void ACI_ProgramMapTableChanged(U8BIT *pmt)
Handle PMT change.
Definition: ap_ci.c:1638
E_STB_DP_POLARITY STB_DPGetPolarity(U8BIT path)
Reads the polarity value from decode path store.
Definition: stbdpc.c:6157
SI_PAT_TABLE * STB_SIParsePatTable(SI_TABLE_RECORD *table_rec)
Parses the Pat table supplied in TABLE_RECORD format to create a PAT_TABLE structure. Returns a pointer to the table. Application must call STB_SIReleasePatTable to free the data.
Definition: stbsitab.c:8611
U8BIT * ADB_GetServicePMTData(void *s_ptr, U16BIT *data_len)
Returns the current PMT data for the given service.
Definition: ap_dbacc.c:11293
Definition: stbsitab.h:560
ADB_NETWORK_REC * DBDEF_AddNetworkRec(U16BIT net_id, ADB_SATELLITE_REC *satellite)
Adds a new network record to the database with the given network ID.
Definition: ap_dbdef.c:4644
Application timer functions and defines.
void STB_SIRestartTableRequest(void *filter_handle)
restarts the section filtering on an existing filter without changing and pid or match/mask filter se...
Definition: stbsiflt.c:2419
void APP_NvmSave(E_NVM_ITEMS nvm_item, U32BIT new_value, BOOLEAN write_to_flash_now)
Sets the current value for the given DVB setting.
Definition: app_nvm.c:634
SI_TIME_TABLE * STB_SIParseTimeTable(SI_TABLE_RECORD *table_rec)
Parses the tdt or tot table supplied in TABLE_RECORD format to create a TIME_TABLE structure...
Definition: stbsitab.c:10631
E_STB_TUNE_SYSTEM_TYPE STB_TuneGetSystemType(U8BIT path)
Returns the signal type as set by STB_TuneSetTerrType or as re-written by the driver.
BOOLEAN STB_SIReportNit(SI_TABLE_RECORD *table_rec)
Reports the NIT has been received so it can be passed on to other modules.
Definition: stbsiflt.c:2687
BOOLEAN STB_SIReportBat(SI_TABLE_RECORD *table_rec)
Reports the BAT has been received so it can be passed on to other modules.
Definition: stbsiflt.c:2650
void ASI_SetEITParserFunction(F_EitParser parser_func)
Sets a function that will be called when parsing an EIT table and a descriptor is found that the stan...
Definition: ap_si.c:10379
void HBBTV_ProcessAitSection(U16BIT service_id, U8BIT *data, U32BIT nbytes)
Requests the HbbTV engine to process the specified AIT. The HbbTV engine expects the relevant AITs on...
BOOLEAN ASI_DatabaseUpdatesAllowed(E_STB_DP_SIGNAL_TYPE signal_type)
Returns whether service database updates are allowed for the given signal type.
Definition: ap_si.c:10659
void STB_SIReleaseNordigLcn2DescArray(SI_NORDIG_LCN_DESC *desc_array, U16BIT num_entries)
Frees the memory used by the descriptor array specified.
Definition: stbsitab.c:12791
SI_BAT_TABLE * STB_SIParseBatTable(SI_TABLE_RECORD *table_rec)
Parses the BAT table supplied in TABLE_RECORD format to create a SI_BAT_TABLE structure. Returns a pointer to the table. Application must call STB_SIReleaseBatTable to free the data.
Definition: stbsitab.c:9969
void * STB_SIRequestPat(U8BIT path, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for PAT.
Definition: stbsitab.c:7773
void ASI_SetAppSiMode(U8BIT path, E_APP_SI_MODE si_mode)
Sets application SI mode - used before STB_DPStartSI() is called.
Definition: ap_si.c:9534
void ASI_RestartSITables(U8BIT path, BOOLEAN use_standard_pids)
Cancels any existing SI filters and starts a new one for the SDT, TDT, TOT, NIT, EIT (pf...
Definition: ap_si.c:10154
void STB_OSSemaphoreWait(void *semaphore)
Wait on Semaphore Indefinity or Until Released.
void DBDEF_DeleteImageIcons(ADB_IMAGE_ICON *icon_list)
Frees given list of image icons and any associated memory.
Definition: ap_dbdef.c:3849
void DBDEF_DeleteServiceRec(ADB_SERVICE_REC *s_ptr)
Deletes specified service record.
Definition: ap_dbdef.c:1754
void * STB_SIRequestSdtFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, BOOLEAN inc_sdt_actual, BOOLEAN inc_sdt_other, U16BIT tran_id_match, U16BIT tran_id_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for SDT.
Definition: stbsitab.c:8033
void STB_ERSendEvent(BOOLEAN latched, BOOLEAN repeat, U16BIT path_class, U16BIT type, void *data, U32BIT data_size)
Sends an event to event reporting control module.
Definition: stberc.c:571
CI Content Control.
E_STB_DP_SIGNAL_TYPE STB_DPGetSignalType(U8BIT path)
Reads the signal type value from decode path store.
Definition: stbdpc.c:3836
void HBBTV_NotifyProgrammeChanged(void)
Notifies the HbbTV engine that the present/following events have changed on the current service...
void * ADB_GetTransportFromIds(U16BIT net_id, U16BIT onet_id, U16BIT tran_id)
Finds the transport with the given ids.
Definition: ap_dbacc.c:2968
void * STB_SIRequestTdt(U8BIT path, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for TDT.
Definition: stbsitab.c:8408
ADB_STRING * DBDEF_MakeString(U32BIT lang_code, U8BIT *str_ptr, U16BIT nbytes)
Creates an ADB_STRING, copying the given data into it. If the string passed in is NULL or the number ...
Definition: ap_dbdef.c:3890
U8BIT STB_DPGetNumPaths(void)
Returns the maximum number of decode paths.
Definition: stbdpc.c:532
BOOLEAN ADB_AddFavouriteList(U8BIT *name, U32BIT user_data, S16BIT index, U8BIT *list_id)
Creates a new favourite list and adds it to the existing lists, if any.
Definition: ap_dbacc.c:10755
U8BIT STB_DPGetPlaybackPath(void)
Returns the ID of the decode path being used for playback.
Definition: stbdpc.c:1373
U32BIT STB_OSGetClockRTC(void)
Returns the current time in seconds. This is calculated by using the set UTC time and adding the diff...
void STB_SIReleaseTableRecord(SI_TABLE_RECORD *table_rec)
Frees the memory used in a table record passed to the application.
Definition: stbsiflt.c:2463
BOOLEAN ASI_PmtReported(U8BIT path)
Returns TRUE if pmt has been reported to third parties.
Definition: ap_si.c:9617
U8BIT STB_DPGetLivePath(void)
Returns the ID of the decode path being used for live viewing.
Definition: stbdpc.c:1271
void ASI_SetUpdateSdtFunction(F_SdtTableUpdate update_func)
Sets a function that will be called when an SDT table is received.
Definition: ap_si.c:10434
U8BIT STB_TuneGetSignalStrength(U8BIT path)
Returns the current signal strength.
ADB_TRANSPORT_REC * DBDEF_GetNextTransportRec(ADB_TRANSPORT_REC *t_ptr)
Returns the transport following the one given. If the argument is NULL then the first transport will ...
Definition: ap_dbdef.c:4842
BOOLEAN ASI_CheckServiceListReadyDuringSearch(U8BIT path)
Reports the state of the service_list_ready flag which is set when the sdt has been processed in a se...
Definition: ap_si.c:9558
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
void * STB_SIRequestBatFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, U16BIT tran_id_match, U16BIT tran_id_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for Bat.
Definition: stbsitab.c:8172
ADB_SERVICE_REC * DBDEF_FindServiceRec(U16BIT serv_id, ADB_TRANSPORT_REC *t_ptr)
Search for the service with the given service ID on the given transport.
Definition: ap_dbdef.c:6119
void DBDEF_SetNetworkName(ADB_NETWORK_REC *n_ptr, U8BIT *name)
Set or change the name of the given network.
Definition: ap_dbdef.c:4708
void STB_SISearchComplete(U8BIT path, BOOLEAN success, void *event_data, U32BIT data_size)
Indicates SI search is complete.
Definition: stbsiflt.c:2509
void STB_SIReportCurrentPmt(U16BIT service_id, SI_TABLE_RECORD *table_rec, BOOLEAN new_serv, BOOLEAN new_pmt_version)
Reports current pmt has arrived so that it can be passed on to interested parties.
Definition: stbsiflt.c:2542
void ADB_ReleaseDatabaseSearchData(void)
Frees all data that&#39;s only required for service search. This should be called after the search is com...
Definition: ap_dbacc.c:409
void * STB_SIRequestPmt(U8BIT path, E_SI_REQUEST_TYPE req_type, U16BIT pmt_pid, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for PMT.
Definition: stbsitab.c:7810
void STB_ReleaseUnicodeString(U8BIT *string)
Releases the specified unicode string, freeing associated heap resources.
Definition: stbuni.c:1955
U16BIT ADB_GetTransportTid(void *t_ptr)
Returns the transport id of the given transport.
Definition: ap_dbacc.c:2325
void DBDEF_ReleaseAccess(void)
Releases access to the app&#39;s database.
Definition: ap_dbdef.c:245
U16BIT ADB_GetServiceLcn(void *s_ptr)
Returns the logical channel number assigned to the given service.
Definition: ap_dbacc.c:4940
void ASI_RestartCatFilter(U8BIT path)
Forces the SI demux filter collecting the CAT tables to be reset, so a previously processed version o...
Definition: ap_si.c:9804
void DBDEF_SetTransportOrigNetworkId(ADB_TRANSPORT_REC *t_ptr, U16BIT orig_net_id)
Sets the original network ID of the given transport.
Definition: ap_dbdef.c:5387
BOOLEAN ACFG_IsNordigCountry(void)
Returns whether the current country requires Nordig compliance for SI.
Definition: ap_cfg.c:1656
BOOLEAN STB_DPIsOwnedBy(U8BIT path, E_STB_DP_RES_OWNER owner)
Checks whether the path is owned by the given owner.
Definition: stbdpc.c:1966
void ASI_RestartBatFilter(U8BIT path)
Forces the SI demux filter collecting the BAT tables to be reset, so a previously processed versions ...
Definition: ap_si.c:9868
Debug functions header file.
Header file - Function prototypes for linked lists.
Header file - macros and function prototypes for public use.
void * ADB_GetTunedTransport(U8BIT path)
Returns the transport that&#39;s tuned to on the given decode path.
Definition: ap_dbacc.c:3015
BOOLEAN STB_IMGConvertJPEG(U8BIT *image_data, U32BIT image_data_size, U8BIT **output_data, U32BIT *output_data_size, U16BIT *pixel_width, U16BIT *pixel_height)
Converts the given JPEG image data to a bitmap image that can be displayed on-screen, but no scaling is applied.
Definition: image_jpeg.c:118
Header file - macros and function prototypes for public use.
ADB_SERVICE_REC * DBDEF_CopyServiceRec(ADB_SERVICE_REC *orig_serv)
Creates a copy of the given service, copying the service&#39;s attributes, e.g. service name...
Definition: ap_dbdef.c:5663
ADB_TRANSPORT_REC * DBDEF_AddCableTransportRec(U32BIT freq_hz, U32BIT symbol_rate, ADB_NETWORK_REC *network)
Adds a cable transport record with the given frequency and symbol rate.
Definition: ap_dbdef.c:4982
void * ADB_GetTunedService(U8BIT path)
Returns the tuned service for the given decode path.
Definition: ap_dbacc.c:6068
void ASI_RemoveServiceFromPmtList(U16BIT service_id)
Removes the service id from the PMT priority list.
Definition: ap_si.c:9974
BOOLEAN ACI_SetSecureRouting(U8BIT path)
Ensures the TS is routed securely for CI+, either by setting the TS to pass through if a CI slot cont...
Definition: ap_ci.c:1380
U8BIT ACFG_ConvertLangCodeToId(U32BIT lang_code)
Returns the language id for the given language code.
Definition: ap_cfg.c:931
Database access defines, structures and public functions.
BOOLEAN ACTL_AreSubtitlesStarted(void)
Returns whether subtitles have been started, even if they aren&#39;t being displayed. ...
Definition: ap_cntrl.c:3626
U32BIT STB_DPGetFrequency(U8BIT path)
Reads the frequency value from decode path store.
Definition: stbdpc.c:6092
ADB_SERVICE_REC * DBDEF_GetNextServiceRec(ADB_SERVICE_REC *s_ptr)
Returns the service after the one given. If NULL is passed then the first service in the list is retu...
Definition: ap_dbdef.c:5535
ADB_TRANSPORT_REC * DBDEF_FindCableTransportRec(U32BIT freq_hz, U32BIT symbol_rate)
Find the cable transport record in the database matching the given params.
Definition: ap_dbdef.c:5040
Application level CI - internal functions.
void ASI_ClearPmtList(void)
Clears all service ids from the PMT priority list.
Definition: ap_si.c:10009
void ACI_TuneReply(U8BIT path, U32BIT module, E_CIP_TUNER_STATUS status)
This function is called by the host to send the status of the tune operation to the module...
Definition: ap_ci.c:2242
SI_PMT_TABLE * STB_SIParsePmtTable(SI_TABLE_RECORD *table_rec)
Parses the Pmt table supplied in TABLE_RECORD format to create a PMT_TABLE structure. Returns a pointer to the table. Application must call STB_SIReleasePmtTable to free the data.
Definition: stbsitab.c:8738
Application configuration data.
BOOLEAN ACFG_GetRegionCode(U32BIT country_code, U8BIT region_id, U8BIT *code_ptr)
Returns the region code that identifies the given region.
Definition: ap_cfg.c:1498
void STB_SIReleaseSdtTable(SI_SDT_TABLE *sdt_table)
Frees the memory used by the sdt table.
Definition: stbsitab.c:11391
U16BIT ADB_GetTransportOriginalNetworkId(void *t_ptr)
Returns the original network id of the given transport.
Definition: ap_dbacc.c:2385
U8BIT STB_DPGetPathTuner(U8BIT path)
Returns the tuner ID acquired by the given decode path.
Definition: stbdpc.c:1605
U16BIT ASI_GetEITScheduleLimit(void)
Returns the current setting for the number of hours of EIT data that&#39;s kept.
Definition: ap_si.c:10097
U8BIT APVR_GetPlaybackPath(void)
Returns the path currently acquired fro playback.
Definition: ap_pvr.c:3189
Header file - Function prototypes for Event Reporting.
void ASI_RestartNitFilter(U8BIT path)
Forces the SI demux filter collecting the NIT tables to be reset, so a previously processed version o...
Definition: ap_si.c:9826
void * STB_SIRequestBat(U8BIT path, E_SI_REQUEST_TYPE req_type, U16BIT bouquet_id_match, U16BIT bouquet_id_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for Bat.
Definition: stbsitab.c:8133
void STB_CANotifyRunningStatus(U32BIT handle, U8BIT status)
This function will be called when there&#39;s a change to the running status of a service being descrambl...
Definition: ca_glue.c:296
E_STB_DP_MODULATION STB_DPGetModulation(U8BIT path)
Returns the satellite modulation type for the give decode path.
Definition: stbdpc.c:6385
ADB_SERVICE_REC * DBDEF_AddServiceRec(U16BIT serv_id, ADB_TRANSPORT_REC *t_ptr)
Adds a new service record to the service database with the given service ID and parent transport...
Definition: ap_dbdef.c:5598
Header for STB unicode string handling routines.
void DBDEF_DeleteStreamList(ADB_STREAM_REC *slist)
Deletes all records in a service stream list.
Definition: ap_dbdef.c:1941
void DBDEF_SetTunedNetwork(U8BIT path, ADB_NETWORK_REC *n_ptr)
sets the currently tuned network
Definition: ap_dbdef.c:7996
void ASI_RestartSdtFilter(U8BIT path)
Forces the SI demux filter collecting the SDT tables to be reset, so a previously processed versions ...
Definition: ap_si.c:9848
void DBDEF_RequestAccess(void)
Requests access to the app&#39;s database.
Definition: ap_dbdef.c:235
Glue layer between DVB and conditional access systems.
BOOLEAN DBDEF_SetServiceProviderName(ADB_SERVICE_REC *s_ptr, U8BIT *name)
Set or change the name of a service&#39;s provider.
Definition: ap_dbdef.c:5910
void * STB_SIRequestTdtFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for TDT.
Definition: stbsitab.c:8442
BOOLEAN ADB_IsFreesatService(void *s_ptr)
Returns a value indicating whether the given service is a Freesat service.
Definition: ap_dbacc.c:5885
ADB_NETWORK_REC * DBDEF_FindNetworkRec(U16BIT net_id, ADB_SATELLITE_REC *satellite)
Finds the network with the given network ID.
Definition: ap_dbdef.c:4772
void DBDEF_DeleteTransportRec(ADB_TRANSPORT_REC *t_ptr)
Deletes the given transport from the service database, deleting any service records that it&#39;s the par...
Definition: ap_dbdef.c:5431
void HBBTV_NotifyServiceListChange(void)
Notifies the HbbTV ending that it must update Service list. This will cause the engine to subsequentl...
SI_RCT_TABLE * STB_SIParseRctTable(SI_TABLE_RECORD *table_rec)
Parses the related content table (RCT) to create an SI_RCT_TABLE structure.
Definition: stbsitab.c:10720
U16BIT ADB_GetServiceId(void *s_ptr)
Returns the signalled service id of the given service.
Definition: ap_dbacc.c:4960
U32BIT ACFG_GetCountry(void)
Returns the country code the DVB is configured for.
Definition: ap_cfg.c:150
void ASI_SetUpdatePmtFunction(F_PmtTableUpdate update_func)
Sets a function that will be called when a PMT table is received.
Definition: ap_si.c:10423
U16BIT DBDEF_GetReqdVideoPid(ADB_SERVICE_REC *s_ptr, ADB_STREAM_TYPE *video_type)
Returns the video pid and type that should be used for the given service from the list of video strea...
Definition: ap_dbdef.c:6531
application level SI task
ADB_SERVICE_REC * DBDEF_GetNextServiceOnTransport(ADB_SERVICE_REC *s_ptr, ADB_TRANSPORT_REC *t_ptr)
Find the next service following the given service that&#39;s on the given transport.
Definition: ap_dbdef.c:6083
Application stb layer control.
Definition: stbsitab.h:358
void ASI_RefuseSSU(BOOLEAN refuse)
Sets the flag indicating whether the SSU has been refused or not.
Definition: ap_si.c:9730
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
BOOLEAN DBA_SetFieldValue(void *record, U32BIT field_id, U32BIT value)
Set the value of a record&#39;s field. The function will fail if the record doesn&#39;t exist, the record doesn&#39;t include the given field, or the field is a string value.
Definition: dba_nvm.c:1175
void * STB_SIRequestSched(U8BIT path, E_SI_REQUEST_TYPE req_type, E_SI_SCHED_TABLE_REQ reqd_eit_tables, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for EIT schedule table.
Definition: stbsitab.c:8329
U16BIT STB_DPGetSymbolRate(U8BIT path)
Reads the symbol rate value from decode path store.
Definition: stbdpc.c:6222
ADB_NETWORK_REC * DBDEF_GetTunedNetwork(U8BIT path)
gets the currently tuned network
Definition: ap_dbdef.c:8015
void STB_AppFreeMemory(void *addr)
Releases previously allocated application heap memory.
Definition: stbheap.c:781
void DBDEF_SetServicePmtPid(ADB_SERVICE_REC *s_ptr, U16BIT pmt_pid)
Updates the pmt pid.
Definition: ap_dbdef.c:6959
void ASI_AddServiceToPmtList(U16BIT service_id)
Add the given service id to the list of services whose PMT will be requested with a higher priority t...
Definition: ap_si.c:9939
void * STB_SIRequestRct(U8BIT path, E_SI_REQUEST_TYPE req_type, U16BIT rct_pid, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for RCT on given PID.
Definition: stbsitab.c:8575
ADB_TRANSPORT_REC * DBDEF_GetTunedTransport(U8BIT path)
gets the currently tuned transport
Definition: ap_dbdef.c:8053
Application level HBBTV callback functions.
U32BIT STB_TuneGetActualSymbolRate(U8BIT path)
Returns the actual symbol rate when a tuner has locked.
void ASI_SetSearchServiceType(E_SEARCH_SERVICE_TYPE service_type)
Set the type for services that should be added during a service search.
Definition: ap_si.c:9927
BOOLEAN DBDEF_SetServiceShortName(ADB_SERVICE_REC *s_ptr, U8BIT *name)
Set or change the short name of a service.
Definition: ap_dbdef.c:5850
ADB_NETWORK_REC * DBDEF_FindOrAddPrivateNetwork(void *satellite)
Find or add a private network, assigning an unused private network ID.
Definition: ap_dbdef.c:10603
void * STB_SIRequestSchedFromPid(U8BIT path, U16BIT pid, E_SI_REQUEST_TYPE req_type, E_SI_SCHED_TABLE_REQ reqd_eit_tables, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for EIT schedule table.
Definition: stbsitab.c:8371
void STB_GCSetGMTTime(U8BIT hour, U8BIT min, U8BIT secs)
Sets current GMT time.
Definition: stbgc.c:1042
BOOLEAN STB_DPIsRecordingPath(U8BIT path)
Is the given decode path being used for recording.
Definition: stbdpc.c:1320
E_STB_TUNE_CMODE STB_TuneGetActualCableMode(U8BIT path)
Returns the cable mode when the tuner has locked.
void ASI_RestartTdtFilter(U8BIT path)
Forces the SI demux filter collecting the TDT tables to be reset, so a previously processed versions ...
Definition: ap_si.c:9908
void ASI_SetUpdateEitFunction(F_EitTableUpdate update_func)
Sets a function that will be called when an EIT table is received.
Definition: ap_si.c:10401
void * STB_SIRequestNit(U8BIT path, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for NIT(actual)
Definition: stbsitab.c:7870
BOOLEAN ASI_SSUGetMandatory(void)
Returns the flag indicating whether the SSU is mandatory and so can&#39;t be refused. ...
Definition: ap_si.c:9750
Definition: stbsitab.h:237
BOOLEAN STB_DPGetDVBS2(U8BIT path)
Returns whether the sat tuner is tuned to DVB-S or DVB-S2.
Definition: stbdpc.c:6338
BOOLEAN STB_DPGetPathCADescrambler(U8BIT path, U32BIT *handle)
Get the handle of the CA descrambler associated with the given path.
Definition: stbdpc.c:1244
void ASI_StopPmtReporting(U8BIT path)
Prevents the current pmt being reported (e.g. to MHEG).
Definition: ap_si.c:9604
void * STB_SIRequestEit(U8BIT path, E_SI_REQUEST_TYPE req_type, E_SI_EIT_TABLE_REQ reqd_eit_tables, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for EIT.
Definition: stbsitab.c:8214
U16BIT STB_SIGetPmtCaIdDescArray(U8BIT *pmt_data, U16BIT **pmt_ca_ids)
Parses the given PMT to produce an array of the CA system IDs required by the service or streams on t...
Definition: stbsitab.c:13038
S8BIT STB_CompareStringsIgnoreCase(U8BIT *string1_ptr, U8BIT *string2_ptr)
Compares the contents of the two given ASCII strings and returns the status (as per strcmp) but ignor...
Definition: stbuni.c:2183
void * STB_DPGetOwnerData(U8BIT path, U32BIT *data_size)
Returns the owner data saved with the path. This data should not be freed.
Definition: stbdpc.c:1993
Header file - Function prototypes for DVB subtitles api.
Header file - Function prototypes for heap memory.
void ASI_SetUpdateNitFunction(F_NitTableUpdate update_func)
Sets a function that will be called when an NIT table is received.
Definition: ap_si.c:10412
void STB_SIModifyPmtRequest(void *fhandle, U16BIT sid_match, U16BIT sid_mask, U16BIT table_count)
Modifies request for PMT to look for different service on SAME PID.
Definition: stbsitab.c:7844
void STB_CiCcSetSDTAcquisitionStatus(BOOLEAN complete)
To implement the first part of the diagram in "Figure 10.2: Shunning Operation" of ci-plus_specificat...
Definition: stbcicc.c:434
E_STREAM_MATCH_TYPE DBDEF_GetReqdSubtitleParams(ADB_SERVICE_REC *s_ptr, U16BIT *pid_ptr, U16BIT *cpage_ptr, U16BIT *apage_ptr)
Gets the appropriate subtitle pid and page ids - looks first for the params matching exactly the requ...
Definition: ap_dbdef.c:6472
void STB_SIReleasePatTable(SI_PAT_TABLE *pat_table)
Frees the memory used by the pat table.
Definition: stbsitab.c:11222
void ASI_EnableBatCollection(BOOLEAN use_bats, U16BIT *bouquet_ids, U16BIT num_ids)
Enables or disables the collection of BATs as part of the SI processing and allows the bouquet IDs of...
Definition: ap_si.c:10112
BOOLEAN ACI_AcquireCISlot(U8BIT path, void *s_ptr)
Acquires a CI slot for the given path on the given service after releasing any slot already being use...
Definition: ap_ci.c:1433
Application header file.
void ASI_ProcessTotTable(SI_TABLE_RECORD *table_rec)
Processes the TOT table record to extract data for the database.
Definition: ap_si.c:10457
void STB_SIReleaseCaIdDescArray(U16BIT *desc_array, U8BIT num_entries)
Frees the memory used by the descriptor array specified.
Definition: stbsitab.c:12090
ADB_TRANSPORT_REC * DBDEF_FindTransportRecByIds(ADB_TRANSPORT_REC *transp, U32BIT net_id, U32BIT onet_id, U32BIT tran_id)
Find a transport record matching the given set of IDs, starting from the given transport.
Definition: ap_dbdef.c:5314
BOOLEAN DBDEF_AllocateLcns(E_STB_DP_SIGNAL_TYPE tuner_type, BOOLEAN assign_lcns)
allocates lcns - expects allocated lcn for all services to be 0
Definition: ap_dbdef.c:7038
void * STB_SIRequestSdt(U8BIT path, E_SI_REQUEST_TYPE req_type, BOOLEAN inc_sdt_actual, BOOLEAN inc_sdt_other, U16BIT tran_id_match, U16BIT tran_id_mask, U16BIT table_count, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for SDT.
Definition: stbsitab.c:7976
void DBA_LockDatabase(void)
Locks the database to prevent access from other threads or processes.
Definition: dba_nvm.c:866
U16BIT STB_GCGetGMTDate(void)
Reads the current GMT date code.
Definition: stbgc.c:1207
void DBA_UnlockDatabase(void)
Unlocks the database to allow other threads or processes to access it.
Definition: dba_nvm.c:876
void STB_SICancelTableRequest(void *filter_ptr)
Stops filtering for SI table.
Definition: stbsiflt.c:2336
E_STREAM_MATCH_TYPE DBDEF_GetReqdTtextPid(ADB_SERVICE_REC *s_ptr, BOOLEAN for_subtitles, U16BIT *pid_ptr, U8BIT *magazine, U8BIT *page)
Gets the appropriate teletext pid - looks first for the params matching exactly the required teletext...
Definition: ap_dbdef.c:6404
void ASI_NotifyEitSchedUpdate(void *serv_ptr, U16BIT event_id, E_APP_SI_EIT_JOURNAL_TYPE type)
Calls the EIT schedule update callback function, if one has been registered, with details of the serv...
Definition: ap_si.c:10572
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
void ASI_SetActiveNetworkId(U16BIT network_id)
Sets the network ID to be used for all future requests to get an NIT. If this value isn&#39;t set...
Definition: ap_si.c:10605
void DBA_SetRecordParent(void *record, void *parent)
Set of change the parent of the given record.
Definition: dba_nvm.c:1080
void ADB_ServiceAddRCTLink(void *serv_ptr, void *link_ptr)
Adds the given RCT link info to the end of the list of existing RCT links already defined for the giv...
Definition: ap_dbacc.c:6110
void ASI_ProcessTdtTable(SI_TABLE_RECORD *table_rec)
Processes the TDT table record to extract data for the database.
Definition: ap_si.c:10521
BOOLEAN ASI_CheckForServiceChange(E_STB_DP_SIGNAL_TYPE tuner_type)
Checks whether the NIT or SDT version numbers have changed, which may indicate a change to the servic...
Definition: ap_si.c:9765
Definition: ap_si.c:226
Definition: stbsitab.h:799
U8BIT STB_DPGetPathDemux(U8BIT path)
Returns the demux path ID acquired by the given decode path.
Definition: stbdpc.c:1711
U16BIT DBDEF_NumStreamsInList(ADB_STREAM_REC *slist)
Returns the number of stream records in the given list.
Definition: ap_dbdef.c:1860
void * ACTL_GetCurrentSatellite(U8BIT path)
Returns the current satellite being used by the given decode path.
Definition: ap_cntrl.c:1071
void DBDEF_DeleteAltServList(ADB_ALT_SERV_REC *aslist)
Deletes all records in a service alternate service list.
Definition: ap_dbdef.c:3797
Definition: ap_si.c:199
Application database access functions.
void STB_SIReleaseNitTable(SI_NIT_TABLE *nit_table)
Frees the memory used by the nit table.
Definition: stbsitab.c:11299
void ASI_ProcessEitTable(SI_TABLE_RECORD *table_rec, BOOLEAN playback)
Processes an EIT table, partial or full, and updates the events of the service it is for...
Definition: ap_si.c:10446
F_AppSiEventHandler STB_SIRegisterAppSiEventHandler(F_AppSiEventHandler func_ptr)
Registers a function to be called to handle SI events. The currently registered event handler is retu...
E_STB_TUNE_TMODE STB_TuneGetActualTerrMode(U8BIT path)
Returns the actual mode of the current terrestrial signal.
ADB_NETWORK_REC * DBDEF_GetNextNetworkRec(ADB_NETWORK_REC *n_ptr)
Returns the network following the one given. If the argument is NULL then the first network will be r...
Definition: ap_dbdef.c:4800
BOOLEAN ASI_SSURefused(void)
Returns the flag indicating whether the SSU was refused.
Definition: ap_si.c:9721
void * STB_SIRequestTot(U8BIT path, E_SI_REQUEST_TYPE req_type, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Generates request for TOT.
Definition: stbsitab.c:8475
void ADB_SetTunedTransport(U8BIT path, void *t_ptr)
Sets the given transport as the one tuned to on the given decode path. The transport&#39;s network is als...
Definition: ap_dbacc.c:2988
Header file - macros and function prototypes for public use.
Header file - Function prototypes for tuner control.
Definition: ap_si.c:191
void DBDEF_SortServicesByLcn(void)
Sort the full service list into ascending logical channel number order.
Definition: ap_dbdef.c:7017
void ASI_AllowDatabaseUpdates(E_STB_DP_SIGNAL_TYPE signal_type, BOOLEAN allow)
Sets whether updates should be allowed to the service database from standard SI tables that are recei...
Definition: ap_si.c:10628