DVBCore  20.3.0
DVBCore Documentation
ap_tmr.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  *******************************************************************************/
26 //---includes for this file-------------------------------------------------------------------------
27 // compiler library header files
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 // third party header files
34 
35 // Ocean Blue Software header files
36 #include "techtype.h" //generic data definitions
37 #include "dbgfuncs.h" //obs debug functions
38 
39 #include "stbhwdsk.h"
40 #include "stbhwos.h"
41 #include "stbhwc.h" // STB_SPDebugWrite
42 
43 #include "stbgc.h"
44 #include "stbdpc.h"
45 #include "stbsiflt.h"
46 #include "stbsitab.h"
47 #include "stbpvr.h" // STB PVR
48 #include "stbpvrmsg.h"
49 #include "stbheap.h" // STB_AppFreeMemory
50 #include "stbuni.h" // STB_ConcatUnicodeStrings()
51 #include "stbllist.h"
52 #include "stberc.h"
53 
54 #ifdef INTEGRATE_HBBTV
55 #include "hbbtv_api.h"
56 #endif
57 
58 #include "app.h"
59 #include "ap_pvr.h" // for PVR functionality
60 
61 #include "ap_cfg.h"
62 #include "ap_dbacc.h"
63 #include "ap_tmr.h"
64 #include "ap_dbdef.h"
65 #include "ap_cntrl.h"
66 #include "ap_state.h"
67 
68 #include "dba.h"
69 
70 #ifdef PVR_LOG
71 extern FILE *pvr_log;
72 extern void LogDateTime();
73 #endif
74 
75 //---constant definitions for this file-------------------------------------------------------------
76 
77 #if 0
78 #ifdef FUNCTION_START
79 #undef FUNCTION_START
80 #endif
81 #define FUNCTION_START(X) STB_SPDebugWrite(">> %s\n", #X)
82 
83 #ifdef FUNCTION_FINISH
84 #undef FUNCTION_FINISH
85 #endif
86 #define FUNCTION_FINISH(X) STB_SPDebugWrite("<< %s\n", #X)
87 #endif
88 
89 /*#define TMR_DEBUG*/
90 #ifdef TMR_DEBUG
91 #define TMR_DBG(x) STB_SPDebugWrite x
92 #else
93 #define TMR_DBG(x)
94 #endif
95 
96 /*#define TMR_PVR_DEBUG*/
97 #ifdef TMR_PVR_DEBUG
98 #define TMR_PVR_DBG(x) STB_SPDebugWrite x
99 #else
100 #define TMR_PVR_DBG(x)
101 #endif
102 
103 /* The number of seconds added to a timer to allow an event triggered recording to overrun
104  * before the recording is stopped */
105 #define EVENT_DURATION_OVERRUN (2 * 60 * 60)
106 #define NORDIG_EVENT_DURATION_OVERRUN (4 * 60 * 60)
107 
108 
109 //---local typedefs, structs, enumerations for this file--------------------------------------------
110 
111 /* This structure is used for timer database filters */
112 typedef struct
113 {
114  U32DHMS start_time;
115  U32DHMS end_time;
116 } S_TIME_SLOT;
117 
118 typedef struct
119 {
120  U32BIT timer_handle;
121  BOOLEAN is_recommendation;
122  BOOLEAN do_not_delete;
123  U8BIT prog_crid[TMR_PVR_CRID_LEN_MAX];
124  U8BIT other_crid[TMR_PVR_CRID_LEN_MAX];
126 
127 
128 //---local (static) variable declarations for this file---------------------------------------------
129 // (internal variables declared static to make them local)
130 static void *alt_event_queue;
131 
132 //---local function prototypes for this file--------------------------------------------------------
133 // (internal functions declared static to make them local)
134 static BOOLEAN DeleteTimer(U32BIT handle);
135 
136 // ---- PVR action timer ----
137 static BOOLEAN ActionTimerRecStart(ADB_TIMER_REC *timer);
138 static void AlternateEventTask(void *param);
139 
140 static void TimerTask(void *param);
141 static BOOLEAN StartRecordTimer(ADB_TIMER_REC *timer, BOOLEAN recordings_can_start, BOOLEAN *start_record);
142 static BOOLEAN HasTimerExpired(U32BIT handle);
143 static BOOLEAN RescheduleTimer(ADB_TIMER_REC *timer);
144 
145 #ifdef TMR_DEBUG
146 static void DumpTimer(ADB_TIMER_REC *timer);
147 #endif
148 
149 static void GetActualStartEndTime(U32DHMS timer_start, U32DHMS timer_duration, S32BIT start_padding, S32BIT end_padding,
150  U32DHMS *start_time, U32DHMS *end_time);
151 static void SetTimerFields(ADB_TIMER_REC *timer, S_TIMER_INFO *info);
152 static U8BIT GetNumSimultaneousRecordings(U32BIT handle, U16BIT onet_id, U16BIT trans_id,
153  U16BIT serv_id, U8BIT max_recordings, U32DHMS start_date_time,
154  U32DHMS end_date_time, BOOLEAN include_start_padding, BOOLEAN include_end_padding,
155  U32BIT **conflicting_timers);
156 static BOOLEAN SetStartPadding(ADB_TIMER_REC *timer, S32BIT padding);
157 static S32BIT GetStartPadding(ADB_TIMER_REC *timer);
158 static BOOLEAN SetEndPadding(ADB_TIMER_REC *timer, S32BIT padding);
159 static S32BIT GetEndPadding(ADB_TIMER_REC *timer);
160 
161 
162 //---global function definitions-----------------------------------------------
163 
168 void ATMR_Initialise(void)
169 {
170  FUNCTION_START(ATMR_Initialise);
171 
172  TMR_DBG(("ATMR_Initialise"));
173 
174  /* Start the main timer background task */
175  STB_OSCreateTask(TimerTask, NULL, 4096, 11, (U8BIT *)"TimerTask");
176 
177  /* Create queue and task used to find alternative events for recording */
178  alt_event_queue = STB_OSCreateQueue(sizeof(S_ALT_EVENT_DATA), 30);
179  STB_OSCreateTask(AlternateEventTask, NULL, 4096, 6, (U8BIT *)"AltEvent");
180 
181  FUNCTION_FINISH(ATMR_Initialise);
182 }
183 
190 {
191  U32BIT handle;
192  ADB_TIMER_REC *timer;
193  void *s_ptr;
194 
195  FUNCTION_START(ATMR_AddTimer);
196 
197  handle = INVALID_TIMER_HANDLE;
198 
199  if ((info != NULL) && ((info->type == TIMER_TYPE_ALARM) || (info->type == TIMER_TYPE_SLEEP) ||
200  (info->type == TIMER_TYPE_PVR_RECORD) || (info->type == TIMER_TYPE_PRIVATE)))
201  {
203 
204  timer = DBDEF_AddTimerRec(!info->ram_only);
205  if (timer != NULL)
206  {
207  SetTimerFields(timer, info);
208 
209  if (timer->type == TIMER_TYPE_PVR_RECORD)
210  {
211 #ifdef INTEGRATE_HBBTV
212  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_NEWLY_SCHEDULED);
213 #endif
214  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_BOOKING_CREATED,
215  (void *)&timer->handle, sizeof(timer->handle));
216 
217  /* If the timer is event triggered and the event has already started
218  * then recording should be started now */
219  s_ptr = ADB_FindServiceByIds(timer->u.record.orig_net_id, timer->u.record.transport_id,
220  timer->u.record.service_id);
221  ATMR_CheckRecordStatus(TRUE, s_ptr);
222  }
223 
224  if (timer->dba_rec != NULL)
225  {
226  DBA_SaveRecord(timer->dba_rec);
227  }
228 
229  handle = timer->handle;
230  }
231 
233  }
234 
235  FUNCTION_FINISH(ATMR_AddTimer);
236 
237  return(handle);
238 }
239 
251 U32BIT ATMR_AddTimerForEvent(void *event_ptr, void *serv_ptr, BOOLEAN record, BOOLEAN event_triggered)
252 {
253  U32BIT handle;
254  S_TIMER_INFO info;
255  U8BIT *string;
256  U16BIT str_len;
257  U16BIT onet_id;
258  U16BIT trans_id;
259  U16BIT serv_id;
260 
261  FUNCTION_START(ATMR_AddTimerForEvent);
262 
263  handle = INVALID_TIMER_HANDLE;
264 
265  if ((event_ptr != NULL) && (serv_ptr != NULL))
266  {
267  memset(&info, 0, sizeof(info));
268 
269  info.frequency = TIMER_FREQ_ONCE;
270  info.start_time = ADB_GetEventStartDateTime(event_ptr);
271 
272  if ((string = ADB_GetEventName(event_ptr)) != NULL)
273  {
274  if ((str_len = STB_GetNumBytesInString(string)) <= TMR_MAX_NAME_LENGTH)
275  {
276  memcpy(info.name, string, str_len);
277  }
278  else
279  {
280  /* Event name too long, truncate with null */
281  memcpy(info.name, string, TMR_MAX_NAME_LENGTH);
282  info.name[TMR_MAX_NAME_LENGTH - 1] = '\0';
283  }
284 
285  STB_ReleaseUnicodeString(string);
286  }
287 
288  ADB_GetServiceIds(serv_ptr, &onet_id, &trans_id, &serv_id);
289 
290  if (record)
291  {
292  info.type = TIMER_TYPE_PVR_RECORD;
293  info.u.record.duration = ADB_GetEventDuration(event_ptr);
294  info.u.record.service_id = serv_id;
295  info.u.record.transport_id = trans_id;
296  info.u.record.orig_net_id = onet_id;
297 
298  info.u.record.start_padding = 0;
299  info.u.record.end_padding = 0;
300 
301  info.u.record.event_triggered = event_triggered;
302  if (event_triggered)
303  {
304  info.u.record.event_id = ADB_GetEventId(event_ptr);
305  }
306 
307  /* Set recording onto the default disk */
308  info.u.record.disk_id = STB_PVRGetDefaultDisk();
309  }
310  else
311  {
312  info.type = TIMER_TYPE_ALARM;
313  info.u.alarm.service_id = serv_id;
314  info.u.alarm.transport_id = trans_id;
315  info.u.alarm.orig_net_id = onet_id;
316  }
317 
318  handle = ATMR_AddTimer(&info);
319  }
320 
321  FUNCTION_FINISH(ATMR_AddTimerForEvent);
322 
323  return(handle);
324 }
325 
332 BOOLEAN ATMR_UpdateTimerDuration(U32BIT handle, U32DHMS duration)
333 {
334  BOOLEAN retval;
335  ADB_TIMER_REC *timer;
336  U32DHMS old_duration;
337  U32DHMS time_diff;
338 
339  FUNCTION_START(ATMR_UpdateTimerDuration);
340 
341  retval = FALSE;
342 
344 
345  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
346  {
347  if (timer->dba_rec != NULL)
348  {
349  /* Once a recording has started the duration held in memory may have been adjusted,
350  * e.g. to prevent overrun if event triggered, so the value held in the database
351  * is read (as this won't have been adjusted) to calculate the difference between
352  * the old duration and the new, which can then be applied to the timer */
353  DBA_GetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DURATION, &old_duration);
354  }
355  else
356  {
357  old_duration = timer->u.record.duration;
358  }
359 
360  if (old_duration < duration)
361  {
362  /* Duration is being extended */
363  time_diff = STB_GCCalculateDHMS(duration, old_duration, CALC_SUB);
364  timer->u.record.duration = STB_GCCalculateDHMS(timer->u.record.duration, time_diff, CALC_ADD);
365  }
366  else
367  {
368  /* Duration is being shortened */
369  time_diff = STB_GCCalculateDHMS(old_duration, duration, CALC_SUB);
370  timer->u.record.duration = STB_GCCalculateDHMS(timer->u.record.duration, time_diff, CALC_SUB);
371  }
372 
373  if (timer->dba_rec != NULL)
374  {
375  /* Update the database and save the change */
376  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DURATION, duration);
377  DBA_SaveRecord(timer->dba_rec);
379  }
380 
381  retval = TRUE;
382  }
383 
385 
386  FUNCTION_FINISH(ATMR_UpdateTimerDuration);
387 
388  return(retval);
389 }
390 
397 BOOLEAN ATMR_UpdateTimer(U32BIT handle, S_TIMER_INFO *info)
398 {
399  BOOLEAN retval;
400  ADB_TIMER_REC *timer;
401 
402  FUNCTION_START(ATMR_UpdateTimer);
403 
404  retval = FALSE;
405  if ((info != NULL) && ((info->type == TIMER_TYPE_ALARM) || (info->type == TIMER_TYPE_SLEEP) ||
406  (info->type == TIMER_TYPE_PVR_RECORD) || (info->type == TIMER_TYPE_PRIVATE)))
407  {
409 
410  timer = DBDEF_FindTimerRec(handle);
411  if (timer != NULL)
412  {
413  SetTimerFields(timer, info);
414 
415  if (timer->dba_rec != NULL)
416  {
417  DBA_SaveRecord(timer->dba_rec);
418  }
419 
420  retval = TRUE;
421  }
422 
424  }
425 
426  FUNCTION_FINISH(ATMR_UpdateTimer);
427 
428  return(retval);
429 }
430 
436 BOOLEAN ATMR_DeleteTimer(U32BIT handle)
437 {
438  BOOLEAN timer_deleted;
439  ADB_TIMER_REC *timer;
440 
441  FUNCTION_START(ATMR_DeleteTimer);
442 
444 
445  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
446  {
447  timer_deleted = DeleteTimer(handle);
448  }
449  else
450  {
451  timer_deleted = FALSE;
452  }
453 
455 
456  FUNCTION_FINISH(ATMR_DeleteTimer);
457 
458  return(timer_deleted);
459 }
460 
470 BOOLEAN ATMR_GetTimerList(U32BIT **timer_list, U16BIT *list_size_ptr, E_TIMER_TYPE list_type,
471  BOOLEAN date_time_order)
472 {
473  ADB_TIMER_REC *timer;
474  U16BIT list_size, index;
475  BOOLEAN result;
476 
477  FUNCTION_START(ATMR_GetTimerList);
478 
479  result = TRUE;
480 
482 
483  /* Sort the timer list */
484  DBDEF_SortTimers(date_time_order);
485 
486  /* Find the number of timers of the type requested */
487  for (list_size = 0, timer = DBDEF_GetNextTimerRec(NULL); timer != NULL;
488  timer = DBDEF_GetNextTimerRec(timer))
489  {
490  if ((list_type == TIMER_TYPE_ALL) || (timer->type == list_type))
491  {
492  list_size++;
493  }
494  }
495 
496  if (list_size > 0)
497  {
498  *timer_list = (U32BIT *)STB_AppGetMemory(list_size * sizeof(U32BIT));
499  if (*timer_list == NULL)
500  {
501  list_size = 0;
502  result = FALSE;
503  }
504  else
505  {
506  *list_size_ptr = list_size;
507 
508  for (index = 0, timer = DBDEF_GetNextTimerRec(NULL); timer != NULL;
509  timer = DBDEF_GetNextTimerRec(timer))
510  {
511  if ((list_type == TIMER_TYPE_ALL) || (timer->type == list_type))
512  {
513  (*timer_list)[index] = timer->handle;
514  index++;
515  }
516  }
517  }
518  }
519  else
520  {
521  *timer_list = NULL;
522  *list_size_ptr = 0;
523  result = FALSE;
524  }
525 
527 
528  FUNCTION_FINISH(ATMR_GetTimerList);
529 
530  return(result);
531 }
532 
538 void ATMR_ReleaseTimerList(U32BIT *timer_list, U16BIT list_size)
539 {
540  FUNCTION_START(ATMR_ReleaseTimerList);
541 
542  USE_UNWANTED_PARAM(list_size);
543 
544  if (timer_list != NULL)
545  {
546  STB_AppFreeMemory(timer_list);
547  }
548 
549  FUNCTION_FINISH(ATMR_ReleaseTimerList);
550 }
551 
558 BOOLEAN ATMR_StartRecord(U8BIT path)
559 {
560  ADB_TIMER_REC *timer;
561  U32BIT recording_handle;
562  U32DHMS stop_date_time;
563  BOOLEAN timer_found;
564  BOOLEAN recording_started;
565 
566  FUNCTION_START(ATMR_StartRecord);
567 
568  TMR_PVR_DBG(("ATMR_StartRecord(%d)", path));
569 
571 
572  timer_found = FALSE;
573  recording_started = FALSE;
574 
575  /* Find the recording timer waiting to be started on the given path */
576  for (timer = DBDEF_GetNextTimerRec(NULL); !timer_found && (timer != NULL);
577  timer = DBDEF_GetNextTimerRec(timer))
578  {
579  if ((timer->type == TIMER_TYPE_PVR_RECORD) && timer->starting && (timer->u.record.path == path))
580  {
581  /* Found the timer related to the recording to be started */
582  timer_found = TRUE;
583 
584  /* Get starting timer values */
585  stop_date_time = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
586 
587  /* Stop timer in the future (stop >= now) */
588  if (STB_GCIsFutureDateTime(DHMS_DATE(stop_date_time), DHMS_HOUR(stop_date_time),
589  DHMS_MINS(stop_date_time), DHMS_SECS(stop_date_time)))
590  {
591  TMR_PVR_DBG(("ATMR_StartRecord: stop timer in future - start new recording"));
592 
594 
595 #ifdef INTEGRATE_HBBTV
596  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_ACQUIRING_RESOURCES);
597 #endif
598 
599  /* Start new recording */
600  if (APVR_StartNewRecording(timer->u.record.disk_id, path, timer->name,
601  timer->u.record.event_id, timer->u.record.prog_crid, timer->u.record.other_crid,
602  &recording_handle))
603  {
604  TMR_PVR_DBG(("ATMR_StartRecord(%u): Started recording \"%s\"", path, timer->name));
605 
606  /* Set the recording handle in the timer */
607  timer->u.record.recording_handle = recording_handle;
608  timer->u.record.programme_started = TRUE;
609  timer->u.record.programme_finished = FALSE;
610 
611  timer->starting = FALSE;
612  timer->started = TRUE;
613  recording_started = TRUE;
614 
615  STB_PVRRecordingSetAdditionalInfo(recording_handle, timer->u.record.additional_info);
616  STB_PVRRecordingSetStartPadding(recording_handle, GetStartPadding(timer));
617  STB_PVRRecordingSetEndPadding(recording_handle, GetEndPadding(timer));
618  STB_PVRRecordingSetLocked(recording_handle, timer->u.record.do_not_delete);
619 
620 #ifdef INTEGRATE_HBBTV
621  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_STARTED);
622 #endif
623  }
624  else
625  {
626  /* Failed to start the recording */
627  TMR_PVR_DBG(("ATMR_StartRecord(%u): Failed to start recording \"%s\"", path, timer->name));
628 
629  /* Mark the timer as not started and missed so that it's rescheduled, if possible */
630  timer->missed = TRUE;
631  timer->started = FALSE;
632  timer->starting = FALSE;
633 
634 #ifdef INTEGRATE_HBBTV
635  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_FAILED_UNKNOWN_ERROR);
636 #endif
637  }
638  }
639  else
640  {
641  /* Stop time in the past, so make sure the timer is no longer referencing a recording */
642  TMR_PVR_DBG(("ATMR_StartRecord(%u): Timer is marked as starting but the stop time is in the past", path));
643  timer->u.record.recording_handle = STB_PVR_INVALID_HANDLE;
644 
645  /* Mark the timer as not started and missed so that it's rescheduled, if possible */
646  timer->missed = TRUE;
647  timer->starting = FALSE;
648  timer->started = FALSE;
649  }
650  }
651  }
652 
654 
655  FUNCTION_FINISH(ATMR_StartRecord);
656 
657  return(recording_started);
658 }
659 
665 void ATMR_RecordingFailed(U8BIT path)
666 {
667  ADB_TIMER_REC *timer;
668  ADB_TIMER_REC *next_timer;
669 
670  FUNCTION_START(ATMR_RecordingFailed);
671 
673 
674  /* Find the timer with the given recording handle */
675  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
676  {
677  if ((timer->type == TIMER_TYPE_PVR_RECORD) && timer->starting && (timer->u.record.path == path))
678  {
679  next_timer = NULL;
680 
681  if ((timer->frequency == TIMER_FREQ_ONCE) &&
682  (STB_GetNumBytesInString(timer->u.record.prog_crid) == 0))
683  {
684  /* Timer isn't to be repeated and there's no crid so can't be rescheduled, so destroy it */
685  TMR_PVR_DBG(("ATMR_RecordingFailed(%u): Destroy timer 0x%08lx", path, timer->handle));
686 
687  DeleteTimer(timer->handle);
688 
690  }
691  else
692  {
693  /* Mark the timer as not started and missed so that it's rescheduled */
694  timer->missed = TRUE;
695  timer->starting = FALSE;
696  timer->started = FALSE;
697  }
698  }
699  else
700  {
701  next_timer = DBDEF_GetNextTimerRec(timer);
702  }
703  }
704 
706 
707  FUNCTION_FINISH(ATMR_RecordingFailed);
708 }
709 
724 BOOLEAN ATMR_InitialiseTimer(S_TIMER_INFO *timer_info, E_TIMER_TYPE timer_type, void *serv_ptr,
725  void *event_ptr)
726 {
727  BOOLEAN retval;
728  U8BIT *name;
729  U8BIT *crid;
730  U32BIT name_len;
731  U32DHMS now;
732  U32DHMS time_diff;
733 
734  FUNCTION_START(ATMR_InitialiseTimer);
735 
736  retval = FALSE;
737 
738  if (timer_info != NULL)
739  {
740  memset(timer_info, 0, sizeof(*timer_info));
741 
742  /* Set default values */
743  timer_info->type = timer_type;
744  timer_info->frequency = TIMER_FREQ_ONCE;
745 
746  retval = TRUE;
747 
748  switch (timer_info->type)
749  {
750  case TIMER_TYPE_SLEEP:
751  {
752  /* Set sleep time to now assuming this will be modified later */
753  timer_info->start_time = STB_GCNowDHMSGmt();
754  break;
755  }
756 
757  case TIMER_TYPE_ALARM:
758  {
759  timer_info->u.alarm.ramp_volume = FALSE;
760 
761  if (serv_ptr != NULL)
762  {
763  timer_info->u.alarm.change_service = TRUE;
764  ADB_GetServiceIds(serv_ptr, &timer_info->u.alarm.orig_net_id,
765  &timer_info->u.alarm.transport_id, &timer_info->u.alarm.service_id);
766  }
767  else
768  {
769  timer_info->u.alarm.change_service = FALSE;
770  }
771 
772  if (event_ptr != NULL)
773  {
774  /* Set the alarm based on the given event */
775  timer_info->start_time = ADB_GetEventStartDateTime(event_ptr);
776  if ((name = ADB_GetEventName(event_ptr)) != NULL)
777  {
778  name_len = STB_GetNumBytesInString(name);
779  if (name_len > TMR_MAX_NAME_LENGTH)
780  {
781  memcpy(timer_info->name, name, TMR_MAX_NAME_LENGTH);
782  timer_info->name[TMR_MAX_NAME_LENGTH - 1] = '\0';
783  }
784  else
785  {
786  memcpy(timer_info->name, name, name_len);
787  }
788  }
789  }
790  else
791  {
792  /* Set alarm time to now assuming this will be modified later */
793  timer_info->start_time = STB_GCNowDHMSGmt();
794  }
795  break;
796  }
797 
798  case TIMER_TYPE_PVR_RECORD:
799  {
800  timer_info->u.record.disk_id = STB_PVRGetDefaultDisk();
801 
802  if (serv_ptr != NULL)
803  {
804  ADB_GetServiceIds(serv_ptr, &timer_info->u.record.orig_net_id,
805  &timer_info->u.record.transport_id, &timer_info->u.record.service_id);
806  }
807 
808  if (event_ptr != NULL)
809  {
810  if ((name = ADB_GetEventName(event_ptr)) != NULL)
811  {
812  name_len = STB_GetNumBytesInString(name);
813  if (name_len > TMR_MAX_NAME_LENGTH)
814  {
815  memcpy(timer_info->name, name, TMR_MAX_NAME_LENGTH);
816  timer_info->name[TMR_MAX_NAME_LENGTH - 1] = '\0';
817  }
818  else
819  {
820  memcpy(timer_info->name, name, name_len);
821  }
822  }
823 
824  timer_info->u.record.event_id = ADB_GetEventId(event_ptr);
825  timer_info->u.record.event_triggered = TRUE;
826  timer_info->start_time = ADB_GetEventStartDateTime(event_ptr);
827  timer_info->u.record.duration = ADB_GetEventDuration(event_ptr);
828  timer_info->u.record.start_padding = 0;
829  timer_info->u.record.end_padding = 0;
830 
831  if (!STB_GCIsFutureDateTime(DHMS_DATE(timer_info->start_time),
832  DHMS_HOUR(timer_info->start_time), DHMS_MINS(timer_info->start_time),
833  DHMS_SECS(timer_info->start_time)))
834  {
835  /* Event has already started so the recording needs to start immediately */
836  now = STB_GCNowDHMSGmt();
837  time_diff = STB_GCCalculateDHMS(now, timer_info->start_time, CALC_SUB);
838  timer_info->start_time = now;
839  timer_info->u.record.duration = STB_GCCalculateDHMS(timer_info->u.record.duration,
840  time_diff, CALC_SUB);
841  }
842 
843  crid = ADB_GetEventFullProgrammeCrid(serv_ptr, event_ptr);
844  if (crid != NULL)
845  {
846  strncpy((char *)timer_info->u.record.prog_crid, (char *)crid, TMR_PVR_CRID_LEN_MAX);
847  STB_AppFreeMemory(crid);
848  }
849  }
850  else
851  {
852  timer_info->u.record.event_triggered = FALSE;
853 
854  /* Set record time to now and default duration of 2 hours */
855  timer_info->start_time = STB_GCNowDHMSGmt();
856  timer_info->u.record.duration = DHMS_CREATE(0, 2, 0, 0);
857  }
858  break;
859  }
860 
861  case TIMER_TYPE_PRIVATE:
862  {
863  break;
864  }
865 
866  default:
867  {
868  retval = FALSE;
869  break;
870  }
871  }
872  }
873 
874  FUNCTION_FINISH(ATMR_InitialiseTimer);
875 
876  return(retval);
877 }
878 
885 BOOLEAN ATMR_GetTimerInfo(U32BIT handle, S_TIMER_INFO *timer_info)
886 {
887  BOOLEAN retval;
888  ADB_TIMER_REC *timer;
889 
890  FUNCTION_START(ATMR_GetTimerInfo);
891 
892  retval = FALSE;
893 
895 
896  if ((timer_info != NULL) && ((timer = DBDEF_FindTimerRec(handle)) != NULL))
897  {
898  memset(timer_info, 0, sizeof(S_TIMER_INFO));
899 
900  if (timer->dba_rec == NULL)
901  {
902  timer_info->ram_only = TRUE;
903  }
904  else
905  {
906  timer_info->ram_only = FALSE;
907  }
908 
909  timer_info->type = timer->type;
910  timer_info->frequency = timer->frequency;
911  timer_info->start_time = timer->start_time;
912  memcpy(&timer_info->name[0], &timer->name[0], TMR_MAX_NAME_LENGTH);
913 
914  switch (timer->type)
915  {
916  case TIMER_TYPE_SLEEP:
917  /* No more info to be copied */
918  break;
919 
920  case TIMER_TYPE_ALARM:
921  {
922  timer_info->u.alarm.change_service = timer->u.alarm.change_service;
923  timer_info->u.alarm.orig_net_id = timer->u.alarm.orig_net_id;
924  timer_info->u.alarm.transport_id = timer->u.alarm.transport_id;
925  timer_info->u.alarm.service_id = timer->u.alarm.service_id;
926  timer_info->u.alarm.ramp_volume = timer->u.alarm.ramp_volume;
927  break;
928  }
929 
930  case TIMER_TYPE_PVR_RECORD:
931  {
932  timer_info->u.record.duration = timer->u.record.duration;
933  timer_info->u.record.event_triggered = timer->u.record.event_triggered;
934  timer_info->u.record.event_id = timer->u.record.event_id;
935  timer_info->u.record.orig_net_id = timer->u.record.orig_net_id;
936  timer_info->u.record.transport_id = timer->u.record.transport_id;
937  timer_info->u.record.service_id = timer->u.record.service_id;
938  timer_info->u.record.disk_id = timer->u.record.disk_id;
939  timer_info->u.record.recommendation = timer->u.record.recommendation;
940  timer_info->u.record.start_padding = GetStartPadding(timer);
941  timer_info->u.record.end_padding = GetEndPadding(timer);
942  timer_info->u.record.notify_time = timer->u.record.notify_time;
943  timer_info->u.record.do_not_delete = timer->u.record.do_not_delete;
944 
945  memcpy(&timer_info->u.record.prog_crid[0], &timer->u.record.prog_crid[0],
946  TMR_PVR_CRID_LEN_MAX);
947  memcpy(&timer_info->u.record.other_crid[0], &timer->u.record.other_crid[0],
948  TMR_PVR_CRID_LEN_MAX);
949  break;
950  }
951 
952  default:
953  /* Unknown or private timer */
954  break;
955  }
956 
957  retval = TRUE;
958  }
959 
961 
962  FUNCTION_FINISH(ATMR_GetTimerInfo);
963 
964  return(retval);
965 }
966 
972 void* ATMR_GetRecordService(U8BIT path)
973 {
974  ADB_TIMER_REC *timer;
975  void *s_ptr;
976 
977  FUNCTION_START(ATMR_GetRecordService);
978 
979  TMR_PVR_DBG(("ATMR_GetRecordService(%u)", path));
980 
982 
983  s_ptr = NULL;
984 
985  /* Find the recording timer on the given path */
986  for (timer = DBDEF_GetNextTimerRec(NULL); (s_ptr == NULL) && (timer != NULL);
987  timer = DBDEF_GetNextTimerRec(timer))
988  {
989  if ((timer->type == TIMER_TYPE_PVR_RECORD) && (timer->u.record.path == path))
990  {
991  /* Found the timer, get the service */
992  s_ptr = ADB_FindServiceByIds(timer->u.record.orig_net_id, timer->u.record.transport_id,
993  timer->u.record.service_id);
994  }
995  }
996 
998 
999  FUNCTION_FINISH(ATMR_GetRecordService);
1000 
1001  return(s_ptr);
1002 }
1003 
1009 U8BIT* ATMR_GetName(U32BIT handle)
1010 {
1011  ADB_TIMER_REC *timer;
1012  U8BIT *retval;
1013 
1014  FUNCTION_START(ATMR_GetName);
1015 
1017 
1018  retval = NULL;
1019 
1020  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1021  {
1022  retval = timer->name;
1023  }
1024 
1026 
1027  FUNCTION_FINISH(ATMR_GetName);
1028 
1029  return(retval);
1030 }
1031 
1036 void ATMR_SetName(U32BIT handle, U8BIT *name)
1037 {
1038  ADB_TIMER_REC *timer;
1039  U32BIT size;
1040 
1041  FUNCTION_START(ATMR_SetName);
1042 
1044 
1045  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1046  {
1047  size = strlen((char *)name) + 1;
1048  if (size >= TMR_MAX_NAME_LENGTH)
1049  {
1050  size = TMR_MAX_NAME_LENGTH - 1;
1051  }
1052  memcpy(timer->name, name, size);
1053  timer->name[size] = 0;
1054 
1055  if (timer->dba_rec != NULL)
1056  {
1057  DBA_SetFieldString(timer->dba_rec, DBA_FIELD_REC_NAME, timer->name, size);
1058  }
1059  }
1060 
1062 
1063  FUNCTION_FINISH(ATMR_SetName);
1064 }
1065 
1072 U32DHMS ATMR_GetStartDateTime(U32BIT handle)
1073 {
1074  ADB_TIMER_REC *timer;
1075  U32DHMS retval;
1076 
1077  FUNCTION_START(ATMR_GetStartDateTime);
1078 
1080 
1081  retval = 0;
1082 
1083  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1084  {
1085  retval = timer->start_time;
1086  }
1087 
1089 
1090  FUNCTION_FINISH(ATMR_GetStartDateTime);
1091 
1092  return(retval);
1093 }
1094 
1100 U32DHMS ATMR_GetDuration(U32BIT handle)
1101 {
1102  ADB_TIMER_REC *timer;
1103  U32DHMS retval;
1104 
1105  FUNCTION_START(ATMR_GetDuration);
1106 
1108 
1109  retval = 0;
1110 
1111  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1112  {
1113  retval = timer->u.record.duration;
1114  }
1115 
1117 
1118  FUNCTION_FINISH(ATMR_GetDuration);
1119 
1120  return(retval);
1121 }
1122 
1129 U32DHMS ATMR_GetEndDateTime(U32BIT handle)
1130 {
1131  ADB_TIMER_REC *timer;
1132  U32DHMS retval;
1133 
1134  FUNCTION_START(ATMR_GetEndDateTime);
1135 
1137 
1138  retval = 0;
1139 
1140  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1141  {
1142  if (timer->type == TIMER_TYPE_PVR_RECORD)
1143  {
1144  retval = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
1145  }
1146  else
1147  {
1148  retval = timer->start_time;
1149  }
1150  }
1151 
1153 
1154  FUNCTION_FINISH(ATMR_GetEndDateTime);
1155 
1156  return(retval);
1157 }
1158 
1164 E_TIMER_TYPE ATMR_GetType(U32BIT handle)
1165 {
1166  ADB_TIMER_REC *timer;
1167  E_TIMER_TYPE timer_type;
1168 
1169  FUNCTION_START(ATMR_GetType);
1170 
1172 
1173  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1174  {
1175  timer_type = timer->type;
1176  }
1177  else
1178  {
1179  timer_type = TIMER_TYPE_NONE;
1180  }
1181 
1183 
1184  FUNCTION_FINISH(ATMR_GetType);
1185 
1186  return(timer_type);
1187 }
1188 
1194 E_TIMER_FREQ ATMR_GetFrequency(U32BIT handle)
1195 {
1196  ADB_TIMER_REC *timer;
1197  E_TIMER_FREQ timer_freq;
1198 
1199  FUNCTION_START(ATMR_GetFrequency);
1200 
1202 
1203  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1204  {
1205  timer_freq = timer->frequency;
1206  }
1207  else
1208  {
1209  timer_freq = TIMER_FREQ_ONCE;
1210  }
1211 
1213 
1214  FUNCTION_FINISH(ATMR_GetFrequency);
1215 
1216  return(timer_freq);
1217 }
1218 
1224 BOOLEAN ATMR_GetChangeService(U32BIT handle)
1225 {
1226  ADB_TIMER_REC *timer;
1227  BOOLEAN change_service;
1228 
1229  FUNCTION_START(ATMR_GetChangeService);
1230 
1232 
1233  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_ALARM))
1234  {
1235  change_service = timer->u.alarm.change_service;
1236  }
1237  else
1238  {
1239  change_service = FALSE;
1240  }
1241 
1243 
1244  FUNCTION_FINISH(ATMR_GetChangeService);
1245 
1246  return(change_service);
1247 }
1248 
1254 BOOLEAN ATMR_GetRampVolume(U32BIT handle)
1255 {
1256  ADB_TIMER_REC *timer;
1257  BOOLEAN ramp_volume;
1258 
1259  FUNCTION_START(ATMR_GetRampVolume);
1260 
1262 
1263  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_ALARM))
1264  {
1265  ramp_volume = timer->u.alarm.ramp_volume;
1266  }
1267  else
1268  {
1269  ramp_volume = FALSE;
1270  }
1271 
1273 
1274  FUNCTION_FINISH(ATMR_GetRampVolume);
1275 
1276  return(ramp_volume);
1277 }
1278 
1284 U16BIT ATMR_GetEventId(U32BIT handle)
1285 {
1286  ADB_TIMER_REC *timer;
1287  U16BIT event_id;
1288 
1289  FUNCTION_START(ATMR_GetEventId);
1290 
1292 
1293  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1294  {
1295  event_id = timer->u.record.event_id;
1296  }
1297  else
1298  {
1299  event_id = 0;
1300  }
1301 
1303 
1304  FUNCTION_FINISH(ATMR_GetEventId);
1305 
1306  return(event_id);
1307 }
1308 
1315 U16BIT ATMR_GetServiceId(U32BIT handle)
1316 {
1317  ADB_TIMER_REC *timer;
1318  U16BIT service_id;
1319 
1320  FUNCTION_START(ATMR_GetServiceId);
1321 
1322  service_id = ADB_INVALID_DVB_ID;
1323 
1325 
1326  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1327  {
1328  if (timer->type == TIMER_TYPE_ALARM)
1329  {
1330  service_id = timer->u.alarm.service_id;
1331  }
1332  else if (timer->type == TIMER_TYPE_PVR_RECORD)
1333  {
1334  service_id = timer->u.record.service_id;
1335  }
1336  }
1337 
1339 
1340  FUNCTION_FINISH(ATMR_GetServiceId);
1341 
1342  return(service_id);
1343 }
1344 
1351 U16BIT ATMR_GetTransportId(U32BIT handle)
1352 {
1353  ADB_TIMER_REC *timer;
1354  U16BIT trans_id;
1355 
1356  FUNCTION_START(ATMR_GetTransportId);
1357 
1358  trans_id = ADB_INVALID_DVB_ID;
1359 
1361 
1362  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1363  {
1364  if (timer->type == TIMER_TYPE_ALARM)
1365  {
1366  trans_id = timer->u.alarm.transport_id;
1367  }
1368  else if (timer->type == TIMER_TYPE_PVR_RECORD)
1369  {
1370  trans_id = timer->u.record.transport_id;
1371  }
1372  }
1373 
1375 
1376  FUNCTION_FINISH(ATMR_GetTransportId);
1377 
1378  return(trans_id);
1379 }
1380 
1387 U16BIT ATMR_GetOriginalNetworkId(U32BIT handle)
1388 {
1389  ADB_TIMER_REC *timer;
1390  U16BIT onet_id;
1391 
1392  FUNCTION_START(ATMR_GetOriginalNetworkId);
1393 
1394  onet_id = ADB_INVALID_DVB_ID;
1395 
1397 
1398  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1399  {
1400  if (timer->type == TIMER_TYPE_ALARM)
1401  {
1402  onet_id = timer->u.alarm.orig_net_id;
1403  }
1404  else if (timer->type == TIMER_TYPE_PVR_RECORD)
1405  {
1406  onet_id = timer->u.record.orig_net_id;
1407  }
1408  }
1409 
1411 
1412  FUNCTION_FINISH(ATMR_GetOriginalNetworkId);
1413 
1414  return(onet_id);
1415 }
1416 
1422 BOOLEAN ATMR_GetMissed(U32BIT handle)
1423 {
1424  ADB_TIMER_REC *timer;
1425  BOOLEAN missed;
1426 
1427  FUNCTION_START(ATMR_GetMissed);
1428 
1430 
1431  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
1432  {
1433  missed = timer->missed;
1434  }
1435  else
1436  {
1437  missed = FALSE;
1438  }
1439 
1441 
1442  FUNCTION_FINISH(ATMR_GetMissed);
1443 
1444  return(missed);
1445 }
1446 
1453 U8BIT* ATMR_GetProgrammeCrid(U32BIT handle)
1454 {
1455  ADB_TIMER_REC *timer;
1456  U8BIT *prog_crid;
1457 
1458  FUNCTION_START(ATMR_GetProgrammeCrid);
1459 
1460  prog_crid = NULL;
1461 
1463 
1464  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1465  {
1466  if (strlen((char *)timer->u.record.prog_crid) > 0)
1467  {
1468  prog_crid = timer->u.record.prog_crid;
1469  }
1470  }
1471 
1473 
1474  FUNCTION_FINISH(ATMR_GetProgrammeCrid);
1475 
1476  return(prog_crid);
1477 }
1478 
1485 BOOLEAN ATMR_HasSeriesCrid(U32BIT handle)
1486 {
1487  ADB_TIMER_REC *timer;
1488  BOOLEAN retval;
1489 
1490  FUNCTION_START(ATMR_HasSeriesCrid);
1491 
1492  retval = FALSE;
1493 
1495 
1496  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1497  {
1498  if (!timer->u.record.recommendation &&
1499  (strlen((char *)timer->u.record.other_crid) > 0))
1500  {
1501  retval = TRUE;
1502  }
1503  }
1504 
1506 
1507  FUNCTION_FINISH(ATMR_HasSeriesCrid);
1508 
1509  return(retval);
1510 }
1511 
1518 BOOLEAN ATMR_HasRecommendationCrid(U32BIT handle)
1519 {
1520  ADB_TIMER_REC *timer;
1521  BOOLEAN retval;
1522 
1523  FUNCTION_START(ATMR_HasRecommendationCrid);
1524 
1526 
1527  retval = FALSE;
1528 
1529  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1530  {
1531  if (timer->u.record.recommendation &&
1532  (strlen((char *)timer->u.record.other_crid) > 0))
1533  {
1534  retval = TRUE;
1535  }
1536  }
1537 
1539 
1540  FUNCTION_FINISH(ATMR_HasRecommendationCrid);
1541 
1542  return(retval);
1543 }
1544 
1553 U8BIT* ATMR_GetOtherCrid(U32BIT handle)
1554 {
1555  ADB_TIMER_REC *timer;
1556  U8BIT *crid;
1557 
1558  FUNCTION_START(ATMR_GetOtherCrid);
1559 
1560  crid = NULL;
1561 
1563 
1564  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1565  {
1566  if (strlen((char *)timer->u.record.other_crid) > 0)
1567  {
1568  crid = timer->u.record.other_crid;
1569  }
1570  }
1571 
1573 
1574  FUNCTION_FINISH(ATMR_GetOtherCrid);
1575 
1576  return(crid);
1577 }
1578 
1584 U16BIT ATMR_GetDiskId(U32BIT handle)
1585 {
1586  ADB_TIMER_REC *timer;
1587  U16BIT disk_id;
1588 
1589  FUNCTION_START(ATMR_GetDiskId);
1590 
1592 
1593  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1594  {
1595  disk_id = timer->u.record.disk_id;
1596  }
1597  else
1598  {
1599  disk_id = INVALID_DISK_ID;
1600  }
1601 
1603 
1604  FUNCTION_FINISH(ATMR_GetDiskId);
1605 
1606  return(disk_id);
1607 }
1608 
1614 void ATMR_SetDiskId(U32BIT handle, U16BIT disk_id)
1615 {
1616  ADB_TIMER_REC *timer;
1617 
1618  FUNCTION_START(ATMR_SetDiskId);
1619 
1621 
1622  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1623  {
1624  timer->u.record.disk_id = disk_id;
1625 
1626  if (timer->dba_rec != NULL)
1627  {
1628  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DISKID, (U32BIT)disk_id);
1629  }
1630  }
1631 
1633 
1634  FUNCTION_FINISH(ATMR_SetDiskId);
1635 }
1636 
1643 U32BIT ATMR_GetRecordingHandle(U32BIT handle)
1644 {
1645  ADB_TIMER_REC *timer;
1646  U32BIT recording_handle;
1647 
1648  FUNCTION_START(ATMR_GetRecordingHandle);
1649 
1650  recording_handle = STB_PVR_INVALID_HANDLE;
1651 
1653 
1654  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
1655  {
1656  recording_handle = timer->u.record.recording_handle;
1657  }
1658 
1660 
1661  FUNCTION_FINISH(ATMR_GetRecordingHandle);
1662 
1663  return(recording_handle);
1664 }
1665 
1674 void ATMR_HandleTimerEvent(U32BIT handle)
1675 {
1676  ADB_TIMER_REC *timer;
1677  S_TIMER_INFO info;
1678  BOOLEAN delete_timer;
1679  BOOLEAN timers_updated;
1680  BOOLEAN stop_recording;
1681  U32BIT overrun_duration;
1682  U32DHMS start_date_time, end_date_time;
1683  U32BIT recording_handle;
1684 
1685  FUNCTION_START(ATMR_HandleTimerEvent);
1686 
1687  /* Action expired timers first so that back to back recordings will work
1688  * with any current recording being stopped before a new one is started.
1689  * Any expired timers that aren't to be rescheduled are marked for deletion */
1691 
1692  delete_timer = FALSE;
1693  timers_updated = FALSE;
1694 
1695  timer = DBDEF_FindTimerRec(handle);
1696  if (timer != NULL)
1697  {
1698  /* Check whether it's expired */
1699  if (timer->expired)
1700  {
1701  TMR_DBG(("ATMR_HandleTimerEvent: Timer 0x%08lx has expired", timer->handle));
1702 
1703  memset(&info, 0, sizeof(info));
1704 
1705  switch (timer->type)
1706  {
1707  case TIMER_TYPE_SLEEP:
1708  {
1709  /* Clear the flag that indicates the timer is to be started */
1710  timer->starting = FALSE;
1711 
1712  if (timer->frequency == TIMER_FREQ_ONCE)
1713  {
1714  /* Timer is no longer required so destroy it */
1715  delete_timer = TRUE;
1716  }
1717 
1718  /* Setup details of the timer and send an event to the app */
1719  info.type = TIMER_TYPE_SLEEP;
1720  info.start_time = timer->start_time;
1721  info.frequency = timer->frequency;
1722 
1723  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_TIMER_TRIGGERED,
1724  (void *)&info, sizeof(info));
1725  break;
1726  }
1727 
1728  case TIMER_TYPE_ALARM:
1729  {
1730  /* Clear the flag that indicates the timer is to be started */
1731  timer->starting = FALSE;
1732 
1733  if (timer->frequency == TIMER_FREQ_ONCE)
1734  {
1735  /* Timer is no longer required so destroy it */
1736  delete_timer = TRUE;
1737  }
1738 
1739  /* Setup details of the timer and send an event to the app */
1740  info.type = TIMER_TYPE_ALARM;
1741  info.start_time = timer->start_time;
1742  info.frequency = timer->frequency;
1743  memcpy(&info.name[0], &timer->name[0], sizeof(timer->name));
1744  info.u.alarm.change_service = timer->u.alarm.change_service;
1745  info.u.alarm.orig_net_id = timer->u.alarm.orig_net_id;
1746  info.u.alarm.transport_id = timer->u.alarm.transport_id;
1747  info.u.alarm.service_id = timer->u.alarm.service_id;
1748  info.u.alarm.ramp_volume = timer->u.alarm.ramp_volume;
1749 
1750  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_TIMER_TRIGGERED,
1751  (void *)&info, sizeof(info));
1752  break;
1753  }
1754 
1755  case TIMER_TYPE_PVR_RECORD:
1756  {
1757  if (timer->u.record.event_triggered)
1758  {
1759  stop_recording = FALSE;
1760 
1761  if (timer->u.record.programme_finished)
1762  {
1763  /* The programme being recorded is no longer the now event and the end
1764  * of the timer has triggered, so the recording should be stopped */
1765  stop_recording = TRUE;
1766  TMR_PVR_DBG(("Programme has finished and timer 0x%x has expired, stopping recording",
1767  timer->handle));
1768  }
1769  else
1770  {
1771  /* The timer has triggered, which will include any padding, but the end of
1772  * the programme hasn't been seen yet, so check that the recording doesn't
1773  * overrun by more than's allowed */
1774  if (ACFG_IsNordigCountry())
1775  {
1776  overrun_duration = NORDIG_EVENT_DURATION_OVERRUN;
1777  }
1778  else if (ACFG_GetCountry() == COUNTRY_CODE_UK)
1779  {
1780  overrun_duration = EVENT_DURATION_OVERRUN;
1781  }
1782  else
1783  {
1784  overrun_duration = 0;
1785  }
1786 
1787  GetActualStartEndTime(timer->start_time, timer->u.record.duration, 0,
1788  overrun_duration, &start_date_time, &end_date_time);
1789 
1790  if (!STB_GCIsFutureDateTime(DHMS_DATE(end_date_time), DHMS_HOUR(end_date_time),
1791  DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
1792  {
1793  /* Programme has overrun and now needs to be stopped */
1794  stop_recording = TRUE;
1795  TMR_PVR_DBG(("Timer 0x%x has overrun, stopping recording", timer->handle));
1796  }
1797  }
1798  }
1799  else
1800  {
1801  /* End of the timer triggers the end of recording */
1802  stop_recording = TRUE;
1803  TMR_PVR_DBG(("Timer 0x%x has expired, stopping recording", timer->handle));
1804  }
1805 
1806  if (stop_recording)
1807  {
1808  if (timer->u.record.recording_handle != STB_PVR_INVALID_HANDLE)
1809  {
1810 #ifdef INTEGRATE_HBBTV
1811  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_COMPLETED);
1812 #endif
1813  /* Stop recording */
1814  recording_handle = timer->u.record.recording_handle;
1816  stop_recording = APVR_StopRecording(recording_handle);
1818 
1819  if (stop_recording)
1820  {
1821  /* Stopping the recording may have deleted the timer,
1822  * so the timer shouldn't be referenced anymore and the timers should be saved */
1823  timers_updated = TRUE;
1824  timer = NULL;
1825  }
1826  else
1827  {
1828  if (!STB_DPIsLivePath(timer->u.record.path))
1829  {
1830  /* Reset the tuned service on the path even though the recording was not
1831  * stopped successfully for some reason. The tune state will be set to
1832  * off and guarantee a tuning will be performed for the next recording
1833  * which uses the same path */
1834  ACTL_TuneToService(timer->u.record.path, NULL, NULL, FALSE, TRUE);
1835  }
1836 
1837  /* Release the path as well */
1838  STB_DPReleasePath(timer->u.record.path, RES_OWNER_DVB);
1839  timer->u.record.path = INVALID_RES_ID;
1840  }
1841  }
1842  else
1843  {
1844  if (timer->u.record.path != INVALID_RES_ID)
1845  {
1846  /* Recording didn't start but resources need to be released */
1847  if (!STB_DPIsLivePath(timer->u.record.path))
1848  {
1849  /* Reset the tuned service on the path even the recording was not started successfully
1850  * for some reason. the tune state will be set to off and guarantee a tuning will be performed
1851  * for the next recording which use the same path */
1852  ACTL_TuneToService(timer->u.record.path, NULL, NULL, FALSE, TRUE);
1853  }
1854 
1855  STB_DPReleasePath(timer->u.record.path, RES_OWNER_DVB);
1856  timer->u.record.path = INVALID_RES_ID;
1857  }
1858  else if (timer->frequency == TIMER_FREQ_ONCE)
1859  {
1860  /* Timer is no longer required so destroy it */
1861  delete_timer = TRUE;
1862  }
1863  }
1864  }
1865 
1866  /* No event needs to be sent to the app for this timer because starting/stopping
1867  * of recording will cause events to be sent for the app to handle */
1868  break;
1869  }
1870 
1871  case TIMER_TYPE_PRIVATE:
1872  /* Private timers are handled elsewhere */
1873  break;
1874 
1875  default:
1876  TMR_DBG(("ATMR_HandleTimerEvent: Unrecognised expired timer 0x%08lx, type=0x%02x",
1877  timer->handle, timer->type));
1878  break;
1879  }
1880  }
1881 
1882  if ((timer != NULL) && delete_timer)
1883  {
1884  TMR_DBG(("ATMR_HandleTimerEvent: deleting expired timer 0x%08lx", timer->handle));
1885  DeleteTimer(timer->handle);
1886  timer = NULL;
1887 
1888  timers_updated = TRUE;
1889  }
1890 
1891  if (timer != NULL)
1892  {
1893  if (timer->starting)
1894  {
1895  switch (timer->type)
1896  {
1897  case TIMER_TYPE_PVR_RECORD:
1898  /* The recording should be started */
1899  TMR_PVR_DBG(("ATMR_HandleTimerEvent: 0x%x, start recording", timer->handle));
1900  if (ActionTimerRecStart(timer))
1901  {
1902  /* Update the state machine */
1904  }
1905 
1906  /* Timers may be updated whether the recording is started or not,
1907  * so they need to be saved */
1908  timers_updated = TRUE;
1909  break;
1910 
1911  default:
1912  /* Alarm and sleep timers shouldn't get be in this situation because they expire when started */
1913  TMR_DBG(("ATMR_HandleTimerEvent: Timer type %d (0x%08lx) is set to start but hasn't been handled",
1914  timer->type, timer->handle));
1915  break;
1916  }
1917  }
1918  }
1919  }
1920 
1922 
1923  if (timers_updated)
1924  {
1925  ADB_SaveDatabase();
1926  }
1927 
1928  FUNCTION_FINISH(ATMR_HandleTimerEvent);
1929 }
1930 
1939 BOOLEAN ATMR_CheckRecordStatus(BOOLEAN recordings_can_start, void *service)
1940 {
1941  ADB_TIMER_REC *timer;
1942  ADB_TIMER_REC *next_timer;
1943  void *s_ptr;
1944  void *now_event;
1945  S32BIT event_id;
1946  BOOLEAN timers_updated;
1947  BOOLEAN record_started;
1948 
1949  FUNCTION_START(ATMR_CheckRecordStatus);
1950 
1951  timers_updated = FALSE;
1952  record_started = FALSE;
1953 
1955 
1956  /* First check all the timers to see if any should be stopped.
1957  * This will be done when the initial now/next events are received on startup,
1958  * which will result in any timers that are no longer valid being deleted.
1959  */
1960  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
1961  {
1962  next_timer = DBDEF_GetNextTimerRec(timer);
1963 
1964  /* Make sure the timer isn't selected - user may have selected it in the timer screen */
1965  timer->selected = FALSE;
1966 
1967  /* If the timer has been started and has a valid service ID then check it */
1968  if (timer->started && (timer->type == TIMER_TYPE_PVR_RECORD) &&
1969  timer->u.record.event_triggered && (timer->u.record.event_id != 0))
1970  {
1971  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, timer->u.record.orig_net_id,
1972  timer->u.record.transport_id, timer->u.record.service_id);
1973  if (((service == NULL) && (s_ptr != NULL)) || (s_ptr == service))
1974  {
1975  /* Check the service's now event to see whether it's the same as the timer's event */
1976  ADB_GetNowNextEvents(s_ptr, &now_event, NULL);
1977 
1978  if (now_event != NULL)
1979  {
1980  if ((timer->u.record.event_id != ADB_GetEventId(now_event)) &&
1981  timer->u.record.programme_started)
1982  {
1983  if (!timer->u.record.programme_finished)
1984  {
1985  TMR_PVR_DBG(("%s: Programme for timer 0x%x has finished", __FUNCTION__, timer->handle));
1986  timer->u.record.programme_finished = TRUE;
1987  }
1988 
1989  timers_updated |= HasTimerExpired(timer->handle);
1990  }
1991 
1992  ADB_ReleaseEventData(now_event);
1993  }
1994  }
1995  }
1996  }
1997 
1998  /* Go through the timers and delete any that are selected (marked for deletion) */
1999  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
2000  {
2001  next_timer = DBDEF_GetNextTimerRec(timer);
2002 
2003  if (timer->selected)
2004  {
2005  /* Delete marked timer */
2006  TMR_PVR_DBG(("%s: deleting expired timer 0x%08x", __FUNCTION__, timer->handle));
2007  DeleteTimer(timer->handle);
2008  timers_updated = TRUE;
2009  }
2010  }
2011 
2012  /* Check whether any now events should start a recording */
2013  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = DBDEF_GetNextTimerRec(timer))
2014  {
2015  /* Check whether the timer is associated with an event and whether that event has now started */
2016  if ((timer->type == TIMER_TYPE_PVR_RECORD) && !timer->missed && !timer->expired &&
2017  timer->u.record.event_triggered && !timer->u.record.programme_started)
2018  {
2019  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, timer->u.record.orig_net_id,
2020  timer->u.record.transport_id, timer->u.record.service_id);
2021  if (s_ptr != NULL)
2022  {
2023  ADB_GetNowNextEvents(s_ptr, &now_event, NULL);
2024 
2025  if (now_event != NULL)
2026  {
2027  event_id = ADB_GetEventId(now_event);
2028  if (timer->u.record.event_id == event_id)
2029  {
2030  TMR_PVR_DBG(("%s: Programme for timer 0x%x has started", __FUNCTION__, timer->handle));
2031  timer->u.record.programme_started = TRUE;
2032  }
2033 
2034  ADB_ReleaseEventData(now_event);
2035  }
2036  }
2037  }
2038 
2039  /* If the timer hasn't already been started then check whether it now needs to */
2040  if ((timer->type == TIMER_TYPE_PVR_RECORD) && !timer->started && !timer->missed &&
2041  (!timer->starting || (timer->u.record.path == INVALID_RES_ID)))
2042  {
2043  s_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID, timer->u.record.orig_net_id,
2044  timer->u.record.transport_id, timer->u.record.service_id);
2045  if (s_ptr != NULL)
2046  {
2047  if (!timer->u.record.event_triggered)
2048  {
2049  timers_updated |= StartRecordTimer(timer, recordings_can_start, &record_started);
2050  }
2051  else
2052  {
2053  ADB_GetNowNextEvents(s_ptr, &now_event, NULL);
2054 
2055  if (now_event != NULL)
2056  {
2057  /* The recording can be started if the 'now' event is the one to be recorded */
2058  if (timer->u.record.event_id == ADB_GetEventId(now_event))
2059  {
2060  if (recordings_can_start)
2061  {
2062  TMR_PVR_DBG(("%s: Timer 0x%x, start recording for event %lu @ %02u:%02u:%02u",
2063  __FUNCTION__, timer->handle, timer->u.record.event_id,
2064  DHMS_HOUR(timer->start_time), DHMS_MINS(timer->start_time),
2065  DHMS_SECS(timer->start_time)));
2066  }
2067 
2068  timers_updated |= StartRecordTimer(timer, recordings_can_start, &record_started);
2069  }
2070 
2071  ADB_ReleaseEventData(now_event);
2072  }
2073  }
2074  }
2075 #ifdef TMR_DEBUG
2076  else
2077  {
2078  TMR_PVR_DBG(("ATMR_CheckRecordStatus: Can't find service 0x%04x/0x%04x/0x%04x",
2079  timer->u.record.orig_net_id, timer->u.record.transport_id, timer->u.record.service_id));
2080  }
2081 #endif
2082  }
2083  }
2084 
2085  if (timers_updated)
2086  {
2087  ADB_SaveDatabase();
2088  }
2089 
2091 
2092  FUNCTION_FINISH(ATMR_CheckRecordStatus);
2093 
2094  return(record_started);
2095 }
2096 
2103 {
2104  ADB_TIMER_REC *timer;
2105  ADB_TIMER_REC *next_timer;
2106  void *serv_ptr;
2107  void *event_ptr;
2108  U32DHMS event_start;
2109  U32DHMS event_duration;
2110  U32DHMS end_time;
2111  U32DHMS rec_end_time;
2112  BOOLEAN updated;
2113  BOOLEAN event_missed;
2114  S_ALT_EVENT_DATA alt_event_data;
2115 
2116  FUNCTION_START(ATMR_EitUpdated);
2117 
2119 
2120  updated = FALSE;
2121 
2122  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
2123  {
2124  next_timer = DBDEF_GetNextTimerRec(timer);
2125 
2126  if (timer->type == TIMER_TYPE_PVR_RECORD)
2127  {
2128  /* Only check the timer if it hasn't already expired */
2129  if (!timer->expired)
2130  {
2131  if ((timer->u.record.service_id != 0) && (timer->u.record.event_id != 0))
2132  {
2133  serv_ptr = DBDEF_FindServiceRecByIds(NULL, ADB_INVALID_DVB_ID,
2134  timer->u.record.orig_net_id, timer->u.record.transport_id,
2135  timer->u.record.service_id);
2136  if (serv_ptr != NULL)
2137  {
2138  /* Check if the timer is already marked as missed */
2139  if (timer->missed)
2140  {
2141  event_missed = TRUE;
2142  }
2143  else
2144  {
2145  event_missed = FALSE;
2146 
2147  /* Find the event from the service's EIT list */
2148  event_ptr = ADB_GetEvent(serv_ptr, timer->u.record.event_id);
2149  if (event_ptr == NULL)
2150  {
2151  /* Event not found in the schedule */
2152  TMR_PVR_DBG(("ATMR_EitUpdated: Event %lu on %lu @ %02lu:%02lu not found in schedule",
2153  timer->u.record.event_id, DHMS_DATE(timer->start_time),
2154  DHMS_HOUR(timer->start_time), DHMS_MINS(timer->start_time)));
2155 
2156  event_missed = TRUE;
2157  }
2158  else
2159  {
2160  /* The event may still be in the schedule if it's already past,
2161  * so check that the event isn't already over */
2162  event_start = ADB_GetEventStartDateTime(event_ptr);
2163  event_duration = ADB_GetEventDuration(event_ptr);
2164  end_time = STB_GCCalculateDHMS(event_start, event_duration, CALC_ADD);
2165 
2166  if (!timer->started &&
2167  !STB_GCIsFutureDateTime(DHMS_DATE(end_time), DHMS_HOUR(end_time),
2168  DHMS_MINS(end_time), DHMS_SECS(end_time)))
2169  {
2170  /* Event is in the past */
2171  event_missed = TRUE;
2172  TMR_PVR_DBG(("ATMR_EitUpdated: Event %d ending on %d @ %02d:%02d has been missed",
2173  timer->u.record.event_id, DHMS_DATE(end_time), DHMS_HOUR(end_time),
2174  DHMS_MINS(end_time)));
2175  }
2176  else
2177  {
2178  /* Check that the start time or duration hasn't changed.
2179  * The actual start time may be different from the scheduled time if the
2180  * recording is event triggered and has started early, so only stop the
2181  * recording if this isn't the case */
2182  if ((timer->start_time != event_start) &&
2183  (timer->u.record.event_triggered && !timer->u.record.programme_started))
2184  {
2185  if ((timer->u.record.recording_handle != STB_PVR_INVALID_HANDLE) &&
2186  (event_start > timer->start_time))
2187  {
2188  /* The event has been rescheduled to a later time, but the
2189  * recording has already started, which will either be due to
2190  * start padding, or the recording is time trigegred and the
2191  * start time for the event has passed. In either case, the
2192  * recording should be stopped and deleted and the timer reset so
2193  * it triggers again at the new time to restart the recording */
2194  if (!STB_DPIsLivePath(timer->u.record.path))
2195  {
2197  STB_DPStopSI(timer->u.record.path);
2199  }
2200 
2201  STB_DPStopRecording(timer->u.record.path);
2202  STB_DPReleasePath(timer->u.record.path, RES_OWNER_DVB);
2203  timer->u.record.path = INVALID_RES_ID;
2204 
2205  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION,
2206  EV_PVR_RECORDING_STOPPED, &timer->u.record.recording_handle,
2207  sizeof(timer->u.record.recording_handle));
2208 
2209  APVR_DeleteRecording(timer->u.record.recording_handle);
2210  timer->u.record.recording_handle = STB_PVR_INVALID_HANDLE;
2211 
2212  timer->starting = FALSE;
2213  timer->started = FALSE;
2214  timer->u.record.notified = FALSE;
2215  }
2216 
2217  timer->start_time = event_start;
2218  if (timer->dba_rec != NULL)
2219  {
2220  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_STARTTIME, event_start);
2221  }
2222  updated = TRUE;
2223  }
2224 
2225  if (timer->u.record.duration != event_duration)
2226  {
2227  /* The duration will be different if the event wasn't recorded
2228  * from the beginning, so check the end time to decide whether
2229  * the duration has actually been changed */
2230  rec_end_time = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
2231 
2232  if (end_time != rec_end_time)
2233  {
2234  timer->u.record.duration = event_duration;
2235  if (timer->dba_rec != NULL)
2236  {
2237  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DURATION, event_duration);
2238  }
2239  updated = TRUE;
2240  }
2241  }
2242 
2243 #ifdef INTEGRATE_HBBTV
2244  if (updated)
2245  {
2246  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_UPDATED);
2247  }
2248 #endif
2249  }
2250 
2251  ADB_ReleaseEventData(event_ptr);
2252  }
2253  }
2254 
2255  if (event_missed)
2256  {
2257  /* Has the event been completely missed? */
2258  end_time = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
2259 
2260  if (!STB_GCIsFutureDateTime(DHMS_DATE(end_time), DHMS_HOUR(end_time),
2261  DHMS_MINS(end_time), 0))
2262  {
2263  /* Recording has been completely missed, check whether there's an
2264  * alternate instance that can be recorded instead */
2265  if (STB_GetNumBytesInString(timer->u.record.prog_crid) > 0)
2266  {
2267  /* Search for an alternate instance of the event.
2268  * Searching the EIT data for alternative events can take a long time,
2269  * so if the event isn't already marked as missed, mark it as missed,
2270  * inform the user via a message and pass the info required to look
2271  * for an alternative event to another background task */
2272  if (!timer->missed)
2273  {
2274  TMR_PVR_DBG(("Missed event on %u @ %02u:%02u and ends on %d @ %02d:%02d (today=%d)\n",
2275  DHMS_DATE(timer->start_time), DHMS_HOUR(timer->start_time),
2276  DHMS_MINS(timer->start_time), DHMS_DATE(end_time), DHMS_HOUR(end_time),
2277  DHMS_MINS(end_time), STB_GCGetGMTDate()));
2278 
2279  /* Mark the recording as missed */
2280  timer->missed = TRUE;
2281  if (timer->dba_rec != NULL)
2282  {
2283  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_MISSED, timer->missed);
2284  }
2285 
2286  updated = TRUE;
2287 #ifdef INTEGRATE_HBBTV
2288  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_UPDATED);
2289 #endif
2290  }
2291 
2292  /* Setup the data to passed to the background task */
2293  alt_event_data.timer_handle = timer->handle;
2294  alt_event_data.is_recommendation = timer->u.record.recommendation;
2295  alt_event_data.do_not_delete = timer->u.record.do_not_delete;
2296  strncpy((char *)alt_event_data.prog_crid, (char *)timer->u.record.prog_crid, TMR_PVR_CRID_LEN_MAX);
2297  strncpy((char *)alt_event_data.other_crid, (char *)timer->u.record.other_crid, TMR_PVR_CRID_LEN_MAX);
2298 
2299  STB_OSWriteQueue(alt_event_queue, (void *)&alt_event_data,
2300  sizeof(alt_event_data), TIMEOUT_NOW);
2301  }
2302  else
2303  {
2304  /* Mark the recording as missed */
2305  if (!timer->missed)
2306  {
2307  TMR_PVR_DBG(("Missed event on %u @ %02u:%02u and ends on %d @ %02d:%02d (today=%d)\n",
2308  DHMS_DATE(timer->start_time), DHMS_HOUR(timer->start_time),
2309  DHMS_MINS(timer->start_time), DHMS_DATE(end_time), DHMS_HOUR(end_time),
2310  DHMS_MINS(end_time), STB_GCGetGMTDate()));
2311 
2312  /* As it isn't possible to find an alternative for the event, the timer
2313  * should be deleted now a message has been added */
2314  DeleteTimer(timer->handle);
2315  }
2316  }
2317  }
2318  }
2319  }
2320  else
2321  {
2322  /* Service not found, delete the timer */
2323  TMR_PVR_DBG(("ATMR_EitUpdated: Service not found, timer deleted!!"));
2324  DeleteTimer(timer->handle);
2325  }
2326  }
2327  }
2328  }
2329  }
2330 
2332 
2333  if (updated)
2334  {
2335  ADB_SaveDatabase();
2336  }
2337 
2338  FUNCTION_FINISH(ATMR_EitUpdated);
2339 }
2340 
2346 U32BIT ATMR_FindRecordingTimer(U32BIT recording_handle)
2347 {
2348  U32BIT handle;
2349  ADB_TIMER_REC *timer;
2350 
2351  FUNCTION_START(ATMR_FindRecordingTimer);
2352 
2353  handle = INVALID_TIMER_HANDLE;
2354 
2356 
2357  /* Find the timer with the given recording handle */
2358  timer = DBDEF_GetNextTimerRec(NULL);
2359  while (timer != NULL)
2360  {
2361  if ((timer->type == TIMER_TYPE_PVR_RECORD) &&
2362  (timer->u.record.recording_handle == recording_handle))
2363  {
2364  handle = timer->handle;
2365  break;
2366  }
2367 
2368  timer = DBDEF_GetNextTimerRec(timer);
2369  }
2370 
2372 
2373  FUNCTION_FINISH(ATMR_FindRecordingTimer);
2374 
2375  return(handle);
2376 }
2377 
2382 void ATMR_DeleteRecordingTimer(U32BIT recording_handle)
2383 {
2384  ADB_TIMER_REC *timer;
2385  ADB_TIMER_REC *next_timer;
2386 
2387  FUNCTION_START(ATMR_DeleteRecordingTimer);
2388 
2390 
2391  /* Find the timer with the given recording handle */
2392  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
2393  {
2394  next_timer = DBDEF_GetNextTimerRec(timer);
2395 
2396  if (timer->u.record.recording_handle == recording_handle)
2397  {
2398  if (timer->frequency == TIMER_FREQ_ONCE)
2399  {
2400  /* Destroy timer */
2401  TMR_PVR_DBG(("ATMR_DeleteRecordingTimer: Destroy timer 0x%08lx", timer->handle));
2402  DeleteTimer(timer->handle);
2403 
2404  /* Ensure any timer changes are saved to NVM */
2405  ADB_SaveDatabase();
2406  }
2407  else
2408  {
2409  /* Clear recording handle for next recording */
2410  timer->u.record.recording_handle = STB_PVR_INVALID_HANDLE;
2411  TMR_PVR_DBG(("ATMR_DeleteRecordingTimer: timer periodic, do not destroy, clear recording handle"));
2412  }
2413  break;
2414  }
2415  }
2416 
2418 
2419  FUNCTION_FINISH(ATMR_DeleteRecordingTimer);
2420 }
2421 
2432 U8BIT ATMR_GetNumSimultaneousRecordings(U8BIT max_recordings, U32DHMS start_date_time,
2433  U32DHMS end_date_time, U32BIT **conflicting_timers)
2434 {
2435  U8BIT num_recordings;
2436 
2437  FUNCTION_START(ATMR_GetNumSimultaneousRecordings);
2438 
2440 
2441  num_recordings = GetNumSimultaneousRecordings(INVALID_TIMER_HANDLE, ADB_INVALID_DVB_ID,
2442  ADB_INVALID_DVB_ID, ADB_INVALID_DVB_ID, max_recordings, start_date_time, end_date_time, FALSE, FALSE,
2443  conflicting_timers);
2444 
2446 
2447  FUNCTION_FINISH(ATMR_GetNumSimultaneousRecordings);
2448 
2449  return(num_recordings);
2450 }
2451 
2466 void* ATMR_RecordEvent(void *serv_ptr, void *event_ptr, U8BIT *prog_crid, U8BIT *other_crid,
2467  BOOLEAN is_recommendation, BOOLEAN check_alternatives, BOOLEAN do_not_delete)
2468 {
2469  S_TIMER_INFO timer_info;
2470  U32DHMS start_time;
2471  U32DHMS end_time;
2472  U8BIT num_recordings;
2473  void *result_event_ptr = event_ptr;
2474 #ifdef TMR_PVR_DEBUG
2475  U8BIT *event_prog_crid;
2476 #endif
2477  U32BIT *conflicts;
2478 
2479  FUNCTION_START(ATMR_RecordEvent);
2480 
2481  /* Check whether this recording is possible */
2482  start_time = ADB_GetEventStartDateTime(event_ptr);
2483  end_time = ADB_GetEventEndDateTime(event_ptr);
2484 
2485  num_recordings = ATMR_GetNumSimultaneousRecordings(STB_HWGetNumRecorders(), start_time,
2486  end_time, &conflicts);
2487 
2488  if (num_recordings == STB_HWGetNumRecorders())
2489  {
2490  /* Recording this event isn't possible */
2491  if ((prog_crid != NULL) && check_alternatives)
2492  {
2493  /* Check whether there are any alternatives */
2494  result_event_ptr = ADB_FindEventFromCrid(prog_crid, event_ptr, &serv_ptr);
2495  }
2496  else
2497  {
2498  /* The event can't be recorded and as it doesn't have a programme CRID
2499  * so no alternatives can be searched for */
2500  result_event_ptr = NULL;
2501  }
2502  }
2503 
2504  if (result_event_ptr == NULL)
2505  {
2506  U16BIT serv_id, trans_id, onet_id;
2507  U8BIT t, n;
2508  void *s_ptr, *event;
2509  U8BIT *p_crid, *o_crid;
2510 
2511  for (t = 0; t < num_recordings; t++)
2512  {
2513  serv_id = ATMR_GetServiceId(conflicts[t]);
2514  trans_id = ATMR_GetTransportId(conflicts[t]);
2515  onet_id = ATMR_GetOriginalNetworkId(conflicts[t]);
2516 
2517  p_crid = NULL;
2518  o_crid = NULL;
2519 
2520  s_ptr = ADB_FindServiceByIds(onet_id, trans_id, serv_id);
2521  if (s_ptr != NULL)
2522  {
2523  event = ADB_GetEvent(s_ptr, ATMR_GetEventId(conflicts[t]));
2524  if (event != NULL)
2525  {
2526  p_crid = ADB_GetEventProgrammeCrid(s_ptr, event);
2527  if ((p_crid != NULL) && check_alternatives)
2528  {
2529  /* Check whether there are any alternatives */
2530  event = ADB_FindEventFromCrid(p_crid, event, &s_ptr);
2531  if (event != NULL)
2532  {
2533  start_time = ADB_GetEventStartDateTime(event);
2534  end_time = ADB_GetEventEndDateTime(event);
2535 
2537  end_time, NULL);
2538  if (n < STB_HWGetNumRecorders())
2539  {
2540  #ifdef TMR_PVR_DEBUG
2541  event_prog_crid = ADB_GetEventFullProgrammeCrid(s_ptr, event);
2542 
2543  TMR_PVR_DBG((" Moving programmed event to \"%s\", start: %d:%d.%d, len: %d.%d, event=%d",
2544  ADB_GetEventName(event), ADB_GetEventStartDate(event),
2547  ADB_GetEventId(event)));
2548  if (event_prog_crid != NULL)
2549  {
2550  TMR_PVR_DBG((" prog CRID=\"%s\"", event_prog_crid));
2551  STB_AppFreeMemory(event_prog_crid);
2552  }
2553  #endif
2554 
2555  ATMR_InitialiseTimer(&timer_info, TIMER_TYPE_PVR_RECORD, s_ptr, event);
2556 
2557  o_crid = ADB_GetEventSeriesCrid(0, s_ptr, event);
2558  if (o_crid != NULL)
2559  {
2560  strncpy((char *)timer_info.u.record.other_crid, (char *)o_crid, TMR_PVR_CRID_LEN_MAX);
2561  STB_AppFreeMemory(o_crid);
2562  }
2563 
2564  timer_info.u.record.recommendation = ATMR_HasRecommendationCrid(conflicts[t]);
2565  timer_info.u.record.disk_id = STB_PVRGetDefaultDisk();
2566  timer_info.u.record.event_triggered = TRUE;
2567  timer_info.u.record.do_not_delete = do_not_delete;
2568  timer_info.u.record.start_padding = 0;
2569  timer_info.u.record.end_padding = 0;
2570 
2571  /* Add the timer to record the event */
2572  ATMR_AddTimer(&timer_info);
2573 
2574  /* Now remove the conflicting timer */
2575  ATMR_DeleteTimer(conflicts[t]);
2576 
2577  result_event_ptr = event_ptr;
2578  }
2579  }
2580  }
2581  }
2582  }
2583 
2584  if (p_crid != NULL)
2585  {
2586  STB_AppFreeMemory(p_crid);
2587  }
2588 
2589  if (result_event_ptr != NULL)
2590  {
2591  break; /* Conflict resolved */
2592  }
2593  }
2594  }
2595 
2596  if (result_event_ptr != NULL)
2597  {
2598  ATMR_InitialiseTimer(&timer_info, TIMER_TYPE_PVR_RECORD, serv_ptr, result_event_ptr);
2599 
2600  if (other_crid != NULL)
2601  {
2602  strncpy((char *)timer_info.u.record.other_crid, (char *)other_crid, TMR_PVR_CRID_LEN_MAX);
2603  }
2604 
2605  timer_info.u.record.recommendation = is_recommendation;
2606  timer_info.u.record.disk_id = STB_PVRGetDefaultDisk();
2607  timer_info.u.record.event_triggered = TRUE;
2608  timer_info.u.record.do_not_delete = do_not_delete;
2609 
2610 #ifdef TMR_PVR_DEBUG
2611  TMR_PVR_DBG((" Recording event \"%s\", start: %d:%d.%d, len: %d.%d, event=%d",
2612  ADB_GetEventName(result_event_ptr), DHMS_DATE(timer_info.start_time),
2613  DHMS_HOUR(timer_info.start_time), DHMS_MINS(timer_info.start_time),
2614  DHMS_HOUR(timer_info.u.record.duration), DHMS_MINS(timer_info.u.record.duration),
2615  timer_info.u.record.event_id));
2616 
2617  event_prog_crid = ADB_GetEventFullProgrammeCrid(serv_ptr, result_event_ptr);
2618  if (event_prog_crid != NULL)
2619  {
2620  TMR_PVR_DBG((" prog CRID=\"%s\"", event_prog_crid));
2621  STB_AppFreeMemory(event_prog_crid);
2622  }
2623 #endif
2624 
2625  /* Add the timer to record the event */
2626  ATMR_AddTimer(&timer_info);
2627  }
2628 
2629  if (conflicts != NULL)
2630  {
2631  STB_AppFreeMemory(conflicts);
2632  }
2633 
2634  ADB_SaveDatabase();
2635 
2636  FUNCTION_FINISH(ATMR_RecordEvent);
2637 
2638  return(result_event_ptr);
2639 }
2640 
2653 BOOLEAN ATMR_RecordSplitEvent(void *serv_ptr, U8BIT *prog_crid, U32DHMS start_date_time,
2654  BOOLEAN do_not_delete, BOOLEAN search_forward)
2655 {
2656  void *event_ptr;
2657  void *alt_event_ptr;
2658  U32DHMS limit_date_time;
2659  U32DHMS end_date_time;
2660  U32DHMS next_date_time;
2661  U32DHMS event_start_time;
2662  U8BIT *event_crid;
2663  U16BIT service_id;
2664  BOOLEAN continue_search;
2665  BOOLEAN event_recorded;
2666 
2667  FUNCTION_START(ATMR_RecordSplitEvent);
2668 
2669  event_recorded = FALSE;
2670 
2671  service_id = ADB_GetServiceId(serv_ptr);
2672 
2673  if (search_forward)
2674  {
2675  /* Calculate the time beyond which searching should be stopped */
2676  limit_date_time = STB_GCCalculateDHMS(start_date_time, DHMS_CREATE(0, 3, 0, 0), CALC_ADD);
2677 
2678  next_date_time = start_date_time;
2679  continue_search = TRUE;
2680 
2681  while (continue_search)
2682  {
2683  TMR_PVR_DBG(("--- Searching for event after %d:%02d.%02d", DHMS_DATE(next_date_time),
2684  DHMS_HOUR(next_date_time), DHMS_MINS(next_date_time)));
2685 
2686  event_ptr = ADB_GetLaterEvent(serv_ptr, DHMS_DATE(next_date_time),
2687  DHMS_HOUR(next_date_time), DHMS_MINS(next_date_time));
2688 
2689  if (event_ptr != NULL)
2690  {
2691  /* The event found must start within 3 hours of the previous event */
2692  event_start_time = ADB_GetEventStartDateTime(event_ptr);
2693 
2694  if (limit_date_time >= event_start_time)
2695  {
2696  event_crid = ADB_GetEventFullProgrammeCrid(serv_ptr, event_ptr);
2697 #ifdef TMR_PVR_DEBUG
2698  if (event_crid != NULL)
2699  {
2700  TMR_PVR_DBG((" Found event in time limit, crid=\"%s\"", event_crid));
2701  }
2702  else
2703  {
2704  TMR_PVR_DBG((" Found event in time limit"));
2705  }
2706 #endif
2707 
2708  /* Check that the CRIDs are the same */
2709  if ((event_crid != NULL) && (STB_CompareStringsIgnoreCase(event_crid, prog_crid) == 0))
2710  {
2711  /* Event has the same CRID and is within 3 hours of the previous event.
2712  * Make sure it isn't already booked for recording */
2713  if (!ATMR_FindTimerFromCridAndEvent(prog_crid, service_id, ADB_GetEventId(event_ptr)))
2714  {
2715  TMR_PVR_DBG((" Recording event @ %d:%02d.%02d, crid=\"%s\"",
2716  ADB_GetEventStartDate(event_ptr), ADB_GetEventStartHour(event_ptr),
2717  ADB_GetEventStartMin(event_ptr), event_crid));
2718  TMR_PVR_DBG((" Search forward: Recording event @ %d:%02d.%02d, crid=\"%s\", event_id=%u\n",
2719  ADB_GetEventStartDate(event_ptr), ADB_GetEventStartHour(event_ptr),
2720  ADB_GetEventStartMin(event_ptr), event_crid, ADB_GetEventId(event_ptr)));
2721 
2722  /* Book this event for recording */
2723  alt_event_ptr = ATMR_RecordEvent(serv_ptr, event_ptr, prog_crid, NULL,
2724  FALSE, FALSE, do_not_delete);
2725  if (alt_event_ptr != NULL)
2726  {
2727  event_recorded = TRUE;
2728 
2729  if (alt_event_ptr != event_ptr)
2730  {
2731  /* An alternative event has been used so release the original */
2732  ADB_ReleaseEventData(event_ptr);
2733  event_ptr = alt_event_ptr;
2734  }
2735 
2736  /* Search for additional split events before and after this part */
2737  ATMR_RecordSplitEvent(serv_ptr, prog_crid,
2738  ADB_GetEventStartDateTime(event_ptr), do_not_delete, FALSE);
2739 
2740  ATMR_RecordSplitEvent(serv_ptr, prog_crid,
2741  ADB_GetEventStartDateTime(event_ptr), do_not_delete, TRUE);
2742  }
2743  else
2744  {
2745  /* Failed to record this part of the split event, so.... ? */
2746  }
2747  }
2748  }
2749 
2750  /* Continue the search after this event */
2751  next_date_time = STB_GCCalculateDHMS(event_start_time,
2752  ADB_GetEventDuration(event_ptr), CALC_ADD);
2753 
2754  if (event_crid != NULL)
2755  {
2756  STB_AppFreeMemory(event_crid);
2757  }
2758  }
2759  else
2760  {
2761  /* Event found is outside of the 3 hour limit */
2762  continue_search = FALSE;
2763  TMR_PVR_DBG((" No more events within 3 hours"));
2764  }
2765 
2766  ADB_ReleaseEventData(event_ptr);
2767  }
2768  else
2769  {
2770  /* No later events found so stop the search but save the CRID so that when the
2771  * EIT is updated it can be checked for new events appearing */
2772  continue_search = FALSE;
2773  TMR_PVR_DBG((" No more events"));
2774  }
2775  }
2776  }
2777  else /* Search backwards through the EPG */
2778  {
2779  /* Calculate the time beyond which searching should be stopped */
2780  limit_date_time = STB_GCCalculateDHMS(start_date_time, DHMS_CREATE(0, 3, 0, 0), CALC_SUB);
2781 
2782  next_date_time = start_date_time;
2783  continue_search = TRUE;
2784 
2785  while (continue_search)
2786  {
2787  TMR_PVR_DBG(("--- Searching for event before %d:%02d.%02d", DHMS_DATE(next_date_time),
2788  DHMS_HOUR(next_date_time), DHMS_MINS(next_date_time)));
2789 
2790  event_ptr = ADB_GetEarlierEvent(serv_ptr, DHMS_DATE(next_date_time),
2791  DHMS_HOUR(next_date_time), DHMS_MINS(next_date_time));
2792 
2793  if (event_ptr != NULL)
2794  {
2795  /* The event found must finish within 3 hours of the previous event */
2796  event_start_time = ADB_GetEventStartDateTime(event_ptr);
2797  end_date_time = STB_GCCalculateDHMS(event_start_time, ADB_GetEventDuration(event_ptr), CALC_ADD);
2798 
2799  if (limit_date_time <= end_date_time)
2800  {
2801  event_crid = ADB_GetEventFullProgrammeCrid(serv_ptr, event_ptr);
2802 #ifdef TMR_PVR_DEBUG
2803  if (event_crid != NULL)
2804  {
2805  TMR_PVR_DBG((" Found event in time limit, crid=\"%s\"", event_crid));
2806  }
2807  else
2808  {
2809  TMR_PVR_DBG((" Found event in time limit"));
2810  }
2811 #endif
2812 
2813  /* Check that the CRIDs are the same */
2814  if ((event_crid != NULL) && (STB_CompareStringsIgnoreCase(event_crid, prog_crid) == 0))
2815  {
2816  /* Event has the same CRID and is within 3 hours of the previous event.
2817  * Make sure it isn't already booked for recording */
2818  if (!ATMR_FindTimerFromCridAndEvent(prog_crid, service_id, ADB_GetEventId(event_ptr)))
2819  {
2820  TMR_PVR_DBG((" Recording event @ %d:%02d.%02d, crid=\"%s\"",
2821  ADB_GetEventStartDate(event_ptr), ADB_GetEventStartHour(event_ptr),
2822  ADB_GetEventStartMin(event_ptr), event_crid));
2823  TMR_PVR_DBG((" Search backward: Recording event @ %d:%02d.%02d, crid=\"%s\", event_id=%u\n",
2824  ADB_GetEventStartDate(event_ptr), ADB_GetEventStartHour(event_ptr),
2825  ADB_GetEventStartMin(event_ptr), event_crid, ADB_GetEventId(event_ptr)));
2826 
2827  /* Book this event for recording */
2828  alt_event_ptr = ATMR_RecordEvent(serv_ptr, event_ptr, prog_crid, NULL,
2829  do_not_delete, FALSE, FALSE);
2830  if (alt_event_ptr != NULL)
2831  {
2832  event_recorded = TRUE;
2833  if (alt_event_ptr != event_ptr)
2834  {
2835  /* An alternative event has been used so release the original */
2836  ADB_ReleaseEventData(event_ptr);
2837  event_ptr = alt_event_ptr;
2838  }
2839 
2840  /* Search for additional split events before and after this part */
2841  ATMR_RecordSplitEvent(serv_ptr, prog_crid,
2842  ADB_GetEventStartDateTime(event_ptr), do_not_delete, FALSE);
2843 
2844  ATMR_RecordSplitEvent(serv_ptr, prog_crid,
2845  ADB_GetEventStartDateTime(event_ptr), do_not_delete, TRUE);
2846  }
2847  else
2848  {
2849  /* Failed to record this part of the split event, so......? */
2850  }
2851  }
2852  }
2853 
2854  /* Continue the search before this event */
2855  next_date_time = ADB_GetEventStartDateTime(event_ptr);
2856 
2857  if (event_crid != NULL)
2858  {
2859  STB_AppFreeMemory(event_crid);
2860  }
2861  }
2862  else
2863  {
2864  /* Event found is outside of the 3 hour limit */
2865  continue_search = FALSE;
2866  TMR_PVR_DBG((" No events within 3 hours"));
2867  }
2868 
2869  ADB_ReleaseEventData(event_ptr);
2870  }
2871  else
2872  {
2873  /* No earlier events found so stop the search but save the CRID so that when the
2874  * EIT is updated it can be checked for new events appearing */
2875  continue_search = FALSE;
2876  TMR_PVR_DBG((" No more events"));
2877  }
2878  }
2879  }
2880 
2881  FUNCTION_FINISH(ATMR_RecordSplitEvent);
2882 
2883  return(event_recorded);
2884 }
2885 
2895 U32BIT ATMR_GetFirstWakeupTime(U32DHMS *date_time, U16BIT *onet_id, U16BIT *trans_id,
2896  U16BIT *service_id)
2897 {
2898  ADB_TIMER_REC *timer;
2899  U32BIT handle;
2900  U32DHMS end_date_time;
2901 
2902  FUNCTION_START(AMTR_GetFirstWakeupTime);
2903 
2905 
2906  handle = INVALID_TIMER_HANDLE;
2907  *date_time = 0;
2908 
2909  /* As the timer list is sorted in date/time order, just need to find the first recording timer */
2910  DBDEF_SortTimers(TRUE);
2911 
2912  for (timer = DBDEF_GetNextTimerRec(NULL); (handle == INVALID_TIMER_HANDLE) && (timer != NULL);
2913  timer = DBDEF_GetNextTimerRec(timer))
2914  {
2915  if (timer->type == TIMER_TYPE_ALARM)
2916  {
2917  if (!timer->missed && STB_GCIsFutureDateTime(DHMS_DATE(timer->start_time),
2918  DHMS_HOUR(timer->start_time), DHMS_MINS(timer->start_time), DHMS_SECS(timer->start_time)))
2919  {
2920  *date_time = timer->start_time;
2921  *onet_id = timer->u.alarm.orig_net_id;
2922  *trans_id = timer->u.alarm.transport_id;
2923  *service_id = timer->u.alarm.service_id;
2924  handle = timer->handle;
2925  }
2926  }
2927  else if (timer->type == TIMER_TYPE_PVR_RECORD)
2928  {
2929  /* Has this timer already been missed? */
2930  end_date_time = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
2931 
2932  TMR_PVR_DBG(("%s: handle=0x%08x, start=%u@%02u:%02u, end=%u@%02u:%02u, missed=%u",
2933  __FUNCTION__, timer->handle, DHMS_DATE(timer->start_time), DHMS_HOUR(timer->start_time),
2934  DHMS_MINS(timer->start_time), DHMS_DATE(end_date_time), DHMS_HOUR(end_date_time),
2935  DHMS_MINS(end_date_time), timer->missed));
2936 
2937  if (!timer->missed && STB_GCIsFutureDateTime(DHMS_DATE(end_date_time),
2938  DHMS_HOUR(end_date_time), DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
2939  {
2940  *date_time = timer->start_time;
2941  *onet_id = timer->u.record.orig_net_id;
2942  *trans_id = timer->u.record.transport_id;
2943  *service_id = timer->u.record.service_id;
2944  handle = timer->handle;
2945  }
2946  }
2947  }
2948 
2950 
2951  FUNCTION_FINISH(AMTR_GetFirstWakeupTime);
2952 
2953  return(handle);
2954 }
2955 
2964 U32BIT ATMR_FindTimerFromEvent(U16BIT onet_id, U16BIT trans_id, U16BIT serv_id, U16BIT event_id)
2965 {
2966  ADB_TIMER_REC *timer;
2967  U32BIT timer_handle;
2968 
2969  FUNCTION_START(ATMR_FindTimerFromEvent);
2970 
2972 
2973  timer_handle = INVALID_TIMER_HANDLE;
2974 
2975  for (timer = DBDEF_GetNextTimerRec(NULL); (timer_handle == INVALID_TIMER_HANDLE) && (timer != NULL);
2976  timer = DBDEF_GetNextTimerRec(timer))
2977  {
2978  if (timer->type == TIMER_TYPE_PVR_RECORD)
2979  {
2980  if ((timer->u.record.orig_net_id == onet_id) && (timer->u.record.transport_id == trans_id) &&
2981  (timer->u.record.service_id == serv_id) && (timer->u.record.event_id == event_id))
2982  {
2983  timer_handle = timer->handle;
2984  }
2985  }
2986  }
2987 
2989 
2990  FUNCTION_FINISH(ATMR_FindTimerFromEvent);
2991 
2992  return(timer_handle);
2993 }
2994 
3000 U32BIT ATMR_FindTimerFromCrid(U8BIT *prog_crid)
3001 {
3002  ADB_TIMER_REC *timer;
3003  U32BIT timer_handle;
3004 
3005  FUNCTION_START(ATMR_FindTimerFromCrid);
3006 
3008 
3009  timer_handle = INVALID_TIMER_HANDLE;
3010 
3011  for (timer = DBDEF_GetNextTimerRec(NULL); (timer_handle == INVALID_TIMER_HANDLE) && (timer != NULL);
3012  timer = DBDEF_GetNextTimerRec(timer))
3013  {
3014  if (timer->type == TIMER_TYPE_PVR_RECORD)
3015  {
3016  if (STB_CompareStringsIgnoreCase(timer->u.record.prog_crid, prog_crid) == 0)
3017  {
3018  timer_handle = timer->handle;
3019  }
3020  }
3021  }
3022 
3024 
3025  FUNCTION_FINISH(ATMR_FindTimerFromCrid);
3026 
3027  return(timer_handle);
3028 }
3029 
3038 U32BIT ATMR_FindTimerFromCridAndEvent(U8BIT *prog_crid, U16BIT service_id, U16BIT event_id)
3039 {
3040  ADB_TIMER_REC *timer;
3041  U32BIT timer_handle;
3042 
3043  FUNCTION_START(ATMR_FindTimerFromCridAndEvent);
3044 
3046 
3047  timer_handle = INVALID_TIMER_HANDLE;
3048 
3049  for (timer = DBDEF_GetNextTimerRec(NULL); (timer_handle == INVALID_TIMER_HANDLE) && (timer != NULL);
3050  timer = DBDEF_GetNextTimerRec(timer))
3051  {
3052  if (timer->type == TIMER_TYPE_PVR_RECORD)
3053  {
3054  if (timer->u.record.service_id == service_id)
3055  {
3056  if (STB_CompareStringsIgnoreCase(timer->u.record.prog_crid, prog_crid) == 0)
3057  {
3058  if (timer->u.record.event_id == event_id)
3059  {
3060  timer_handle = timer->handle;
3061  }
3062  }
3063  }
3064  }
3065  }
3066 
3068 
3069  FUNCTION_FINISH(ATMR_FindTimerFromCridAndEvent);
3070 
3071  return(timer_handle);
3072 }
3073 
3079 void ATMR_DeleteTimersForSeriesRecommendations(U8BIT *crid, BOOLEAN is_recommendation)
3080 {
3081  ADB_TIMER_REC *timer;
3082  ADB_TIMER_REC *next_timer;
3083  BOOLEAN timer_deleted;
3084 
3086 
3088 
3089  TMR_PVR_DBG(("ATMR_DeleteTimersForSeriesRecommendations(\"%s\")", crid));
3090 
3091  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = next_timer)
3092  {
3093  next_timer = DBDEF_GetNextTimerRec(timer);
3094  timer_deleted = FALSE;
3095 
3096  if (is_recommendation)
3097  {
3098  /* A recommendation could refer to a single event, so the programme crid also needs to
3099  * be checked against the given crid */
3100  if (STB_CompareStringsIgnoreCase(timer->u.record.prog_crid, crid) == 0)
3101  {
3102  TMR_PVR_DBG(("ATMR_DeleteTimersForSeriesRecommendations: Deleting timer 0x%08lx", timer->handle));
3103  DeleteTimer(timer->handle);
3104  timer_deleted = TRUE;
3105  }
3106  }
3107 
3108  if (!timer_deleted &&
3109  (STB_CompareStringsIgnoreCase(timer->u.record.other_crid, crid) == 0))
3110  {
3111  TMR_PVR_DBG(("ATMR_DeleteTimersForSeriesRecommendations: Deleting timer 0x%08lx", timer->handle));
3112  DeleteTimer(timer->handle);
3113  }
3114  }
3115 
3117 
3119 }
3120 
3128 void ATMR_SetAdditionalInfo(U32BIT handle, U8BIT *info, U32BIT size)
3129 {
3130  ADB_TIMER_REC *timer;
3131 
3132  FUNCTION_START(ATMR_SetAdditionalInfo);
3133 
3135 
3136  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
3137  {
3138  if (size >= TMR_PVR_ADDINFO_LEN_MAX)
3139  {
3140  size = TMR_PVR_ADDINFO_LEN_MAX - 1;
3141  }
3142 
3143  memcpy(timer->u.record.additional_info, info, size);
3144  timer->u.record.additional_info[size] = 0;
3145 
3146  if (timer->dba_rec != NULL)
3147  {
3148  DBA_SetFieldString(timer->dba_rec, DBA_FIELD_TIMER_ADDITIONAL_INFO,
3149  timer->u.record.additional_info, size);
3150  }
3151 
3152  if (timer->started)
3153  {
3154  STB_PVRRecordingSetAdditionalInfo(timer->u.record.recording_handle, info);
3155  }
3156  }
3157 
3159 
3160  FUNCTION_FINISH(ATMR_SetAdditionalInfo);
3161 }
3162 
3170 U8BIT* ATMR_GetAdditionalInfo(U32BIT handle, U32BIT *size)
3171 {
3172  ADB_TIMER_REC *timer;
3173  U8BIT *additional_info = NULL;
3174 
3175  FUNCTION_START(ATMR_SetAdditionalInfo);
3176 
3178 
3179  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
3180  {
3181  *size = strlen((char *)timer->u.record.additional_info) + 1;
3182  additional_info = STB_AppGetMemory(*size);
3183  strncpy((char *)additional_info, (char *)timer->u.record.additional_info, *size);
3184  }
3185 
3187 
3188  FUNCTION_FINISH(ATMR_SetAdditionalInfo);
3189 
3190  return additional_info;
3191 }
3192 
3200 S32BIT ATMR_GetStartPadding(U32BIT handle)
3201 {
3202  ADB_TIMER_REC *timer;
3203  S32BIT retval;
3204 
3205  FUNCTION_START(ATMR_GetStartPadding);
3206 
3208 
3209  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
3210  {
3211  retval = GetStartPadding(timer);
3212  }
3213  else
3214  {
3215  retval = 0;
3216  }
3217 
3219 
3220  FUNCTION_FINISH(ATMR_GetStartPadding);
3221 
3222  return retval;
3223 }
3224 
3233 BOOLEAN ATMR_SetStartPadding(U32BIT handle, S32BIT start_padding)
3234 {
3235  BOOLEAN retval;
3236  ADB_TIMER_REC *timer;
3237 
3238  FUNCTION_START(ATMR_SetStartPadding);
3239 
3241 
3242  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
3243  {
3244  retval = SetStartPadding(timer, start_padding);
3245 
3246  if (retval && (timer->dba_rec != NULL))
3247  {
3248  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_START_PADDING,
3249  timer->u.record.start_padding);
3250  }
3251  }
3252  else
3253  {
3254  retval = FALSE;
3255  }
3256 
3258 
3259  FUNCTION_FINISH(ATMR_SetStartPadding);
3260 
3261  return retval;
3262 }
3263 
3271 S32BIT ATMR_GetEndPadding(U32BIT handle)
3272 {
3273  S32BIT retval;
3274  ADB_TIMER_REC *timer;
3275 
3276  FUNCTION_START(ATMR_GetEndPadding);
3277 
3279 
3280  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
3281  {
3282  retval = GetEndPadding(timer);
3283  }
3284  else
3285  {
3286  retval = 0;
3287  }
3288 
3290 
3291  FUNCTION_FINISH(ATMR_GetEndPadding);
3292 
3293  return retval;
3294 }
3295 
3304 BOOLEAN ATMR_SetEndPadding(U32BIT handle, S32BIT end_padding)
3305 {
3306  BOOLEAN retval;
3307  ADB_TIMER_REC *timer;
3308 
3309  FUNCTION_START(ATMR_SetEndPadding);
3310 
3312 
3313  if ((timer = DBDEF_FindTimerRec(handle)) != NULL)
3314  {
3315  retval = SetEndPadding(timer, end_padding);
3316  }
3317  else
3318  {
3319  retval = FALSE;
3320  }
3321 
3323 
3324  FUNCTION_FINISH(ATMR_SetEndPadding);
3325 
3326  return retval;
3327 }
3328 
3336 BOOLEAN ATMR_SetDoNotDelete(U32BIT handle, BOOLEAN do_not_delete)
3337 {
3338  ADB_TIMER_REC *timer;
3339  BOOLEAN retval;
3340 
3341  FUNCTION_START(ATMR_SetDoNotDelete);
3342 
3343  retval = FALSE;
3344 
3346 
3347  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
3348  {
3349  timer->u.record.do_not_delete = do_not_delete;
3350  }
3351 
3353 
3354  FUNCTION_FINISH(ATMR_SetDoNotDelete);
3355 
3356  return(retval);
3357 }
3358 
3364 BOOLEAN ATMR_GetDoNotDelete(U32BIT handle)
3365 {
3366  ADB_TIMER_REC *timer;
3367  BOOLEAN retval;
3368 
3369  FUNCTION_START(ATMR_GetDoNotDelete);
3370 
3372 
3373  if (((timer = DBDEF_FindTimerRec(handle)) != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
3374  {
3375  retval = timer->u.record.do_not_delete;
3376  }
3377  else
3378  {
3379  retval = FALSE;
3380  }
3381 
3383 
3384  FUNCTION_FINISH(ATMR_GetDoNotDelete);
3385 
3386  return(retval);
3387 }
3388 
3389 /*!**************************************************************************
3390  * @brief Prints details of all existing timers
3391  ****************************************************************************/
3393 {
3394 #ifdef TMR_DEBUG
3395  ADB_TIMER_REC *timer;
3396 
3397  FUNCTION_START(ATMR_DumpAllTimers);
3398 
3400 
3401  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = DBDEF_GetNextTimerRec(timer))
3402  {
3403  DumpTimer(timer);
3404  }
3405 
3407 
3408  FUNCTION_FINISH(ATMR_DumpAllTimers);
3409 #endif
3410 }
3411 
3412 //---local function definitions------------------------------------------------
3413 
3419 static BOOLEAN DeleteTimer(U32BIT handle)
3420 {
3421  ADB_TIMER_REC *timer;
3422  BOOLEAN timer_deleted;
3423 
3424  FUNCTION_START(DeleteTimer);
3425 
3426  timer_deleted = FALSE;
3427 
3428  timer = DBDEF_FindTimerRec(handle);
3429  if (timer != NULL)
3430  {
3431  if (timer->type == TIMER_TYPE_PVR_RECORD)
3432  {
3433  /* If the recording is stopped successfully then it will delete the timer,
3434  * so it's only deleted here if the recording isn't stopped for some reason */
3435  if ((timer->u.record.recording_handle == STB_PVR_INVALID_HANDLE) ||
3436  !APVR_StopRecording(timer->u.record.recording_handle))
3437  {
3438  DBDEF_DeleteTimerRec(timer);
3439 
3440 #ifdef INTEGRATE_HBBTV
3441  HBBTV_NotifyRecordingEvent(handle, HBBTV_RECORDING_DELETED);
3442 #endif
3443  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_BOOKING_DELETED,
3444  (void *)&handle, sizeof(handle));
3445  }
3446  }
3447  else
3448  {
3449  DBDEF_DeleteTimerRec(timer);
3450  }
3451 
3452  timer_deleted = TRUE;
3453  }
3454 
3455  FUNCTION_FINISH(DeleteTimer);
3456 
3457  return(timer_deleted);
3458 }
3459 
3471 static BOOLEAN ActionTimerRecStart(ADB_TIMER_REC *timer)
3472 {
3473  BOOLEAN retval;
3474  U32DHMS gmt;
3475  U32DHMS stop_time;
3476  BOOLEAN new_tuned_service;
3477  U32BIT recording_handle;
3478 
3479  FUNCTION_START(ActionTimerRecStart);
3480 
3481  retval = FALSE;
3482 
3483  TMR_PVR_DBG(("ActionTimerRecStart()"));
3484 
3485  stop_time = STB_GCCalculateDHMS(timer->start_time, timer->u.record.duration, CALC_ADD);
3486  gmt = STB_GCNowDHMSGmt();
3487 
3488  /* Stop timer in the future (stop >= now) */
3489  if (stop_time > gmt)
3490  {
3491  TMR_PVR_DBG(("ActionTimerRecStart: stop timer in future - start new recording"));
3492 
3493 #ifdef INTEGRATE_HBBTV
3494  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_ACQUIRING_RESOURCES);
3495 #endif
3496 
3497  /* Acquire a path for recording */
3498  timer->u.record.path = APVR_PrepareNewRecording(timer->u.record.orig_net_id,
3499  timer->u.record.transport_id, timer->u.record.service_id, &new_tuned_service);
3500 
3501  if (timer->u.record.path != INVALID_RES_ID)
3502  {
3503  /* The recording may not actually be started here but all is successful so far */
3504  retval = TRUE;
3505 
3506  TMR_PVR_DBG(("ActionTimerRecStart: APVR_PrepareNewRecording, path=%u", timer->u.record.path));
3507 
3508  /* If the tuner was being used for live viewing then it may not have been retuned
3509  * if the service to be recorded is the one that was already being viewed. If this
3510  * is the case then the recording needs to be started now as the events indicating
3511  * tuning status won't be sent and so the recording wouldn't start.
3512  */
3513  if (!new_tuned_service)
3514  {
3515  TMR_PVR_DBG(("ActionTimerRecStart: Starting recording \"%s\" with path %d",
3516  timer->name, timer->u.record.path));
3517 
3518  STB_PVRStartRecordRunning(timer->u.record.path);
3519 
3520  timer->started = APVR_StartNewRecording(timer->u.record.disk_id, timer->u.record.path,
3521  timer->name, timer->u.record.event_id, timer->u.record.prog_crid,
3522  timer->u.record.other_crid, &recording_handle);
3523 
3524  if (timer->started)
3525  {
3526  /* Set the recording handle in the timer */
3527  timer->u.record.recording_handle = recording_handle;
3528  timer->u.record.programme_finished = FALSE;
3529 
3530  TMR_PVR_DBG(("ActionTimerRecStart: Recording started"));
3531 
3532  STB_PVRRecordingSetAdditionalInfo(recording_handle, timer->u.record.additional_info);
3533  STB_PVRRecordingSetStartPadding(recording_handle, GetStartPadding(timer));
3534  STB_PVRRecordingSetEndPadding(recording_handle, GetEndPadding(timer));
3535  STB_PVRRecordingSetLocked(recording_handle, timer->u.record.do_not_delete);
3536 
3537 #ifdef INTEGRATE_HBBTV
3538  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_STARTED);
3539 #endif
3540  }
3541  else
3542  {
3543  /* Recording tried to start but failed */
3544  TMR_PVR_DBG(("ActionTimerRecStart: Failed to start recording"));
3545 
3546  ACTL_TuneOff(timer->u.record.path);
3547  STB_DPReleasePath(timer->u.record.path, RES_OWNER_DVB);
3548  timer->u.record.path = INVALID_RES_ID;
3549 
3550  /* Mark the timer as missed so that it's rescheduled */
3551  timer->missed = TRUE;
3552 
3553  if (timer->dba_rec != NULL)
3554  {
3555  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_MISSED, timer->missed);
3556  }
3557 
3558  /* Send event to UI to inform a recording has failed */
3559  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_RECORDING_FAILED, NULL, 0);
3560 
3561 #ifdef INTEGRATE_HBBTV
3562  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_FAILED_UNKNOWN_ERROR);
3563 #endif
3564 
3565  retval = FALSE;
3566  }
3567 
3568  timer->starting = FALSE;
3569  }
3570  }
3571  else
3572  {
3573  TMR_PVR_DBG(("ActionTimerRecStart: Failed to get a tuner to record"));
3574 
3575  /* Mark the timer as missed so that it's rescheduled */
3576  timer->starting = FALSE;
3577  timer->missed = TRUE;
3578 
3579  if (timer->dba_rec != NULL)
3580  {
3581  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_MISSED, timer->missed);
3582  }
3583 
3584  /* Send event to UI to inform a recording has failed */
3585  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_RECORDING_FAILED, NULL, 0);
3586 
3587 #ifdef INTEGRATE_HBBTV
3588  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_FAILED_RESOURCE_LIMITATION);
3589 #endif
3590  }
3591  }
3592  else
3593  {
3594  TMR_PVR_DBG(("ActionTimerRecStart: Stop time in the past, so recording has been missed"));
3595 
3596  /* Stop time in the past, mark it as missed so that it's rescheduled */
3597  timer->u.record.recording_handle = STB_PVR_INVALID_HANDLE;
3598  timer->missed = TRUE;
3599  timer->starting = FALSE;
3600 
3601  if (timer->dba_rec != NULL)
3602  {
3603  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_MISSED, timer->missed);
3604  }
3605 
3606 #ifdef INTEGRATE_HBBTV
3607  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_FAILED_UNKNOWN_ERROR);
3608 #endif
3609  }
3610 
3611  FUNCTION_FINISH(ActionTimerRecStart);
3612 
3613  return(retval);
3614 }
3615 
3621 static void TimerTask(void *param)
3622 {
3623  ADB_TIMER_REC *timer;
3624  ADB_TIMER_REC *next_timer;
3625  U32DHMS start_date_time, end_date_time;
3626  BOOLEAN timer_updated;
3627  BOOLEAN start_record;
3628 
3629  FUNCTION_START(TimerTask);
3630 
3631  USE_UNWANTED_PARAM(param);
3632 
3633  /* Wait for the date/time to be set */
3634  while (STB_GCGetGMTDate() == 0)
3635  {
3636  STB_OSTaskDelay(100);
3637  }
3638 
3640 
3641  timer_updated = FALSE;
3642 
3643  /* Check each timer to determine whether it's expired, missed, etc. */
3644  timer = DBDEF_GetNextTimerRec(NULL);
3645  while (timer != NULL)
3646  {
3647  next_timer = DBDEF_GetNextTimerRec(timer);
3648 
3649  /* Ignore timers that are already marked as missed */
3650  if (!timer->missed)
3651  {
3652  if (timer->type == TIMER_TYPE_PVR_RECORD)
3653  {
3654  GetActualStartEndTime(timer->start_time, timer->u.record.duration,
3655  GetStartPadding(timer), GetEndPadding(timer), &start_date_time,
3656  &end_date_time);
3657  }
3658  else
3659  {
3660  start_date_time = timer->start_time;
3661  end_date_time = timer->start_time;
3662  }
3663 
3664  if (!STB_GCIsFutureDateTime(DHMS_DATE(start_date_time), DHMS_HOUR(start_date_time),
3665  DHMS_MINS(start_date_time), DHMS_SECS(start_date_time)))
3666  {
3667  /* The start time of this timer has already passed, check whether it's expired */
3668  if (STB_GCIsFutureDateTime(DHMS_DATE(end_date_time), DHMS_HOUR(end_date_time),
3669  DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
3670  {
3671  /* The end time hasn't yet been reached, so set the timer as starting */
3672  timer->starting = TRUE;
3673 
3674  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_SUCCESS, (void *)&timer->handle,
3675  sizeof(timer->handle));
3676  }
3677  else
3678  {
3679  /* The timer has been missed, see if it can be rescheduled */
3680  timer_updated = TRUE;
3681 
3682  if (!RescheduleTimer(timer))
3683  {
3684  /* Timer hasn't been rescheduled */
3685  if ((timer->type != TIMER_TYPE_PVR_RECORD) ||
3686  ((STB_GetNumBytesInString(timer->u.record.prog_crid) == 0) &&
3687  (STB_GetNumBytesInString(timer->u.record.other_crid) == 0)))
3688  {
3689  /* The timer can be deleted */
3690  DeleteTimer(timer->handle);
3691  }
3692  else
3693  {
3694  /* Set it as expired and leave it to the app to deal with */
3695  timer->expired = TRUE;
3696  timer_updated |= FALSE;
3697  }
3698  }
3699  }
3700  }
3701  }
3702 
3703  timer = next_timer;
3704  }
3705 
3706  if (timer_updated)
3707  {
3708  /* Timers have been changed so save the database */
3709  ADB_SaveDatabase();
3710  }
3711 
3713 
3714  while (1)
3715  {
3716  TMR_DBG(("Time now (GMT): %d/%d/%d %02d:%02d", STB_GCGetGMTDay(), STB_GCGetGMTMonth(),
3718 
3720 
3721  timer_updated = FALSE;
3722 
3723  /* First check for any timers that need to be stopped.
3724  * This needs to be done first to ensure that back-to-back recordings are
3725  * stopped and started in the correct order */
3726  timer = DBDEF_GetNextTimerRec(NULL);
3727  while (timer != NULL)
3728  {
3729  /* Has this timer already been started, or is it still starting? */
3730  if (timer->started || timer->starting)
3731  {
3732  /* Check whether it's time to stop */
3733  timer_updated |= HasTimerExpired(timer->handle);
3734  }
3735  else if (timer->expired)
3736  {
3737  /* Timer has expired but is still running, so send the event again */
3738  TMR_DBG(("[%s:%d]: Timer 0x%x still expired", __FUNCTION__, __LINE__, timer->handle));
3739 
3740  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_SUCCESS, (void *)&timer->handle,
3741  sizeof(timer->handle));
3742  }
3743 
3744  timer = DBDEF_GetNextTimerRec(timer);
3745  }
3746 
3747  /* Now check for any timers that are due to be started */
3748  timer = DBDEF_GetNextTimerRec(NULL);
3749  while (timer != NULL)
3750  {
3751  /* Has this timer already been started? */
3752  if (!timer->started && !timer->expired && !timer->missed)
3753  {
3754  if (timer->type == TIMER_TYPE_PVR_RECORD)
3755  {
3756  timer_updated |= StartRecordTimer(timer, TRUE, &start_record);
3757  }
3758  else
3759  {
3760  /* Check whether this timer should be started */
3761  if (!timer->starting && !timer->missed &&
3762  !STB_GCIsFutureDateTime(DHMS_DATE(timer->start_time), DHMS_HOUR(timer->start_time),
3763  DHMS_MINS(timer->start_time), DHMS_SECS(timer->start_time)))
3764  {
3765  /* Timer should now be started */
3766  TMR_DBG(("[%s:%d]: Timer 0x%x starting", __FUNCTION__, __LINE__, timer->handle));
3767 
3768  timer->starting = TRUE;
3769 
3770  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_SUCCESS,
3771  (void *)&timer->handle, sizeof(timer->handle));
3772  }
3773  }
3774  }
3775 
3776  timer = DBDEF_GetNextTimerRec(timer);
3777  }
3778 
3779  /* Ensure database is saved */
3780  if (timer_updated)
3781  {
3782  ADB_SaveDatabase();
3783  }
3784 
3786 
3787  /* Wait five secs */
3788  STB_OSTaskDelay(5000);
3789  }
3790 
3791  FUNCTION_FINISH(TimerTask);
3792 }
3793 
3794 static BOOLEAN StartRecordTimer(ADB_TIMER_REC *timer, BOOLEAN recordings_can_start, BOOLEAN *start_record)
3795 {
3796  BOOLEAN timer_updated;
3797  U32DHMS start_date_time, end_date_time;
3798  U32BIT notify_time;
3799  U32DHMS padding_start, padding_end;
3800  U8BIT max_recordings;
3801  U8BIT num_recordings;
3802  BOOLEAN start_timer;
3803  BOOLEAN conflict_resolved;
3804  U32BIT *conflicts;
3805  U8BIT i;
3806  S32BIT start_padding;
3807  S32BIT end_padding;
3808  S32BIT padding;
3809  U32DHMS time_diff;
3810  S32BIT padding_time;
3811 
3812  FUNCTION_START(StartRecordTimer);
3813 
3814  timer_updated = FALSE;
3815  *start_record = FALSE;
3816 
3817  start_padding = GetStartPadding(timer);
3818  end_padding = GetEndPadding(timer);
3819 
3820  GetActualStartEndTime(timer->start_time, timer->u.record.duration, start_padding, end_padding,
3821  &start_date_time, &end_date_time);
3822 
3823  /* Check whether a notification needs to be sent that this timer is about to start */
3824  if (!timer->u.record.notified)
3825  {
3826  notify_time = timer->u.record.notify_time;
3827  if (notify_time == 0)
3828  {
3829  notify_time = APVR_GetNotifyTime();
3830  }
3831 
3832  if (notify_time != 0)
3833  {
3834  notify_time = STB_GCCalculateDHMS(start_date_time,
3835  STB_GCCreateDHMSFromSeconds(notify_time), CALC_SUB);
3836 
3837  if (!STB_GCIsFutureDateTime(DHMS_DATE(notify_time), DHMS_HOUR(notify_time),
3838  DHMS_MINS(notify_time), DHMS_SECS(notify_time)))
3839  {
3840  TMR_PVR_DBG(("%s: Timer 0x%x being notified", __FUNCTION__, timer->handle));
3841 
3842  /* Send notification that the timer is going to be triggered */
3843  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_FAIL,
3844  (void *)&timer->handle, sizeof(timer->handle));
3845 
3846  timer->u.record.notified = TRUE;
3847  }
3848  }
3849  }
3850 
3851  /* Check whether this timer should be started */
3852  if (!timer->starting && !timer->missed &&
3853  (!STB_GCIsFutureDateTime(DHMS_DATE(start_date_time), DHMS_HOUR(start_date_time),
3854  DHMS_MINS(start_date_time), DHMS_SECS(start_date_time)) ||
3855  (timer->u.record.event_triggered && timer->u.record.programme_started)))
3856  {
3857  if (timer->type == TIMER_TYPE_PVR_RECORD)
3858  {
3859  start_timer = FALSE;
3860 
3861  max_recordings = STB_HWGetNumRecorders();
3862 
3863  if (start_padding != 0)
3864  {
3865  /* Find the number of recordings in progress during the start padding */
3866  GetActualStartEndTime(timer->start_time, 0, start_padding, 0, &padding_start,
3867  &padding_end);
3868  padding_end = timer->start_time;
3869 
3870  num_recordings = GetNumSimultaneousRecordings(timer->handle, timer->u.record.orig_net_id,
3871  timer->u.record.transport_id, timer->u.record.service_id, max_recordings,
3872  padding_start, padding_end, TRUE, TRUE, &conflicts);
3873 
3874  if (num_recordings < max_recordings)
3875  {
3876  /* This recording can be started */
3877  start_timer = TRUE;
3878  }
3879  else
3880  {
3881  TMR_PVR_DBG(("[%s:%d]: Resolving conflict for timer 0x%x, @ %02u:%02u:%02u (padding %d/%d)",
3882  __FUNCTION__, __LINE__, timer->handle, DHMS_HOUR(start_date_time),
3883  DHMS_MINS(start_date_time), DHMS_SECS(start_date_time), start_padding, end_padding));
3884 
3885  /* Check all the conflicting timers to see whether the conflict can be resolved.
3886  * Timers are first checked to see if reducing padding is possible */
3887  for (i = 0, conflict_resolved = FALSE; !conflict_resolved && (i < max_recordings) &&
3888  (conflicts[i] != INVALID_TIMER_HANDLE); i++)
3889  {
3890  if ((ATMR_GetEndDateTime(conflicts[i]) < padding_end) &&
3891  ((padding = ATMR_GetEndPadding(conflicts[i])) != 0))
3892  {
3893  /* Found a timer with end padding that conflicts with the start padding of this
3894  * recording. The difference between the actual start and end times of the two
3895  * is the total padding time available and this needs to be split between the
3896  * two timers */
3897  time_diff = timer->start_time - ATMR_GetEndDateTime(conflicts[i]);
3898  padding_time = DHMS_MINS(time_diff) * 60 + DHMS_SECS(time_diff);
3899 
3900  /* Back-to-back recordings are ignored this time in preference to ones where
3901  * the padding can be reduced rather than being set to zero */
3902  if (padding_time != 0)
3903  {
3904  if (ATMR_GetEndPadding(conflicts[i]) < (padding_time / 2))
3905  {
3906  /* End padding already less than the new padding time, so just the start
3907  * padding will be reduced */
3908  padding_time -= ATMR_GetEndPadding(conflicts[i]);
3909 
3910  TMR_PVR_DBG(("[%s:%d]: Changing start padding of timer 0x%x from %d to %d",
3911  __FUNCTION__, __LINE__, timer->handle, start_padding, padding_time));
3912 
3913  SetStartPadding(timer, padding_time);
3914  }
3915  else if (start_padding < (padding_time / 2))
3916  {
3917  /* Start padding already less than the new padding time, so just the
3918  * end padding will be reduced */
3919  padding_time -= start_padding;
3920 
3921  TMR_PVR_DBG(("[%s:%d]: Changing end padding of timer 0x%x from %d to %d",
3922  __FUNCTION__, __LINE__, conflicts[i], ATMR_GetEndPadding(conflicts[i]),
3923  padding_time));
3924 
3925  ATMR_SetEndPadding(conflicts[i], padding_time);
3926  }
3927  else
3928  {
3929  /* The total padding time can be split between the two timers */
3930  TMR_PVR_DBG(("[%s:%d]: Splitting padding:", __FUNCTION__, __LINE__));
3931  TMR_PVR_DBG((" timer 0x%x start padding %d to %d",
3932  timer->handle, start_padding, padding_time / 2));
3933 
3934  SetStartPadding(timer, padding_time / 2);
3935 
3936  TMR_PVR_DBG((" timer 0x%x end padding %d to %d", conflicts[i],
3937  ATMR_GetEndPadding(conflicts[i]),
3938  padding_time - GetStartPadding(timer)));
3939 
3940  ATMR_SetEndPadding(conflicts[i], padding_time - GetStartPadding(timer));
3941  }
3942 
3943  conflict_resolved = TRUE;
3944 
3945  /* Check whether the recording associated with the conflicted timer
3946  * should now be stopped */
3947  HasTimerExpired(conflicts[i]);
3948  }
3949  }
3950  }
3951 
3952  /* If the conflict hasn't been resolved, now check whether there are any back-to-back
3953  * recordings, which means all padding will need to be removed */
3954  for (i = 0; !conflict_resolved && (i < max_recordings) &&
3955  (conflicts[i] != INVALID_TIMER_HANDLE); i++)
3956  {
3957  if (timer->start_time == ATMR_GetEndDateTime(conflicts[i]))
3958  {
3959  /* Found a back-to-back recording, so remove the padding from both of them,
3960  * but the recording can't be started yet */
3961  TMR_PVR_DBG(("[%s:%d]: Found back-to-back recording with timer 0x%x, setting padding to 0",
3962  __FUNCTION__, __LINE__, conflicts[i]));
3963 
3964  SetStartPadding(timer, 0);
3965  ATMR_SetEndPadding(conflicts[i], 0);
3966  conflict_resolved = TRUE;
3967 
3968  /* Check whether the recording associated with the conflicted timer
3969  * should now be stopped */
3970  HasTimerExpired(conflicts[i]);
3971  }
3972  }
3973 
3974  if (conflict_resolved)
3975  {
3976  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x padding now %d/%d", __FUNCTION__, __LINE__,
3977  timer->handle, GetStartPadding(timer), GetEndPadding(timer)));
3978 
3979  for (i = 0; (i < max_recordings) && (conflicts[i] != INVALID_TIMER_HANDLE); i++)
3980  {
3981  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x padding now %d/%d", __FUNCTION__, __LINE__,
3982  conflicts[i], ATMR_GetStartPadding(conflicts[i]),
3983  ATMR_GetEndPadding(conflicts[i])));
3984  }
3985 
3986  STB_AppFreeMemory(conflicts);
3987  conflicts = NULL;
3988 
3989  /* Check whether the resources are now available to start this recording */
3990  start_padding = GetStartPadding(timer);
3991  end_padding = GetEndPadding(timer);
3992 
3993  GetActualStartEndTime(timer->start_time, 0, start_padding, 0,
3994  &padding_start, &padding_end);
3995  padding_end = timer->start_time;
3996 
3997  num_recordings = GetNumSimultaneousRecordings(timer->handle,
3998  timer->u.record.orig_net_id, timer->u.record.transport_id,
3999  timer->u.record.service_id, max_recordings,
4000  padding_start, padding_end, TRUE, TRUE, &conflicts);
4001 
4002  if (num_recordings < max_recordings)
4003  {
4004  /* The conflict has been resolved, which means padding will have been changed,
4005  * so check again whether the timer should be started yet */
4006  GetActualStartEndTime(timer->start_time, timer->u.record.duration,
4007  start_padding, end_padding, &start_date_time, &end_date_time);
4008 
4009  if (!STB_GCIsFutureDateTime(DHMS_DATE(start_date_time), DHMS_HOUR(start_date_time),
4010  DHMS_MINS(start_date_time), DHMS_SECS(start_date_time)))
4011  {
4012  /* This recording can be started */
4013  start_timer = TRUE;
4014  }
4015  }
4016  }
4017  }
4018 
4019  if (conflicts != NULL)
4020  {
4021  STB_AppFreeMemory(conflicts);
4022  }
4023  }
4024  else
4025  {
4026  /* Check whether the resources are available to start this recording */
4027  num_recordings = GetNumSimultaneousRecordings(timer->handle, timer->u.record.orig_net_id,
4028  timer->u.record.transport_id, timer->u.record.service_id, max_recordings,
4029  timer->start_time, ATMR_GetEndDateTime(timer->handle), TRUE, TRUE, &conflicts);
4030 
4031  if (num_recordings < max_recordings)
4032  {
4033  if (!timer->u.record.event_triggered || timer->u.record.programme_started)
4034  {
4035  /* This recording can be started */
4036  start_timer = TRUE;
4037  }
4038  }
4039  else
4040  {
4041  TMR_PVR_DBG(("[%s:%d]: Resolving conflict for timer 0x%x, @ %02u:%02u:%02u (padding %d/%d)",
4042  __FUNCTION__, __LINE__, timer->handle, DHMS_HOUR(start_date_time),
4043  DHMS_MINS(start_date_time), DHMS_SECS(start_date_time), start_padding, end_padding));
4044 
4045  /* Check the conflicting recordings to see if they have end padding
4046  * that can be changed and so resolve the conflict */
4047  for (i = 0, conflict_resolved = FALSE; !conflict_resolved && (i < max_recordings) &&
4048  (conflicts[i] != INVALID_TIMER_HANDLE); i++)
4049  {
4050  if ((ATMR_GetEndDateTime(conflicts[i]) <= timer->start_time) &&
4051  (ATMR_GetEndPadding(conflicts[i]) != 0))
4052  {
4053  /* Found a recording with end padding that can be changed */
4054  time_diff = timer->start_time - ATMR_GetEndDateTime(conflicts[i]);
4055  padding_time = DHMS_MINS(time_diff) * 60 + DHMS_SECS(time_diff);
4056 
4057  TMR_PVR_DBG(("[%s:%d]: Changing end padding for timer 0x%x from %d to %d",
4058  __FUNCTION__, __LINE__, conflicts[i], ATMR_GetEndPadding(conflicts[i]),
4059  padding_time));
4060 
4061  ATMR_SetEndPadding(conflicts[i], padding_time);
4062  conflict_resolved = TRUE;
4063 
4064  /* Check whether the recording associated with the conflicted timer
4065  * should now be stopped */
4066  HasTimerExpired(conflicts[i]);
4067  }
4068  }
4069 
4070  if (conflict_resolved)
4071  {
4072  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x padding now %d/%d", __FUNCTION__, __LINE__,
4073  timer->handle, start_padding, end_padding));
4074 
4075  for (i = 0; (i < max_recordings) && (conflicts[i] != INVALID_TIMER_HANDLE); i++)
4076  {
4077  TMR_PVR_DBG(("[%s:%d]:: Timer 0x%x padding now %d/%d", __FUNCTION__, __LINE__,
4078  conflicts[i], ATMR_GetStartPadding(conflicts[i]),
4079  ATMR_GetEndPadding(conflicts[i])));
4080  }
4081 
4082  STB_AppFreeMemory(conflicts);
4083  conflicts = NULL;
4084 
4085  /* Check whether the resources are now available to start this recording */
4086  num_recordings = GetNumSimultaneousRecordings(timer->handle,
4087  timer->u.record.orig_net_id, timer->u.record.transport_id,
4088  timer->u.record.service_id, max_recordings, timer->start_time,
4089  ATMR_GetEndDateTime(timer->handle), TRUE, TRUE, &conflicts);
4090 
4091  if (num_recordings < max_recordings)
4092  {
4093  if (!timer->u.record.event_triggered || timer->u.record.programme_started)
4094  {
4095  /* This recording can be started */
4096  start_timer = TRUE;
4097  }
4098  }
4099  }
4100  }
4101 
4102  if (conflicts != NULL)
4103  {
4104  STB_AppFreeMemory(conflicts);
4105  }
4106  }
4107  }
4108  else
4109  {
4110  start_timer = TRUE;
4111  }
4112 
4113  if (start_timer)
4114  {
4115  *start_record = TRUE;
4116 
4117  if (recordings_can_start)
4118  {
4119  /* Timer should now be started but first check that it hasn't also expired */
4120  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x starting", __FUNCTION__, __LINE__, timer->handle));
4121 
4122  timer->starting = TRUE;
4123 
4124  if (timer->u.record.duration == 0)
4125  {
4126  /* Timer type is just triggered by the start time, so this timer has now expired */
4127  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x has expired due to 0 duration!", __FUNCTION__,
4128  __LINE__, timer->handle));
4129 
4130  timer->expired = TRUE;
4131  timer_updated |= RescheduleTimer(timer);
4132  }
4133 
4134  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_SUCCESS,
4135  (void *)&timer->handle, sizeof(timer->handle));
4136  }
4137  }
4138  }
4139  else if (recordings_can_start && timer->starting && !timer->missed &&
4140  (timer->u.record.path != INVALID_RES_ID))
4141  {
4142  if (!ATMR_StartRecord(timer->u.record.path))
4143  {
4144  /* Recording didn't start, so release the path */
4145  ACTL_TuneOff(timer->u.record.path);
4146  STB_DPReleasePath(timer->u.record.path, RES_OWNER_DVB);
4147 
4148  /* Send event to UI to inform a recording has failed */
4149  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_RECORDING_FAILED, NULL, 0);
4150  }
4151  }
4152 
4153  FUNCTION_FINISH(StartRecordTimer);
4154 
4155  return(timer_updated);
4156 }
4157 
4158 static BOOLEAN HasTimerExpired(U32BIT handle)
4159 {
4160  BOOLEAN expired;
4161  ADB_TIMER_REC *timer;
4162  U32DHMS start_date_time, end_date_time;
4163 #ifdef TMR_DEBUG
4164  U8BIT start_day, wday, start_month;
4165  U16BIT start_year;
4166  U8BIT end_day, end_month;
4167  U16BIT end_year;
4168 #endif
4169 
4170  FUNCTION_START(HasTimerExpired);
4171 
4172  expired = FALSE;
4173 
4174  timer = DBDEF_FindTimerRec(handle);
4175  if ((timer != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
4176  {
4177  if (timer->type == TIMER_TYPE_PVR_RECORD)
4178  {
4179  GetActualStartEndTime(timer->start_time, timer->u.record.duration,
4180  GetStartPadding(timer), GetEndPadding(timer), &start_date_time, &end_date_time);
4181  }
4182  else
4183  {
4184  start_date_time = timer->start_time;
4185  end_date_time = timer->start_time;
4186  }
4187 
4188 #ifdef TMR_DEBUG
4189  STB_GCGetMJDDateInfo(DHMS_DATE(start_date_time), &start_day, &wday, &start_month, &start_year);
4190  STB_GCGetMJDDateInfo(DHMS_DATE(end_date_time), &end_day, &wday, &end_month, &end_year);
4191  TMR_DBG(("Timer 0x%x, start:%d/%d/%d %02d:%02d, end %d/%d/%d %02d:%02d; started:%s starting:%s", timer->handle,
4192  start_day, start_month, start_year, DHMS_HOUR(start_date_time), DHMS_MINS(start_date_time),
4193  end_day, end_month, end_year, DHMS_HOUR(end_date_time), DHMS_MINS(end_date_time),
4194  timer->started ? "TRUE" : "FALSE", timer->starting ? "TRUE" : "FALSE"));
4195 #endif
4196 
4197  if (timer->type == TIMER_TYPE_PVR_RECORD)
4198  {
4199  if (!timer->u.record.event_triggered &&
4200  !STB_GCIsFutureDateTime(DHMS_DATE(end_date_time), DHMS_HOUR(end_date_time),
4201  DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
4202  {
4203  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x expired", __FUNCTION__, __LINE__, timer->handle));
4204  expired = TRUE;
4205  }
4206  else if (timer->u.record.event_triggered)
4207  {
4208  if (timer->u.record.programme_finished &&
4209  ((GetEndPadding(timer) == 0) || !STB_GCIsFutureDateTime(DHMS_DATE(end_date_time),
4210  DHMS_HOUR(end_date_time), DHMS_MINS(end_date_time), DHMS_SECS(end_date_time))))
4211  {
4212  /* The programme has finished or the end time has been reached, so mark the timer
4213  * as expired so the recording will be stopped if it isn't event triggered */
4214  TMR_PVR_DBG(("[%s:%d]: Timer 0x%x expired", __FUNCTION__, __LINE__, timer->handle));
4215  expired = TRUE;
4216  }
4217  else if (!timer->u.record.programme_started && !STB_GCIsFutureDateTime(DHMS_DATE(end_date_time),
4218  DHMS_HOUR(end_date_time), DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
4219  {
4220  /* Programme didn't appear in EITpf so hasn't started and the end time has now been
4221  * reached, so assume the event has been missed */
4222  TMR_PVR_DBG(("[%s:%d]: Event missed, timer 0x%x expired", __FUNCTION__, __LINE__, timer->handle));
4223  expired = TRUE;
4224  }
4225  }
4226  }
4227  else if (!STB_GCIsFutureDateTime(DHMS_DATE(end_date_time), DHMS_HOUR(end_date_time),
4228  DHMS_MINS(end_date_time), DHMS_SECS(end_date_time)))
4229  {
4230  TMR_DBG(("%s: Timer 0x%x expired", __FUNCTION__, timer->handle));
4231  expired = TRUE;
4232  }
4233 
4234  if (expired)
4235  {
4236  /* Timer has now completed/expired */
4237  timer->starting = FALSE;
4238  timer->expired = TRUE;
4239 
4240  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_TIMER, EV_TYPE_SUCCESS, (void *)&timer->handle,
4241  sizeof(timer->handle));
4242 
4243  if (RescheduleTimer(timer))
4244  {
4245  if (timer->type == TIMER_TYPE_PVR_RECORD)
4246  {
4247 #ifdef INTEGRATE_HBBTV
4248  HBBTV_NotifyRecordingEvent(timer->handle, HBBTV_RECORDING_UPDATED);
4249 #endif
4250  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_APPLICATION, EV_PVR_BOOKING_CREATED,
4251  (void *)&timer->handle, sizeof(timer->handle));
4252  }
4253  }
4254  }
4255  }
4256 
4257  FUNCTION_FINISH(HasTimerExpired);
4258 
4259  return(expired);
4260 }
4261 
4262 static BOOLEAN RescheduleTimer(ADB_TIMER_REC *timer)
4263 {
4264  BOOLEAN rescheduled;
4265  U16BIT code;
4266  U8BIT hour, mins, secs;
4267  E_STB_GC_WEEKDAY wday;
4268  U8BIT oohour, oomin, nohour, nomin;
4269  BOOLEAN ooneg, noneg;
4270  BOOLEAN check_offset = FALSE;
4271 
4272  FUNCTION_START(RescheduleTimer);
4273 
4274  rescheduled = FALSE;
4275 
4276  /* Set flag to show the timer is no longer started */
4277  timer->started = FALSE;
4278 
4279  code = DHMS_DATE(timer->start_time);
4280  hour = DHMS_HOUR(timer->start_time);
4281  mins = DHMS_MINS(timer->start_time);
4282  secs = DHMS_SECS(timer->start_time);
4283 
4284  /* Get old local time offset */
4285  STB_GCGetLocalTimeChange(code, hour, mins, secs, &oohour, &oomin, &ooneg);
4286 
4287  /* Adjust date/time? */
4288  switch (timer->frequency)
4289  {
4290  case TIMER_FREQ_ONCE:
4291  /* Timer doesn't need to be rescheduled */
4292  break;
4293 
4294  case TIMER_FREQ_WEEKLY:
4295  /* Next week, same time */
4296  code += 7;
4297  check_offset = TRUE;
4298  rescheduled = TRUE;
4299  break;
4300 
4301  case TIMER_FREQ_WEEKENDDAYS:
4302  /* Next weekend day, same time */
4303  wday = STB_GCGetDateWeekDay(code);
4304  if (wday == WEEKDAY_MONDAY)
4305  code += 5;
4306  if (wday == WEEKDAY_TUESDAY)
4307  code += 4;
4308  if (wday == WEEKDAY_WEDNESDAY)
4309  code += 3;
4310  if (wday == WEEKDAY_THURSDAY)
4311  code += 2;
4312  if (wday == WEEKDAY_FRIDAY)
4313  code += 1;
4314  if (wday == WEEKDAY_SATURDAY)
4315  code += 1;
4316  if (wday == WEEKDAY_SUNDAY)
4317  code += 6;
4318  check_offset = TRUE;
4319  rescheduled = TRUE;
4320  break;
4321 
4322  case TIMER_FREQ_WEEKDAYS:
4323  /* Next week day, same time */
4324  wday = STB_GCGetDateWeekDay(code);
4325  if (wday == WEEKDAY_MONDAY)
4326  code += 1;
4327  if (wday == WEEKDAY_TUESDAY)
4328  code += 1;
4329  if (wday == WEEKDAY_WEDNESDAY)
4330  code += 1;
4331  if (wday == WEEKDAY_THURSDAY)
4332  code += 1;
4333  if (wday == WEEKDAY_FRIDAY)
4334  code += 3;
4335  if (wday == WEEKDAY_SATURDAY)
4336  code += 2;
4337  if (wday == WEEKDAY_SUNDAY)
4338  code += 1;
4339  check_offset = TRUE;
4340  rescheduled = TRUE;
4341  break;
4342 
4343  case TIMER_FREQ_DAILY:
4344  /* Tomorrow, same time */
4345  code += 1;
4346  check_offset = TRUE;
4347  rescheduled = TRUE;
4348  break;
4349 
4350  case TIMER_FREQ_HOURLY:
4351  /* Today, one hour later */
4352  hour = DHMS_HOUR(timer->start_time) + 1;
4353  if (hour > 23)
4354  {
4355  /* Or tomorrow? */
4356  code += 1;
4357  hour -= 24;
4358  }
4359  rescheduled = TRUE;
4360  break;
4361 
4362  default:
4363  break;
4364  }
4365 
4366  /* Adjust timer for new local time offset? */
4367  if (check_offset == TRUE)
4368  {
4369  STB_GCGetLocalTimeChange(code, hour, mins, secs, &nohour, &nomin, &noneg);
4370  if ((oohour != nohour) || (oomin != nomin) || (ooneg != noneg))
4371  {
4372  if (ooneg)
4373  {
4374  STB_GCCalculateDateTime(code, hour, mins, secs, oohour, oomin, 0,
4375  &code, &hour, &mins, &secs, CALC_SUB);
4376  }
4377  else
4378  {
4379  STB_GCCalculateDateTime(code, hour, mins, secs, oohour, oomin, 0,
4380  &code, &hour, &mins, &secs, CALC_ADD);
4381  }
4382 
4383  if (noneg)
4384  {
4385  STB_GCCalculateDateTime(code, hour, mins, secs, nohour, nomin, 0,
4386  &code, &hour, &mins, &secs, CALC_ADD);
4387  }
4388  else
4389  {
4390  STB_GCCalculateDateTime(code, hour, mins, secs, nohour, nomin, 0,
4391  &code, &hour, &mins, &secs, CALC_SUB);
4392  }
4393  }
4394  }
4395 
4396  /* Set new time */
4397  timer->start_time = DHMS_CREATE(code, hour, mins, secs);
4398 
4399  if (timer->dba_rec != NULL)
4400  {
4401  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_STARTTIME, timer->start_time);
4402  }
4403 
4404  if (rescheduled && (timer->type == TIMER_TYPE_PVR_RECORD))
4405  {
4406  /* Reset the notified flag so the notification event is sent for the next scheduled recording */
4407  timer->u.record.notified = FALSE;
4408  }
4409 
4410  FUNCTION_FINISH(RescheduleTimer);
4411 
4412  return(rescheduled);
4413 }
4414 
4421 static void AlternateEventTask(void *param)
4422 {
4423  S_ALT_EVENT_DATA alt_event_data;
4424  void *serv_ptr;
4425  void *event_ptr;
4426  void *alt_event_ptr;
4427 #ifdef TMR_PVR_DEBUG
4428  U32DHMS start_time;
4429 #endif
4430  U8BIT *new_prog_crid;
4431 
4432  USE_UNWANTED_PARAM(param);
4433 
4434  while (TRUE)
4435  {
4436  if (STB_OSReadQueue(alt_event_queue, &alt_event_data, sizeof(alt_event_data), TIMEOUT_NEVER))
4437  {
4438  /* Look for an alternative event. As the recording has been missed, the original
4439  * event isn't required but may still be in the schedule */
4440  event_ptr = ADB_FindEventFromCrid(alt_event_data.prog_crid, NULL, &serv_ptr);
4441  if (event_ptr != NULL)
4442  {
4443 #ifdef TMR_PVR_DEBUG
4444  start_time = ADB_GetEventStartDateTime(event_ptr);
4445 #endif
4446 
4447  /* Delete the original timer */
4449  DeleteTimer(alt_event_data.timer_handle);
4451 
4452  TMR_PVR_DBG(("Alternative event found for \"%s\" on %lu @ %02lu:%02lu on LCN %d\n",
4453  ADB_GetEventName(event_ptr), DHMS_DATE(start_time), DHMS_HOUR(start_time),
4454  DHMS_MINS(start_time), ADB_GetServiceLcn(serv_ptr)));
4455 
4456  /* Set the new event to be recorded */
4457  new_prog_crid = ADB_GetEventProgrammeCrid(serv_ptr, event_ptr);
4458  alt_event_ptr = ATMR_RecordEvent(serv_ptr, event_ptr, new_prog_crid,
4459  alt_event_data.other_crid, alt_event_data.is_recommendation, TRUE,
4460  alt_event_data.do_not_delete);
4461 
4462  if ((alt_event_ptr != NULL) && (alt_event_ptr != event_ptr))
4463  {
4464  ADB_ReleaseEventData(alt_event_ptr);
4465  }
4466 
4467  STB_AppFreeMemory(new_prog_crid);
4468  ADB_ReleaseEventData(event_ptr);
4469 
4470  /* Force update NVM in case power is lost */
4471  ADB_SaveDatabase();
4472  }
4473  }
4474  }
4475 }
4476 
4487 static void GetActualStartEndTime(U32DHMS timer_start, U32DHMS timer_duration, S32BIT start_padding, S32BIT end_padding,
4488  U32DHMS *start_time, U32DHMS *end_time)
4489 {
4490  U32BIT pad_hours, pad_mins, pad_secs;
4491 
4492  if (start_padding == 0)
4493  {
4494  *start_time = timer_start;
4495  }
4496  else
4497  {
4498  pad_hours = 0;
4499  pad_mins = 0;
4500  pad_secs = (start_padding < 0) ? (-1 * start_padding) : start_padding;
4501 
4502  while (pad_secs > 59)
4503  {
4504  pad_secs -= 60;
4505  pad_mins++;
4506  }
4507  while (pad_mins > 59)
4508  {
4509  pad_mins -= 60;
4510  pad_hours++;
4511  }
4512 
4513  if (start_padding > 0)
4514  {
4515  *start_time = STB_GCCalculateDHMS(timer_start,
4516  STB_GCCreateDHMS(0, pad_hours, pad_mins, pad_secs), CALC_SUB);
4517  }
4518  else
4519  {
4520  *start_time = STB_GCCalculateDHMS(timer_start,
4521  STB_GCCreateDHMS(0, pad_hours, pad_mins, pad_secs), CALC_ADD);
4522  }
4523  }
4524 
4525  *end_time = STB_GCCalculateDHMS(timer_start, timer_duration, CALC_ADD);
4526 
4527  if (end_padding != 0)
4528  {
4529  pad_hours = 0;
4530  pad_mins = 0;
4531  pad_secs = (end_padding < 0) ? (-1 * end_padding) : end_padding;
4532 
4533  while (pad_secs > 59)
4534  {
4535  pad_secs -= 60;
4536  pad_mins++;
4537  }
4538  while (pad_mins > 59)
4539  {
4540  pad_mins -= 60;
4541  pad_hours++;
4542  }
4543 
4544  if (end_padding > 0)
4545  {
4546  *end_time = STB_GCCalculateDHMS(*end_time,
4547  STB_GCCreateDHMS(0, pad_hours, pad_mins, pad_secs), CALC_ADD);
4548  }
4549  else
4550  {
4551  *end_time = STB_GCCalculateDHMS(*end_time,
4552  STB_GCCreateDHMS(0, pad_hours, pad_mins, pad_secs), CALC_SUB);
4553  }
4554  }
4555 }
4556 
4564 static void SetTimerFields(ADB_TIMER_REC *timer, S_TIMER_INFO *info)
4565 {
4566  U16BIT name_len;
4567 
4568  /* Set rest of timer fields based on info provided */
4569  timer->type = info->type;
4570 
4571  if ((info->frequency != TIMER_FREQ_ONCE) &&
4572  (info->frequency != TIMER_FREQ_WEEKLY) &&
4573  (info->frequency != TIMER_FREQ_WEEKENDDAYS) &&
4574  (info->frequency != TIMER_FREQ_WEEKDAYS) &&
4575  (info->frequency != TIMER_FREQ_DAILY))
4576  {
4577  timer->frequency = TIMER_FREQ_ONCE;
4578  }
4579  else
4580  {
4581  timer->frequency = info->frequency;
4582  }
4583 
4584  timer->start_time = info->start_time;
4585 
4586  if ((name_len = STB_GetNumBytesInString(info->name)) != 0)
4587  {
4588  memcpy(timer->name, info->name, name_len);
4589  }
4590  else
4591  {
4592  timer->name[0] = 0;
4593  }
4594 
4595  if (timer->dba_rec != NULL)
4596  {
4597  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_TYPE, timer->type);
4598  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_FREQUENCY, timer->frequency);
4599  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_STARTTIME, timer->start_time);
4600  DBA_SetFieldString(timer->dba_rec, DBA_FIELD_REC_NAME, timer->name, name_len);
4601  }
4602 
4603  switch (timer->type)
4604  {
4605  case TIMER_TYPE_ALARM:
4606  {
4607  timer->u.alarm.change_service = info->u.alarm.change_service;
4608 
4609  timer->u.alarm.orig_net_id = info->u.alarm.orig_net_id;
4610  timer->u.alarm.transport_id = info->u.alarm.transport_id;
4611  timer->u.alarm.service_id = info->u.alarm.service_id;
4612 
4613  timer->u.alarm.ramp_volume = info->u.alarm.ramp_volume;
4614 
4615  if (timer->dba_rec != NULL)
4616  {
4617  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_ORIG_NET_ID, timer->u.alarm.orig_net_id);
4618  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TRANSPORT_ID, timer->u.alarm.transport_id);
4619  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_SERVICE_ID, timer->u.alarm.service_id);
4620  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_RAMPVOLUME, timer->u.alarm.ramp_volume);
4621  }
4622  break;
4623  }
4624 
4625  case TIMER_TYPE_PVR_RECORD:
4626  {
4627  timer->u.record.duration = info->u.record.duration;
4628 
4629  timer->u.record.event_triggered = info->u.record.event_triggered;
4630  timer->u.record.event_id = info->u.record.event_id;
4631 
4632  timer->u.record.orig_net_id = info->u.record.orig_net_id;
4633  timer->u.record.transport_id = info->u.record.transport_id;
4634  timer->u.record.service_id = info->u.record.service_id;
4635 
4636  timer->u.record.disk_id = info->u.record.disk_id;
4637 
4638  timer->u.record.recommendation = info->u.record.recommendation;
4639 
4640  if (info->u.record.start_padding != timer->u.record.start_padding)
4641  {
4642  timer->u.record.has_start_padding = TRUE;
4643  timer->u.record.start_padding = info->u.record.start_padding;
4644  }
4645 
4646  if (info->u.record.end_padding != timer->u.record.end_padding)
4647  {
4648  timer->u.record.has_end_padding = TRUE;
4649  timer->u.record.end_padding = info->u.record.end_padding;
4650  }
4651 
4652  timer->u.record.notify_time = info->u.record.notify_time;
4653  timer->u.record.do_not_delete = info->u.record.do_not_delete;
4654 
4655  if ((name_len = STB_GetNumBytesInString(info->u.record.prog_crid)) != 0)
4656  {
4657  memcpy(timer->u.record.prog_crid, info->u.record.prog_crid, name_len);
4658  if (timer->dba_rec != NULL)
4659  {
4660  DBA_SetFieldString(timer->dba_rec, DBA_FIELD_TIMER_CRID, timer->u.record.prog_crid, name_len);
4661  }
4662  }
4663  else
4664  {
4665  timer->u.record.prog_crid[0] = '\0';
4666  }
4667 
4668  if ((name_len = STB_GetNumBytesInString(info->u.record.other_crid)) != 0)
4669  {
4670  memcpy(timer->u.record.other_crid, info->u.record.other_crid, name_len);
4671  if (timer->dba_rec != NULL)
4672  {
4673  DBA_SetFieldString(timer->dba_rec, DBA_FIELD_TIMER_OTHERCRID, timer->u.record.other_crid, name_len);
4674  }
4675  }
4676  else
4677  {
4678  timer->u.record.other_crid[0] = '\0';
4679  }
4680 
4681  if (timer->dba_rec != NULL)
4682  {
4683  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DURATION, timer->u.record.duration);
4684  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_EVENT_TRIGGERED,
4685  timer->u.record.event_triggered);
4686  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_EVENTID, timer->u.record.event_id);
4687  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_ORIG_NET_ID, timer->u.record.orig_net_id);
4688  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TRANSPORT_ID, timer->u.record.transport_id);
4689  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_SERVICE_ID, timer->u.record.service_id);
4690  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DISKID, timer->u.record.disk_id);
4691  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_CRID_RECOMMENDED, timer->u.record.recommendation);
4692  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_NOTIFY_TIME, timer->u.record.notify_time);
4693  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DO_NOT_DELETE, timer->u.record.do_not_delete);
4694  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_START_PADDING, timer->u.record.start_padding);
4695  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_END_PADDING, timer->u.record.end_padding);
4696  }
4697 
4698  timer->u.record.path = INVALID_RES_ID;
4699  break;
4700  }
4701 
4702  default:
4703  break;
4704  }
4705 }
4706 
4723 static U8BIT GetNumSimultaneousRecordings(U32BIT handle, U16BIT onet_id, U16BIT trans_id,
4724  U16BIT serv_id, U8BIT max_recordings, U32DHMS start_date_time,
4725  U32DHMS end_date_time, BOOLEAN include_start_padding, BOOLEAN include_end_padding,
4726  U32BIT **conflicting_timers)
4727 {
4728  ADB_TIMER_REC *timer;
4729  U32DHMS timer_duration;
4730  U32DHMS timer_end, timer_start;
4731  S_TIME_SLOT *timer_slot;
4732  U8BIT slot, max_slot;
4733  BOOLEAN slot_found;
4734 
4735 // FUNCTION_START(GetNumSimultaneousRecordings);
4736 
4737  /*
4738  * This function works by allocating an array of time slots that represent each of the tuners,
4739  * given by the max number of recordings. The list of timers is iterated, after being sorted
4740  * into date/time order, and for each timer that overlaps with the given start/end times the
4741  * time slots (tuners) are checked to see whether any of them are free to be used for that time
4742  * period (does the timer start/end overlap with the time slot start/end?). If the times overlap
4743  * for each used time slot then a new slot is required, but if not, then a slot can be reused.
4744  * The maximum number of slots used defines the maximum number of simultaneous recordings that
4745  * will take place during the given time period.
4746  */
4747  max_slot = 0;
4748 
4749  TMR_PVR_DBG(("GetNumSimultaneousRecordings(0x%x): between %02d.%02d -> %02d.%02d, max_recordings=%d",
4750  handle, DHMS_HOUR(start_date_time), DHMS_MINS(start_date_time), DHMS_HOUR(end_date_time),
4751  DHMS_MINS(end_date_time), max_recordings));
4752 
4753  /* Allocate memory to store the max number of simultaneous timers */
4754  timer_slot = (S_TIME_SLOT *)STB_AppGetMemory(max_recordings * sizeof(S_TIME_SLOT));
4755  if (conflicting_timers != NULL)
4756  {
4757  *conflicting_timers = (U32BIT *)STB_AppGetMemory(max_recordings * sizeof(U32BIT));
4758  if (*conflicting_timers != NULL)
4759  {
4760  for (slot = 0; slot < max_recordings; slot++)
4761  {
4762  (*conflicting_timers)[slot] = INVALID_TIMER_HANDLE;
4763  }
4764  }
4765  }
4766 
4767  DBDEF_SortTimers(TRUE);
4768 
4769  for (timer = DBDEF_GetNextTimerRec(NULL); timer != NULL; timer = DBDEF_GetNextTimerRec(timer))
4770  {
4771  if ((timer->type == TIMER_TYPE_PVR_RECORD) &&
4772  ((handle == INVALID_TIMER_HANDLE) || (timer->handle != handle)) &&
4773  !timer->expired && !timer->missed)
4774  {
4775  /* Get the timer's duration as saved in the database, if possible, so any extensions
4776  * to allow for overrun are ignored */
4777  if (timer->dba_rec != NULL)
4778  {
4779  DBA_GetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_DURATION, &timer_duration);
4780  }
4781  else
4782  {
4783  timer_duration = timer->u.record.duration;
4784  }
4785 
4786  GetActualStartEndTime(timer->start_time, timer_duration,
4787  (include_start_padding ? GetStartPadding(timer) : 0),
4788  (include_end_padding ? GetEndPadding(timer) : 0),
4789  &timer_start, &timer_end);
4790 
4791  TMR_PVR_DBG(("GetNumSimultaneousRecordings: Timer 0x%08lx: %u @ %02d.%02d -> %02d.%02d",
4792  timer->handle, DHMS_DATE(timer_start), DHMS_HOUR(timer_start), DHMS_MINS(timer_start),
4793  DHMS_HOUR(timer_end), DHMS_MINS(timer_end)));
4794 
4795  /* Check whether this timer coincides with the given period, but ignore timers that
4796  * coincide but are on the same service, i.e. it's a back-to-back recording, because
4797  * this event can't clash with the one that follows it */
4798  if ((timer_end > start_date_time) && (timer_start < end_date_time) &&
4799  ((onet_id != timer->u.record.orig_net_id) ||
4800  (trans_id != timer->u.record.transport_id) ||
4801  (serv_id != timer->u.record.service_id)))
4802  {
4803  /* Timer coincides with given time period.
4804  * Check whether the timer needs to be inserted into a new slot */
4805  slot_found = FALSE;
4806  for (slot = 0; !slot_found && (slot < max_slot) && (slot < max_recordings); )
4807  {
4808  if (timer_start >= timer_slot[slot].end_time)
4809  {
4810  TMR_PVR_DBG(("GetNumSimultaneousRecordings: Using slot %d", slot));
4811 
4812  /* This slot can be used for this timer */
4813  timer_slot[slot].start_time = timer_start;
4814  timer_slot[slot].end_time = timer_end;
4815 
4816  if ((conflicting_timers != NULL) && (*conflicting_timers != NULL))
4817  {
4818  TMR_PVR_DBG(("[%s:%d] Saving timer 0x%x\n", __FUNCTION__, __LINE__, timer->handle));
4819  (*conflicting_timers)[slot] = timer->handle;
4820  }
4821 
4822  slot_found = TRUE;
4823  }
4824  else
4825  {
4826  slot++;
4827  }
4828  }
4829 
4830  if (!slot_found && (max_slot < max_recordings))
4831  {
4832  TMR_PVR_DBG(("GetNumSimultaneousRecordings: New slot %d", max_slot));
4833  /* This timer needs a new slot */
4834  timer_slot[max_slot].start_time = timer_start;
4835  timer_slot[max_slot].end_time = timer_end;
4836 
4837  if ((conflicting_timers != NULL) && (*conflicting_timers != NULL))
4838  {
4839  (*conflicting_timers)[max_slot] = timer->handle;
4840  }
4841 
4842  max_slot++;
4843  }
4844  }
4845  }
4846  }
4847 
4848  STB_AppFreeMemory(timer_slot);
4849 
4850 // FUNCTION_FINISH(GetNumSimultaneousRecordings);
4851 
4852  return(max_slot);
4853 }
4854 
4855 static BOOLEAN SetStartPadding(ADB_TIMER_REC *timer, S32BIT padding)
4856 {
4857  BOOLEAN retval;
4858 
4859  if ((timer != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
4860  {
4861  timer->u.record.has_start_padding = TRUE;
4862  timer->u.record.start_padding = padding;
4863 
4864  retval = TRUE;
4865  }
4866  else
4867  {
4868  retval = FALSE;
4869  }
4870 
4871  return(retval);
4872 }
4873 
4874 static S32BIT GetStartPadding(ADB_TIMER_REC *timer)
4875 {
4876  S32BIT padding;
4877 
4878  padding = 0;
4879 
4880  if ((timer != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
4881  {
4882  if (timer->u.record.has_start_padding)
4883  {
4884  padding = timer->u.record.start_padding;
4885  }
4886  else
4887  {
4888  padding = APVR_GetStartPadding();
4889  }
4890  }
4891 
4892  return(padding);
4893 }
4894 
4895 static BOOLEAN SetEndPadding(ADB_TIMER_REC *timer, S32BIT padding)
4896 {
4897  BOOLEAN retval;
4898 
4899  if ((timer != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
4900  {
4901  timer->u.record.has_end_padding = TRUE;
4902  timer->u.record.end_padding = padding;
4903 
4904  if (timer->dba_rec != NULL)
4905  {
4906  DBA_SetFieldValue(timer->dba_rec, DBA_FIELD_TIMER_END_PADDING,
4907  timer->u.record.end_padding);
4908  }
4909 
4910  if (timer->started)
4911  {
4912  STB_PVRRecordingSetEndPadding(timer->u.record.recording_handle, timer->u.record.end_padding);
4913  }
4914 
4915  retval = TRUE;
4916  }
4917  else
4918  {
4919  retval = FALSE;
4920  }
4921 
4922  return(retval);
4923 }
4924 
4925 static S32BIT GetEndPadding(ADB_TIMER_REC *timer)
4926 {
4927  S32BIT padding;
4928 
4929  padding = 0;
4930 
4931  if ((timer != NULL) && (timer->type == TIMER_TYPE_PVR_RECORD))
4932  {
4933  if (timer->u.record.has_end_padding)
4934  {
4935  padding = timer->u.record.end_padding;
4936  }
4937  else
4938  {
4939  padding = APVR_GetEndPadding();
4940  }
4941  }
4942 
4943  return(padding);
4944 }
4945 
4946 #ifdef TMR_DEBUG
4947 
4951 static void DumpTimer(ADB_TIMER_REC *timer)
4952 {
4953  FUNCTION_START(DumpTimer);
4954 
4955  TMR_DBG(("Timer 0x%08lx: ", timer->handle));
4956  TMR_DBG((" name=\"%s\"", timer->name));
4957  TMR_DBG((" freq=%u", timer->frequency));
4958  TMR_DBG((" starts on=%u %02u:%02u:%02u",
4959  DHMS_DATE(timer->start_time), DHMS_HOUR(timer->start_time), DHMS_MINS(timer->start_time),
4960  DHMS_SECS(timer->start_time)));
4961 
4962  switch (timer->type)
4963  {
4964  case TIMER_TYPE_SLEEP:
4965  TMR_DBG((" type=SLEEP"));
4966  break;
4967 
4968  case TIMER_TYPE_ALARM:
4969  TMR_DBG((" type=ALARM"));
4970  TMR_DBG((" ramp volume=%u", timer->u.alarm.ramp_volume));
4971  TMR_DBG((" change service=%u", timer->u.alarm.change_service));
4972  TMR_DBG((" service=0x%04x/0x%04x/0x%04x", timer->u.alarm.orig_net_id,
4973  timer->u.alarm.transport_id, timer->u.alarm.service_id));
4974  break;
4975 
4976  case TIMER_TYPE_PVR_RECORD:
4977  TMR_DBG((" type=PVR RECORD"));
4978  TMR_DBG((" duration=%02u:%02u", DHMS_HOUR(timer->u.record.duration),
4979  DHMS_MINS(timer->u.record.duration)));
4980  TMR_DBG((" event triggered=%u", timer->u.record.event_triggered));
4981  if (timer->u.record.event_triggered)
4982  {
4983  TMR_DBG((" event id=%u", timer->u.record.event_id));
4984  }
4985  TMR_DBG((" service=0x%04x/0x%04x/0x%04x", timer->u.record.orig_net_id,
4986  timer->u.record.transport_id, timer->u.record.service_id));
4987  TMR_DBG((" disk id=0x%04x", timer->u.record.disk_id));
4988  if (strlen((char *)timer->u.record.prog_crid) != 0)
4989  {
4990  TMR_DBG((" prog crid=\"%s\"", timer->u.record.prog_crid));
4991  }
4992  if (strlen((char *)timer->u.record.other_crid) != 0)
4993  {
4994  TMR_DBG((" other crid=\"%s\"", timer->u.record.other_crid));
4995  TMR_DBG((" recommendation=%u", timer->u.record.recommendation));
4996  }
4997  TMR_DBG((" start padding=%u", timer->u.record.start_padding));
4998  TMR_DBG((" end padding=%u", timer->u.record.end_padding));
4999  TMR_DBG((" notify time=%u", timer->u.record.notify_time));
5000  TMR_DBG((" do_not_delete=%u", timer->u.record.do_not_delete));
5001  TMR_DBG((" recording handle=%08x", timer->u.record.recording_handle));
5002  TMR_DBG((" path=%u", timer->u.record.path));
5003  break;
5004 
5005  default:
5006  TMR_DBG((" type=OTHER(0x%02x)", timer->type));
5007  break;
5008  }
5009 
5010  TMR_DBG((" starting=%u", timer->starting));
5011  TMR_DBG((" started=%u", timer->started));
5012  TMR_DBG((" expired=%u", timer->expired));
5013  TMR_DBG((" missed=%u", timer->missed));
5014  TMR_DBG((" selected=%u", timer->selected));
5015 
5016  FUNCTION_FINISH(DumpTimer);
5017 }
5018 
5019 #endif /* TMR_DEBUG */
5020 
U32BIT ATMR_FindTimerFromEvent(U16BIT onet_id, U16BIT trans_id, U16BIT serv_id, U16BIT event_id)
Searches the timers for a recording timer with the given event and service IDs.
Definition: ap_tmr.c:2964
U32BIT ATMR_FindTimerFromCridAndEvent(U8BIT *prog_crid, U16BIT service_id, U16BIT event_id)
Searches the timers for a recording timer with the given programme CRID and event ID...
Definition: ap_tmr.c:3038
U32DHMS ADB_GetEventDuration(void *event_ptr)
Returns a value representing the duration of the given event.
Definition: ap_dbacc.c:8513
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
U8BIT STB_GCGetGMTDay(void)
Reads the current GMT day number.
Definition: stbgc.c:1273
U8BIT * ADB_GetEventSeriesCrid(U8BIT index, void *serv_ptr, void *event_ptr)
Returns the full series CRID of the given event The returned string should be freed using STB_AppFree...
Definition: ap_dbacc.c:9355
U32DHMS STB_GCCreateDHMSFromSeconds(U32BIT num_seconds)
Creates a DHMS value consisting of hours, minutes and seconds from a number of seconds.
Definition: stbgc.c:2110
BOOLEAN ATMR_HasRecommendationCrid(U32BIT handle)
Does the timer have a recommendation crid?
Definition: ap_tmr.c:1518
E_TIMER_FREQ ATMR_GetFrequency(U32BIT handle)
Returns the frequency setting for the given timer.
Definition: ap_tmr.c:1194
void ADB_SaveDatabase(void)
Saves the database to non-volatile memory.
Definition: ap_dbacc.c:502
macros and function prototypes for public use
BOOLEAN ATMR_HasSeriesCrid(U32BIT handle)
Does the timer have a series crid?
Definition: ap_tmr.c:1485
U16BIT ATMR_GetEventId(U32BIT handle)
Returns the event ID for a PVR recording timer.
Definition: ap_tmr.c:1284
U8BIT * ADB_GetEventFullProgrammeCrid(void *serv_ptr, void *event_ptr)
Returns the full programme CRID of the given event (including IMI). The returned string should be fre...
Definition: ap_dbacc.c:9193
Function prototypes for HW control.
U8BIT STB_GCGetGMTMin(void)
Reads the current GMT minute.
Definition: stbgc.c:1112
void ATMR_DeleteTimersForSeriesRecommendations(U8BIT *crid, BOOLEAN is_recommendation)
Deletes any PVR record timers with the given series CRID.
Definition: ap_tmr.c:3079
void STB_PVRRecordingSetEndPadding(U32BIT handle, S32BIT end_padding)
Sets the end padding value for the specified recording.
Definition: stbpvr.c:1924
void * ADB_GetEvent(void *serv_ptr, U16BIT event_id)
Returns a copy of the event with the given event ID on the given service.
Definition: ap_dbacc.c:8026
U16BIT ATMR_GetOriginalNetworkId(U32BIT handle)
Returns the original network ID for an alarm or PVR recording timer.
Definition: ap_tmr.c:1387
BOOLEAN STB_DPIsLivePath(U8BIT path)
Is the given decode path being used for live viewing.
Definition: stbdpc.c:1297
Application configuration.
void ATMR_Initialise(void)
Performs initialisation of the timers, reading existing entries from the database, rescheduling or deleting any timers that have been missed and starting background tasks.
Definition: ap_tmr.c:168
Application database control.
U32DHMS STB_GCNowDHMSGmt(void)
Reads the current GMT date code and time.
Definition: stbgc.c:2264
void ATMR_RecordingFailed(U8BIT path)
Handles the timer when a recording fails to start for some reason. This may result in the timer being...
Definition: ap_tmr.c:665
U32BIT ATMR_AddTimer(S_TIMER_INFO *info)
Creates a new timer based on the information supplied.
Definition: ap_tmr.c:189
Header file - macros and function prototypes for public use.
void STB_GCGetLocalTimeChange(U16BIT code, U8BIT hour, U8BIT min, U8BIT secs, U8BIT *ohour, U8BIT *omin, BOOLEAN *neg)
Reads local time offset from GMT.
Definition: stbgc.c:986
void ACTL_TuneOff(U8BIT path)
Stops tuning on the given path.
Definition: ap_cntrl.c:2079
BOOLEAN ATMR_UpdateTimerDuration(U32BIT handle, U32DHMS duration)
Updates the duration for an existing PVR recording timer.
Definition: ap_tmr.c:332
void STB_PVRRecordingSetAdditionalInfo(U32BIT handle, U8BIT *additional_info)
Sets the additional info string for a recording.
Definition: stbpvr.c:1721
S32BIT ATMR_GetStartPadding(U32BIT handle)
Returns the value of start padding associated with the specified timer The start padding is the numbe...
Definition: ap_tmr.c:3200
U32DHMS ADB_GetEventStartDateTime(void *event_ptr)
Returns a value representing the date and time of the start of the given event.
Definition: ap_dbacc.c:8441
void * STB_AppGetMemory(U32BIT bytes)
Attempts to allocate memory from the application heap.
Definition: stbheap.c:651
BOOLEAN ATMR_SetDoNotDelete(U32BIT handle, BOOLEAN do_not_delete)
Sets the do_not_delete flag in a recording timer, which if set to TRUE, will lock any recordings that...
Definition: ap_tmr.c:3336
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
U8BIT * ADB_GetEventProgrammeCrid(void *serv_ptr, void *event_ptr)
Returns the programme CRID of the given event (excluding IMI) The returned string should be freed usi...
Definition: ap_dbacc.c:9268
U16BIT ATMR_GetServiceId(U32BIT handle)
Returns the service ID for an alarm or PVR recording timer.
Definition: ap_tmr.c:1315
U16BIT ADB_GetEventStartDate(void *event_ptr)
Returns the MJD date code for the start of the given event.
Definition: ap_dbacc.c:8473
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
void DBDEF_DeleteTimerRec(ADB_TIMER_REC *timer)
Deletes the given timer from the database.
Definition: ap_dbdef.c:9966
void STB_DPStopRecording(U8BIT path)
Requests stop of recording on specified path.
Definition: stbdpc.c:2164
Definition: ap_tmr.h:97
void STB_GCCalculateDateTime(U16BIT code, U8BIT hour, U8BIT min, U8BIT secs, U8BIT ohour, U8BIT omin, U8BIT osecs, U16BIT *rcode, U8BIT *rhour, U8BIT *rmin, U8BIT *rsecs, E_STB_GC_CALCTYPE calc)
Adds or subtracts offset from a date/time.
Definition: stbgc.c:1540
BOOLEAN ATMR_GetTimerInfo(U32BIT handle, S_TIMER_INFO *timer_info)
Copies timer data for the given timer info the info structure provided.
Definition: ap_tmr.c:885
BOOLEAN ATMR_CheckRecordStatus(BOOLEAN recordings_can_start, void *service)
Checks all timers to see whether any recordings should be started or stopped as a result of the now e...
Definition: ap_tmr.c:1939
PVR messages database access functions header file.
BOOLEAN APVR_StartNewRecording(U16BIT disk_id, U8BIT path, U8BIT *recording_name, U16BIT event_id, U8BIT *prog_crid, U8BIT *other_crid, U32BIT *rec_handle)
Starts a recording after any tuning has completed and sets the info to be stored with it...
Definition: ap_pvr.c:1837
U8BIT ATMR_GetNumSimultaneousRecordings(U8BIT max_recordings, U32DHMS start_date_time, U32DHMS end_date_time, U32BIT **conflicting_timers)
Counts the number of simultaneous recordings (EXT and PVR) between the given start and end dates/time...
Definition: ap_tmr.c:2432
void STB_PVRRecordingSetStartPadding(U32BIT handle, S32BIT start_padding)
Sets the start padding value for the specified recording.
Definition: stbpvr.c:1861
BOOLEAN ATMR_GetTimerList(U32BIT **timer_list, U16BIT *list_size_ptr, E_TIMER_TYPE list_type, BOOLEAN date_time_order)
Returns a list of all the timer handles and the number of items in the list.
Definition: ap_tmr.c:470
U32BIT ATMR_AddTimerForEvent(void *event_ptr, void *serv_ptr, BOOLEAN record, BOOLEAN event_triggered)
Creates a timer based on the given event. If a recording timer is created, it will be set to record o...
Definition: ap_tmr.c:251
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 * ADB_FindServiceByIds(U16BIT onet_id, U16BIT tid, U16BIT sid)
Returns a pointer to the service matching the given IDs.
Definition: ap_dbacc.c:4071
void ASTE_StartRecording(void)
Definition: ap_state.c:140
Application timer functions and defines.
void ADB_GetNowNextEvents(void *serv_ptr, void **now_event, void **next_event)
Makes copies of the now and/or next events (EITp/f) for the given service. The returned events should...
Definition: ap_dbacc.c:7587
BOOLEAN ATMR_InitialiseTimer(S_TIMER_INFO *timer_info, E_TIMER_TYPE timer_type, void *serv_ptr, void *event_ptr)
Sets up the given timer info structure with default values for the given timer type using the service...
Definition: ap_tmr.c:724
BOOLEAN STB_DPReleasePath(U8BIT path, E_STB_DP_RES_OWNER owner)
Releases the decode path and all resources no longer needed. The path won&#39;t be released if the path i...
Definition: stbdpc.c:785
Header file - macros and function prototypes for public use.
S32BIT ATMR_GetEndPadding(U32BIT handle)
Returns the value of end padding associated with the specified timer The end padding is the number of...
Definition: ap_tmr.c:3271
U8BIT ADB_GetEventStartMin(void *event_ptr)
Returns the minute (0-59) value for the start of the given event.
Definition: ap_dbacc.c:8493
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
BOOLEAN ATMR_SetStartPadding(U32BIT handle, S32BIT start_padding)
Sets the value of start padding associated with the specified timer The start padding is the number o...
Definition: ap_tmr.c:3233
U32BIT ATMR_GetFirstWakeupTime(U32DHMS *date_time, U16BIT *onet_id, U16BIT *trans_id, U16BIT *service_id)
Searches the timers for the first timer that will cause the DVB to wakeup that hasn&#39;t been missed...
Definition: ap_tmr.c:2895
U16BIT ATMR_GetDiskId(U32BIT handle)
Returns the disk id for the given timer if the timer is a PVR recording timer.
Definition: ap_tmr.c:1584
U8BIT * ATMR_GetName(U32BIT handle)
Get the name of the timer with the given handle.
Definition: ap_tmr.c:1009
U8BIT STB_GCGetGMTMonth(void)
Reads the current GMT month number.
Definition: stbgc.c:1305
U8BIT APVR_PrepareNewRecording(U16BIT onet_id, U16BIT trans_id, U16BIT service_id, BOOLEAN *new_tuned_service)
Acquires a decode path for recording the given service and tunes to it.
Definition: ap_pvr.c:1793
U16BIT ATMR_GetTransportId(U32BIT handle)
Returns the transport ID for an alarm or PVR recording timer.
Definition: ap_tmr.c:1351
void STB_PVRStartRecordRunning(U8BIT path)
Set to start recording in running mode.
Definition: stbpvr.c:4978
U8BIT ADB_GetEventDurationMin(void *event_ptr)
Returns the minute value (0-59) for the duration of the given event.
Definition: ap_dbacc.c:8555
void STB_ReleaseUnicodeString(U8BIT *string)
Releases the specified unicode string, freeing associated heap resources.
Definition: stbuni.c:1955
BOOLEAN ATMR_GetMissed(U32BIT handle)
Gets the timer&#39;s missed flag.
Definition: ap_tmr.c:1422
U16BIT STB_GCGetGMTYear(void)
Reads the current GMT year number.
Definition: stbgc.c:1337
void DBDEF_ReleaseAccess(void)
Releases access to the app&#39;s database.
Definition: ap_dbdef.c:245
void ATMR_DumpAllTimers(void)
Prints details of all existing timers.
Definition: ap_tmr.c:3392
U16BIT ADB_GetServiceLcn(void *s_ptr)
Returns the logical channel number assigned to the given service.
Definition: ap_dbacc.c:4940
BOOLEAN ACFG_IsNordigCountry(void)
Returns whether the current country requires Nordig compliance for SI.
Definition: ap_cfg.c:1656
BOOLEAN DBA_SetFieldString(void *record, U32BIT field_id, U8BIT *string, U16BIT num_bytes)
Set the string value of a record&#39;s field. The function will fail if the record doesn&#39;t exist...
Definition: dba_nvm.c:1227
void ATMR_ReleaseTimerList(U32BIT *timer_list, U16BIT list_size)
Release the given array of timer handles.
Definition: ap_tmr.c:538
U32DHMS ATMR_GetStartDateTime(U32BIT handle)
Get the start date & time of the timer with the given handle. The date/time returned will be in UTC...
Definition: ap_tmr.c:1072
Debug functions header file.
Header file - Function prototypes for linked lists.
Header file - macros and function prototypes for public use.
U8BIT * ATMR_GetOtherCrid(U32BIT handle)
Returns a pointer to the other CRID string from a recording timer. This will either be a series or re...
Definition: ap_tmr.c:1553
Header file - macros and function prototypes for public use.
Database access defines, structures and public functions.
U8BIT ADB_GetEventDurationHour(void *event_ptr)
Returns the hour value for the duration of the given event.
Definition: ap_dbacc.c:8545
void * ADB_GetLaterEvent(void *serv_ptr, U16BIT date, U8BIT hour, U8BIT min)
Returns a copy of the event following the given date/time on the given service.
Definition: ap_dbacc.c:8321
void * ATMR_RecordEvent(void *serv_ptr, void *event_ptr, U8BIT *prog_crid, U8BIT *other_crid, BOOLEAN is_recommendation, BOOLEAN check_alternatives, BOOLEAN do_not_delete)
Adds a timer to perform a recording based on the given event and service. Conflicts are checked and a...
Definition: ap_tmr.c:2466
Header file - Function prototypes for Event Reporting.
BOOLEAN ATMR_DeleteTimer(U32BIT handle)
Delete the timer with the given handle.
Definition: ap_tmr.c:436
Header for STB unicode string handling routines.
void * ATMR_GetRecordService(U8BIT path)
Returns the service for the recording timer on the given path.
Definition: ap_tmr.c:972
void ATMR_SetName(U32BIT handle, U8BIT *name)
Sets the name of the timer with the given handle.
Definition: ap_tmr.c:1036
void * ADB_FindEventFromCrid(U8BIT *prog_crid, void *original_event_ptr, void **serv_ptr)
Finds an alternative event for the given programme CRID and returns a pointer to a copy of the event ...
Definition: ap_dbacc.c:9535
void * ADB_GetEarlierEvent(void *serv_ptr, U16BIT date, U8BIT hour, U8BIT min)
Returns a copy of the event preceeding the given date/time on the given service.
Definition: ap_dbacc.c:8244
void DBDEF_RequestAccess(void)
Requests access to the app&#39;s database.
Definition: ap_dbdef.c:235
U8BIT ACTL_TuneToService(U8BIT path, S_ACTL_OWNER_INFO *owner_info, void *s_ptr, BOOLEAN override_lock, BOOLEAN for_live)
Starts the process of tuning to the specified service. If the service is to be tuned on the live path...
Definition: ap_cntrl.c:1651
BOOLEAN ATMR_StartRecord(U8BIT path)
Finds the timer using the given decode path and if it&#39;s a recording timer the recording will be start...
Definition: ap_tmr.c:558
U32BIT ATMR_GetRecordingHandle(U32BIT handle)
Returns the recording handle associated with a PVR recording timer.
Definition: ap_tmr.c:1643
void ATMR_DeleteRecordingTimer(U32BIT recording_handle)
Delete the PVR record timer with the given recording handle.
Definition: ap_tmr.c:2382
BOOLEAN STB_GCIsFutureDateTime(U16BIT code, U8BIT hour, U8BIT min, U8BIT secs)
Tests given date and time against current GMT date and time.
Definition: stbgc.c:1411
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
U32BIT STB_GetNumBytesInString(U8BIT *string_ptr)
Determines the no of bytes of the given string.
Definition: stbuni.c:311
Application stb layer control.
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_DPStopSI(U8BIT path)
Requests stop of SI engine.
Definition: stbdpc.c:3076
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
BOOLEAN APVR_StopRecording(U32BIT recording_handle)
Stops the given recording.
Definition: ap_pvr.c:2156
void STB_AppFreeMemory(void *addr)
Releases previously allocated application heap memory.
Definition: stbheap.c:781
Application level HBBTV callback functions.
U8BIT STB_GCGetGMTHour(void)
Reads the current GMT hour.
Definition: stbgc.c:1081
BOOLEAN STB_PVRRecordingSetLocked(U32BIT handle, BOOLEAN state)
Sets the locked state of a recording.
Definition: stbpvr.c:2531
U8BIT ADB_GetEventStartHour(void *event_ptr)
Returns the hour (0-23) value for the start of the given event.
Definition: ap_dbacc.c:8483
BOOLEAN ATMR_GetRampVolume(U32BIT handle)
Returns the ramp volume setting for an alarm timer.
Definition: ap_tmr.c:1254
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...
void * STB_OSCreateQueue(U16BIT msg_size, U16BIT msg_max)
Create Queue of given number of messages and size of message.
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
S32BIT APVR_GetStartPadding(void)
Returns the current setting for the start padding time added to all recording timers.
Definition: ap_pvr.c:816
void STB_GCGetMJDDateInfo(U16BIT code, U8BIT *day, U8BIT *wday, U8BIT *month, U16BIT *year)
Returns the date info from the given MJD date code.
Definition: stbgc.c:1902
U32BIT ATMR_FindRecordingTimer(U32BIT recording_handle)
Finds the timer for the given recording handle.
Definition: ap_tmr.c:2346
Header file - Function prototypes for heap memory.
void ADB_GetServiceIds(void *s_ptr, U16BIT *onet_id, U16BIT *trans_id, U16BIT *serv_id)
Returns the original network id, transport id and service id for the given service.
Definition: ap_dbacc.c:4982
U8BIT * ATMR_GetProgrammeCrid(U32BIT handle)
Returns a pointer to the programme CRID string from a recording timer. The returned value shouldn&#39;t b...
Definition: ap_tmr.c:1453
void ATMR_SetAdditionalInfo(U32BIT handle, U8BIT *info, U32BIT size)
Sets the additioinal information string for the specified timer and commits the change to the databas...
Definition: ap_tmr.c:3128
U8BIT * ATMR_GetAdditionalInfo(U32BIT handle, U32BIT *size)
Gets the additional information string associated with a timer. The name is allocated in UI temp memo...
Definition: ap_tmr.c:3170
Application header file.
void DBDEF_SortTimers(BOOLEAN date_time_order)
Sorts timer list into date/time or alphabetical order.
Definition: ap_dbdef.c:9946
BOOLEAN STB_OSReadQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Read a message from a queue.
U32DHMS ADB_GetEventEndDateTime(void *event_ptr)
Returns a value representing the date and time of the end of the given event.
Definition: ap_dbacc.c:8575
U8BIT STB_HWGetNumRecorders(void)
Returns the number of recordings that can take place at the same time.
Function prototypes for disk functions.
void HBBTV_NotifyRecordingEvent(U32BIT id, E_HBBTV_RECORDING_EVENT event)
Notifies the HbbTV engine of a recording event.
BOOLEAN ATMR_GetChangeService(U32BIT handle)
Returns the change service setting for an alarm timer.
Definition: ap_tmr.c:1224
void STB_OSTaskDelay(U16BIT timeout)
Delay Task for Specifed Time Period.
U16BIT STB_GCGetGMTDate(void)
Reads the current GMT date code.
Definition: stbgc.c:1207
BOOLEAN ATMR_SetEndPadding(U32BIT handle, S32BIT end_padding)
Sets the value of end padding associated with the specified timer The end padding is the number of se...
Definition: ap_tmr.c:3304
U16BIT ADB_GetEventId(void *event_ptr)
Returns the event id for the given event.
Definition: ap_dbacc.c:8970
BOOLEAN ATMR_RecordSplitEvent(void *serv_ptr, U8BIT *prog_crid, U32DHMS start_date_time, BOOLEAN do_not_delete, BOOLEAN search_forward)
Searches for events within 3 hours of the given start date/time for an event with the given programme...
Definition: ap_tmr.c:2653
S32BIT APVR_GetEndPadding(void)
Returns the current setting for the end padding time added to all recording timers.
Definition: ap_pvr.c:827
ADB_TIMER_REC * DBDEF_GetNextTimerRec(ADB_TIMER_REC *timer_ptr)
Returns the next timer record after the one given. If the argument is NULL then the first record is r...
Definition: ap_dbdef.c:9922
BOOLEAN DBA_GetFieldValue(void *record, U32BIT field_id, U32BIT *value)
Gets 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:1341
E_TIMER_TYPE ATMR_GetType(U32BIT handle)
Returns the type of the given timer.
Definition: ap_tmr.c:1164
BOOLEAN APVR_DeleteRecording(U32BIT handle)
Delete the given recording, including all files associated with it and remove it from the database of...
Definition: ap_pvr.c:2320
BOOLEAN ATMR_UpdateTimer(U32BIT handle, S_TIMER_INFO *info)
Updates all the timer fields.
Definition: ap_tmr.c:397
ADB_TIMER_REC * DBDEF_AddTimerRec(BOOLEAN store_in_nvm)
Creates a new timer record in the database, assigning it a unique handle.
Definition: ap_dbdef.c:9833
U16BIT APVR_GetNotifyTime(void)
Returns the current recording notification time in seconds.
Definition: ap_pvr.c:775
U8BIT * ADB_GetEventName(void *event_ptr)
Returns the name of the event as a UTF-8 string. The returned string should be freed using STB_Releas...
Definition: ap_dbacc.c:8740
U32DHMS ATMR_GetEndDateTime(U32BIT handle)
Get the end date & time of the timer with the given handle. The date/time returned will be in UTC...
Definition: ap_tmr.c:1129
U32BIT ATMR_FindTimerFromCrid(U8BIT *prog_crid)
Searches the timers for a recording timer with the given programme CRID.
Definition: ap_tmr.c:3000
U16BIT STB_PVRGetDefaultDisk(void)
Returns the set default disk, or finds the first mounted (usable) disk if a default hasn&#39;t been set...
Definition: stbpvr.c:512
U32DHMS ATMR_GetDuration(U32BIT handle)
Returns the duration of the PVR record timer with the given handle.
Definition: ap_tmr.c:1100
void ATMR_HandleTimerEvent(U32BIT handle)
Used by the DVB stack to handle an event for the given timer. If the timer requires the app to deal w...
Definition: ap_tmr.c:1674
Application database access functions.
BOOLEAN ATMR_GetDoNotDelete(U32BIT handle)
Returns the setting of the do not delete flag for the given timer.
Definition: ap_tmr.c:3364
ADB_TIMER_REC * DBDEF_FindTimerRec(U32BIT handle)
Returns the timer record with the given timer handle.
Definition: ap_dbdef.c:9899
Header file - macros and function prototypes for public use.
void ATMR_EitUpdated(void)
Checks each recording timer that&#39;s linked to an event to see whether the event is still in the schedu...
Definition: ap_tmr.c:2102
E_STB_GC_WEEKDAY STB_GCGetDateWeekDay(U16BIT code)
Returns the weekday number of the specified date code.
Definition: stbgc.c:1448
void ATMR_SetDiskId(U32BIT handle, U16BIT disk_id)
Set the disk for the given timer if the timer is a recording timer.
Definition: ap_tmr.c:1614
void ADB_ReleaseEventData(void *event_ptr)
Frees any memory allocated for the given event and the event itself.
Definition: ap_dbacc.c:7907