DVBCore  20.3.0
DVBCore Documentation
stbsiflt.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  *******************************************************************************/
25 // gives direct COM port access
26 /* #define STB_DEBUG */
27 
28 // prints filter use
29 /* #define DEBUG_SI_FILTER */
30 /* #define DEBUG_SI_FILTER_FAILURES */
31 /* #define DEBUG_SI_FILTER_INT */
32 /* #define DEBUG_FILTER_PERFORMANCE */
33 
34 // prints table requests
35 /* #define DEBUG_TABLE_REQUESTS */
36 
37 /* #define DEBUG_PMT_REPORTING */
38 /* #define DEBUG_CAT_REPORTING */
39 
40 //---includes for this file----------------------------------------------------
41 // compiler library header files
42 
43 #include <stdio.h>
44 #include <string.h>
45 
46 // third party header files
47 
48 // Ocean Blue Software header files
49 
50 #include <techtype.h>
51 #include <dbgfuncs.h>
52 
53 #include "stberc.h"
54 #include "stbhwdmx.h"
55 #include "stbhwos.h"
56 #include "stbllist.h"
57 #include "stbheap.h"
58 //#include "stbresmgr.h"
59 #include "stbdpc.h"
60 
61 #include "stbsic.h"
62 #include "stbsiflt.h"
63 #include "stbsipmt.h"
64 #include "ca_glue.h"
65 
66 
67 //---constant definitions for this file----------------------------------------
68 #ifdef STB_SI_PRINT_REQUIRED
69  #define STB_SI_PRINT(x) DEBUG_PRINTX_CONDITIONAL(DEBUG_STB_SI) x
70 #else
71  #ifdef STB_DEBUG
72  #define STB_SI_PRINT(x) STB_SPDebugWrite x
73  #else
74  #define STB_SI_PRINT(x)
75  #endif
76 #endif
77 
78 #define STB_SI_ERROR(x)
79 
80 #define MAX_ENTRIES_FILT_TASK_QUEUE 100
81 #define MAX_ENTRIES_CNTRL_TASK_QUEUE 50
82 #define MAX_ENTRIES_LOW_PRI_TASK_QUEUE 100
83 
84 #define FILT_TASK_PRIORITY 13 // 1 higher than UI
85 #define CNTRL_TASK_PRIORITY 11 // 1 lower than UI
86 #define LOW_PRI_TASK_PRIORITY 10 // 1 lower than cntrl task
87 
88 #define FILT_TASK_STACK_SIZE 4096
89 #define CNTRL_TASK_STACK_SIZE 4096
90 #define LOW_PRI_TASK_STACK_SIZE 4096
91 
92 
93 // other stuff
94 #define SECT_FILTER_MASK_SIZE 8
95 #define NUM_SECT_RECEIVED_BYTES (256 / 8)
96 
97 #define NUM_PMT_OBSERVERS 4
98 
99 
100 //---local typedef structs for this file---------------------------------------
101 
102 // message queue structures
103 
104 // filter structures, enums etc
105 typedef struct table_list_entry
106 {
107  struct table_list_entry *next;
108  U8BIT tid;
109  U16BIT xtid;
110  U8BIT version;
111  U16BIT num_sect_reqd;
112  U16BIT num_sect_received;
113  U8BIT sect_received[NUM_SECT_RECEIVED_BYTES];
114  U8BIT ev_sched_sect_reqd[NUM_SECT_RECEIVED_BYTES];
115  BOOLEAN complete;
116  BOOLEAN new_table;
117  U8BIT atre_count;
118  SI_SECTION_RECORD *section_list;
119  SI_SECTION_RECORD *segment_list[NUM_SECT_RECEIVED_BYTES];
120  BOOLEAN ev_sched_segment_notified[NUM_SECT_RECEIVED_BYTES];
121  enum {VALID, DELETED} state;
123 
124 typedef struct filter_status
125 {
126  struct filter_status *next;
127  U32BIT id;
128  U8BIT path;
129  BOOLEAN low_priority;
130  BOOLEAN crc;
131  E_SI_TABLE_FORMAT_TYPE table_format;
132  E_SI_REQUEST_TYPE req_type;
133  void (*return_fn)(void *, U32BIT, SI_TABLE_RECORD *);
134  U32BIT return_param;
135  U16BIT pid;
136  U16BIT pfid;
137  U16BIT mfid;
138  U8BIT match_array[SECT_FILTER_MASK_SIZE];
139  U8BIT mask_array[SECT_FILTER_MASK_SIZE];
140  U16BIT buff_len;
141  U8BIT *data_start;
142  U8BIT *data_end;
143  U16BIT num_tables_reqd;
144  U16BIT num_tables_received;
145  TABLE_LIST_ENTRY *table_list;
146  TABLE_LIST_ENTRY *last_rxed_table;
147  #ifdef DEBUG_FILTER_PERFORMANCE
148  U32BIT start_time;
149  #endif
150  BOOLEAN traversing;
151 } FILTER_STATUS;
152 
153 typedef struct cntrl_task_msg
154 {
155  U8BIT path;
156  enum {SI_EVENT, TABLE_READY, SECTION_RECEIVED, SEGMENT_READY} type;
157  FILTER_STATUS *flt_ptr;
158  TABLE_LIST_ENTRY *tbl_entry;
159  SI_SECTION_RECORD *sec_rec;
160  U32BIT numval;
162 
163 //---local (static) variable declarations for this file------------------------
164 // (internal variables declared static to make them local)
165 
166 static void *cntrl_task_ptr;
167 static void *low_pri_task_ptr;
168 static void *filt_task_ptr;
169 
170 static void *cntrl_task_msg_queue;
171 static void *low_pri_task_msg_queue;
172 static void *filt_task_msg_queue;
173 
174 static void *table_mutex;
175 static void *section_sema;
176 static void *filter_mutex;
177 
178 // status variable
179 static U8BIT num_paths;
180 static E_STB_SI_STATUS *si_status;
181 static BOOLEAN cntrl_task_stop_pending;
182 static BOOLEAN low_pri_task_stop_pending;
183 
184 // linked list of filters
185 static FILTER_STATUS *filter_list;
186 
187 // pointer to application si interface
188 static void (*app_si_interface_ptr)(U8BIT, E_APP_SI_EVENT_TYPE);
189 
190 // function to be called to pass pmt to mheg interface
191 static F_PmtObserver pmt_observers[NUM_PMT_OBSERVERS] = {0, 0, 0, 0};
192 
193 //---local function prototypes for this file-----------------------------------
194 // (internal functions declared static to make them local)
195 
196 static void SiControlTask(void *notused);
197 static void SiFilterTask(void *notused);
198 static void SiLowPriTableTask(void *notused);
199 
200 static FILTER_STATUS* GetFilter(U8BIT path, U16BIT pid, U8BIT tid_match, U8BIT tid_mask,
201  E_SI_TABLE_FORMAT_TYPE format, U16BIT expected_tables,
202  U16BIT xtid_match, U16BIT xtid_mask, E_SI_REQUEST_TYPE req_type,
203  U16BIT buff_size, BOOLEAN crc, BOOLEAN low_priority,
204  void (*ret_fn)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param);
205 static void StartFilter(FILTER_STATUS *filter_ptr);
206 static void StopFilter(FILTER_STATUS *filter_ptr);
207 static void ModifyFilter(FILTER_STATUS *filter_ptr, U8BIT tid_match, U8BIT tid_mask,
208  U16BIT xtid_match, U16BIT xtid_mask, U16BIT expected_tables);
209 static void ReleaseFilter(FILTER_STATUS *filter_ptr);
210 static BOOLEAN ValidateFilterPtr(FILTER_STATUS *filter_ptr);
211 
212 static void HandleSiInterrupt(U8BIT path, U16BIT bytes, U16BIT pfid);
213 
214 static void ActionTableReadyEvent(FILTER_STATUS *filter_ptr, BOOLEAN *stop_flag_ptr);
215 static void ActionSectionReceivedEvent(FILTER_STATUS *filter_ptr, TABLE_LIST_ENTRY *table_entry,
216  SI_SECTION_RECORD *section_rec, BOOLEAN *stop_flag_ptr);
217 static void ActionSegmentReadyEvent(FILTER_STATUS *filter_ptr, TABLE_LIST_ENTRY *table_entry,
218  U32BIT sect_num, BOOLEAN *stop_flag_ptr);
219 
220 static TABLE_LIST_ENTRY* AddTableListEntry(FILTER_STATUS *filter_ptr, U8BIT tid, U16BIT xtid,
221  U8BIT ver, U16BIT num_sect);
222 static void ResetTableListEntry(TABLE_LIST_ENTRY *table_entry, U8BIT ver, U16BIT last_sect);
223 static TABLE_LIST_ENTRY* FindTableListEntry(FILTER_STATUS *filter_ptr, U8BIT tid, U16BIT xtid);
224 static void FreeTableList(FILTER_STATUS *filter_ptr);
225 static void ProcessTableEntries(FILTER_STATUS *filter_ptr);
226 static SI_SECTION_RECORD* AddSectionRecord(TABLE_LIST_ENTRY *table_entry, U8BIT sect_num, U16BIT data_len,
227  U8BIT *data_ptr, BOOLEAN add_to_table, BOOLEAN add_to_segment_list);
228 static void FreeSectionList(TABLE_LIST_ENTRY *table_entry);
229 
230 
231 
232 //--- structures, variables etc associated with the control of private data-------------------------
233 
234 
235 
236 //---local function definitions------------------------------------------------
237 
249 static void SiControlTask(void *notused)
250 {
251  CNTRL_TASK_MSG msg;
252  BOOLEAN msg_ready;
253  FILTER_STATUS *filter_ptr;
254 
255  FUNCTION_START(SiControlTask);
256 
257  // fool compiler into thinking these parameters are used - stops unnecessary warning
258  USE_UNWANTED_PARAM(notused);
259 
260  while (1)
261  {
262  // Waits for an event to be reported, or the next 100 ms to elapse
263  msg_ready = STB_OSReadQueue(cntrl_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), 100);
264  if (msg_ready == TRUE)
265  {
266  if ((cntrl_task_stop_pending == TRUE) &&
267  ((msg.type != SI_EVENT) || (msg.numval != SI_EVENT_STOP)))
268  {
269  // ignore all events other than stop when stop event is pending
270  STB_SI_PRINT(("SICtask - s.e.p. ignore"));
271  }
272  else
273  {
274  if (msg.type == SI_EVENT)
275  {
276  // message is SI event - maintain status and pass event to application
277  switch (msg.numval)
278  {
279  case SI_EVENT_STOP:
280  {
281  STB_SI_PRINT(("SITask(%d) stop", msg.path));
282  if (app_si_interface_ptr != NULL)
283  {
284  (app_si_interface_ptr)(msg.path, STOP_SI);
285  }
286  si_status[msg.path] = SI_STOPPED;
287  cntrl_task_stop_pending = FALSE;
288 
289  // wait for low priority task to get its stop event...
290  STB_SI_PRINT(("SITask(%d) wait for low priority stop", msg.path));
291  while (low_pri_task_stop_pending == TRUE)
292  {
293  STB_OSTaskDelay(10);
294  }
295  STB_SI_PRINT(("SITask(%d) finished waiting for low priority stop", msg.path));
296  }
297  break;
298 
299  case SI_EVENT_SEARCH:
300  {
301  STB_SI_PRINT(("SITask(%d) starting search - %dMHz",
302  msg.path, STB_DPGetFrequency(msg.path)));
303  if (app_si_interface_ptr != NULL)
304  {
305  (app_si_interface_ptr)(msg.path, START_SI_SEARCHING);
306  }
307  si_status[msg.path] = SI_SEARCHING;
308  }
309  break;
310 
311  case SI_EVENT_UPDATE:
312  {
313  STB_SI_PRINT(("SITask(%d) starting update - %dMHz",
314  msg.path, STB_DPGetFrequency(msg.path)));
315  if (app_si_interface_ptr != NULL)
316  {
317  (app_si_interface_ptr)(msg.path, START_SI_UPDATING_NEW_TRANSPORT);
318  }
319  si_status[msg.path] = SI_UPDATING;
320  }
321  break;
322 
323  case SI_EVENT_SERVICE_CHANGE:
324  {
325  STB_SI_PRINT(("SITask(%d) channel change", msg.path));
326  if (app_si_interface_ptr != NULL)
327  {
328  (app_si_interface_ptr)(msg.path, START_SI_UPDATING_SAME_TRANSPORT);
329  }
330  }
331  break;
332  }
333  }
334  else if (msg.type == TABLE_READY)
335  {
336  // TABLE READY event - msg.flt_ptr is a filter_ptr
337  filter_ptr = msg.flt_ptr;
338  #ifdef DEBUG_SI_FILTER
339  STB_SI_PRINT(("SITask(%d) table ready filter %p", msg.path, filter_ptr));
340  #endif
341  ActionTableReadyEvent(filter_ptr, &cntrl_task_stop_pending);
342  }
343  else if (msg.type == SECTION_RECEIVED)
344  {
345  /* Section received event */
346  filter_ptr = msg.flt_ptr;
347  #ifdef DEBUG_SI_FILTER
348  STB_SI_PRINT(("SITask(%d) section received filter %p", msg.path, filter_ptr));
349  #endif
350  ActionSectionReceivedEvent(filter_ptr, msg.tbl_entry,
351  msg.sec_rec, &cntrl_task_stop_pending);
352  }
353  else if (msg.type == SEGMENT_READY)
354  {
355  // TABLE READY event - msg.flt_ptr is a filter_ptr
356  filter_ptr = msg.flt_ptr;
357  #ifdef DEBUG_SI_FILTER
358  STB_SI_PRINT(("SITask(%d) segment ready filter %p", msg.path, filter_ptr));
359  #endif
360  ActionSegmentReadyEvent(filter_ptr, msg.tbl_entry, msg.numval,
361  &cntrl_task_stop_pending);
362  }
363  }
364  }
365  else
366  {
367  // timeout - report it to the application
368  if (app_si_interface_ptr != NULL)
369  {
370  (app_si_interface_ptr)(INVALID_RES_ID, SI_TIMEOUT);
371  }
372  }
373  }
374 
375  FUNCTION_FINISH(SiControlTask);
376 }
377 
389 static void SiLowPriTableTask(void *notused)
390 {
391  CNTRL_TASK_MSG msg;
392  BOOLEAN msg_ready;
393  FILTER_STATUS *filter_ptr;
394 
395  FUNCTION_START(SiLowPriTableTask);
396 
397  // fool compiler into thinking these parameters are used - stops unnecessary warning
398  USE_UNWANTED_PARAM(notused);
399  while (1)
400  {
401  // Waits for an event to be reported
402  msg_ready = STB_OSReadQueue(low_pri_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG),
403  TIMEOUT_NEVER);
404  if (msg_ready == TRUE)
405  {
406  if ((low_pri_task_stop_pending == TRUE) &&
407  ((msg.type != SI_EVENT) || (msg.numval != SI_EVENT_STOP)))
408  {
409  // ignore all events other than stop when stop event is pending
410  STB_SI_PRINT(("SI Low Pri task - s.e.p. ignore"));
411  }
412  else
413  {
414  if ((msg.type == SI_EVENT) && (msg.numval == SI_EVENT_STOP))
415  {
416  STB_SI_PRINT(("SI low pri task(%d) stop", msg.path));
417  low_pri_task_stop_pending = FALSE;
418  }
419  else if (msg.type == TABLE_READY)
420  {
421  // TABLE READY event - msg.flt_ptr is a filter_ptr
422  filter_ptr = msg.flt_ptr;
423  #ifdef DEBUG_SI_FILTER
424  STB_SI_PRINT(("SI low priority(%d) table ready filter %p", msg.path, filter_ptr));
425  #endif
426  ActionTableReadyEvent(filter_ptr, &low_pri_task_stop_pending);
427  }
428  else if (msg.type == SECTION_RECEIVED)
429  {
430  // TABLE READY event - msg.flt_ptr is a filter_ptr
431  filter_ptr = msg.flt_ptr;
432  #ifdef DEBUG_SI_FILTER
433  STB_SI_PRINT(("SI low priority(%d) section received filter %p", msg.path, filter_ptr));
434  #endif
435  ActionSectionReceivedEvent(filter_ptr, msg.tbl_entry,
436  msg.sec_rec, &low_pri_task_stop_pending);
437  }
438  else if (msg.type == SEGMENT_READY)
439  {
440  // TABLE READY event - msg.flt_ptr is a filter_ptr
441  filter_ptr = msg.flt_ptr;
442  #ifdef DEBUG_SI_FILTER
443  STB_SI_PRINT(("SI low priority(%d) segment ready filter %p", msg.path, filter_ptr));
444  #endif
445  ActionSegmentReadyEvent(filter_ptr, msg.tbl_entry, msg.numval,
446  &low_pri_task_stop_pending);
447  }
448  }
449  }
450  }
451 
452  FUNCTION_FINISH(SiLowPriTableTask);
453 }
454 
463 static void ActionSegmentReadyEvent(FILTER_STATUS *filter_ptr, TABLE_LIST_ENTRY *table_entry,
464  U32BIT sect_num, BOOLEAN *stop_flag_ptr)
465 {
466  static U8BIT actn_tbl_rdy_evt_cnt = 0;
467  SI_TABLE_RECORD *table_rec;
468  BOOLEAN filter_ok;
469  BOOLEAN filter_changed;
470  U32BIT saved_id;
471  U8BIT save_atre;
472  U8BIT segment_num;
473 
474  FUNCTION_START(ActionSegmentReadyEvent);
475 
476  STB_OSMutexLock(filter_mutex);
477 
478  filter_ok = ValidateFilterPtr(filter_ptr);
479  if (filter_ok == TRUE)
480  {
481  save_atre = actn_tbl_rdy_evt_cnt++;
482 
483  filter_ptr->traversing = TRUE;
484  filter_changed = FALSE;
485 
486  STB_OSMutexLock(table_mutex);
487 
488  if ((table_entry != NULL) && (*stop_flag_ptr == FALSE))
489  {
490  table_entry->atre_count = save_atre;
491 
492  // make a table record to pass to callback function
493  table_rec = STB_GetMemory(sizeof(SI_TABLE_RECORD));
494  if (table_rec != NULL)
495  {
496  // set up the table record
497  table_rec->path = filter_ptr->path;
498  table_rec->tid = table_entry->tid;
499  table_rec->xtid = table_entry->xtid;
500  table_rec->pid = filter_ptr->pid;
501  table_rec->version = table_entry->version;
502  table_rec->num_sect = table_entry->num_sect_received;
503 
504  // swap the section list from the table entry to the table record
505  segment_num = sect_num / 8;
506  STB_OSSemaphoreWait(section_sema);
507  table_rec->section_list = table_entry->segment_list[segment_num];
508  table_entry->segment_list[segment_num] = NULL;
509  STB_OSSemaphoreSignal(section_sema);
510 
511  // pass table record to return function - it will call STB_SIReleaseTableRec
512  // when it has finished with it
513  #ifdef DEBUG_TABLE_REQUESTS
514  STB_SI_PRINT(("report table - rec %p", table_rec));
515  #endif
516  saved_id = filter_ptr->id;
517 
518  (filter_ptr->return_fn)(filter_ptr, filter_ptr->return_param, table_rec);
519 
520  // action function may have cancelled or restarted the filter so we must check here
521  // that it is valid to continue through the table list...
522  //
523  // ...first check that the filter_ptr is still valid - if not then exit the loop
524  filter_ok = ValidateFilterPtr(filter_ptr);
525  if (filter_ok == FALSE)
526  {
527  filter_changed = TRUE;
528  }
529  else
530  {
531  // filter_ptr is still in the list but...
532  //
533  // the action function may have restarted or modified the filter (using
534  // STB_SIRestartTableRequest or STB_SIModifyTableRequest respectively) both of
535  // which would have deleted the table list which we are traversing.
536  //
537  // in addition it is possible for the action function to cancel one
538  // filter and then get another which happens to be allocated the same address in
539  // memory. In this case ValidateFilterPtr() would have correctly returned true
540  // because the same filter_ptr is in the list of filters.
541  //
542  // so, we protect against these problems by checking the filter id. The id is set
543  // each time StartFilter() is called - i.e. when a new filter is requested, or an
544  // existing filter is modified or restarted. Before the call to the action
545  // function the filter id was copied into saved_id - if it is not the same now
546  // the filter has been changed. In this case filter_ptr and/or table_entry are no
547  // longer valid.
548  if (filter_ptr->id != saved_id)
549  {
550  filter_changed = TRUE;
551  }
552  else
553  {
554  table_entry->complete = FALSE;
555  }
556  }
557  }
558  }
559 
560  if (filter_changed == FALSE)
561  {
562  filter_ptr->traversing = FALSE;
563  ProcessTableEntries(filter_ptr);
564  }
565 
566  STB_OSMutexUnlock(table_mutex);
567  }
568 
569  STB_OSMutexUnlock(filter_mutex);
570 
571  FUNCTION_FINISH(ActionSegmentReadyEvent);
572 }
573 
587 static void ActionTableReadyEvent(FILTER_STATUS *filter_ptr, BOOLEAN *stop_flag_ptr)
588 {
589  static U8BIT actn_tbl_rdy_evt_cnt = 0;
590  TABLE_LIST_ENTRY *table_entry;
591  SI_TABLE_RECORD *table_rec;
592  BOOLEAN filter_ok;
593  BOOLEAN filter_changed;
594  U32BIT saved_id;
595  U8BIT save_atre;
596 
597  FUNCTION_START(ActionTableReadyEvent);
598 
599  STB_OSMutexLock(filter_mutex);
600 
601  filter_ok = ValidateFilterPtr(filter_ptr);
602  if (filter_ok == TRUE)
603  {
604  save_atre = actn_tbl_rdy_evt_cnt++;
605  // check filter for any complete tables
606  filter_ptr->traversing = TRUE;
607  filter_changed = FALSE;
608 
609  STB_OSMutexLock(table_mutex);
610 
611  /* Find first valid table entry */
612  table_entry = filter_ptr->table_list;
613  while ((table_entry != NULL) && (table_entry->state != VALID))
614  {
615  table_entry = table_entry->next;
616  }
617 
618  while ((table_entry != NULL) && (*stop_flag_ptr == FALSE))
619  {
620  table_entry->atre_count = save_atre;
621  if (table_entry->complete == TRUE)
622  {
623  // make a table record to pass to callback function
624  table_rec = STB_GetMemory(sizeof(SI_TABLE_RECORD));
625  if (table_rec != NULL)
626  {
627  // set up the table record
628  table_rec->path = filter_ptr->path;
629  table_rec->tid = table_entry->tid;
630  table_rec->xtid = table_entry->xtid;
631  table_rec->pid = filter_ptr->pid;
632  table_rec->version = table_entry->version;
633  table_rec->num_sect = table_entry->num_sect_received;
634 
635  // swap the section list from the table entry to the table record
636  STB_OSSemaphoreWait(section_sema);
637  table_rec->section_list = table_entry->section_list;
638  table_entry->section_list = NULL;
639  STB_OSSemaphoreSignal(section_sema);
640 
641  // pass table record to return function - it will call STB_SIReleaseTableRec
642  // when it has finished with it
643  #ifdef DEBUG_TABLE_REQUESTS
644  STB_SI_PRINT(("report table - rec %p", table_rec));
645  #endif
646  saved_id = filter_ptr->id;
647 
648  (filter_ptr->return_fn)(filter_ptr, filter_ptr->return_param, table_rec);
649 
650  // action function may have cancelled or restarted the filter so we must check here
651  // that it is valid to continue through the table list...
652  //
653  // ...first check that the filter_ptr is still valid - if not then exit the loop
654  filter_ok = ValidateFilterPtr(filter_ptr);
655  if (filter_ok == FALSE)
656  {
657  filter_changed = TRUE;
658  break;
659  }
660  else
661  {
662  // filter_ptr is still in the list but...
663  //
664  // the action function may have restarted or modified the filter (using
665  // STB_SIRestartTableRequest or STB_SIModifyTableRequest respectively) both of
666  // which would have deleted the table list which we are traversing.
667  //
668  // in addition it is possible for the action function to cancel one
669  // filter and then get another which happens to be allocated the same address in
670  // memory. In this case ValidateFilterPtr() would have correctly returned true
671  // because the same filter_ptr is in the list of filters.
672  //
673  // so, we protect against these problems by checking the filter id. The id is set
674  // each time StartFilter() is called - i.e. when a new filter is requested, or an
675  // existing filter is modified or restarted. Before the call to the action
676  // function the filter id was copied into saved_id - if it is not the same now
677  // the filter has been changed. In this case filter_ptr and/or table_entry are no
678  // longer valid.
679  if (filter_ptr->id != saved_id)
680  {
681  filter_changed = TRUE;
682  break;
683  }
684  else
685  {
686  table_entry->complete = FALSE;
687  }
688  }
689  }
690  }
691  // move to next table
692  table_entry = filter_ptr->table_list;
693  while ((table_entry != NULL) &&
694  ((table_entry->state != VALID) || (table_entry->atre_count == save_atre)))
695  {
696  table_entry = table_entry->next;
697  }
698  }
699 
700  if (filter_changed == FALSE)
701  {
702  filter_ptr->traversing = FALSE;
703  ProcessTableEntries(filter_ptr);
704  }
705 
706  STB_OSMutexUnlock(table_mutex);
707  }
708 
709  STB_OSMutexUnlock(filter_mutex);
710 
711  FUNCTION_FINISH(ActionTableReadyEvent);
712 }
713 
727 static void ActionSectionReceivedEvent(FILTER_STATUS *filter_ptr, TABLE_LIST_ENTRY *table_entry,
728  SI_SECTION_RECORD *section_rec, BOOLEAN *stop_flag_ptr)
729 {
730  SI_TABLE_RECORD *table_rec;
731  BOOLEAN filter_ok;
732  BOOLEAN filter_changed;
733  U32BIT saved_id;
734 
735  FUNCTION_START(ActionSectionReceivedEvent);
736 
737  STB_OSMutexLock(filter_mutex);
738 
739  filter_ok = ValidateFilterPtr(filter_ptr);
740  if (filter_ok == TRUE)
741  {
742  // check filter for any complete tables
743  filter_ptr->traversing = TRUE;
744  filter_changed = FALSE;
745 
746  if ((table_entry != NULL) && (*stop_flag_ptr == FALSE))
747  {
748  // make a table record to pass to callback function
749  table_rec = STB_GetMemory(sizeof(SI_TABLE_RECORD));
750  if (table_rec != NULL)
751  {
752  // set up the table record
753  table_rec->path = filter_ptr->path;
754  table_rec->tid = table_entry->tid;
755  table_rec->xtid = table_entry->xtid;
756  table_rec->pid = filter_ptr->pid;
757  table_rec->version = table_entry->version;
758  table_rec->num_sect = 1;
759  table_rec->section_list = section_rec;
760 
761  // pass table record to return function - it will call STB_SIReleaseTableRec
762  // when it has finished with it
763  #ifdef DEBUG_TABLE_REQUESTS
764  STB_SI_PRINT(("report table - rec %p", table_rec));
765  #endif
766  saved_id = filter_ptr->id;
767  (filter_ptr->return_fn)(filter_ptr, filter_ptr->return_param, table_rec);
768 
769  // action function may have cancelled or restarted the filter so we must check here
770  // that it is valid to continue through the table list...
771  //
772  // ...first check that the filter_ptr is still valid - if not then exit the loop
773  filter_ok = ValidateFilterPtr(filter_ptr);
774  if (filter_ok == FALSE)
775  {
776  filter_changed = TRUE;
777  }
778  else
779  {
780  // filter_ptr is still in the list but...
781  //
782  // the action function may have restarted or modified the filter (using
783  // STB_SIRestartTableRequest or STB_SIModifyTableRequest respectively) both of
784  // which would have deleted the table list which we are traversing.
785  //
786  // in addition it is possible for the action function to cancel one
787  // filter and then get another which happens to be allocated the same address in
788  // memory. In this case ValidateFilterPtr() would have correctly returned true
789  // because the same filter_ptr is in the list of filters.
790  //
791  // so, we protect against these problems by checking the filter id. The id is set
792  // each time StartFilter() is called - i.e. when a new filter is requested, or an
793  // existing filter is modified or restarted. Before the call to the action
794  // function the filter id was copied into saved_id - if it is not the same now
795  // the filter has been changed. In this case filter_ptr and/or table_entry are no
796  // longer valid.
797  if (filter_ptr->id != saved_id)
798  {
799  filter_changed = TRUE;
800  }
801  else
802  {
803  table_entry->complete = FALSE;
804  }
805  }
806  }
807  }
808 
809  if (filter_changed == FALSE)
810  {
811  filter_ptr->traversing = FALSE;
812  ProcessTableEntries(filter_ptr);
813  }
814  }
815 
816  STB_OSMutexUnlock(filter_mutex);
817 
818  FUNCTION_FINISH(ActionSectionReceivedEvent);
819 }
820 
832 static void SiFilterTask(void *notused)
833 {
834  BOOLEAN msg_ready;
835  FILTER_STATUS *filter_ptr;
836  BOOLEAN filter_ok;
837  U8BIT *data_ptr;
838  U16BIT sect_len;
839  U8BIT tid;
840  U16BIT xtid;
841  U8BIT version;
842  U8BIT sect;
843  TABLE_LIST_ENTRY *table_entry;
844  BOOLEAN sect_reqd;
845  SI_SECTION_RECORD *section_rec;
846  BOOLEAN finished;
847  BOOLEAN table_ready;
848  U16BIT last_sect;
849  CNTRL_TASK_MSG msg;
850  BOOLEAN all_sect_recvd;
851  BOOLEAN use_data;
852  U16BIT i;
853 
854  FUNCTION_START(SiFilterTask);
855 
856  // fool compiler into thinking these parameters are used - stops unnecessary warning
857  USE_UNWANTED_PARAM(notused);
858 
859  while (1)
860  {
861  // Waits for a section received to be reported
862  msg_ready = STB_OSReadQueue(filt_task_msg_queue, (void *)&filter_ptr, sizeof(FILTER_STATUS *),
863  TIMEOUT_NEVER);
864  if (msg_ready == TRUE)
865  {
866  STB_OSMutexLock(filter_mutex);
867 
868  filter_ok = ValidateFilterPtr(filter_ptr);
869  if (filter_ok == FALSE)
870  {
871  #ifdef DEBUG_SI_FILTER
872  STB_SI_PRINT(("ActionSectRxed: filter %p - invalid filter", filter_ptr));
873  #endif
874  }
875  else
876  {
877  table_ready = FALSE;
878 
879  // process all the sections in the buffer at the moment if any
880  finished = FALSE;
881  data_ptr = filter_ptr->data_start;
882  while ((data_ptr < filter_ptr->data_end) && (finished == FALSE))
883  {
884  use_data = TRUE;
885 
886  tid = data_ptr[0];
887  sect_len = (((data_ptr[1] & 0x0f) << 8) | data_ptr[2]) + 3;
888 
889  // section number is only relevant for multi-section formats
890  if (filter_ptr->table_format == MULTI_SECT)
891  {
892  // first check if it is a current section - only accept currents
893  if ((data_ptr[5] & 0x01) == 0)
894  {
895  // not a current table
896  use_data = FALSE;
897 #ifdef DEBUG_SI_FILTER_INT
898  STB_SI_PRINT(("SiFilterTask: Section isn't for a current table"));
899 #endif
900  }
901  else
902  {
903  // find the xtid, version and section number from the data
904  xtid = (data_ptr[3] << 8) | data_ptr[4];
905  version = (data_ptr[5] >> 1) & 0x1f;
906  sect = data_ptr[6];
907 
908  STB_OSMutexLock(table_mutex);
909 
910  table_entry = FindTableListEntry(filter_ptr, tid, xtid);
911  if (table_entry != NULL)
912  {
913  if ((filter_ptr->req_type == ONE_SHOT_REQUEST) && (table_entry->complete == TRUE))
914  {
915  // if this is a one shot filter and the table is already complete then we
916  // don't need this section even if it is a new version. The filter might
917  // still be running because there are other tables expected
918  use_data = FALSE;
919 #ifdef DEBUG_SI_FILTER_INT
920  STB_SI_PRINT(("SiFilterTask: Section is for an already complete table"));
921 #endif
922  }
923  else
924  {
925  if (table_entry->version == version)
926  {
927  if (((table_entry->sect_received[sect >> 3] >> (sect & 0x07)) & 0x01) != 0)
928  {
929  // already got it - return false
930  use_data = FALSE;
931 #ifdef DEBUG_SI_FILTER_INT
932  STB_SI_PRINT(("SiFilterTask: Section has already been received"));
933 #endif
934  }
935  }
936  }
937  }
938 
939  STB_OSMutexUnlock(table_mutex);
940  }
941  }
942 
943  if (use_data == TRUE)
944  {
945  #ifdef DEBUG_SI_FILTER
946  STB_SI_PRINT(("ActionSectRxed: filter %p dptr %p (data %p to %p)", filter_ptr,
947  data_ptr, filter_ptr->data_start, filter_ptr->data_end));
948  #endif
949  if (filter_ptr->table_format == SINGLE_SECT)
950  {
951  xtid = 0;
952  version = 0;
953  sect = 0;
954  last_sect = 0;
955  #ifdef DEBUG_SI_FILTER
956  STB_SI_PRINT(("single-sect format: len %d tab 0x%02x", sect_len, tid));
957  #endif
958  }
959  else
960  {
961  // it is a multi section format...
962  // find the xtid, version and section number from the data
963  xtid = (data_ptr[3] << 8) | data_ptr[4];
964  version = (data_ptr[5] >> 1) & 0x1f;
965  sect = data_ptr[6];
966  last_sect = data_ptr[7];
967 
968  #ifdef DEBUG_SI_FILTER
969  STB_SI_PRINT(("multi-sect format: len %d tab 0x%02x/0x%04x ver %d sect %d",
970  sect_len, tid, xtid, version, sect));
971  #endif
972  }
973 
974  sect_reqd = FALSE;
975 
976  STB_OSMutexLock(table_mutex);
977 
978  table_entry = FindTableListEntry(filter_ptr, tid, xtid);
979  if (table_entry == NULL)
980  {
981  table_entry = AddTableListEntry(filter_ptr, tid, xtid, version, last_sect);
982  if (table_entry != NULL)
983  {
984  sect_reqd = TRUE;
985  }
986  }
987  else
988  {
989  // update last_rxed_table
990  filter_ptr->last_rxed_table = table_entry;
991 
992  // if the table is not complete check if this section is required
993  if (table_entry->complete == FALSE)
994  {
995  if (filter_ptr->table_format == SINGLE_SECT)
996  {
997  // single section format
998  sect_reqd = TRUE;
999  }
1000  else
1001  {
1002  // multi-section format - check for version change
1003  if (table_entry->version != version)
1004  {
1005  #ifdef DEBUG_SI_FILTER
1006  STB_SI_PRINT(("Free existing table for new version"));
1007  #endif
1008  // free any existing sections because they are out of date
1009  ResetTableListEntry(table_entry, version, last_sect);
1010  sect_reqd = TRUE;
1011  }
1012  else
1013  {
1014  // same version - have we already got this section
1015  if (((table_entry->sect_received[sect >> 3] >> (sect & 0x07)) & 0x01) == 0)
1016  {
1017  // not got the section - add it
1018  sect_reqd = TRUE;
1019  }
1020  }
1021  }
1022  }
1023  }
1024 
1025  STB_OSMutexUnlock(table_mutex);
1026 
1027  if (sect_reqd == TRUE)
1028  {
1029  all_sect_recvd = FALSE;
1030 
1031 #ifndef EIT_REPORT_SEGMENTS
1032  /* Pass each section from an EIT table to the app as it arrives */
1033  if ((0x50 <= tid) && (tid <= 0x6f))
1034  {
1035  // add the section - copy the whole section data incl header and crc
1036  section_rec = AddSectionRecord(table_entry, sect, sect_len, data_ptr, FALSE, FALSE);
1037  if (section_rec != NULL)
1038  {
1039  msg.path = filter_ptr->path;
1040  msg.type = SECTION_RECEIVED;
1041  msg.flt_ptr = filter_ptr;
1042  msg.tbl_entry = table_entry;
1043  msg.sec_rec = section_rec;
1044  if (filter_ptr->low_priority == TRUE)
1045  {
1046  /* Allow writes to this queue to timeout to avoid lockups */
1047  if (STB_OSWriteQueue(low_pri_task_msg_queue, (void *)&msg,
1048  sizeof(CNTRL_TASK_MSG), TIMEOUT_NOW) == FALSE)
1049  {
1050  /* Mark the section as not received, and try to notify it later */
1051  table_entry->sect_received[sect >> 3] &= ~(1 << (sect & 0x07));
1052 
1053  /* section_rec pointer hasn't been added to the list in table_entry
1054  * (AddSectionRecord called with FALSE), so we only need to free it */
1055  STB_FreeMemory(section_rec);
1056  }
1057  }
1058  else
1059  {
1060  STB_OSWriteQueue(cntrl_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), TIMEOUT_NEVER);
1061  }
1062  }
1063  }
1064  else
1065 #endif
1066  {
1067  /* Check if table is complete */
1068  if ((0x50 <= tid) && (tid <= 0x6f))
1069  {
1070  /* Add the section - copy the whole section data incl header and crc */
1071  section_rec = AddSectionRecord(table_entry, sect, sect_len, data_ptr, TRUE, TRUE);
1072  if (section_rec != NULL)
1073  {
1074  /* Check if all sections received for this segment */
1075  for (i = 0; i < NUM_SECT_RECEIVED_BYTES; i++)
1076  {
1077  if (!table_entry->ev_sched_segment_notified[i] &&
1078  (table_entry->ev_sched_sect_reqd[i] == table_entry->sect_received[i]))
1079  {
1080  /* All sections for this segment have been received and it
1081  * hasn't yet been notified */
1082  msg.path = filter_ptr->path;
1083  msg.type = SEGMENT_READY;
1084  msg.flt_ptr = filter_ptr;
1085  msg.tbl_entry = table_entry;
1086  msg.numval = sect;
1087  if (filter_ptr->low_priority)
1088  {
1089  if (STB_OSWriteQueue(low_pri_task_msg_queue, (void *)&msg,
1090  sizeof(CNTRL_TASK_MSG), TIMEOUT_NOW))
1091  {
1092  table_entry->ev_sched_segment_notified[i] = TRUE;
1093  }
1094  }
1095  else
1096  {
1097  STB_OSWriteQueue(cntrl_task_msg_queue, (void *)&msg,
1098  sizeof(CNTRL_TASK_MSG), TIMEOUT_NEVER);
1099 
1100  table_entry->ev_sched_segment_notified[i] = TRUE;
1101  }
1102  }
1103  }
1104  }
1105  }
1106  else
1107  {
1108  /* Add the section - copy the whole section data incl header and crc */
1109  section_rec = AddSectionRecord(table_entry, sect, sect_len, data_ptr, TRUE, FALSE);
1110  if (section_rec != NULL)
1111  {
1112  /* For non-event schedule tables check if all sections arrived */
1113  all_sect_recvd = (table_entry->num_sect_received >= table_entry->num_sect_reqd);
1114  }
1115  }
1116  }
1117 
1118  // for non-event schedule tables check if all sections arrived
1119  if (all_sect_recvd == TRUE)
1120  {
1121  // mark table record complete
1122  #ifdef DEBUG_SI_FILTER
1123  STB_SI_PRINT(("Table complete"));
1124  #endif
1125  #ifdef DEBUG_FILTER_PERFORMANCE
1126  STB_SI_PRINT(("SI filter %p table complete @ %dms", filter_ptr, STB_OSGetClockDiff(filter_ptr->start_time)));
1127  #endif
1128  table_entry->complete = TRUE;
1129  table_ready = TRUE;
1130  if (table_entry->new_table == TRUE)
1131  {
1132  filter_ptr->num_tables_received++;
1133  table_entry->new_table = FALSE;
1134  }
1135 
1136  // check if filter is done
1137  if (filter_ptr->req_type == ONE_SHOT_REQUEST)
1138  {
1139  // this is a one-shot filter - if all tables have arrived then stop the filter
1140  if (filter_ptr->num_tables_received >= filter_ptr->num_tables_reqd)
1141  {
1142  StopFilter(filter_ptr);
1143  finished = TRUE;
1144  }
1145  }
1146  }
1147  }
1148  }
1149 
1150  // move data_ptr past this section
1151  data_ptr += sect_len;
1152  }
1153 
1154  // done all relevant sections in the buffer - reset the buffer pointer to the start
1155  filter_ptr->data_end = filter_ptr->data_start;
1156 
1157  // if a table is ready (could be more than one table) send a message to the control task
1158  if (table_ready)
1159  {
1160  msg.path = filter_ptr->path;
1161  msg.type = TABLE_READY;
1162  msg.flt_ptr = filter_ptr;
1163  if (filter_ptr->low_priority == TRUE)
1164  {
1165  /* Allow writes to this queue to timeout to avoid lockups */
1166  STB_OSWriteQueue(low_pri_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), TIMEOUT_NOW);
1167  }
1168  else
1169  {
1170  STB_OSWriteQueue(cntrl_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), TIMEOUT_NEVER);
1171  }
1172  }
1173  }
1174 
1175  STB_OSMutexUnlock(filter_mutex);
1176  }
1177  }
1178  FUNCTION_FINISH(SiFilterTask);
1179 }
1180 
1198 static void HandleSiInterrupt(U8BIT demux_path, U16BIT nbytes, U16BIT pfid)
1199 {
1200  U16BIT sect_len;
1201  U16BIT free_len;
1202  BOOLEAN sect_valid;
1203  FILTER_STATUS *filter_ptr;
1204  U8BIT *data_ptr;
1205  U8BIT demux_num;
1206 
1207  STB_OSMutexLock(filter_mutex);
1208 
1209  // find si filter on which interrupt has occurred
1210  filter_ptr = filter_list;
1211  while (filter_ptr != NULL)
1212  {
1213  if ((filter_ptr->pfid == pfid) &&
1214  (STB_DPGetPathDemux(filter_ptr->path) == demux_path))
1215  {
1216  break;
1217  }
1218  filter_ptr = filter_ptr->next;
1219  }
1220 
1221  if (filter_ptr == NULL)
1222  {
1223  // filter not found - skip section to keep link driver happy
1224  STB_SI_ERROR(("HandleSiInterrupt(%u): Failed to find filter, pfid=%d!", demux_path, pfid));
1225  #ifdef DEBUG_SI_FILTER_INT
1226  STB_SI_PRINT(("Int - filt? skip"));
1227  #endif
1228  }
1229  else
1230  {
1231  // valid filter...
1232 
1233  #ifdef DEBUG_SI_FILTER_INT
1234  STB_SI_PRINT(("Int - filt %p", filter_ptr));
1235  #endif
1236 
1237  // check buffer space. We don't know how long the section is - nbytes may cover more than
1238  // one section. The best we can do is check that we have room for nbytes bytes - there may
1239  // only be one section, but if there is more than one the length of the first section will
1240  // be less than nbytes
1241  free_len = filter_ptr->buff_len - (filter_ptr->data_end - filter_ptr->data_start);
1242  if (nbytes > free_len)
1243  {
1244  // not enough room - skip the section
1245  #ifdef DEBUG_SI_FILTER_INT
1246  STB_SI_PRINT(("Int - no room skip"));
1247  #endif
1248  STB_DMXSkipPIDFilterSect(STB_DPGetPathDemux(filter_ptr->path), pfid);
1249  }
1250  else
1251  {
1252  // setup pointer to data for faster access
1253  data_ptr = filter_ptr->data_end;
1254 
1255  // copy single section
1256  demux_num = STB_DPGetPathDemux(filter_ptr->path);
1257  if (demux_num != INVALID_RES_ID)
1258  {
1259  sect_valid = STB_DMXCopyPIDFilterSect(demux_num, data_ptr, free_len, pfid);
1260  if (sect_valid == FALSE)
1261  {
1262  #ifdef DEBUG_SI_FILTER_INT
1263  STB_SI_PRINT(("Int - sect err"));
1264  #endif
1265  }
1266  else
1267  {
1268  // get section length (+3 is for table id and section length bytes
1269  sect_len = (((data_ptr[1] & 0x0f) << 8) | data_ptr[2]) + 3;
1270 
1271  // Move end pointer to end of section just received
1272  filter_ptr->data_end += sect_len;
1273 
1274  // trigger task
1275  if (!STB_OSWriteQueue(filt_task_msg_queue, (void *)&filter_ptr, sizeof(FILTER_STATUS *), TIMEOUT_NOW))
1276  {
1277  /* Failed to write to the queue */
1278  filter_ptr->data_end -= sect_len;
1279 #ifdef DEBUG_SI_FILTER_INT
1280  STB_SI_PRINT(("HandleSiInterrupt: Failed to write to the queue!"));
1281 #endif
1282  }
1283  }
1284  }
1285  }
1286  }
1287 
1288  STB_OSMutexUnlock(filter_mutex);
1289 }
1290 
1315 static FILTER_STATUS* GetFilter(U8BIT path, U16BIT pid, U8BIT tid_match, U8BIT tid_mask,
1316  E_SI_TABLE_FORMAT_TYPE format, U16BIT expected_tables,
1317  U16BIT xtid_match, U16BIT xtid_mask, E_SI_REQUEST_TYPE req_type,
1318  U16BIT buff_size, BOOLEAN crc, BOOLEAN low_priority,
1319  void (*ret_fn)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
1320 {
1321  U16BIT pfid;
1322  U16BIT mfid;
1323  U8BIT *match_ptr;
1324  U8BIT *mask_ptr;
1325  FILTER_STATUS *filter_ptr;
1326  BOOLEAN success;
1327  U8BIT demux_num;
1328 
1329  FUNCTION_START(GetFilter);
1330 
1331  success = FALSE;
1332 
1333  demux_num = STB_DPGetPathDemux(path);
1334 
1335  if (demux_num == INVALID_RES_ID)
1336  {
1337  filter_ptr = NULL;
1338  }
1339  else
1340  {
1341  // get memory for a filter and its buffer
1342  filter_ptr = (FILTER_STATUS *)STB_GetMemory(sizeof(FILTER_STATUS) + buff_size);
1343  if (filter_ptr != NULL)
1344  {
1345  // create the match/mask arrays and setup section filter...
1346  match_ptr = filter_ptr->match_array;
1347  mask_ptr = filter_ptr->mask_array;
1348  memset(match_ptr, 0, SECT_FILTER_MASK_SIZE);
1349  memset(mask_ptr, 0, SECT_FILTER_MASK_SIZE);
1350  match_ptr[0] = tid_match;
1351  mask_ptr[0] = tid_mask;
1352 
1353  if (format == MULTI_SECT)
1354  {
1355  // always look for current
1356  match_ptr[3] = 0x01;
1357  mask_ptr[3] = 0x01;
1358 
1359  // set xtid match/mask
1360  match_ptr[1] = (U8BIT)(xtid_match >> 8);
1361  match_ptr[2] = (U8BIT)(xtid_match & 0x00ff);
1362  mask_ptr[1] = (U8BIT)(xtid_mask >> 8);
1363  mask_ptr[2] = (U8BIT)(xtid_mask & 0x00ff);
1364  }
1365 
1366  pfid = STB_DMXGrabPIDFilter(demux_num, pid, HandleSiInterrupt);
1367 
1368  if (pfid != STB_DMX_PID_FILTER_INVALID)
1369  {
1370  mfid = STB_DMXGrabSectFilter(demux_num, pfid);
1371  if (mfid == STB_DMX_SECT_FILTER_INVALID)
1372  {
1373  STB_DMXReleasePIDFilter(demux_num, pfid);
1374  }
1375  else
1376  {
1377  // setup the filter status block
1378  filter_ptr->next = NULL;
1379  filter_ptr->path = path;
1380  filter_ptr->table_format = format;
1381  filter_ptr->req_type = req_type;
1382  filter_ptr->return_fn = ret_fn;
1383  filter_ptr->return_param = ret_param;
1384  filter_ptr->pid = pid;
1385  filter_ptr->pfid = pfid;
1386  filter_ptr->mfid = mfid;
1387  filter_ptr->buff_len = buff_size;
1388  filter_ptr->data_start = ((U8BIT *)filter_ptr) + sizeof(FILTER_STATUS);
1389  filter_ptr->data_end = filter_ptr->data_start;
1390  filter_ptr->num_tables_reqd = expected_tables;
1391  filter_ptr->num_tables_received = 0;
1392  filter_ptr->table_list = NULL;
1393  filter_ptr->last_rxed_table = NULL;
1394  filter_ptr->low_priority = low_priority;
1395  filter_ptr->traversing = FALSE;
1396 
1397  filter_ptr->crc = crc;
1398  STB_DMXSetupSectFilter(demux_num, mfid, match_ptr, mask_ptr, 0, crc);
1399 
1400  // add the filter status block to the top of the linked list
1401  STB_OSMutexLock(filter_mutex);
1402  filter_ptr->next = filter_list;
1403  filter_list = filter_ptr;
1404  STB_OSMutexUnlock(filter_mutex);
1405 
1406  // indicate success
1407  success = TRUE;
1408  #ifdef DEBUG_SI_FILTER
1409  STB_SI_PRINT(("GetFilter: filter %p", filter_ptr));
1410  #endif
1411  }
1412  }
1413  }
1414  }
1415 
1416  if (success == FALSE)
1417  {
1418  if (filter_ptr != NULL)
1419  {
1420  STB_FreeMemory(filter_ptr);
1421  filter_ptr = NULL;
1422  }
1423  #ifdef DEBUG_SI_FILTER_FAILURES
1424  STB_SI_PRINT(("GetFilter: FAILED"));
1425  #endif
1426  }
1427 
1428  FUNCTION_FINISH(GetFilter);
1429  return(filter_ptr);
1430 }
1431 
1448 static void ModifyFilter(FILTER_STATUS *filter_ptr, U8BIT tid_match, U8BIT tid_mask,
1449  U16BIT xtid_match, U16BIT xtid_mask, U16BIT expected_tables)
1450 {
1451  U8BIT *match_ptr;
1452  U8BIT *mask_ptr;
1453 
1454  FUNCTION_START(ModifyFilter);
1455 
1456  #ifdef DEBUG_SI_FILTER
1457  STB_SI_PRINT(("ModifyFilter: filter %p", filter_ptr));
1458  #endif
1459 
1460  filter_ptr->data_start = ((U8BIT *)filter_ptr) + sizeof(FILTER_STATUS);
1461  filter_ptr->data_end = filter_ptr->data_start;
1462  filter_ptr->num_tables_reqd = expected_tables;
1463  filter_ptr->num_tables_received = 0;
1464 
1465  // create the match/mask arrays and setup section filter...
1466  match_ptr = filter_ptr->match_array;
1467  mask_ptr = filter_ptr->mask_array;
1468  memset(match_ptr, 0, SECT_FILTER_MASK_SIZE);
1469  memset(mask_ptr, 0, SECT_FILTER_MASK_SIZE);
1470  match_ptr[0] = tid_match;
1471  mask_ptr[0] = tid_mask;
1472 
1473  if (filter_ptr->table_format == MULTI_SECT)
1474  {
1475  // always look for current
1476  match_ptr[3] = 0x01;
1477  mask_ptr[3] = 0x01;
1478 
1479  // set xtid match/mask
1480  match_ptr[1] = (U8BIT)(xtid_match >> 8);
1481  match_ptr[2] = (U8BIT)(xtid_match & 0x00ff);
1482  mask_ptr[1] = (U8BIT)(xtid_mask >> 8);
1483  mask_ptr[2] = (U8BIT)(xtid_mask & 0x00ff);
1484  }
1485 
1486  STB_DMXSetupSectFilter(STB_DPGetPathDemux(filter_ptr->path), filter_ptr->mfid, match_ptr,
1487  mask_ptr, 0, filter_ptr->crc);
1488 
1489  FUNCTION_FINISH(ModifyFilter);
1490 }
1491 
1503 static void StartFilter(FILTER_STATUS *filter_ptr)
1504 {
1505  FUNCTION_START(StartFilter);
1506 
1507  #ifdef DEBUG_SI_FILTER
1508  STB_SI_PRINT(("StartFilter: %p", filter_ptr));
1509  #endif
1510 
1511  // initialise data pointer
1512  filter_ptr->data_end = filter_ptr->data_start;
1513 
1514  // update the id - used in control task to uniquely identify filter run
1515  filter_ptr->id = STB_OSGetClockMilliseconds();
1516 
1517  #ifdef DEBUG_FILTER_PERFORMANCE
1518  filter_ptr->start_time = STB_OSGetClockMilliseconds();
1519  #endif
1520 
1521  // start the pid filter
1522  STB_DMXStartPIDFilter(STB_DPGetPathDemux(filter_ptr->path), filter_ptr->pfid);
1523 
1524  FUNCTION_FINISH(StartFilter);
1525 }
1526 
1538 static void StopFilter(FILTER_STATUS *filter_ptr)
1539 {
1540  U8BIT demux;
1541 
1542  FUNCTION_START(StopFilter);
1543 
1544  #ifdef DEBUG_SI_FILTER
1545  STB_SI_PRINT(("StopFilter: %p", filter_ptr));
1546  #endif
1547 
1548  // stop the pid filter
1549  demux = STB_DPGetPathDemux(filter_ptr->path);
1550  if (demux != INVALID_RES_ID)
1551  {
1552  STB_DMXStopPIDFilter(demux, filter_ptr->pfid);
1553  }
1554 
1555  FUNCTION_FINISH(StopFilter);
1556 }
1557 
1569 static void ReleaseFilter(FILTER_STATUS *filter_ptr)
1570 {
1571  FILTER_STATUS *temp_ptr;
1572  FILTER_STATUS **prev_ptr;
1573  U8BIT demux_num;
1574 
1575  FUNCTION_START(ReleaseFilter);
1576 
1577  // find filter in linked list
1578  temp_ptr = filter_list;
1579  prev_ptr = &filter_list;
1580  while (temp_ptr != NULL)
1581  {
1582  if (temp_ptr == filter_ptr)
1583  {
1584  #ifdef DEBUG_SI_FILTER
1585  STB_SI_PRINT(("ReleaseFilter: %p", filter_ptr));
1586  #endif
1587 
1588  // found it - remove it from the linked list
1589  *prev_ptr = filter_ptr->next;
1590 
1591  // free pid and section filters
1592  demux_num = STB_DPGetPathDemux(filter_ptr->path);
1593  if (demux_num != INVALID_RES_ID)
1594  {
1595  STB_DMXReleaseSectFilter(demux_num, filter_ptr->mfid);
1596  STB_DMXReleasePIDFilter(demux_num, filter_ptr->pfid);
1597  }
1598 
1599  // free any memory used in table records.
1600  FreeTableList(filter_ptr);
1601  ProcessTableEntries(filter_ptr);
1602 
1603  // free the filter status block itself
1604  STB_FreeMemory((void *)filter_ptr);
1605  break;
1606  }
1607  prev_ptr = &temp_ptr->next;
1608  temp_ptr = temp_ptr->next;
1609  }
1610 
1611  FUNCTION_FINISH(ReleaseFilter);
1612 }
1613 
1625 static BOOLEAN ValidateFilterPtr(FILTER_STATUS *filter_ptr)
1626 {
1627  FILTER_STATUS *temp_ptr;
1628  BOOLEAN ret_val;
1629 
1630  FUNCTION_START(ValidateFilterPtr);
1631 
1632  ret_val = FALSE;
1633 
1634  // find filter in linked list
1635  temp_ptr = filter_list;
1636  while (temp_ptr != NULL)
1637  {
1638  if (temp_ptr == filter_ptr)
1639  {
1640  ret_val = TRUE;
1641  break;
1642  }
1643  temp_ptr = temp_ptr->next;
1644  }
1645 
1646  FUNCTION_FINISH(ValidateFilterPtr);
1647  return(ret_val);
1648 }
1649 
1665 static TABLE_LIST_ENTRY* AddTableListEntry(FILTER_STATUS *filter_ptr, U8BIT tid, U16BIT xtid, U8BIT ver, U16BIT last_sect)
1666 {
1667  TABLE_LIST_ENTRY *table_entry;
1668  U16BIT i;
1669  U8BIT last_sect_byte;
1670 
1671  FUNCTION_START(AddTableListEntry);
1672 
1673  ASSERT(filter_ptr != NULL);
1674 
1675  table_entry = STB_GetMemory(sizeof(TABLE_LIST_ENTRY));
1676  if (table_entry != NULL)
1677  {
1678  #ifdef DEBUG_SI_FILTER
1679  STB_SI_PRINT(("AddTableRec: tab 0x%02x/0x%04x v%d %d sections ", tid, xtid, ver, (last_sect + 1)));
1680  #endif
1681  memset(table_entry, 0, sizeof(TABLE_LIST_ENTRY));
1682 
1683  table_entry->new_table = TRUE;
1684  table_entry->tid = tid;
1685  table_entry->xtid = xtid;
1686  table_entry->version = ver;
1687  table_entry->num_sect_reqd = last_sect + 1;
1688  table_entry->state = VALID;
1689 
1690  // for event schedule tables setup reqd section map
1691  if ((0x50 <= tid) && (tid <= 0x6f))
1692  {
1693  last_sect_byte = last_sect >> 3;
1694  for (i = 0; i <= last_sect_byte; i++)
1695  {
1696  table_entry->ev_sched_sect_reqd[i] = 0xff;
1697  table_entry->ev_sched_segment_notified[i] = FALSE;
1698  }
1699  }
1700 
1701  // add new table after last_rxed_table in the table list, unless last_rxed_table is NULL in
1702  // which case add it to the beginning of the list
1703  if (filter_ptr->last_rxed_table == NULL)
1704  {
1705  // add to beginning of list
1706  table_entry->next = filter_ptr->table_list;
1707  filter_ptr->table_list = table_entry;
1708  }
1709  else
1710  {
1711  // add after last_rxed_table
1712  table_entry->next = filter_ptr->last_rxed_table->next;
1713  filter_ptr->last_rxed_table->next = table_entry;
1714  }
1715 
1716  // make last_rxed_table point to latest table
1717  filter_ptr->last_rxed_table = table_entry;
1718  }
1719  #ifdef DEBUG_SI_FILTER_FAILURES
1720  else
1721  {
1722  STB_SI_PRINT(("AddTableRec: FAILED"));
1723  }
1724  #endif
1725 
1726  FUNCTION_FINISH(AddTableListEntry);
1727  return(table_entry);
1728 }
1729 
1744 static void ResetTableListEntry(TABLE_LIST_ENTRY *table_entry, U8BIT ver, U16BIT last_sect)
1745 {
1746  U16BIT i;
1747  U8BIT last_sect_byte;
1748 
1749  FUNCTION_START(ResetTableListEntry);
1750 
1751  ASSERT(table_entry != NULL);
1752 
1753  FreeSectionList(table_entry);
1754 
1755  table_entry->version = ver;
1756  table_entry->num_sect_reqd = last_sect + 1;
1757  table_entry->num_sect_received = 0;
1758  memset(table_entry->sect_received, 0, NUM_SECT_RECEIVED_BYTES);
1759  memset(table_entry->ev_sched_sect_reqd, 0, NUM_SECT_RECEIVED_BYTES);
1760 
1761  if ((0x50 <= table_entry->tid) && (table_entry->tid <= 0x6f))
1762  {
1763  last_sect_byte = last_sect >> 3;
1764  for (i = 0; i <= last_sect_byte; i++)
1765  {
1766  table_entry->ev_sched_sect_reqd[i] = 0xff;
1767  table_entry->ev_sched_segment_notified[i] = FALSE;
1768  }
1769  }
1770 
1771  FUNCTION_FINISH(ResetTableListEntry);
1772 }
1773 
1789 static TABLE_LIST_ENTRY* FindTableListEntry(FILTER_STATUS *filter_ptr, U8BIT tid, U16BIT xtid)
1790 {
1791  TABLE_LIST_ENTRY *table_entry;
1792  TABLE_LIST_ENTRY *first_entry;
1793 
1794  // use the last_rxed_table as the starting point for searching the list. This should make it
1795  // quicker because tables are generally sent in order with all sections of one table followed by
1796  // all sections of the next etc
1797  table_entry = filter_ptr->last_rxed_table;
1798  if (table_entry == NULL)
1799  {
1800  // if last_rxed_table is null get first in list
1801  table_entry = filter_ptr->table_list;
1802  }
1803  first_entry = table_entry;
1804 
1805  // search list
1806  while (table_entry != NULL)
1807  {
1808  if ((table_entry->tid == tid) && (table_entry->xtid == xtid))
1809  {
1810  if (table_entry->state == VALID)
1811  {
1812  // found
1813  break;
1814  }
1815  }
1816  // move on to next in list - if reached the end wrap round to the beginning. Keep going until
1817  // we reach the start again
1818  table_entry = table_entry->next;
1819  if (table_entry == NULL)
1820  {
1821  table_entry = filter_ptr->table_list;
1822  }
1823  if (table_entry == first_entry)
1824  {
1825  // done all of them without finding a match - set table_entry to NULL to indicate not found
1826  table_entry = NULL;
1827  break;
1828  }
1829  }
1830 
1831  return(table_entry);
1832 }
1833 
1845 static void FreeTableList(FILTER_STATUS *filter_ptr)
1846 {
1847  TABLE_LIST_ENTRY *table_entry;
1848  TABLE_LIST_ENTRY *next_entry;
1849 
1850  FUNCTION_START(FreeTableList);
1851 
1852  ASSERT(filter_ptr != NULL);
1853 
1854  STB_OSMutexLock(table_mutex);
1855 
1856  table_entry = filter_ptr->table_list;
1857  if (filter_ptr->traversing)
1858  {
1859  /* Mark entries as DELETED */
1860  while (table_entry != NULL)
1861  {
1862  next_entry = table_entry->next;
1863  FreeSectionList(table_entry);
1864  table_entry->state = DELETED;
1865  table_entry = next_entry;
1866  }
1867  }
1868  else
1869  {
1870  /* Delete entries */
1871  while (table_entry != NULL)
1872  {
1873  next_entry = table_entry->next;
1874  FreeSectionList(table_entry);
1875  STB_FreeMemory(table_entry);
1876  table_entry = next_entry;
1877  }
1878  filter_ptr->table_list = NULL;
1879  filter_ptr->last_rxed_table = NULL;
1880  }
1881 
1882  STB_OSMutexUnlock(table_mutex);
1883 
1884  FUNCTION_FINISH(FreeTableList);
1885 }
1886 
1900 static void ProcessTableEntries(FILTER_STATUS *filter_ptr)
1901 {
1902  TABLE_LIST_ENTRY **table_entry_mod;
1903  TABLE_LIST_ENTRY *table_entry;
1904 
1905  FUNCTION_START(ProcessTableEntries);
1906 
1907  ASSERT(filter_ptr != NULL);
1908 
1909  STB_OSMutexLock(table_mutex);
1910 
1911  table_entry_mod = &filter_ptr->table_list;
1912  while (*table_entry_mod != NULL)
1913  {
1914  if ((*table_entry_mod)->state == DELETED)
1915  {
1916  table_entry = *table_entry_mod;
1917  *table_entry_mod = table_entry->next;
1918  if (filter_ptr->last_rxed_table == table_entry)
1919  {
1920  filter_ptr->last_rxed_table = table_entry->next;
1921  }
1922  STB_FreeMemory(table_entry);
1923  }
1924  else
1925  {
1926  table_entry_mod = &((*table_entry_mod)->next);
1927  }
1928  }
1929 
1930  STB_OSMutexUnlock(table_mutex);
1931 
1932  FUNCTION_FINISH(ProcessTableEntries);
1933 }
1934 
1950 static SI_SECTION_RECORD* AddSectionRecord(TABLE_LIST_ENTRY *table_entry, U8BIT sect_num, U16BIT data_len,
1951  U8BIT *data_ptr, BOOLEAN add_to_table, BOOLEAN add_to_segment_list)
1952 {
1953  SI_SECTION_RECORD *section_rec;
1954  SI_SECTION_RECORD *next_sect_rec;
1955  SI_SECTION_RECORD **prev_rec_next_ptr;
1956  U8BIT segment_last_sect;
1957 
1958  FUNCTION_START(AddSectionRecord);
1959 
1960  section_rec = STB_GetMemory(sizeof(SI_SECTION_RECORD) + data_len);
1961  if (section_rec != NULL)
1962  {
1963  section_rec->sect_num = sect_num;
1964  section_rec->data_len = data_len;
1965  section_rec->next = NULL;
1966  memcpy(&section_rec->data_start, data_ptr, data_len);
1967 
1968  STB_OSSemaphoreWait(section_sema);
1969 
1970  if (add_to_table)
1971  {
1972  // add to the section list in section order...
1973  // ...find the right place in the list
1974  if (add_to_segment_list)
1975  {
1976  next_sect_rec = table_entry->segment_list[sect_num >> 3];
1977  prev_rec_next_ptr = &(table_entry->segment_list[sect_num >> 3]);
1978  }
1979  else
1980  {
1981  next_sect_rec = table_entry->section_list;
1982  prev_rec_next_ptr = &(table_entry->section_list);
1983  }
1984 
1985  while (next_sect_rec != NULL)
1986  {
1987  if (sect_num < next_sect_rec->sect_num)
1988  {
1989  break;
1990  }
1991  prev_rec_next_ptr = &(next_sect_rec->next);
1992  next_sect_rec = next_sect_rec->next;
1993  }
1994 
1995  // ...insert the record - this could be at the front, in the middle or on the end.
1996  section_rec->next = next_sect_rec;
1997  *prev_rec_next_ptr = section_rec;
1998  }
1999 
2000  // add this section to the record of sections received
2001  table_entry->sect_received[sect_num >> 3] |= (0x01 << (sect_num & 0x07));
2002  table_entry->num_sect_received++;
2003 
2004  STB_OSSemaphoreSignal(section_sema);
2005 
2006  // if this is an event schedule table update the sections required map from the
2007  // segment_last_section field
2008  if ((0x50 <= table_entry->tid) && (table_entry->tid <= 0x6f))
2009  {
2010  // event schedule tables - update ev_sched_sect_reqd array
2011  // (bitmap, 1 = sect reqd, 0 = sect not used)
2012  segment_last_sect = data_ptr[12];
2013  table_entry->ev_sched_sect_reqd[sect_num >> 3] = ~(0xff << ((segment_last_sect & 0x07) + 1));
2014  }
2015 
2016  #ifdef DEBUG_SI_FILTER
2017  STB_SI_PRINT(("AddSectionRec: sect %d [of %d]", sect_num, table_entry->num_sect_reqd));
2018  #endif
2019  }
2020  #ifdef DEBUG_SI_FILTER_FAILURES
2021  else
2022  {
2023  STB_SI_PRINT(("AddSectionRec: FAILED"));
2024  }
2025  #endif
2026  FUNCTION_FINISH(AddSectionRecord);
2027  return(section_rec);
2028 }
2029 
2041 static void FreeSectionList(TABLE_LIST_ENTRY *table_entry)
2042 {
2043  SI_SECTION_RECORD *section_rec;
2044  SI_SECTION_RECORD *next_rec;
2045  U16BIT i;
2046 
2047  FUNCTION_START(FreeSectionList);
2048 
2049  ASSERT(table_entry != NULL);
2050 
2051  STB_OSSemaphoreWait(section_sema);
2052 
2053  section_rec = table_entry->section_list;
2054  while (section_rec != NULL)
2055  {
2056  next_rec = section_rec->next;
2057  STB_FreeMemory(section_rec);
2058  section_rec = next_rec;
2059  }
2060  table_entry->section_list = NULL;
2061 
2062  for (i = 0; i < NUM_SECT_RECEIVED_BYTES; i++)
2063  {
2064  section_rec = table_entry->segment_list[i];
2065  while (section_rec != NULL)
2066  {
2067  next_rec = section_rec->next;
2068  STB_FreeMemory(section_rec);
2069  section_rec = next_rec;
2070  }
2071  table_entry->segment_list[i] = NULL;
2072  }
2073 
2074  STB_OSSemaphoreSignal(section_sema);
2075 
2076  FUNCTION_FINISH(FreeSectionList);
2077 }
2078 
2079 //---global function definitions-----------------------------------------------
2080 
2093 {
2094  U8BIT i;
2095 
2096  FUNCTION_START(STB_SITerrInitialise);
2097 
2098  num_paths = STB_DPGetNumPaths(); //STB_OSGetTunerPaths();
2099  STB_SI_PRINT(("STB_SITerrInitialise (paths = %d)", num_paths));
2100 
2101  // grab enough memory for status for each path
2102  si_status = STB_GetMemory(sizeof(E_STB_SI_STATUS) * num_paths);
2103  ASSERT(si_status != NULL);
2104 
2105  // Create the message queues
2106  filt_task_msg_queue = STB_OSCreateQueue(sizeof(FILTER_STATUS *), MAX_ENTRIES_FILT_TASK_QUEUE);
2107  cntrl_task_msg_queue = STB_OSCreateQueue(sizeof(CNTRL_TASK_MSG), MAX_ENTRIES_CNTRL_TASK_QUEUE);
2108  low_pri_task_msg_queue = STB_OSCreateQueue(sizeof(CNTRL_TASK_MSG), MAX_ENTRIES_LOW_PRI_TASK_QUEUE);
2109 
2110  // Create the Tasks
2111  filt_task_ptr = STB_OSCreateTask(SiFilterTask, NULL, FILT_TASK_STACK_SIZE, FILT_TASK_PRIORITY, (U8BIT *)"SiFilt");
2112  cntrl_task_ptr = STB_OSCreateTask(SiControlTask, NULL, CNTRL_TASK_STACK_SIZE, CNTRL_TASK_PRIORITY, (U8BIT *)"SiCntrl");
2113  low_pri_task_ptr = STB_OSCreateTask(SiLowPriTableTask, NULL, LOW_PRI_TASK_STACK_SIZE, LOW_PRI_TASK_PRIORITY, (U8BIT *)"SiLowPri");
2114 
2115  // Create semaphores to control access to table list and section lists
2116  table_mutex = STB_OSCreateMutex();
2117  section_sema = STB_OSCreateSemaphore();
2118  filter_mutex = STB_OSCreateMutex();
2119 
2120  // init status vars
2121  for (i = 0; i < num_paths; i++)
2122  {
2123  si_status[i] = SI_STOPPED;
2124  }
2125 
2126  FUNCTION_FINISH(STB_SITerrInitialise);
2127 }
2128 
2140 void STB_SITerrSendEvent(U8BIT path, U32BIT events)
2141 {
2142  CNTRL_TASK_MSG msg;
2143 
2144  FUNCTION_START(STB_SITerrSendEvent);
2145 
2146  msg.path = path;
2147  msg.type = SI_EVENT;
2148  msg.numval = events;
2149 
2150  if (events == SI_EVENT_STOP)
2151  {
2152  // set flags to tell cntrl task and low priority task there is a stop event in the queue,
2153  // so that the queue will be flushed up to stop event
2154  low_pri_task_stop_pending = TRUE;
2155  cntrl_task_stop_pending = TRUE;
2156 
2157  STB_OSWriteQueue(low_pri_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), TIMEOUT_NEVER);
2158  }
2159  STB_OSWriteQueue(cntrl_task_msg_queue, (void *)&msg, sizeof(CNTRL_TASK_MSG), TIMEOUT_NEVER);
2160 
2161  FUNCTION_FINISH(STB_SITerrSendEvent);
2162 }
2163 
2175 E_STB_SI_STATUS STB_SITerrGetStatus(U8BIT path)
2176 {
2177  E_STB_SI_STATUS ret_val;
2178 
2179  FUNCTION_START(STB_SITerrGetStatus);
2180 
2181  ASSERT(path < num_paths);
2182  ret_val = si_status[path];
2183 
2184  FUNCTION_FINISH(STB_SITerrGetStatus);
2185 
2186  return(ret_val);
2187 }
2188 
2200 void STB_SIRegisterPmtObserver(F_PmtObserver func_ptr)
2201 {
2202  U8BIT index;
2203  FUNCTION_START(STB_SIRegisterPmtObserver);
2204  for (index = 0; index != NUM_PMT_OBSERVERS; index++)
2205  {
2206  if (pmt_observers[index] == func_ptr)
2207  {
2208  break;
2209  }
2210  }
2211  if (index == NUM_PMT_OBSERVERS)
2212  {
2213  for (index = 0; index != NUM_PMT_OBSERVERS; index++)
2214  {
2215  if (pmt_observers[index] == NULL)
2216  {
2217  pmt_observers[index] = func_ptr;
2218  break;
2219  }
2220  }
2221  }
2222  FUNCTION_FINISH(STB_SIRegisterPmtObserver);
2223 }
2224 
2236 void STB_SIUnregisterPmtObserver(F_PmtObserver func_ptr)
2237 {
2238  U8BIT index;
2239 
2240  FUNCTION_START(STB_SIUnregisterPmtObserver);
2241 
2242  /* Find a blank slot and save the callback function */
2243  for (index = 0; index != NUM_PMT_OBSERVERS; index++)
2244  {
2245  if (pmt_observers[index] == func_ptr)
2246  {
2247  pmt_observers[index] = NULL;
2248  break;
2249  }
2250  }
2251  FUNCTION_FINISH(STB_SIUnregisterPmtObserver);
2252 }
2253 
2259 F_AppSiEventHandler STB_SIRegisterAppSiEventHandler(void (*func_ptr)(U8BIT, E_APP_SI_EVENT_TYPE))
2260 {
2261  F_AppSiEventHandler old_func;
2262 
2263  FUNCTION_START(STB_SIRegisterAppSiEventHandler);
2264 
2265  old_func = app_si_interface_ptr;
2266  app_si_interface_ptr = func_ptr;
2267 
2268  FUNCTION_FINISH(STB_SIRegisterAppSiEventHandler);
2269 
2270  return(old_func);
2271 }
2272 
2297 void* STB_SIRequestTable(U8BIT path, U16BIT pid, U8BIT tid_match, U8BIT tid_mask,
2298  E_SI_TABLE_FORMAT_TYPE format, U16BIT expected_tables,
2299  U16BIT xtid_match, U16BIT xtid_mask, E_SI_REQUEST_TYPE req_type,
2300  U16BIT buff_size, BOOLEAN crc, BOOLEAN low_priority,
2301  void (*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
2302 {
2303  FILTER_STATUS *filter_ptr;
2304 
2305  FUNCTION_START(STB_SIRequestTable);
2306 
2307  #ifdef DEBUG_TABLE_REQUESTS
2308  STB_SI_PRINT(("STB_SIRequestTable - path %d, pid 0x%04x, tid 0x%02x[0x%02x], format %d",
2309  path, pid, tid_match, tid_mask, format));
2310  STB_SI_PRINT((" xtid 0x%04x[0x%04x], exp %d, rtype %d, buff %d, crc %d, lp %d",
2311  xtid_match, xtid_mask, expected_tables, req_type, buff_size, crc, low_priority));
2312  #endif
2313 
2314  filter_ptr = GetFilter(path, pid, tid_match, tid_mask, format, expected_tables, xtid_match,
2315  xtid_mask, req_type, buff_size, crc, low_priority, callback, ret_param);
2316  if (filter_ptr != NULL)
2317  {
2318  StartFilter(filter_ptr);
2319  }
2320 
2321  FUNCTION_FINISH(STB_SIRequestTable);
2322  return((void *)filter_ptr);
2323 }
2324 
2336 void STB_SICancelTableRequest(void *filter_handle)
2337 {
2338  FILTER_STATUS *filter_ptr;
2339  BOOLEAN filter_ok;
2340 
2341  FUNCTION_START(STB_SICancelTableRequest);
2342 
2343  #ifdef DEBUG_TABLE_REQUESTS
2344  STB_SI_PRINT(("STB_SICancelTableRequest - filter %p", filter_handle));
2345  #endif
2346 
2347  STB_OSMutexLock(filter_mutex);
2348 
2349  filter_ptr = (FILTER_STATUS *)filter_handle;
2350  filter_ok = ValidateFilterPtr(filter_ptr);
2351  if (filter_ok == TRUE)
2352  {
2353  StopFilter(filter_ptr);
2354  ReleaseFilter(filter_ptr);
2355  }
2356 
2357  STB_OSMutexUnlock(filter_mutex);
2358 
2359  FUNCTION_FINISH(STB_SICancelTableRequest);
2360 }
2361 
2378 void STB_SIModifyTableRequest(void *filter_handle, U8BIT tid_match, U8BIT tid_mask,
2379  U16BIT xtid_match, U16BIT xtid_mask, U16BIT expected_tables)
2380 {
2381  FILTER_STATUS *filter_ptr;
2382  BOOLEAN filter_ok;
2383 
2384  FUNCTION_START(STB_SIModifyTableRequest);
2385 
2386  #ifdef DEBUG_TABLE_REQUESTS
2387  STB_SI_PRINT(("STB_SIModifyTableRequest - filter %p", filter_handle));
2388  #endif
2389 
2390  STB_OSMutexLock(filter_mutex);
2391 
2392  filter_ptr = (FILTER_STATUS *)filter_handle;
2393  filter_ok = ValidateFilterPtr(filter_ptr);
2394  if (filter_ok == TRUE)
2395  {
2396  StopFilter(filter_ptr);
2397  FreeTableList(filter_ptr);
2398  ModifyFilter(filter_ptr, tid_match, tid_mask, xtid_match, xtid_mask, expected_tables);
2399  StartFilter(filter_ptr);
2400  }
2401 
2402  STB_OSMutexUnlock(filter_mutex);
2403 
2404  FUNCTION_FINISH(STB_SIModifyTableRequest);
2405 }
2406 
2419 void STB_SIRestartTableRequest(void *filter_handle)
2420 {
2421  FILTER_STATUS *filter_ptr;
2422  BOOLEAN filter_ok;
2423 
2424  FUNCTION_START(STB_SIRestartTableRequest);
2425 
2426  #ifdef DEBUG_TABLE_REQUESTS
2427  STB_SI_PRINT(("STB_SIRestartTableRequest - filter %p", filter_handle));
2428  #endif
2429 
2430  STB_OSMutexLock(filter_mutex);
2431 
2432  filter_ptr = (FILTER_STATUS *)filter_handle;
2433  filter_ok = ValidateFilterPtr(filter_ptr);
2434  if (filter_ok == TRUE)
2435  {
2436  StopFilter(filter_ptr);
2437  FreeTableList(filter_ptr);
2438 
2439  // reset buffer and table received
2440  filter_ptr->data_start = ((U8BIT *)filter_ptr) + sizeof(FILTER_STATUS);
2441  filter_ptr->data_end = filter_ptr->data_start;
2442  filter_ptr->num_tables_received = 0;
2443 
2444  StartFilter(filter_ptr);
2445  }
2446 
2447  STB_OSMutexUnlock(filter_mutex);
2448 
2449  FUNCTION_FINISH(STB_SIRestartTableRequest);
2450 }
2451 
2464 {
2465  SI_SECTION_RECORD *section_rec;
2466  SI_SECTION_RECORD *next_rec;
2467 
2468  FUNCTION_START(STB_SIReleaseTableRecord);
2469 
2470  ASSERT(table_rec != NULL);
2471 
2472  #ifdef DEBUG_TABLE_REQUESTS
2473  STB_SI_PRINT(("STB_SIReleaseTableRecord - table_rec %p", table_rec));
2474  #endif
2475 
2476  if (table_rec != NULL)
2477  {
2478  STB_OSSemaphoreWait(section_sema);
2479 
2480  // first free section list
2481  section_rec = table_rec->section_list;
2482  while (section_rec != NULL)
2483  {
2484  next_rec = section_rec->next;
2485  STB_FreeMemory(section_rec);
2486  section_rec = next_rec;
2487  }
2488 
2489  STB_OSSemaphoreSignal(section_sema);
2490 
2491  // now free table record itself
2492  STB_FreeMemory(table_rec);
2493  }
2494 
2495  FUNCTION_FINISH(STB_SIReleaseTableRecord);
2496 }
2497 
2509 void STB_SISearchComplete(U8BIT path, BOOLEAN success, void *event_data, U32BIT data_size)
2510 {
2511  FUNCTION_START(STB_SISearchComplete);
2512 
2513  si_status[path] = SI_STOPPED;
2514 
2515  if (success)
2516  {
2517  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_SEARCH, EV_TYPE_SUCCESS, event_data, data_size);
2518  }
2519  else
2520  {
2521  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_SEARCH, EV_TYPE_FAIL, event_data, data_size);
2522  }
2523 
2524  STB_SI_PRINT(("SITask(%d) finished search", path));
2525 
2526  FUNCTION_FINISH(STB_SISearchComplete);
2527 }
2528 
2542 void STB_SIReportCurrentPmt(U16BIT service_id, SI_TABLE_RECORD *table_rec, BOOLEAN new_serv,
2543  BOOLEAN new_pmt_version)
2544 {
2545  SI_SECTION_RECORD *sect_rec;
2546  U8BIT index;
2547  U32BIT ca_handle;
2548 
2549  FUNCTION_START(STB_SIReportCurrentPmt);
2550 
2551  if (table_rec != NULL)
2552  {
2553  #ifdef DEBUG_PMT_REPORTING
2554  STB_SI_PRINT(("STB_SIReportCurrentPmt: serv_id 0x%04x new_serv %d", table_rec->xtid, new_serv));
2555  #endif
2556 
2557  // pmts should only have one section so get the first section record from the table_rec
2558  sect_rec = table_rec->section_list;
2559 
2560  if (sect_rec != NULL)
2561  {
2562  /* Report the PMT to all registered observers */
2563  for (index = 0; index != NUM_PMT_OBSERVERS; index++)
2564  {
2565  if (pmt_observers[index] != 0)
2566  {
2567  (pmt_observers[index])(service_id, &(sect_rec->data_start));
2568  }
2569  }
2570 
2571  if (new_serv || new_pmt_version)
2572  {
2573  if (STB_DPGetPathCADescrambler(table_rec->path, &ca_handle))
2574  {
2575  /* Report the PMT to the CA */
2576  STB_CAReportPMT(ca_handle, &(sect_rec->data_start), sect_rec->data_len);
2577  }
2578  }
2579  }
2580  }
2581  else
2582  {
2583  #ifdef DEBUG_PMT_REPORTING
2584  STB_SI_PRINT(("STB_SIReportCurrentPmt: NULL table_rec"));
2585  #endif
2586  /* Report removal of service to all registered observers */
2587  for (index = 0; index != NUM_PMT_OBSERVERS; index++)
2588  {
2589  if (pmt_observers[index] != 0)
2590  {
2591  (pmt_observers[index])(service_id, NULL);
2592  }
2593  }
2594  }
2595  FUNCTION_FINISH(STB_SIReportCurrentPmt);
2596 }
2597 
2604 {
2605  SI_SECTION_RECORD *sect_rec;
2606  U8BIT i;
2607  U32BIT ca_handle;
2608  BOOLEAN reported;
2609 
2610  FUNCTION_START(STB_SIReportCat);
2611 
2612  reported = FALSE;
2613 
2614  if (table_rec != NULL)
2615  {
2616  #ifdef DEBUG_CAT_REPORTING
2617  STB_SI_PRINT(("STB_SIReportCat: version %d num_sects %d", table_rec->version, table_rec->num_sect));
2618  #endif
2619 
2620  if (STB_DPGetPathCADescrambler(table_rec->path, &ca_handle))
2621  {
2622  // work through the table reporting a section at a time
2623  sect_rec = table_rec->section_list;
2624  for (i = 0; ((i < table_rec->num_sect) && (sect_rec != NULL)); i++)
2625  {
2626  STB_CAReportCAT(ca_handle, &(sect_rec->data_start), sect_rec->data_len);
2627  sect_rec = sect_rec->next;
2628  }
2629 
2630  reported = TRUE;
2631  }
2632  }
2633  else
2634  {
2635  #ifdef DEBUG_CAT_REPORTING
2636  STB_SI_PRINT(("STB_SIReportCat: NULL table_rec"));
2637  #endif
2638  }
2639 
2640  FUNCTION_FINISH(STB_SIReportCat);
2641 
2642  return(reported);
2643 }
2644 
2651 {
2652  SI_SECTION_RECORD *sect_rec;
2653  U8BIT i;
2654  U32BIT ca_handle;
2655  BOOLEAN reported;
2656 
2657  FUNCTION_START(STB_SIReportBat);
2658 
2659  reported = FALSE;
2660 
2661  if (table_rec != NULL)
2662  {
2663  if (STB_DPGetPathCADescrambler(table_rec->path, &ca_handle))
2664  {
2665  /* Work through the table reporting a section at a time */
2666  sect_rec = table_rec->section_list;
2667  for (i = 0; ((i < table_rec->num_sect) && (sect_rec != NULL)); i++)
2668  {
2669  STB_CAReportBAT(ca_handle, &(sect_rec->data_start), sect_rec->data_len);
2670  sect_rec = sect_rec->next;
2671  }
2672 
2673  reported = TRUE;
2674  }
2675  }
2676 
2677  FUNCTION_FINISH(STB_SIReportBat);
2678 
2679  return(reported);
2680 }
2681 
2688 {
2689  SI_SECTION_RECORD *sect_rec;
2690  U8BIT i;
2691  U32BIT ca_handle;
2692  BOOLEAN reported;
2693 
2694  FUNCTION_START(STB_SIReportNit);
2695 
2696  reported = FALSE;
2697 
2698  if (table_rec != NULL)
2699  {
2700  if (STB_DPGetPathCADescrambler(table_rec->path, &ca_handle))
2701  {
2702  /* Work through the table reporting a section at a time */
2703  sect_rec = table_rec->section_list;
2704  for (i = 0; ((i < table_rec->num_sect) && (sect_rec != NULL)); i++)
2705  {
2706  STB_CAReportNIT(ca_handle, &(sect_rec->data_start), sect_rec->data_len);
2707  sect_rec = sect_rec->next;
2708  }
2709 
2710  reported = TRUE;
2711  }
2712  }
2713 
2714  FUNCTION_FINISH(STB_SIReportNit);
2715 
2716  return(reported);
2717 }
2718 
2719 //*****************************************************************************
2720 // End of file
2721 //*****************************************************************************
2722 
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
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 * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void STB_DMXStopPIDFilter(U8BIT path, U16BIT pfilt_id)
Stop Specified PID Filter Collecting Data.
void STB_CAReportBAT(U32BIT handle, U8BIT *bat_data, U16BIT data_len)
When there&#39;s an update to the BAT, the updated BAT will be reported to the CA system using this funct...
Definition: ca_glue.c:204
void STB_DMXSetupSectFilter(U8BIT path, U16BIT sfilt_id, U8BIT *match_ptr, U8BIT *mask_ptr, U8BIT not_equal_byte_index, BOOLEAN crc)
Configures a match and mask for a specified section filter.
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_DMXStartPIDFilter(U8BIT path, U16BIT pfilt_id)
Start Specified PID Filter Collecting Data.
BOOLEAN STB_DMXCopyPIDFilterSect(U8BIT path, U8BIT *buffer, U16BIT size, U16BIT pfilt_id)
Copies a filtered section to caller&#39;s buffer.
void STB_CAReportCAT(U32BIT handle, U8BIT *cat_data, U16BIT data_len)
When there&#39;s an update to the CAT for a service, the updated CAT will be reported to the CA system us...
Definition: ca_glue.c:183
void STB_SITerrSendEvent(U8BIT path, U32BIT events)
Sends an event to STB layer SI Terrestrial engine.
Definition: stbsiflt.c:2140
void STB_CAReportNIT(U32BIT handle, U8BIT *nit_data, U16BIT data_len)
When there&#39;s an update to the NIT, the updated NIT will be reported to the CA system using this funct...
Definition: ca_glue.c:225
void STB_OSSemaphoreSignal(void *semaphore)
Signal a Semaphore to Release it by decrementing its counter.
void STB_OSMutexUnlock(void *mutex)
Unlock a mutex (a.k.a. &#39;leave&#39;, &#39;signal&#39; or &#39;release&#39;)
void STB_OSSemaphoreWait(void *semaphore)
Wait on Semaphore Indefinity or Until Released.
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
void STB_SICancelTableRequest(void *filter_handle)
Stops filtering for SI table.
Definition: stbsiflt.c:2336
U8BIT STB_DPGetNumPaths(void)
Returns the maximum number of decode paths.
Definition: stbdpc.c:532
void STB_SITerrInitialise(void)
Initialises STB layer SI engine - terrestrial version.
Definition: stbsiflt.c:2092
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
E_STB_SI_STATUS STB_SITerrGetStatus(U8BIT path)
Reads the SI status.
Definition: stbsiflt.c:2175
Debug functions header file.
void STB_SISearchComplete(U8BIT path, BOOLEAN success, void *event_data, U32BIT data_size)
Indicates SI search is complete.
Definition: stbsiflt.c:2509
void STB_SIModifyTableRequest(void *filter_handle, U8BIT tid_match, U8BIT tid_mask, U16BIT xtid_match, U16BIT xtid_mask, U16BIT expected_tables)
modifies the section filtering on an existing filter
Definition: stbsiflt.c:2378
Header file - Function prototypes for linked lists.
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
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
void STB_OSMutexLock(void *mutex)
Lock a mutex (a.k.a. &#39;enter&#39;, &#39;wait&#39; or &#39;get&#39;).
Definition: stbsiflt.c:105
U32BIT STB_DPGetFrequency(U8BIT path)
Reads the frequency value from decode path store.
Definition: stbdpc.c:6092
void STB_SIRegisterPmtObserver(F_PmtObserver func_ptr)
Registers a function to be called when the PMT changes.
Definition: stbsiflt.c:2200
Header file - Function prototypes for Event Reporting.
void STB_DMXSkipPIDFilterSect(U8BIT path, U16BIT pfilt_id)
Skips (discards) a section in the PID filter buffer.
Glue layer between DVB and conditional access systems.
BOOLEAN STB_OSWriteQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Write a message to the queue.
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
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 STB_DPGetPathCADescrambler(U8BIT path, U32BIT *handle)
Get the handle of the CA descrambler associated with the given path.
Definition: stbdpc.c:1244
void STB_SIUnregisterPmtObserver(F_PmtObserver func_ptr)
Registers a function to be called when the PMT changes.
Definition: stbsiflt.c:2236
void * STB_OSCreateTask(void(*function)(void *), void *param, U32BIT stack, U8BIT priority, U8BIT *name)
Create a New Task to the calling process. Upon success, the created task runs on its own stack...
Header file - macros and function prototypes for public use.
U16BIT STB_DMXGrabSectFilter(U8BIT path, U16BIT pfilt_id)
Allocated a new section filter on the specified PID filter.
void STB_DMXReleaseSectFilter(U8BIT path, U16BIT sfilt_id)
Releases a previously allocated section filter.
void * STB_OSCreateQueue(U16BIT msg_size, U16BIT msg_max)
Create Queue of given number of messages and size of message.
Header file - Function prototypes for heap memory.
void * STB_OSCreateMutex(void)
Create a mutex.
Header file - Function prototypes for operating system.
BOOLEAN STB_OSReadQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Read a message from a queue.
void * STB_SIRequestTable(U8BIT path, U16BIT pid, U8BIT tid_match, U8BIT tid_mask, E_SI_TABLE_FORMAT_TYPE format, U16BIT expected_tables, U16BIT xtid_match, U16BIT xtid_mask, E_SI_REQUEST_TYPE req_type, U16BIT buff_size, BOOLEAN crc, BOOLEAN low_priority, void(*callback)(void *, U32BIT, SI_TABLE_RECORD *), U32BIT ret_param)
Sets up filter for SI table.
Definition: stbsiflt.c:2297
void STB_OSTaskDelay(U16BIT timeout)
Delay Task for Specifed Time Period.
Header file - Function prototypes for Demux control.
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
F_AppSiEventHandler STB_SIRegisterAppSiEventHandler(void(*func_ptr)(U8BIT, E_APP_SI_EVENT_TYPE))
Registers a function to be called to handle SI events.
Definition: stbsiflt.c:2259
U8BIT STB_DPGetPathDemux(U8BIT path)
Returns the demux path ID acquired by the given decode path.
Definition: stbdpc.c:1711
void STB_CAReportPMT(U32BIT handle, U8BIT *pmt_data, U16BIT data_len)
When there&#39;s an update to the PMT for a service, the updated PMT will be reported to the CA system us...
Definition: ca_glue.c:162
U16BIT STB_DMXGrabPIDFilter(U8BIT path, U16BIT pid, FILTER_CALLBACK func)
Get a New PID Filter & Setup Associated Buffer and Callback Function Address.
void STB_DMXReleasePIDFilter(U8BIT path, U16BIT pfilt_id)
Releases a previously allocated PID filter.
Header file - macros and function prototypes for public use.