DVBCore  20.3.0
DVBCore Documentation
stbebutt.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 /*#define EBU_DEBUG*/
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 
35 // third party header files
36 
37 // Ocean Blue Software header files
38 
39 #include <techtype.h>
40 #include <dbgfuncs.h>
41 
42 #define _STBEBUTT_C
43 
44 #include <stbhwmem.h>
45 #include "stbebutt.h"
46 #include "stbhwos.h"
47 #include "stbheap.h"
48 #include "stbpes.h"
49 #include "stbhwosd.h"
50 #include "stbdpc.h"
51 #include "stbhwav.h"
52 
53 //---constant definitions for this file----------------------------------------
54 
55 #define COLLATION_QUEUE_SIZE 400
56 
57 #define SD_WIDTH 720
58 #define SD_HEIGHT 576
59 
60 #ifdef EBU_DEBUG
61 #define EBU_DBG(x, ...) STB_SPDebugWrite( "%s:%d(%d)" x, __FUNCTION__,__LINE__,STB_OSGetClockMilliseconds(), ##__VA_ARGS__)
62 #define EBU_PRINT(x, ...) STB_SPDebugNoCnWrite(x, ##__VA_ARGS__)
63 #define EBU_TPRINT(x, ...)
64 #else
65 #define EBU_DBG(x, ...)
66 #define EBU_PRINT(x, ...)
67 #define EBU_TPRINT(x, ...)
68 #endif
69 
70 #if 0
71 #ifdef FUNCTION_START
72 #undef FUNCTION_START
73 #endif
74 #define FUNCTION_START(x) STB_SPDebugWrite(">> %s\n", # x)
75 
76 #ifdef FUNCTION_FINISH
77 #undef FUNCTION_FINISH
78 #endif
79 #define FUNCTION_FINISH(x) STB_SPDebugWrite("<< %s\n", # x)
80 #endif
81 
82 // Used within PESCollectionCallback() to extract individual Teletext packets from a PES data block.
83 #define PES_DATA_FIELD_WIDTH 46
84 
85 // Hamming decoding constants
86 #define HAMMING_8_4_DATA_MASK 0x000f
87 #define HAMMING_CORRECTION_MASK 0x03f0
88 #define HAMMING_ERROR_MASK 0xfc00
89 
90 #define HAMMING_CORRECTION_COUNT(a) ((a & HAMMING_CORRECTION_MASK) >> 4)
91 #define HAMMING_ERROR_COUNT(a) ((a & HAMMING_ERROR_MASK) >> 10)
92 
93 #define COLLATION_TASK_PRIORITY 10
94 #define COLLATION_TASK_STACK_SIZE 4096
95 
96 #define DISPLAY_TASK_PRIORITY 10
97 #define DISPLAY_TASK_STACK_SIZE 4096
98 
99 // These flags are used to mark pages in the cache according to the relevamt requirement to keep
100 // the data - this is based apon the caching requests made by the driver.
101 // These flags are stored in the upper unused bits of S_CACHE_PAGE->page_number
102 #define CACHE_PAGE_NUMBER_MASK 0x0fff
103 #define CACHE_PAGE_FLOF_REQUESTED 0x8000
104 #define CACHE_PAGE_HISTORY_REQUESTED 0x4000
105 #define CACHE_PAGE_PREVNEXT_REQUESTED 0x2000
106 #define CACHE_PAGE_LOCKED 0x1000 // set when displayed or requested!
107 
108 // This is used when (for instance) no sub-code is specified when making a display request
109 #define PAGE_SUB_CODE_UNDEFINED 0xffff
110 
111 // Cache constants used to limit data capacity.
112 #define MAX_HISTORY_CACHE_REQUESTS 32
113 
114 // This defines the maximum number of page FLOF editorial links that are analysed - this figure
115 // can be no higher than 6, but stting it to 4 will result in no localised index definitions
116 // being used.
117 #define MAX_EDITORIAL_LINKS 6
118 
119 // This constant defines how deeply the editorial links from the currently displayed page are
120 // analysed to determine which pages should be cached.
121 // The minimum sensible value is 2, and values over 5 are not recommended if memory constaints are
122 // a consideration!
123 #define MAX_EDITORIAL_LINK_TIERS 5
124 
125 // These constants determine how many directly adjacent pages before and after the currently
126 // displayed page are cached.
127 #define NUM_NEXT_CACHE_REQUESTS 16
128 #define NUM_PREVIOUS_CACHE_REQUESTS 8
129 
130 #define INVALID_PREVNEXT_CACHE_PAGE_NUMBER 0x1000
131 
132 #define MAX_PAGE_HISTORY 32
133 
134 // The palette used by our system consists of a bank of 256 TRGB values.
135 
136 // The first value in the bank is set to transparent.
137 // (This is used as background color for areas of unused teletext plane)
138 #define PALETTE_BACKGROUND_TRANSPARENT 0
139 
140 // This background allocation is fixed as back colur - this differs from PALETTE_BACKGROUND_BLACK
141 // in that it is unaffected by 'video-mix' display mode.
142 // This is essentailly used to enforce a non-transparent display of page header content under
143 // certain conditions when the rest of the page has a transparent backdrop.
144 #define PALETTE_BACKGROUND_BLACK_FIXED 1
145 
146 // These are used for background colour references, and will be made transparent when
147 // video 'mix' mode toggling.
148 #define PALETTE_BACKGROUND_BLACK 2
149 #define PALETTE_BACKGROUND_RED 3
150 #define PALETTE_BACKGROUND_GREEN 4
151 #define PALETTE_BACKGROUND_YELLOW 5
152 #define PALETTE_BACKGROUND_BLUE 6
153 #define PALETTE_BACKGROUND_MAGENTA 7
154 #define PALETTE_BACKGROUND_CYAN 8
155 #define PALETTE_BACKGROUND_WHITE 9
156 
157 // These are used for foreground colour references, and are UNAFFECTED by
158 // video 'mix' mode toggling.
159 #define PALETTE_FOREGROUND_BLACK 10
160 #define PALETTE_FOREGROUND_RED 11
161 #define PALETTE_FOREGROUND_GREEN 12
162 #define PALETTE_FOREGROUND_YELLOW 13
163 #define PALETTE_FOREGROUND_BLUE 14
164 #define PALETTE_FOREGROUND_MAGENTA 15
165 #define PALETTE_FOREGROUND_CYAN 16
166 #define PALETTE_FOREGROUND_WHITE 17
167 
168 // This definition is for clarity - when displaying page content outside of Subtitle and newsflash
169 // text boxes, the display is simply painted for transparency.
170 #define PALETTE_FOREGROUND_UNBOXED 0
171 
172 // This constant defines the LUT offset of the first dynamically defined palette entry.
173 // These entries, known as 'palette effects' are reserved for foreground background colour pairings
174 // involved in palette related effects such as flashing and concealed content. This method permits
175 // dynamic page content to be maintained with no display updates, merely bay altering the relevant
176 // palette entries.
177 #define PALETTE_EFFECT_ORIGIN 18
178 
179 #define NUM_PALETTE_EFFECTS (256 - PALETTE_EFFECT_ORIGIN)
180 
181 // The remaning values are dynamically adjusted to give flash and conceal functionality.
182 // The palette colours used by these LUT entries are defined in an array of page palette
183 // requirements as defined below
184 #define PALETTE_EFFECT_FLASH 0x01
185 #define PALETTE_EFFECT_CONCEAL 0x02
186 #define PALETTE_EFFECT_UNDEFINED 0 // Used as demarkation of first unused attribute array entry.
187 
188 // Indexes used to reference specific font tables within the S_EBUTT_FONT->font_table_set_ptr array
189 // These are also used for the S_TELETEXT_CHARACTER->info mask
190 #define FONT_INDEX_LATIN_G0_SET 0
191 #define FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET 1
192 #define FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN 2
193 #define FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN 3
194 #define FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN 4
195 #define FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET 5
196 #define FONT_INDEX_GREEK_G0_SET 6
197 #define FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET 7
198 #define FONT_INDEX_ARABIC_G0_SET 8
199 #define FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET 9
200 #define FONT_INDEX_HEBREW_G0_SET 10
201 #define FONT_INDEX_G1_BLOCK_MOSAICS_SET 11
202 #define FONT_INDEX_G3_SMOOTH_MOSAICS_LINE_DRAWING_SET 12
203 
204 #define FONT_INDEX_UNDEFINED 13
205 
206 // These are only used for the S_TELETEXT_CHARACTER->imfo mask
207 #define FONT_INDEX_NATIONAL_OPTION_SUBSET 14
208 #define FONT_INDEX_NO_BITMAP 15
209 
210 // Indexes used to reference National Option Subsets for the Latin font.
211 // These are effectively offsets to the tables within the S_EBUTT_FONT->font_table_set_ptr array
212 // These are also used for the S_TELETEXT_CHARACTER->info mask to store the font required for each
213 // character to be rendered.
214 #define NATIONALITY_INDEX_CZECH_SLOVAK 0
215 #define NATIONALITY_INDEX_ENGLISH 1
216 #define NATIONALITY_INDEX_ESTONIAN 2
217 #define NATIONALITY_INDEX_FRENCH 3
218 #define NATIONALITY_INDEX_GERMAN 4
219 #define NATIONALITY_INDEX_ITALIAN 5
220 #define NATIONALITY_INDEX_LETTISH_LITHUANIAN 6
221 #define NATIONALITY_INDEX_POLISH 7
222 #define NATIONALITY_INDEX_PORTUGUESE_SPANISH 8
223 #define NATIONALITY_INDEX_RUMANIAN 9
224 #define NATIONALITY_INDEX_SERB_CROAT_SLOVENIAN 10
225 #define NATIONALITY_INDEX_SWEDISH_FINNISH 11
226 #define NATIONALITY_INDEX_TURKISH 12
227 
228 #define NATIONALITY_INDEX_UNDEFINED 13
229 
230 // This mask maps the bits in S_TELETEXT_CHARACTER-> info onto the FONT_INDEX_???? contants
231 #define TELETEXT_CHARACTER_FONT_INDEX_MASK 0x0f00
232 
233 // This is the absolute index of the character within the given font table.
234 // To acquire a pointer to the bitmap, this will have to be scaled up to a data offset.
235 #define TELETEXT_CHARACTER_BITMAP_INDEX_MASK 0x00ff
236 
237 // These two bits are used in the S_TELETEXT_CHARACTER-> info
238 #define TELETEXT_CHARACTER_DOUBLE_HEIGHT 0x8000
239 #define TELETEXT_CHARACTER_SEPERATED_MOSAIC 0x4000
240 
241 // This nominal constant defines the maximum zoom factor permitted by the system.
242 // At present, there is no functionality that allows the zoom factor to be altered - there is only
243 // the standard double-height support.
244 // NB - this is not related to the scalars passed to STB_EBUTT_DefineDisplayProperties()
245 #define MAX_DISPLAY_ZOOM_SCALAR 2
246 
247 #define MAX_COLUMN 40
248 #define MAX_ROWS 25
249 #define display_x_scalar 1
250 #define display_y_scalar 2
251 
252 #define SUBTITLE_TIMEOUT 5000 /*5 secs*/
253 
254 // This is the essential enumerate used for the state machine used for the user input / page
255 // selection mechanism encapsulated in S_PAGE_CONTROL_INFO.
256 typedef enum e_page_control_state
257 {
258  PAGE_CONTROL_STATE_IDLE, // Initial state (when no page has been selected) and state when
259  // requested page has been dislayed.
260 
261  PAGE_CONTROL_STATE_INPUT, // The user is in process of inputting a three-digit page number.
262 
263  PAGE_CONTROL_STATE_HOLD // The currently displayed page is being held (no sub-page updates)
264 }
265 E_PAGE_CONTROL_STATE;
266 
267 // This enumerate is used to define the user requested page requirement and are used in
268 // S_PAGE_REQUEST_INFO->type
269 typedef enum e_request_type
270 {
271  REQUEST_TYPE_UNDEFINED = 0,
272  REQUEST_TYPE_EXPLICIT,
273  REQUEST_TYPE_INDEX,
274  REQUEST_TYPE_NEXT_PREV_AVAILABLE,
275  REQUEST_TYPE_NEXT_PREV_VISITED,
276  REQUEST_TYPE_NEXT_PREV_SUB,
277  REQUEST_TYPE_EDITORIAL_LINK,
278 
279  REQUEST_TYPE_CANCEL
280 }
281 E_REQUEST_TYPE;
282 
283 // These constants are used to define the contents of the three-digit page display within the
284 // S_PAGE_DISPLAY_INFO.
285 // This enumerate is used as it is independant of any ASCII or font-related representation.
286 typedef enum E_PAGE_INDEX_DIGIT
287 {
288  PAGE_INDEX_DIGIT_0,
289  PAGE_INDEX_DIGIT_1,
290  PAGE_INDEX_DIGIT_2,
291  PAGE_INDEX_DIGIT_3,
292  PAGE_INDEX_DIGIT_4,
293  PAGE_INDEX_DIGIT_5,
294  PAGE_INDEX_DIGIT_6,
295  PAGE_INDEX_DIGIT_7,
296  PAGE_INDEX_DIGIT_8,
297  PAGE_INDEX_DIGIT_9,
298  PAGE_INDEX_DIGIT_A,
299  PAGE_INDEX_DIGIT_B,
300  PAGE_INDEX_DIGIT_C,
301  PAGE_INDEX_DIGIT_D,
302  PAGE_INDEX_DIGIT_E,
303  PAGE_INDEX_DIGIT_F,
304  PAGE_INDEX_DIGIT_UNDEFINED
305 }
306 E_PAGE_INDEX_DIGIT;
307 
308 // These constants are used to define the state of the double-height display mechanism within the
309 // S_PAGE_DISPLAY_INFO.
310 typedef enum e_page_scale_status
311 {
312  PAGE_SCALE_STATUS_NORMAL = 0, // Normal page scale - the whole page should be visible.
313 
314  PAGE_SCALE_STATUS_ZOOM_TOP, // Zoom activated - should show top portion of page.
315  // This is also used when scrolling the zoomed display.
316 
317  PAGE_SCALE_STATUS_ZOOM_BOTTOM // Only used if zoom is x2 - allows double height toggling.
318 }
319 E_PAGE_SCALE_STATUS;
320 
321 // This is used to define which type of page reference is to be extracted when using
322 // GetPageReference() to polulate the S_PAGE_REFERENCE_DATA structure.
323 typedef enum e_page_reference_type
324 {
325  PAGE_REFERENCE_TYPE_HEADER, // Get all the poage header info, including control bits.
326 
327  PAGE_REFERENCE_TYPE_EDITORIAL_LINK, // Get a FLOF shortcut link for a given page.
328 
329  PAGE_REFERENCE_TYPE_GLOBAL_INDEX // Get a global index page reference from magazine-related data.
330 }
331 E_PAGE_REFERENCE_TYPE;
332 
333 //---local typedef structs for this file---------------------------------------
334 
335 // This structure is used to encapsulate the core varibales used in the user-input functionality.
336 // A single instance of this structure is defined within this module, and the data is then
337 // analysed by the caching mechanism and the display update task.
338 typedef struct s_page_control_info
339 {
340  // The variables here are accessed by the control interface, caching, and page display threads,
341  // but there is no requirement for a semaphore mechanism at present.
342 
343  // The core flag defining the user page number input state-machine.
344  E_PAGE_CONTROL_STATE state;
345 
346  // These are used to store the page number as it is input.
347  U8BIT page_digit[3];
348  U16BIT page_digit_offset;
349 
350  // These three flags define user-selected functionality that is analysed by the page display
351  // task.
352  BOOLEAN reveal_required;
353 
354  BOOLEAN video_mix_required;
355 
356  BOOLEAN clear_required;
357 }
359 
360 // This structure is used to encapsulate data that is used to specify each page request.
361 // A single instance of this structure is defined within this module, and is used by all page
362 // request functions (principally RequestPage() ) to record such page selections.
363 typedef struct s_page_request_info
364 {
365  // These are variables configured by page request functionality, and then analysed by the
366  // caching mechanism.
367 
368  // The nature of the page request.
369  E_REQUEST_TYPE type;
370 
371  S16BIT param;
372 
373  // These are set only when the type is REQUEST_TYPE_EXPLICIT.
374  U16BIT page_number;
375  U16BIT page_sub_code;
376 
377  // Set to TRUE if the parameters above require anaysis.
378  BOOLEAN pending;
379 
380  // This is the semaphore used to ptotect multi-threaded access to the variables above.
381  void *semaphore;
382 
383  // The request is converted by the caching mechanism into a specific page number/sub-code.
384  U16BIT target_page_number;
385  U16BIT target_page_sub_code;
386 }
388 
389 // Used to define which Teletext packets are relevant to this driver
390 // implemetation.
391 typedef struct s_packet_validation
392 {
393  BOOLEAN is_required;
394 
395  // Only relevant to packets X/26, X/28, and X/29 at present.
396  BOOLEAN has_designation_code;
397 
398  // Designation codes are 4-bit vales (0 - 15).
399  U8BIT lowest_designation_code;
400  U8BIT highest_designation_code;
401 }
403 
404 // This structure is used to define any specific page information - this can be
405 // magazine-wide or by single page config.
406 typedef struct s_specific_data
407 {
408  U8BIT s_data[2][MAX_COLUMN];
409  BOOLEAN is_defined[2];
410 }
412 
413 // This is the core structure used to store collated Teletext page content.
414 // The same containment is used in the magazines used during the packet collation of each page, and
415 // the storage of cached pages within the driver's heap.
416 // It is this structure's content which is the principle source of data for the parsing of pages
417 // by the display task.
418 typedef struct s_magazine_page
419 {
420  // This is an X/0 packet, which is a page header
421  U8BIT header[MAX_COLUMN];
422 
423  // This is the X/27/0 packet, which is editorial page linking data (for FLOF navigation).
424  U8BIT editorial_page_linking_data[MAX_COLUMN];
425 
426  // This flag stops empty magazine content from being cached!
427  // may also apply if magazine is reset (TV radio service changed, etc.)
428  BOOLEAN is_header_defined;
429 
430  BOOLEAN is_editorial_page_linking_data_defined;
431 
432  U16BIT basic_enhancement_data_defined_mask;
433 
434  U32BIT display_data_defined_mask;
435 
436  // These are X/26/0 to X/26/15 packets, which are enhanced data.
437  U8BIT basic_enhancement_data[16][MAX_COLUMN];
438 
439  // These are X/1 to X/25 packets, which contain all the information that is subsequently
440  // parsed to give a TeleText page display.
441  U8BIT display_data[MAX_ROWS][MAX_COLUMN];
442 
443  // This is either:
444  // the X/28/0 Format 1 packet, which is page specific data.
445  // or
446  // the X/28/1 packet, which is page specific data.
447  S_SPECIFIC_DATA specific_data;
448 }
450 
451 // These are the containers used for caching page content within this driver.
452 // For any given page, there are one or more sub-pages which actually contain the displayed data.
453 // All the cached pages from a specific_data magazine are held in this link-list, and can be refreshed
454 // or deleted as the caching mechanism judges.
455 typedef struct s_cache_subpage
456 {
457  // This differentiates sub-pages on the same page broadcast
458  U16BIT sub_code;
459 
460  // This is used to store the image of the collated data within the relevant magazine.
461  S_MAGAZINE_PAGE collated_data;
462 
463  struct s_cache_subpage *next_ptr;
464 }
466 
467 typedef struct s_cache_page
468 {
469  // This has a theoretical range of 0x100 to 0x8ff
470  // The top four bits are reserved as internal flags.
471  U16BIT page_number;
472 
473  // This is a link-list of all the subpages.
474  S_CACHE_SUBPAGE *subpage_ptr;
475 
476  // This is just a pointer to the latest subpage to be added/updated.
477  S_CACHE_SUBPAGE *latest_subpage_ptr;
478 
479  struct s_cache_page *next_ptr;
480 }
482 
483 // This structure is used to define an array of magazine-related info
484 typedef struct s_magazine_info
485 {
486  S_MAGAZINE_PAGE m_page;
487 
488  // This is either:
489  // the M/29/0 packet, which is magazine specific data.
490  // or
491  // the M/29/1 packet, which is magazine specific data.
492  S_SPECIFIC_DATA m_specific_data;
493 
494  // A 256-bit flag array set as each page is received from collation.
495  // This is set regardless of whether the page is cached.
496  // Array is cleared when TV/Radio service changes.
497  U8BIT m_cache_valid_page_array[32];
498 
499  // header for a link-list of cached page content (as described in S_CACHE_PAGE).
500  S_CACHE_PAGE *m_cache_page_ptr;
501 
502  void *m_mutex;
503 }
505 
506 // This is used to define which type of page reference is to be extracted when using
507 // GetPageReference() to polulate the S_PAGE_REFERENCE_DATA structure.
508 typedef struct s_page_reference_data
509 {
510  U16BIT page_number;
511  U16BIT page_sub_code;
512  U16BIT page_offset;
513 
514  U16BIT magazine_number;
515 
516  BOOLEAN erase_page;
517  BOOLEAN newsflash;
518  BOOLEAN subtitle;
519  BOOLEAN suppress_header;
520  BOOLEAN update_indicator;
521  BOOLEAN interrupted_sequence;
522  BOOLEAN inhibit_display;
523  BOOLEAN magazine_serial;
524  U8BIT national_option_character_subset;
525 }
527 
528 // This structure is used to encapsulate a link-list of references to recently visited teletext
529 // pages. As each page is vitsited, it is moved to the head of the link-list.
530 // Cached page content is marked as being referenced in this way by the setting of
531 // CACHE_PAGE_HISTORY_REQUESTED within the upper unused bits of S_CACHE_PAGE->page_number.
532 //
533 // NB - This link-list is only used if the caching requirements defined to a call to
534 // STB_EBUTT_SetCacheMethod() is EBUTT_CACHING_METHOD_HISTORY, EBUTT_CACHING_METHOD_NAVIGATION,
535 // EBUTT_CACHING_METHOD_NAVIGATION_TREE, or EBUTT_CACHING_METHOD_ALL.
537 {
538  // Thus has a theoretical range of 0x100 to 0x8ff
539  U16BIT page_number;
540 
541  struct s_history_cache_request *next_ptr;
542 }
544 
545 // These structures qre used to encapsulate a link-tree of references to FLOF shorcut references to
546 // other pages for the currently displayed teletext pages.
547 // This tree is dynamically modified as new collated page data is passed to the cache, and the
548 // depth of this tree is restricted by the MAX_EDITORIAL_LINKS constant.
549 // Cached page content is marked as being referenced in this way by the setting of
550 // CACHE_PAGE_FLOF_REQUESTED within the upper unused bits of S_CACHE_PAGE->page_number.
551 //
552 // NB - This link-list is only used if the caching requirements defined to a call to
553 // STB_EBUTT_SetCacheMethod() is EBUTT_CACHING_METHOD_NAVIGATION,
554 // EBUTT_CACHING_METHOD_NAVIGATION_TREE, or EBUTT_CACHING_METHOD_ALL.
556 {
557  // Thus has a theoretical range of 0x0000 to 0x3f7f
558  U16BIT sub_code;
559 
560 
561  BOOLEAN is_parsed;
562 
563  U16BIT link_page_number[MAX_EDITORIAL_LINKS];
564  U16BIT link_sub_code[MAX_EDITORIAL_LINKS];
565  void *link[MAX_EDITORIAL_LINKS]; // Should be cast to S_EDITORIAL_LINK_CACHE_REQUEST*
566 
568 }
570 
572 {
573  // Thus has a theoretical range of 0x100 to 0x8ff
574  U16BIT page_number;
575 
576  U16BIT tier;
577 
579 }
581 
582 // This structure is used to encapsulate all data relevant to each display character location
583 // on the Teletext page display.
584 // An array of these structures is located within the S_PAGE_DISPLAY_INFO, and it is into this area
585 // that the collated page content from the cache is parsed into specific font bitmap and
586 // palette LUT references, ready to be subsequently rendered.
587 typedef struct s_teletext_character
588 {
589  // This is used to ascertain which font bitmap table is being accessed, and which bitmap is used
590  // within the font table.
591  U16BIT info;
592  // Here is the same information for an optional supplimentary diacritic mark.
593  U16BIT diacritic_info;
594 
595  // These are indexes into the palette LUT.
596  // The content of the LUT can be dynamically altered to achieve effects such as flashing/reveal
597  // characters.
598  // NB - if this value is set to PALETTE_FOREGROUND_UNBOXED then the character is outside of a
599  // boxed area on a newsflash/subtitle screen, and should be shown painted transparent.
600  // (Unless of course the upwardly adjacent character has info set with
601  // TELETEXT_CHARACTER_DOUBLE_HEIGHT, in which case nothing is to be done).
602 
603  U8BIT foreground_index;
604  U8BIT background_index;
605 }
607 
608 // Palette attributes represent the additional font requirements for a page display, which include
609 // the dynamically altered content used to achieve effects such as flashing/reveal characters.
610 // The number of these palette references that are required is dependant on the complexity of the
611 // page content, and also on the size of the unused area of the palette LUT not bing used by the
612 // standard (fixed) foreground and background colour definitions.
613 typedef struct s_palette_attribute
614 {
615  U8BIT fore_colour;
616  U8BIT back_colour;
617  U8BIT effect_mask;
618  BOOLEAN fore_colour_used;
619 }
621 
622 // Palette attributes represent the additional font requirements used to achieve anti-aliasing on a
623 // page display.
624 // The number of these palette references that are required is dependant on the complexity of the
625 // page content, and also on the size of the unused area of the palette LUT not bing used by the
626 // standard (fixed) foreground and background colour definitions.
627 typedef struct s_palette_alias
628 {
629  U8BIT fore_colour;
630  U8BIT back_colour;
631 }
633 
634 // This structure is used to encapsulate the core data content of a parsed Teletext page.
635 // A single instance of this structure is defined within this module, and the data that is
636 // passed from by the caching mechanism is rendered into this and the display update task.
637 typedef struct s_page_display_info
638 {
639  U16BIT page_number;
640  U16BIT page_sub_code;
641 
642  S_MAGAZINE_PAGE page_source;
643 
644  // This is either:
645  // the M/29/0 packet, which is magazine specific data.
646  // or
647  // the M/29/1 packet, which is magazine specific data.
648  S_SPECIFIC_DATA mgzn_data;
649 
650  BOOLEAN page_clock_valid;
651 
652  BOOLEAN page_updated;
653 
654  // This is the semaphore used to ptotect multi-threaded access to the variables above.
655  void *page_semaphore;
656 
657  E_PAGE_INDEX_DIGIT page_index_digit[3];
658  BOOLEAN page_index_updated;
659  BOOLEAN page_index_held;
660 
661  // This is the semaphore used to ptotect multi-threaded access to the three variables above.
662  void *page_index_semaphore;
663 
664  U16BIT carousel_page_number;
665  U8BIT carousel_page_header[MAX_COLUMN];
666  BOOLEAN carousel_page_updated;
667 
668  // This is the semaphore used to ptotect multi-threaded access to the three variables above.
669  void *carousel_page_semaphore;
670 
671  U8BIT time_filler_header_data[32];
672  BOOLEAN clock_updated;
673 
674  // This is the semaphore used to ptotect multi-threaded access to the two variables above.
675  void *time_filler_header_data_semaphore;
676 
677  E_PAGE_SCALE_STATUS page_scale_status;
678  U16BIT page_scale_start_row; // defaults to 0
679  U16BIT page_scale_num_rows; // defaults to 25
680  U16BIT page_scale_zoom_scalar; // defaults to 1
681  BOOLEAN page_scale_params_defined;
682  BOOLEAN page_rescaled;
683 
684  // This is the semaphore used to ptotect multi-threaded access to the six variables above.
685  void *page_scale_semaphore;
686 
687  // All varibales above are set by the cache collation task as new page data is acquired,
688  // and accessed by the display update task.
689  // The consequent parsing results in the population of the data content below. No semaphore
690  // mechanism is required for access to this parsed data, as it is the display update thread that
691  // solely manipulates this data in various looped processes.
692 
693  BOOLEAN subtitle;
694  BOOLEAN pts_valid;
695  U8BIT page_pts[5];
696  S32BIT time_offset;
697 
698  // Flag used to denote that page content has been parsed, and that a display update is required.
699  BOOLEAN render_required;
700 
701  // These variables are used to prompt for a clearing of the page display
702  BOOLEAN clear_screen;
703 
704  U8BIT screen_colour;
705 
706  // This is the two-dimensioanl array representing each page character in the 25 rows of 40
707  // characters that represent a full Teletext page.
708  S_TELETEXT_CHARACTER character_map[MAX_ROWS][MAX_COLUMN];
709  // These two row-related flag arrays are used to denote when a display row has valid content,
710  // and when it needs to be re-rendered.
711  BOOLEAN valid_row[MAX_ROWS];
712  BOOLEAN render_row[MAX_ROWS];
713 
714  // Flag used to denote that the palette LUT needs to be recompiled to meet the requirements of
715  // page display.
716  // NB - this also occurs whenever characters are flashing and/or concelaed text is toggled.
717  BOOLEAN palette_update_required;
718 
719  // These flags are used to control the 'video mix' mode whereby the background of the Teletext
720  // display can be toggled to transparency, thus allowing viewing of the current TV service with
721  // the page text superimposed.
722  BOOLEAN video_mix_set;
723  BOOLEAN video_mix_required;
724 
725  // These flags are used to control the status of the flashing content of the Teletext display.
726  // This process is automatically undertaken by the display update task (if required).
727  BOOLEAN flash_set;
728  BOOLEAN flash_required;
729 
730  // These flags are used to control the status of the concealed content of the Teletext display.
731  // This process is toggled at the operator's request.
732  BOOLEAN reveal_required;
733  BOOLEAN reveal_set;
734  BOOLEAN reveal_available;
735 
736  // These flags are used to control the status of the 'page clear' functionaliity of the Teletext
737  // display.
738  // This process is toggled at the operator's request.
739  BOOLEAN clear_required;
740  BOOLEAN clear_set;
741 
742  // These to arrays are populated with the dynamic palette requirements of the teletext page
743  // encapsulated in this structure.
744  S_PALETTE_ATTRIBUTE palette_attribute_array[NUM_PALETTE_EFFECTS];
745  S_PALETTE_ALIAS palette_alias_array[NUM_PALETTE_EFFECTS / 2];
746 
747  // This array is used to house the resultant TRGB palette LUT.
748  U32BIT palette_array[256];
749 }
751 
753 {
754  U8BIT G0_index;
755  U8BIT G2_index;
756  U8BIT national_option_subset_index;
757 }
759 
761 {
762  U8BIT font_index;
763  U16BIT character_offset;
764  U8BIT diacritic_offset;
765 
766  U8BIT alternative_font_index;
767  U16BIT alternative_character_offset;
768 }
770 
772 {
773  U8BIT font_index;
774  U16BIT character_offset;
775 
776  U16BIT alternative_character_offset;
777 }
779 
781 {
782  BOOLEAN pts_present;
783  U8BIT pts[5];
784  U8BIT *data;
786 
787 
788 //---local (static) variable declarations for this file------------------------
789 // (internal variables declared static to make them local)
790 
791 static const S_PACKET_VALIDATION packet_validation_array[32] =
792 {
793  // X/O page header
794  { TRUE, FALSE, 0, 0 },
795  // X/1 to X/25 basic page display content
796  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
797  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
798  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
799  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
800  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
801  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
802  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
803  { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 }, { TRUE, FALSE, 0, 0 },
804  { TRUE, FALSE, 0, 0 },
805  // X/26/0-14 character ammendements
806  { TRUE, TRUE, 0, 14 },
807  // X/27/0 editorial page linking - FLOF navigation
808  { TRUE, TRUE, 0, 0 },
809  // X/28/0 format 0 page specific data
810  // X/28/1 page specific data
811  { TRUE, TRUE, 0, 1 },
812  // X/29/1 character set designation
813  { TRUE, TRUE, 1, 1 },
814  // 8/30/0-3 broadcast service data packets
815  { TRUE, TRUE, 0, 3 },
816  // X/31
817  { FALSE, TRUE, 0, 31 }
818 };
819 
820 // This table is used to decode Hamming 8/4 encoded bytes.
821 // The bottom 4 bits are the (corrected) data bits, so none of the lengthy algoritm
822 // needs to be performed on the encoded data.
823 // If there is a single bit error, then this is reflected in bit 4 being set.
824 // Similarily, an uncorrectable error is reflected in bit 10 being set.
825 // NB - this look-up table was derived by logging the result of passing all
826 // 8-bit values through a conventional algorithm. Simple really.
827 
828 // Use HAMMING_8_4_CORRECTION_MASK and HAMMING_8_4_ERROR_MASK in conjunctiona with this table.
829 
830 static const U16BIT hamming_8_4_table[256] =
831 {
832  0x0011, 0x040f, 0x040f, 0x0018, 0x040f, 0x001c, 0x0014, 0x040f,
833  0x040f, 0x0018, 0x0018, 0x0008, 0x0016, 0x040f, 0x040f, 0x0018,
834  0x040f, 0x001a, 0x0012, 0x040f, 0x0016, 0x040f, 0x040f, 0x001f,
835  0x0016, 0x040f, 0x040f, 0x0018, 0x0006, 0x0016, 0x0016, 0x040f,
836  0x040f, 0x001a, 0x0014, 0x040f, 0x0014, 0x040f, 0x0004, 0x0014,
837  0x0010, 0x040f, 0x040f, 0x0018, 0x040f, 0x001d, 0x0014, 0x040f,
838  0x001a, 0x000a, 0x040f, 0x001a, 0x040f, 0x001a, 0x0014, 0x040f,
839  0x040f, 0x001a, 0x0013, 0x040f, 0x0016, 0x040f, 0x040f, 0x001e,
840  0x0001, 0x0011, 0x0011, 0x040f, 0x0011, 0x040f, 0x040f, 0x001f,
841  0x0011, 0x040f, 0x040f, 0x0018, 0x040f, 0x001d, 0x0015, 0x040f,
842  0x0011, 0x040f, 0x040f, 0x001f, 0x040f, 0x001f, 0x001f, 0x000f,
843  0x040f, 0x001b, 0x0013, 0x040f, 0x0016, 0x040f, 0x040f, 0x001f,
844  0x0011, 0x040f, 0x040f, 0x0019, 0x040f, 0x001d, 0x0014, 0x040f,
845  0x040f, 0x001d, 0x0013, 0x040f, 0x001d, 0x000d, 0x040f, 0x001d,
846  0x040f, 0x001a, 0x0013, 0x040f, 0x0017, 0x040f, 0x040f, 0x001f,
847  0x0013, 0x040f, 0x0003, 0x0013, 0x040f, 0x001d, 0x0013, 0x040f,
848  0x040f, 0x001c, 0x0012, 0x040f, 0x001c, 0x000c, 0x040f, 0x001c,
849  0x0010, 0x040f, 0x040f, 0x0018, 0x040f, 0x001c, 0x0015, 0x040f,
850  0x0012, 0x040f, 0x0002, 0x0012, 0x040f, 0x001c, 0x0012, 0x040f,
851  0x040f, 0x001b, 0x0012, 0x040f, 0x0016, 0x040f, 0x040f, 0x001e,
852  0x0010, 0x040f, 0x040f, 0x0019, 0x040f, 0x001c, 0x0014, 0x040f,
853  0x0000, 0x0010, 0x0010, 0x040f, 0x0010, 0x040f, 0x040f, 0x001e,
854  0x040f, 0x001a, 0x0012, 0x040f, 0x0017, 0x040f, 0x040f, 0x001e,
855  0x0010, 0x040f, 0x040f, 0x001e, 0x040f, 0x001e, 0x001e, 0x000e,
856  0x0011, 0x040f, 0x040f, 0x0019, 0x040f, 0x001c, 0x0015, 0x040f,
857  0x040f, 0x001b, 0x0015, 0x040f, 0x0015, 0x040f, 0x0005, 0x0015,
858  0x040f, 0x001b, 0x0012, 0x040f, 0x0017, 0x040f, 0x040f, 0x001f,
859  0x001b, 0x000b, 0x040f, 0x001b, 0x040f, 0x001b, 0x0015, 0x040f,
860  0x040f, 0x0019, 0x0019, 0x0009, 0x0017, 0x040f, 0x040f, 0x0019,
861  0x0010, 0x040f, 0x040f, 0x0019, 0x040f, 0x001d, 0x0015, 0x040f,
862  0x0017, 0x040f, 0x040f, 0x0019, 0x0007, 0x0017, 0x0017, 0x040f,
863  0x040f, 0x001b, 0x0013, 0x040f, 0x0017, 0x040f, 0x040f, 0x001e
864 };
865 
866 // This table generates the parity checks used for Hamming 24/18 decoding.
867 // There are three banks if values - one for each of the tests A,B,C
868 // The three triplet values are used to each reference a value here,
869 // which are XOR-ed into a single byte value. This value is an index used to
870 // access the two following tables.
871 // NB - the first back is also used for single-byte parity checking.
872 
873 static const U8BIT hamming_24_18_parity_table[3][256] =
874 {
875  {
876  0, 40, 39, 15, 38, 14, 1, 41, 37, 13, 2, 42, 3, 43, 36, 12,
877  36, 12, 3, 43, 2, 42, 37, 13, 1, 41, 38, 14, 39, 15, 0, 40,
878  35, 11, 4, 44, 5, 45, 34, 10, 6, 46, 33, 9, 32, 8, 7, 47,
879  7, 47, 32, 8, 33, 9, 6, 46, 34, 10, 5, 45, 4, 44, 35, 11,
880  34, 10, 5, 45, 4, 44, 35, 11, 7, 47, 32, 8, 33, 9, 6, 46,
881  6, 46, 33, 9, 32, 8, 7, 47, 35, 11, 4, 44, 5, 45, 34, 10,
882  1, 41, 38, 14, 39, 15, 0, 40, 36, 12, 3, 43, 2, 42, 37, 13,
883  37, 13, 2, 42, 3, 43, 36, 12, 0, 40, 39, 15, 38, 14, 1, 41,
884  33, 9, 6, 46, 7, 47, 32, 8, 4, 44, 35, 11, 34, 10, 5, 45,
885  5, 45, 34, 10, 35, 11, 4, 44, 32, 8, 7, 47, 6, 46, 33, 9,
886  2, 42, 37, 13, 36, 12, 3, 43, 39, 15, 0, 40, 1, 41, 38, 14,
887  38, 14, 1, 41, 0, 40, 39, 15, 3, 43, 36, 12, 37, 13, 2, 42,
888  3, 43, 36, 12, 37, 13, 2, 42, 38, 14, 1, 41, 0, 40, 39, 15,
889  39, 15, 0, 40, 1, 41, 38, 14, 2, 42, 37, 13, 36, 12, 3, 43,
890  32, 8, 7, 47, 6, 46, 33, 9, 5, 45, 34, 10, 35, 11, 4, 44,
891  4, 44, 35, 11, 34, 10, 5, 45, 33, 9, 6, 46, 7, 47, 32, 8
892  },
893  {
894  0, 48, 47, 31, 46, 30, 1, 49, 45, 29, 2, 50, 3, 51, 44, 28,
895  44, 28, 3, 51, 2, 50, 45, 29, 1, 49, 46, 30, 47, 31, 0, 48,
896  43, 27, 4, 52, 5, 53, 42, 26, 6, 54, 41, 25, 40, 24, 7, 55,
897  7, 55, 40, 24, 41, 25, 6, 54, 42, 26, 5, 53, 4, 52, 43, 27,
898  42, 26, 5, 53, 4, 52, 43, 27, 7, 55, 40, 24, 41, 25, 6, 54,
899  6, 54, 41, 25, 40, 24, 7, 55, 43, 27, 4, 52, 5, 53, 42, 26,
900  1, 49, 46, 30, 47, 31, 0, 48, 44, 28, 3, 51, 2, 50, 45, 29,
901  45, 29, 2, 50, 3, 51, 44, 28, 0, 48, 47, 31, 46, 30, 1, 49,
902  41, 25, 6, 54, 7, 55, 40, 24, 4, 52, 43, 27, 42, 26, 5, 53,
903  5, 53, 42, 26, 43, 27, 4, 52, 40, 24, 7, 55, 6, 54, 41, 25,
904  2, 50, 45, 29, 44, 28, 3, 51, 47, 31, 0, 48, 1, 49, 46, 30,
905  46, 30, 1, 49, 0, 48, 47, 31, 3, 51, 44, 28, 45, 29, 2, 50,
906  3, 51, 44, 28, 45, 29, 2, 50, 46, 30, 1, 49, 0, 48, 47, 31,
907  47, 31, 0, 48, 1, 49, 46, 30, 2, 50, 45, 29, 44, 28, 3, 51,
908  40, 24, 7, 55, 6, 54, 41, 25, 5, 53, 42, 26, 43, 27, 4, 52,
909  4, 52, 43, 27, 42, 26, 5, 53, 41, 25, 6, 54, 7, 55, 40, 24
910  },
911  {
912  63, 31, 8, 40, 9, 41, 62, 30, 10, 42, 61, 29, 60, 28, 11, 43,
913  11, 43, 60, 28, 61, 29, 10, 42, 62, 30, 9, 41, 8, 40, 63, 31,
914  12, 44, 59, 27, 58, 26, 13, 45, 57, 25, 14, 46, 15, 47, 56, 24,
915  56, 24, 15, 47, 14, 46, 57, 25, 13, 45, 58, 26, 59, 27, 12, 44,
916  13, 45, 58, 26, 59, 27, 12, 44, 56, 24, 15, 47, 14, 46, 57, 25,
917  57, 25, 14, 46, 15, 47, 56, 24, 12, 44, 59, 27, 58, 26, 13, 45,
918  62, 30, 9, 41, 8, 40, 63, 31, 11, 43, 60, 28, 61, 29, 10, 42,
919  10, 42, 61, 29, 60, 28, 11, 43, 63, 31, 8, 40, 9, 41, 62, 30,
920  14, 46, 57, 25, 56, 24, 15, 47, 59, 27, 12, 44, 13, 45, 58, 26,
921  58, 26, 13, 45, 12, 44, 59, 27, 15, 47, 56, 24, 57, 25, 14, 46,
922  61, 29, 10, 42, 11, 43, 60, 28, 8, 40, 63, 31, 62, 30, 9, 41,
923  9, 41, 62, 30, 63, 31, 8, 40, 60, 28, 11, 43, 10, 42, 61, 29,
924  60, 28, 11, 43, 10, 42, 61, 29, 9, 41, 62, 30, 63, 31, 8, 40,
925  8, 40, 63, 31, 62, 30, 9, 41, 61, 29, 10, 42, 11, 43, 60, 28,
926  15, 47, 56, 24, 57, 25, 14, 46, 58, 26, 13, 45, 12, 44, 59, 27,
927  59, 27, 12, 44, 13, 45, 58, 26, 14, 46, 57, 25, 56, 24, 15, 47
928  }
929 };
930 
931 // This table simplifies the process of extracting the lower 4 bits
932 // of the LSB from a Hamming 24/18 encoded triplet.
933 
934 static const U8BIT hamming_24_18_first_byte_table[256] =
935 {
936  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
937  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
938  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
939  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
940  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
941  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
942  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
943  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
944  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
945  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
946  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
947  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
948  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
949  0, 0, 8, 8, 4, 4, 12, 12, 2, 2, 10, 10, 6, 6, 14, 14,
950  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15,
951  1, 1, 9, 9, 5, 5, 13, 13, 3, 3, 11, 11, 7, 7, 15, 15
952 };
953 
954 // This table simplifies the process of extracting the middle and upper 7 bit pairs
955 // of the middle and MSB from a Hamming 24/18 encoded triplet.
956 static const U8BIT hamming_24_18_other_bytes_table[256] =
957 {
958  0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x60, 0x60, 0x10, 0x10, 0x50, 0x50, 0x30, 0x30, 0x70, 0x70,
959  0x08, 0x08, 0x48, 0x48, 0x28, 0x28, 0x68, 0x68, 0x18, 0x18, 0x58, 0x58, 0x38, 0x38, 0x78, 0x78,
960  0x04, 0x04, 0x44, 0x44, 0x24, 0x24, 0x64, 0x64, 0x14, 0x14, 0x54, 0x54, 0x34, 0x34, 0x74, 0x74,
961  0x0c, 0x0c, 0x4c, 0x4c, 0x2c, 0x2c, 0x6c, 0x6c, 0x1c, 0x1c, 0x5c, 0x5c, 0x3c, 0x3c, 0x7c, 0x7c,
962  0x02, 0x02, 0x42, 0x42, 0x22, 0x22, 0x62, 0x62, 0x12, 0x12, 0x52, 0x52, 0x32, 0x32, 0x72, 0x72,
963  0x0a, 0x0a, 0x4a, 0x4a, 0x2a, 0x2a, 0x6a, 0x6a, 0x1a, 0x1a, 0x5a, 0x5a, 0x3a, 0x3a, 0x7a, 0x7a,
964  0x06, 0x06, 0x46, 0x46, 0x26, 0x26, 0x66, 0x66, 0x16, 0x16, 0x56, 0x56, 0x36, 0x36, 0x76, 0x76,
965  0x0e, 0x0e, 0x4e, 0x4e, 0x2e, 0x2e, 0x6e, 0x6e, 0x1e, 0x1e, 0x5e, 0x5e, 0x3e, 0x3e, 0x7e, 0x7e,
966  0x01, 0x01, 0x41, 0x41, 0x21, 0x21, 0x61, 0x61, 0x11, 0x11, 0x51, 0x51, 0x31, 0x31, 0x71, 0x71,
967  0x09, 0x09, 0x49, 0x49, 0x29, 0x29, 0x69, 0x69, 0x19, 0x19, 0x59, 0x59, 0x39, 0x39, 0x79, 0x79,
968  0x05, 0x05, 0x45, 0x45, 0x25, 0x25, 0x65, 0x65, 0x15, 0x15, 0x55, 0x55, 0x35, 0x35, 0x75, 0x75,
969  0x0d, 0x0d, 0x4d, 0x4d, 0x2d, 0x2d, 0x6d, 0x6d, 0x1d, 0x1d, 0x5d, 0x5d, 0x3d, 0x3d, 0x7d, 0x7d,
970  0x03, 0x03, 0x43, 0x43, 0x23, 0x23, 0x63, 0x63, 0x13, 0x13, 0x53, 0x53, 0x33, 0x33, 0x73, 0x73,
971  0x0b, 0x0b, 0x4b, 0x4b, 0x2b, 0x2b, 0x6b, 0x6b, 0x1b, 0x1b, 0x5b, 0x5b, 0x3b, 0x3b, 0x7b, 0x7b,
972  0x07, 0x07, 0x47, 0x47, 0x27, 0x27, 0x67, 0x67, 0x17, 0x17, 0x57, 0x57, 0x37, 0x37, 0x77, 0x77,
973  0x0f, 0x0f, 0x4f, 0x4f, 0x2f, 0x2f, 0x6f, 0x6f, 0x1f, 0x1f, 0x5f, 0x5f, 0x3f, 0x3f, 0x7f, 0x7f
974 };
975 
976 // This table is the mapping from parity checks made by from the result
977 // of analysis of hamming_24_18_parity_table, to the error incurred.
978 // If there is a single bit error, then this is reflected in bit 4 being set.
979 // Similarily, an uncorrectable error is reflected in bit 10 being set.
980 
981 // Use HAMMING_8_4_CORRECTION_MASK and HAMMING_8_4_ERROR_MASK in conjunctiona with this table.
982 
983 static const U16BIT hamming_24_18_error_table[64] =
984 {
985  0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
986  0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
987  0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
988  0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
989  0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
990  0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
991  0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
992  0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400
993 };
994 
995 // This table is the mapping from parity checks made by from the result
996 // of analysis of hamming_24_18_parity_table, to the relevant faulty bit
997 // in the decoded 18 bit word.
998 
999 static const U32BIT hamming_24_18_correction_table[64] =
1000 {
1001  0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L,
1002  0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L,
1003  0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L,
1004  0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L,
1005  0x00000L, 0x00000L, 0x00000L, 0x00001L, 0x00000L, 0x00002L, 0x00004L, 0x00008L,
1006  0x00000L, 0x00010L, 0x00020L, 0x00040L, 0x00080L, 0x00100L, 0x00200L, 0x00400L,
1007  0x00000L, 0x00800L, 0x01000L, 0x02000L, 0x04000L, 0x08000L, 0x10000L, 0x20000L,
1008  0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L, 0x00000L
1009 };
1010 
1011 // This table is used to convert the character set deignations supplied in teletext packets (as
1012 // defined in ETSI EN 300 706 V1.2.1, Table 32) into the font table references used within
1013 // the S_EBUTT_FONT data structure.
1014 
1015 static const S_CHARACTER_SET_MAPPING character_set_mapping_array[256] =
1016 {
1017  // Triplet_1 value is 0000
1018  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ENGLISH },
1019  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_GERMAN },
1020  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_SWEDISH_FINNISH },
1021  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ITALIAN },
1022  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_FRENCH },
1023  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_PORTUGUESE_SPANISH },
1024  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_CZECH_SLOVAK },
1025  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1026  // Triplet_1 value is 0001
1027  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_POLISH },
1028  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_GERMAN },
1029  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_SWEDISH_FINNISH },
1030  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ITALIAN },
1031  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_FRENCH },
1032  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1033  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_CZECH_SLOVAK },
1034  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1035  // Triplet_1 value is 0010
1036  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ENGLISH },
1037  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_GERMAN },
1038  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_SWEDISH_FINNISH },
1039  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ITALIAN },
1040  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_FRENCH },
1041  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_PORTUGUESE_SPANISH },
1042  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_TURKISH },
1043  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1044  // Triplet_1 value is 0011
1045  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1046  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1047  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1048  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1049  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1050  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_SERB_CROAT_SLOVENIAN },
1051  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1052  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_RUMANIAN },
1053  // Triplet_1 value is 0100
1054  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1055  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_GERMAN },
1056  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ESTONIAN },
1057  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_LETTISH_LITHUANIAN },
1058  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1059  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1060  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_CZECH_SLOVAK },
1061  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1062  // Triplet_1 value is 0101 - reserved
1063  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1064  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1065  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1066  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1067  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1068  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1069  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1070  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1071  // Triplet_1 value is 0110
1072  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1073  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1074  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1075  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1076  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1077  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1078  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_TURKISH },
1079  { FONT_INDEX_GREEK_G0_SET, FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1080  // Triplet_1 value is 0111 - reserved
1081  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1082  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1083  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1084  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1085  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1086  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1087  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1088  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1089  // Triplet_1 value is 1000
1090  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_ENGLISH },
1091  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1092  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1093  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1094  { FONT_INDEX_LATIN_G0_SET, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_FRENCH },
1095  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1096  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1097  { FONT_INDEX_ARABIC_G0_SET, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1098  // Triplet_1 value is 1001 - reserved
1099  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1100  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1101  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1102  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1103  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1104  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1105  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1106  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1107  // Triplet_1 value is 1010
1108  { FONT_INDEX_UNDEFINED, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1109  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1110  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1111  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1112  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1113  { FONT_INDEX_HEBREW_G0_SET, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1114  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1115  { FONT_INDEX_ARABIC_G0_SET, FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, NATIONALITY_INDEX_UNDEFINED },
1116  // Triplet_1 value is 1011 - reserved
1117  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1118  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1119  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1120  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1121  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1122  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1123  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1124  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1125  // Triplet_1 value is 1100 - reserved
1126  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1127  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1128  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1129  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1130  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1131  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1132  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1133  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1134  // Triplet_1 value is 1101 - reserved
1135  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1136  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1137  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1138  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1139  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1140  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1141  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1142  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1143  // Triplet_1 value is 1110 - reserved
1144  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1145  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1146  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1147  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1148  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1149  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1150  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1151  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1152  // Triplet_1 value is 1111 - reserved
1153  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1154  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1155  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1156  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1157  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1158  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1159  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED },
1160  { FONT_INDEX_UNDEFINED, FONT_INDEX_UNDEFINED, NATIONALITY_INDEX_UNDEFINED }
1161 };
1162 
1163 // This table defines specific character and diacritic pairings that have a more suitable equivalent
1164 // elsewhere within the font tables.
1165 // This is an enhancement specifically designed for this driver, which ensures that the optimal
1166 // height character is used to ensure clarity for the diacritic mark.
1167 // The substitutions are only required for upper diacritics.
1168 
1169 static const S_DIACRITIC_EQUIVALENT diacritic_equivalent_array[] =
1170 {
1171  // C with accent acute (')
1172  { FONT_INDEX_LATIN_G0_SET, 0x23, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1173  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1174  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1175  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1176  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x40, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1177  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x23, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1178  { FONT_INDEX_HEBREW_G0_SET, 0x23, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 49 },
1179 
1180  // E with accent acute (')
1181  { FONT_INDEX_LATIN_G0_SET, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1182  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1183  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1184  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1185  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x41, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1186  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1187  { FONT_INDEX_HEBREW_G0_SET, 0x25, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 37 },
1188 
1189  // K with accent acute (')
1190  { FONT_INDEX_LATIN_G0_SET, 0x2b, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1191  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x2b, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1192  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x2b, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1193  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x46, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1194  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2b, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1195  { FONT_INDEX_HEBREW_G0_SET, 0x2b, 2, FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x31 },
1196 
1197  // S with accent acute (')
1198  { FONT_INDEX_LATIN_G0_SET, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 59 },
1199  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4b, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 59 },
1200  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x48, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 59 },
1201  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 59 },
1202  { FONT_INDEX_HEBREW_G0_SET, 0x33, 2, FONT_INDEX_NATIONAL_OPTION_SUBSET, 59 },
1203 
1204  // A with circumflex (^)
1205  { FONT_INDEX_LATIN_G0_SET, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1206  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1207  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1208  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1209  { FONT_INDEX_GREEK_G0_SET, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1210  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1211  { FONT_INDEX_HEBREW_G0_SET, 0x21, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 48 },
1212 
1213  // I with circumflex (^)
1214  { FONT_INDEX_LATIN_G0_SET, 0x29, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 87 },
1215  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x44, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 87 },
1216  { FONT_INDEX_GREEK_G0_SET, 0x29, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 87 },
1217  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x29, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 87 },
1218  { FONT_INDEX_HEBREW_G0_SET, 0x29, 3, FONT_INDEX_NATIONAL_OPTION_SUBSET, 87 },
1219 
1220  // O with tilde (~)
1221  { FONT_INDEX_LATIN_G0_SET, 0x2f, 4, FONT_INDEX_NATIONAL_OPTION_SUBSET, 93 },
1222  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x48, 4, FONT_INDEX_NATIONAL_OPTION_SUBSET, 93 },
1223  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2e, 4, FONT_INDEX_NATIONAL_OPTION_SUBSET, 93 },
1224  { FONT_INDEX_HEBREW_G0_SET, 0x2e, 4, FONT_INDEX_NATIONAL_OPTION_SUBSET, 93 },
1225 
1226  // I with upper dot
1227  { FONT_INDEX_LATIN_G0_SET, 0x29, 7, FONT_INDEX_NATIONAL_OPTION_SUBSET, 38 },
1228  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x44, 7, FONT_INDEX_NATIONAL_OPTION_SUBSET, 38 },
1229  { FONT_INDEX_GREEK_G0_SET, 0x29, 7, FONT_INDEX_NATIONAL_OPTION_SUBSET, 38 },
1230  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x29, 7, FONT_INDEX_NATIONAL_OPTION_SUBSET, 38 },
1231  { FONT_INDEX_HEBREW_G0_SET, 0x29, 7, FONT_INDEX_NATIONAL_OPTION_SUBSET, 38 },
1232 
1233  // A with umlaut (two dots above)
1234  { FONT_INDEX_LATIN_G0_SET, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1235  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1236  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1237  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1238  { FONT_INDEX_GREEK_G0_SET, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1239  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1240  { FONT_INDEX_HEBREW_G0_SET, 0x21, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 41 },
1241 
1242  // E with umlaut (two dots above)
1243  { FONT_INDEX_LATIN_G0_SET, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1244  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1245  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1246  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1247  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x41, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1248  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1249  { FONT_INDEX_HEBREW_G0_SET, 0x25, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 23 },
1250 
1251  // I with umlaut (two dots above)
1252  { FONT_INDEX_LATIN_G0_SET, 0x29, 8, FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x3f },
1253  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x44, 8, FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x3f },
1254  { FONT_INDEX_GREEK_G0_SET, 0x29, 8, FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x3f },
1255  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x29, 8, FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x3f },
1256  { FONT_INDEX_HEBREW_G0_SET, 0x29, 8, FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x3f },
1257 
1258  // O with umlaut (two dots above)
1259  { FONT_INDEX_LATIN_G0_SET, 0x2e, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 54 },
1260  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x48, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 54 },
1261  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2e, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 54 },
1262  { FONT_INDEX_HEBREW_G0_SET, 0x2e, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 54 },
1263 
1264  // U with umlaut (two dots above)
1265  { FONT_INDEX_LATIN_G0_SET, 0x35, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 80 },
1266  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4c, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 80 },
1267  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x49, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 80 },
1268  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x35, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 80 },
1269  { FONT_INDEX_HEBREW_G0_SET, 0x35, 8, FONT_INDEX_NATIONAL_OPTION_SUBSET, 80 },
1270 
1271  // A with bolle (small circle above)
1272  { FONT_INDEX_LATIN_G0_SET, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1273  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1274  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1275  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1276  { FONT_INDEX_GREEK_G0_SET, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1277  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1278  { FONT_INDEX_HEBREW_G0_SET, 0x21, 10, FONT_INDEX_NATIONAL_OPTION_SUBSET, 76 },
1279 
1280  // A with hacek (small v above)
1281  { FONT_INDEX_LATIN_G0_SET, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1282  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1283  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1284  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1285  { FONT_INDEX_GREEK_G0_SET, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1286  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1287  { FONT_INDEX_HEBREW_G0_SET, 0x21, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 74 },
1288 
1289  // C with hacek (small v above)
1290  { FONT_INDEX_LATIN_G0_SET, 0x23, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1291  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1292  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1293  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1294  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x40, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1295  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x23, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1296  { FONT_INDEX_HEBREW_G0_SET, 0x23, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 36 },
1297 
1298  // S with hacek (small v above)
1299  { FONT_INDEX_LATIN_G0_SET, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 32 },
1300  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4b, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 32 },
1301  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x48, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 32 },
1302  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 32 },
1303  { FONT_INDEX_HEBREW_G0_SET, 0x33, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 32 },
1304 
1305  // G with hacek (small v above)
1306  { FONT_INDEX_LATIN_G0_SET, 0x27, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 103 },
1307  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x43, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 103 },
1308  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x43, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 103 },
1309  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x27, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 103 },
1310  { FONT_INDEX_HEBREW_G0_SET, 0x27, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 103 },
1311 
1312  // Z with hacek (small v above)
1313  { FONT_INDEX_LATIN_G0_SET, 0x3a, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 67 },
1314  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4f, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 67 },
1315  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x4d, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 67 },
1316  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x3a, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 67 },
1317  { FONT_INDEX_HEBREW_G0_SET, 0x3a, 15, FONT_INDEX_NATIONAL_OPTION_SUBSET, 67 },
1318 
1319  { FONT_INDEX_UNDEFINED, 0x00, 0, FONT_INDEX_UNDEFINED, 0 }
1320 };
1321 
1322 // This table defines sppecific character and diacritic pairings that have a more custom defined
1323 // equivalent within the unused characters 0x40 to 0x5f within the G1 block mosaics font table.
1324 // This is an enhancement specifically designed for this driver, which ensures that the optimal
1325 // height character is used to ensure clarity for the diacritic mark.
1326 // The substitutions are only required for upper diacritics.
1327 
1328 static const S_DIACRITIC_SUBSTITUTION diacritic_substitution_array[] =
1329 {
1330  // A
1331  { FONT_INDEX_LATIN_G0_SET, 0x21, 0 },
1332  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x21, 0 },
1333  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x21, 0 },
1334  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x21, 0 },
1335  { FONT_INDEX_GREEK_G0_SET, 0x21, 0 },
1336  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x21, 0 },
1337  { FONT_INDEX_HEBREW_G0_SET, 0x21, 0 },
1338 
1339  // E
1340  { FONT_INDEX_LATIN_G0_SET, 0x25, 1 },
1341  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x25, 1 },
1342  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x25, 1 },
1343  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x25, 1 },
1344  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x41, 1 },
1345  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x25, 1 },
1346  { FONT_INDEX_HEBREW_G0_SET, 0x25, 1 },
1347 
1348  // I
1349  { FONT_INDEX_LATIN_G0_SET, 0x29, 2 },
1350  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x44, 2 },
1351  { FONT_INDEX_GREEK_G0_SET, 0x29, 2 },
1352  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x29, 2 },
1353  { FONT_INDEX_HEBREW_G0_SET, 0x29, 2 },
1354 
1355  // O
1356  { FONT_INDEX_LATIN_G0_SET, 0x2f, 3 },
1357  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x48, 3 },
1358  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2e, 3 },
1359  { FONT_INDEX_HEBREW_G0_SET, 0x2e, 3 },
1360 
1361  // U
1362  { FONT_INDEX_LATIN_G0_SET, 0x35, 4 },
1363  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4c, 4 },
1364  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x49, 4 },
1365  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x35, 4 },
1366  { FONT_INDEX_HEBREW_G0_SET, 0x35, 4 },
1367 
1368  // C
1369  { FONT_INDEX_LATIN_G0_SET, 0x23, 5 },
1370  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN, 0x33, 5 },
1371  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x33, 5 },
1372  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x33, 5 },
1373  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x40, 5 },
1374  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x23, 5 },
1375  { FONT_INDEX_HEBREW_G0_SET, 0x23, 5 },
1376 
1377  // S
1378  { FONT_INDEX_LATIN_G0_SET, 0x33, 6 },
1379  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4b, 6 },
1380  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x48, 6 },
1381  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x33, 6 },
1382  { FONT_INDEX_HEBREW_G0_SET, 0x33, 6 },
1383 
1384  // K
1385  { FONT_INDEX_LATIN_G0_SET, 0x2b, 7 },
1386  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN, 0x2b, 7 },
1387  { FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN, 0x2b, 7 },
1388  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x46, 7 },
1389  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2b, 7 },
1390  { FONT_INDEX_HEBREW_G0_SET, 0x2b, 7 },
1391 
1392  // Y
1393  { FONT_INDEX_LATIN_G0_SET, 0x39, 8 },
1394  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x4c, 8 },
1395  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x39, 8 },
1396  { FONT_INDEX_HEBREW_G0_SET, 0x39, 8 },
1397 
1398  // Z
1399  { FONT_INDEX_LATIN_G0_SET, 0x3a, 9 },
1400  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x4f, 9 },
1401  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x4d, 9 },
1402  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x3a, 9 },
1403  { FONT_INDEX_HEBREW_G0_SET, 0x3a, 9 },
1404 
1405  // G
1406  { FONT_INDEX_LATIN_G0_SET, 0x27, 10 },
1407  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x43, 10 },
1408  { FONT_INDEX_GREEK_G2_SUPPLIMENTARY_SET, 0x43, 10 },
1409  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x27, 10 },
1410  { FONT_INDEX_HEBREW_G0_SET, 0x27, 10 },
1411 
1412  // T
1413  { FONT_INDEX_LATIN_G0_SET, 0x34, 11 },
1414  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x34, 11 },
1415  { FONT_INDEX_HEBREW_G0_SET, 0x34, 11 },
1416 
1417  // N
1418  { FONT_INDEX_LATIN_G0_SET, 0x2e, 12 },
1419  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x48, 12 },
1420  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x2e, 12 },
1421  { FONT_INDEX_HEBREW_G0_SET, 0x2e, 12 },
1422 
1423  // i
1424  { FONT_INDEX_LATIN_G0_SET, 0x49, 13 },
1425  { FONT_INDEX_CYRILLIC_G2_SUPPLIMENTARY_SET, 0x54, 13 },
1426  { FONT_INDEX_ARABIC_G2_SUPPLIMENTARY_SET, 0x49, 13 },
1427 
1428  { FONT_INDEX_UNDEFINED, 0x00, 0 }
1429 };
1430 
1431 static const U16BIT cache_removal_priority_mask_array[8] =
1432 {
1433  0,
1434  CACHE_PAGE_HISTORY_REQUESTED,
1435  CACHE_PAGE_PREVNEXT_REQUESTED,
1436  CACHE_PAGE_HISTORY_REQUESTED | CACHE_PAGE_PREVNEXT_REQUESTED,
1437  CACHE_PAGE_FLOF_REQUESTED,
1438  CACHE_PAGE_HISTORY_REQUESTED | CACHE_PAGE_FLOF_REQUESTED,
1439  CACHE_PAGE_PREVNEXT_REQUESTED | CACHE_PAGE_FLOF_REQUESTED,
1440  CACHE_PAGE_HISTORY_REQUESTED | CACHE_PAGE_PREVNEXT_REQUESTED | CACHE_PAGE_FLOF_REQUESTED
1441 };
1442 
1443 static const U8BIT option_subset_array[96] =
1444 {
1445  0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1446  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1447  3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1448  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
1449  9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1450  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0
1451 };
1452 
1453 static const U8BIT subset_offset_array[14] =
1454 {
1455  0, 0, 13, 26, 39, 52, 65, 78, 91, 104, 117, 130, 143, 156
1456 };
1457 
1458 
1459 static U32BIT pes_collection_callback_handle;
1460 
1461 static S_PAGE_REQUEST_INFO page_request_info;
1462 
1463 static BOOLEAN is_initialised;
1464 static BOOLEAN is_shown;
1465 static BOOLEAN is_visible;
1466 
1467 static BOOLEAN stream_processing_enabled;
1468 
1469 static S_MAGAZINE_INFO magazine_array[8];
1470 
1471 static S_HISTORY_CACHE_REQUEST *history_cache_request_list;
1472 static BOOLEAN history_cache_reset_requested;
1473 
1474 static S_EDITORIAL_LINK_CACHE_REQUEST *editorial_link_request_root;
1475 static S_EDITORIAL_LINK_CACHE_REQUEST *temp_editorial_link_request_root;
1476 static BOOLEAN editorial_link_cache_reset_requested;
1477 
1478 static U16BIT next_cache_request_array[NUM_NEXT_CACHE_REQUESTS];
1479 static U16BIT previous_cache_request_array[NUM_PREVIOUS_CACHE_REQUESTS];
1480 static BOOLEAN previousnext_cache_reset_requested;
1481 static U16BIT next_prev_page_number;
1482 
1483 static E_EBUTT_CACHING_METHOD caching_method;
1484 
1485 static S_PAGE_CONTROL_INFO page_control_info;
1486 
1487 static S_PAGE_DISPLAY_INFO page_display_info;
1488 static S_PAGE_DISPLAY_INFO page_display_copy;
1489 
1490 static U8BIT broadcast_service_data[2][MAX_COLUMN];
1491 static BOOLEAN is_broadcast_service_data_defined[2];
1492 
1493 static BOOLEAN broadcast_index_page_invocation_required;
1494 static BOOLEAN show_header_row;
1495 
1496 static BOOLEAN stop_teletext;
1497 static U8BIT teletext_path;
1498 
1499 static U8BIT default_character_set_mapping;
1500 
1501 static void *display_task_ptr;
1502 static void *display_task_semaphore;
1503 
1504 static BOOLEAN palette_reset_required;
1505 
1506 static U16BIT display_margin_top;
1507 static U16BIT display_margin_left;
1508 
1509 static U8BIT *display_char_buffer_origin;
1510 static U8BIT *display_char_buffer;
1511 static U16BIT display_char_buffer_size;
1512 
1513 static U8BIT current_gun_intensity = 223; // 87% brightness
1514 static U8BIT current_antialias_level = 8; // Full anti-aliasing
1515 static U8BIT current_transparency_level = 255; // Full mixed-mode transparency
1516 
1517 static BOOLEAN diacritic_substitutions_avaialable;
1518 
1519 static U16BIT page_history_array[MAX_PAGE_HISTORY];
1520 static U16BIT page_history_request_page_number;
1521 static U16BIT page_history_lwm;
1522 static U16BIT page_history_hwm;
1523 static U16BIT page_history_mwm;
1524 
1525 static U32BIT subtitle_timeout;
1526 
1527 static void *ttxt_osd_region;
1528 
1529 static void *collation_start;
1530 static void *collation_stopped;
1531 static BOOLEAN stop_collation;
1532 static BOOLEAN collation_started;
1533 static void *collation_queue;
1534 static U16BIT queue_count;
1535 static U16BIT max_queue_count;
1536 static void *page_free_sem;
1537 
1538 //---local function prototypes------------------------------------------------
1539 
1540 static void* GetMemory(U32BIT bytes);
1541 
1542 // Data decoding funtions
1543 
1544 static BOOLEAN GetHamming8Byte(void *byte, U8BIT *value);
1545 static BOOLEAN GetHamming8Multiple(void *ptr, U8BIT num_bytes, U32BIT *value);
1546 static BOOLEAN GetHamming8DoubleWord(void *dword, U16BIT *value);
1547 static BOOLEAN GetHammimg24Value(void *triplet_ptr, U32BIT *value);
1548 
1549 static BOOLEAN GetParity7Byte(U8BIT byte, U8BIT *value);
1550 
1551 // General packet data service routines
1552 
1553 static BOOLEAN GetPageReference(U8BIT *link_ptr, S_PAGE_REFERENCE_DATA *page_reference_data_ptr,
1554  E_PAGE_REFERENCE_TYPE reference_type, U16BIT base_magazine_number);
1555 
1556 static BOOLEAN IsPacketQueueingRequired(void);
1557 
1558 static BOOLEAN GetPacketAddress(U8BIT *packet_number, U8BIT *magazine_number,
1559  U8BIT *teletext_packet_ptr );
1560 
1561 static U16BIT GetMagazineIndexFromPageNumber(U16BIT page_number);
1562 
1563 static BOOLEAN IsRollingSubCode(U16BIT page_sub_code);
1564 
1565 static void GetBasicPageDisplayInfo(S_PAGE_DISPLAY_INFO *ptr, U8BIT *default_setting,
1566  U8BIT *second_setting, BOOLEAN *boxing_required,
1567  BOOLEAN *header_required, BOOLEAN *body_required,
1568  BOOLEAN *default_row_background_colour_defined,
1569  U8BIT *default_row_background_colour);
1570 
1571 static void GetCharacterPaletteIndexes(S_PAGE_DISPLAY_INFO *display_info_ptr,
1572  U8BIT *foreground_index, U8BIT *background_index,
1573  U8BIT foreground_colour, U8BIT background_colour,
1574  BOOLEAN flashing, BOOLEAN conceal,
1575  BOOLEAN boxing_required, BOOLEAN boxed,
1576  BOOLEAN video_mix_overridden);
1577 
1578 // PES data collection
1579 
1580 static void PESCollectionCallback(U32BIT handle, U8BIT data_identifier, void *data_ptr, U32BIT data_length);
1581 static BOOLEAN AddPESDataToQueue(void *data_ptr, U32BIT data_length);
1582 
1583 static BOOLEAN InitialiseCollation(void);
1584 
1585 BOOLEAN PerformPESCollation(U8BIT *packet_ptr, BOOLEAN pts_valid, U8BIT *pts);
1586 
1587 // Page request funtions
1588 
1589 static void RequestPage(U16BIT page_number, U16BIT page_sub_code);
1590 static void RequestIndexPage(void);
1591 static void RequestNextPrevious(E_REQUEST_TYPE request_type, BOOLEAN increment);
1592 static void RequestNextAvailablePage(void);
1593 static void RequestPreviousAvailablePage(void);
1594 static void RequestNextVisitedPage(void);
1595 static void RequestPreviousVisitedPage(void);
1596 static void RequestEditorialLinkPage(U16BIT index);
1597 static void RequestNextSubPage(void);
1598 static void RequestPreviousSubPage(void);
1599 
1600 // Editorial link heirarchy analysis functions
1601 
1602 static U16BIT GetMaximumEditorialLinkTiers(void);
1603 
1604 static BOOLEAN FindEditorialLinkRecursive(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
1606  S_EDITORIAL_LINK_CACHE_REQUEST **parent_ptr,
1607  U16BIT page_number);
1608 
1609 static BOOLEAN FindEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
1611  S_EDITORIAL_LINK_CACHE_REQUEST **parent_ptr,
1612  U16BIT page_number);
1613 
1614 static BOOLEAN GetEditorialLink(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
1615  S_EDITORIAL_LINK_CACHE_REQUEST **ptr, U16BIT page_number);
1616 
1617 static BOOLEAN RemoveEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST **base_ptr,
1619 
1620 static BOOLEAN GetSubPageEditorialLinks(S_CACHE_SUBPAGE *sub_page_ptr,
1621  U16BIT *page_number_link_array,
1622  U16BIT *page_sub_code_link_array,
1623  U16BIT max_num_links, U16BIT magazine_number);
1624 
1625 static BOOLEAN CreateEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST **ptr,
1626  U16BIT page_number, U16BIT sub_code);
1627 
1628 static void ReTierEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST *ptr, U16BIT tier);
1629 
1630 static void KillEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST **base_ptr);
1631 
1632 static void UpdateEditorialLinkPageRequestRecursive(S_EDITORIAL_LINK_CACHE_REQUEST *ptr,
1633  U16BIT tier);
1634 
1635 static void UpdateEditorialLinkPageRequest(U16BIT page_number, U16BIT sub_code);
1636 
1637 static void FlagEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST *ptr);
1638 
1639 static void DeterminePageEditorialLinks(S_EDITORIAL_LINK_CACHE_REQUEST *ptr,
1640  S_CACHE_SUBPAGE *subpage_ptr);
1641 
1642 // Visited Page history analysis functions
1643 
1644 static BOOLEAN SearchRequestArray(U16BIT *array_ptr, U16BIT array_size, BOOLEAN find_highest,
1645  U16BIT **return_array_ptr);
1646 static BOOLEAN SearchPreviousRequestArray(BOOLEAN find_highest, U16BIT **return_array_ptr);
1647 static BOOLEAN SearchNextRequestArray(BOOLEAN find_highest, U16BIT **return_array_ptr);
1648 
1649 static BOOLEAN IsInPreviousRequestArray(U16BIT page_number);
1650 static BOOLEAN IsInNextRequestArray(U16BIT page_number);
1651 
1652 // Event-related page request functions
1653 
1654 static BOOLEAN GetGlobalIndexPage(U16BIT *page_number, U16BIT *page_sub_code);
1655 static BOOLEAN GetIndexPage(U16BIT *page_number, U16BIT *page_sub_code);
1656 static BOOLEAN GetAvailablePage(U16BIT *page_number, S16BIT page_increment);
1657 static BOOLEAN GetVisitedPage(U16BIT *page_number, U16BIT *page_sub_code, S16BIT page_increment);
1658 static BOOLEAN GetEditorialLinkPage(U16BIT *page_number, U16BIT *page_sub_code, U16BIT link_index);
1659 static BOOLEAN GetSubPage(U16BIT *new_page_sub_code, U16BIT current_page_number,
1660  U16BIT current_page_sub_code, S16BIT page_increment);
1661 
1662 // Page request handling functionality (polled from collation task)
1663 
1664 static void CheckPageRequest(BOOLEAN pts_valid, U8BIT *pts);
1665 
1666 // Page request chache tidyup functions
1667 
1668 static BOOLEAN RemoveCachePage(U16BIT magazine_number, U16BIT mask);
1669 static BOOLEAN RemoveCacheContent(U16BIT magazine_number, BOOLEAN exclude_magazine);
1670 static BOOLEAN RemoveUnrequestedCacheContent(U16BIT magazine_number, BOOLEAN exclude_magazine);
1671 static BOOLEAN RemoveUnrequestedCachePage(U16BIT magazine_number);
1672 
1673 #if 0
1674 static void RemoveAllCacheContent(void);
1675 #endif
1676 
1677 // Page display update invocation function
1678 
1679 static void NotifyDisplayUpdate(S_MAGAZINE_PAGE *collated_page_ptr, U16BIT magazine_number,
1680  U16BIT page_number, U16BIT page_sub_code, BOOLEAN update_clock, BOOLEAN pts_valid, U8BIT *pts);
1681 
1682 // Page request cache checking function
1683 
1684 static void CheckPageCaching(S_MAGAZINE_PAGE *collated_page_ptr,
1685  S_PAGE_REFERENCE_DATA *reference_data_ptr, BOOLEAN pts_valid, U8BIT *pts);
1686 
1687 static void CheckTimeFillingPacket(S_MAGAZINE_PAGE *collated_page_ptr, U16BIT page_number);
1688 
1689 static void CheckHeaderClockContent(S_MAGAZINE_PAGE *collated_page_ptr);
1690 
1691 // Page request history functions
1692 
1693 static void NotifyRequestToPageHistory(U16BIT page_number);
1694 static U16BIT MoveHistoryMarker(U16BIT marker, BOOLEAN advance);
1695 static void NotifyDisplayToPageHistory(U16BIT page_number);
1696 static BOOLEAN GetPreviousPageFromHistory(U16BIT *page_number);
1697 static BOOLEAN GetNextPageFromHistory(U16BIT *page_number);
1698 
1699 static void NotifyPageCollated(S_MAGAZINE_PAGE *collated_page_ptr, U8BIT magazine_number,
1700  BOOLEAN pts_valid, U8BIT *pts);
1701 
1702 static BOOLEAN InitialiseDisplayTask(void);
1703 static void KillDisplayTask(void);
1704 
1705 static BOOLEAN IsNationalOptionSubsetIndex(U8BIT character_index, U8BIT *subset_offset);
1706 
1707 static void GetTripletFields(U32BIT triplet_value, U8BIT *address, U8BIT *mode, U8BIT *data);
1708 
1709 static void DecodeTeletextPageBody(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN enforce_header_display);
1710 static void DecodeTeletextPageNumber(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN video_mix_overridden);
1711 static void DecodeTeletextCarouselHeader(S_PAGE_DISPLAY_INFO *display_info_ptr);
1712 static void DecodeTeletextClock(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN video_mix_overridden);
1713 
1714 static void GetAliasedColourIndexes(S_TELETEXT_CHARACTER *character_ptr, U8BIT *bitmap_ptr,
1715  U8BIT *aliased_foreground_index, U8BIT *aliased_background_index,
1716  S_PAGE_DISPLAY_INFO *display_info_ptr);
1717 
1718 static void RenderCharacter(U16BIT x, U16BIT y, U16BIT x_scalar, U16BIT y_scalar,
1719  S_TELETEXT_CHARACTER *character_ptr, S_PAGE_DISPLAY_INFO *display_info_ptr);
1720 
1721 static U32BIT GetRGBSetting(BOOLEAN tranparency_required, U8BIT transparency_level,
1722  BOOLEAN red_required, BOOLEAN green_required, BOOLEAN blue_required,
1723  U8BIT gun_intensity);
1724 
1725 static U32BIT GetRGBRamping(U32BIT fore_colour, U32BIT back_colour, U32BIT foreground_sixteenths);
1726 
1727 static void RenderDisplay(S_PAGE_DISPLAY_INFO *display_info_ptr);
1728 
1729 static void PerformDisplayUpdate(void);
1730 static void DisplayUpdateTask(void *unwanted_ptr);
1731 static void PESCollationTask(void *param);
1732 
1733 //---local function definitions------------------------------------------------
1734 
1749 static void* GetMemory(U32BIT bytes)
1750 {
1751  // Only allocate heap memory if more than 10% of the total resources are currently available.
1752  // As other STB layer modules consume the remaining memory, this system will ensure that this
1753  // driver will 'retreat' in terms of it's total memory consumption if required.
1754  if (STB_MEMSysRAMUsed() >= 90)
1755  {
1756  return(NULL);
1757  }
1758  else
1759  {
1760  return(STB_GetMemory(bytes));
1761  }
1762 }
1763 
1779 static BOOLEAN GetHamming8Byte(void *byte, U8BIT *value)
1780 {
1781  BOOLEAN retval;
1782 
1783  FUNCTION_START(GetHamming8Byte);
1784 
1785  retval = TRUE;
1786 
1787  if (value != NULL)
1788  {
1789  *value = hamming_8_4_table[*(U8BIT *)byte] & HAMMING_8_4_DATA_MASK;
1790  }
1791 
1792  if (hamming_8_4_table[*(U8BIT *)byte] & HAMMING_ERROR_MASK)
1793  {
1794  retval = FALSE;
1795  }
1796 
1797  FUNCTION_FINISH(GetHamming8Byte);
1798 
1799  return(retval);
1800 }
1801 
1818 static BOOLEAN GetHamming8Multiple(void *ptr, U8BIT num_bytes, U32BIT *value)
1819 {
1820  U8BIT byte_index, byte_value;
1821  BOOLEAN retval;
1822  U8BIT *byte_ptr;
1823 
1824  FUNCTION_START(GetHamming8Multiple);
1825 
1826  retval = FALSE;
1827 
1828  if ((num_bytes > 0) &&
1829  (num_bytes < 9))
1830  {
1831  retval = TRUE;
1832 
1833  if (value != NULL)
1834  {
1835  *value = 0;
1836  }
1837 
1838  byte_ptr = (U8BIT *)ptr;
1839  byte_ptr += num_bytes - 1;
1840 
1841  for (byte_index = 0; byte_index < num_bytes; byte_index++)
1842  {
1843  if (!GetHamming8Byte(byte_ptr, &byte_value))
1844  {
1845  retval = FALSE;
1846  break;
1847  }
1848 
1849  if (value != NULL)
1850  {
1851  *value = (*value << 4L) | byte_value;
1852  }
1853 
1854  byte_ptr--;
1855  }
1856  }
1857 
1858  FUNCTION_FINISH(GetHamming8Multiple);
1859 
1860  return(retval);
1861 }
1862 
1879 static BOOLEAN GetHamming8DoubleWord(void *dword, U16BIT *value)
1880 {
1881  U32BIT long_value;
1882  BOOLEAN retval;
1883 
1884  FUNCTION_START(GetHamming8DoubleWord);
1885 
1886  retval = GetHamming8Multiple(dword, 4, &long_value);
1887 
1888  if (value != NULL)
1889  {
1890  *value = (U16BIT)long_value;
1891  }
1892 
1893  FUNCTION_FINISH(GetHamming8DoubleWord);
1894 
1895  return(retval);
1896 }
1897 
1914 static BOOLEAN GetHammimg24Value(void *triplet_ptr, U32BIT *value)
1915 {
1916  U8BIT parity_index;
1917  BOOLEAN retval;
1918  U8BIT *byte_ptr;
1919 
1920  FUNCTION_START(GetHammimg24Value);
1921 
1922  retval = TRUE;
1923 
1924  byte_ptr = (U8BIT *)triplet_ptr;
1925 
1926  parity_index = hamming_24_18_parity_table[0][*byte_ptr] ^
1927  hamming_24_18_parity_table[1][*(byte_ptr + 1)] ^
1928  hamming_24_18_parity_table[2][*(byte_ptr + 2)];
1929 
1930  if (value != NULL)
1931  {
1932  *value = (U32BIT)hamming_24_18_first_byte_table[*byte_ptr];
1933  *value += (U32BIT)(hamming_24_18_other_bytes_table[*(byte_ptr + 1)] & 0x7f) << 4L;
1934  *value += (U32BIT)(hamming_24_18_other_bytes_table[*(byte_ptr + 2)] & 0x7f) << 11L;
1935 
1936  *value ^= hamming_24_18_correction_table[parity_index];
1937  }
1938 
1939  if (hamming_24_18_error_table[parity_index] & HAMMING_ERROR_MASK)
1940  {
1941  retval = FALSE;
1942  }
1943 
1944  FUNCTION_FINISH(GetHammimg24Value);
1945 
1946  return(retval);
1947 }
1948 
1963 static BOOLEAN GetParity7Byte(U8BIT byte, U8BIT *value)
1964 {
1965  BOOLEAN retval;
1966 
1967  FUNCTION_START(GetParity7Byte);
1968 
1969  retval = FALSE;
1970 
1971  // Use one of the Hamming decoding LUTS to check if the supplied value passes
1972  // odd parity decoding tests.
1973  if (hamming_24_18_parity_table[0][byte] & 32)
1974  {
1975  if (value != NULL)
1976  {
1977  // This LUT effectively extracts the seven data bits and reversed their order.
1978  *value = hamming_24_18_other_bytes_table[byte];
1979  }
1980 
1981  retval = TRUE;
1982  }
1983 
1984  FUNCTION_FINISH(GetParity7Byte);
1985 
1986  return(retval);
1987 }
1988 
2009 static BOOLEAN GetPageReference(U8BIT *link_ptr, S_PAGE_REFERENCE_DATA *page_reference_data_ptr,
2010  E_PAGE_REFERENCE_TYPE reference_type, U16BIT base_magazine_number)
2011 {
2012  U8BIT page_number_units, page_number_tens, control_byte;
2013  BOOLEAN retval;
2014 
2015  static U8BIT reversed_tribit[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2016 
2017  FUNCTION_START(GetPageReference);
2018 
2019  retval = FALSE;
2020 
2021  // Attempt to decode the components of the Teletext Page number from the pointer to the editorial
2022  // link data block.
2023  if (GetHamming8Byte(link_ptr, &page_number_units) == TRUE)
2024  {
2025  if (GetHamming8Byte(link_ptr + 1, &page_number_tens) == TRUE)
2026  {
2027  // Attempt to decode the Teletext Page sub-code
2028  if (GetHamming8DoubleWord(link_ptr + 2, &page_reference_data_ptr->page_sub_code) == TRUE)
2029  {
2030  // Mask out any control bits from the sub-code
2031  page_reference_data_ptr->page_sub_code &= 0x3f7f;
2032 
2033  // Calculate the page offset (within it's magazine -> ?xx)
2034  page_reference_data_ptr->page_offset = (U16BIT)((page_number_tens << 4) +
2035  page_number_units);
2036 
2037  // Now perform functionality depending on the source of the editorial link...
2038  switch (reference_type)
2039  {
2040  // This is an X/0 packet, which is a page header
2041  // Hence we can determine the control flags (as defined in ETSI EN 300 706 V1.2.1,
2042  // section 9.3.1.3 - Control Bits)
2043  case PAGE_REFERENCE_TYPE_HEADER:
2044  {
2045  // We analyse several bytes within the data block, each of which yeilds control
2046  // bit statuses. In each case we will clear each flag by default, in case there
2047  // is a problem parsing the Hamming encoded bytes.
2048 
2049  page_reference_data_ptr->erase_page = FALSE;
2050 
2051  if (GetHamming8Byte(link_ptr + 3, &control_byte) == TRUE)
2052  {
2053  if (control_byte & 0x08)
2054  {
2055  page_reference_data_ptr->erase_page = TRUE;
2056  }
2057  }
2058 
2059  page_reference_data_ptr->newsflash = FALSE;
2060  page_reference_data_ptr->subtitle = FALSE;
2061 
2062  if (GetHamming8Byte(link_ptr + 5, &control_byte) == TRUE)
2063  {
2064  if (control_byte & 0x04)
2065  {
2066  page_reference_data_ptr->newsflash = TRUE;
2067  }
2068  if (control_byte & 0x08)
2069  {
2070  page_reference_data_ptr->subtitle = TRUE;
2071  }
2072  }
2073 
2074  page_reference_data_ptr->suppress_header = FALSE;
2075  page_reference_data_ptr->update_indicator = FALSE;
2076  page_reference_data_ptr->interrupted_sequence = FALSE;
2077  page_reference_data_ptr->inhibit_display = FALSE;
2078 
2079  if (GetHamming8Byte(link_ptr + 6, &control_byte) == TRUE)
2080  {
2081  if (control_byte & 0x01)
2082  {
2083  page_reference_data_ptr->suppress_header = TRUE;
2084  }
2085  if (control_byte & 0x02)
2086  {
2087  page_reference_data_ptr->update_indicator = TRUE;
2088  }
2089  if (control_byte & 0x04)
2090  {
2091  page_reference_data_ptr->interrupted_sequence = TRUE;
2092  }
2093  if (control_byte & 0x08)
2094  {
2095  page_reference_data_ptr->inhibit_display = TRUE;
2096  }
2097  }
2098 
2099  page_reference_data_ptr->magazine_serial = FALSE;
2100  page_reference_data_ptr->national_option_character_subset = 0;
2101 
2102  if (GetHamming8Byte(link_ptr + 7, &control_byte) == TRUE)
2103  {
2104  if (control_byte & 0x01)
2105  {
2106  page_reference_data_ptr->magazine_serial = TRUE;
2107  }
2108 
2109  page_reference_data_ptr->national_option_character_subset =
2110  reversed_tribit[(control_byte & 0x0e) >> 1];
2111  }
2112 
2113  break;
2114  }
2115 
2116  // This is the X/27/0 packet, which is editorial page linking data (as defined in
2117  // ETSI EN 300 706 V1.2.1, section 9.6.1 - Packets X/27/0 to X/27/3 for Editoral
2118  // Linking)
2119  case PAGE_REFERENCE_TYPE_EDITORIAL_LINK:
2120  {
2121  // We analyse two bytes within the data block, so that the magazine number of
2122  // the page link can de determined from the source magazine number.
2123  if (GetHamming8Byte(link_ptr + 3, &control_byte) == TRUE)
2124  {
2125  if (control_byte & 0x08)
2126  {
2127  base_magazine_number ^= 0x01;
2128  }
2129  }
2130 
2131  if (GetHamming8Byte(link_ptr + 5, &control_byte) == TRUE)
2132  {
2133  if (control_byte & 0x04)
2134  {
2135  base_magazine_number ^= 0x02;
2136  }
2137  if (control_byte & 0x08)
2138  {
2139  base_magazine_number ^= 0x04;
2140  }
2141  }
2142  break;
2143  }
2144 
2145  // This is the X/28/0 Format 1 packet, which yeilds a service global index page
2146  // (as defined in ETSI EN 300 706 V1.2.1, section 9.4.2 - Packets X/28/0 Format 1)
2147  case PAGE_REFERENCE_TYPE_GLOBAL_INDEX:
2148  {
2149  // We analyse two bytes within the data block, so that the magazine number of
2150  // the page link can de determined - this is irrespective of the source magazine
2151  // number.
2152  base_magazine_number = 0;
2153 
2154  if (GetHamming8Byte(link_ptr + 3, &control_byte) == TRUE)
2155  {
2156  if (control_byte & 0x08)
2157  {
2158  base_magazine_number |= 0x01;
2159  }
2160  }
2161 
2162  if (GetHamming8Byte(link_ptr + 5, &control_byte) == TRUE)
2163  {
2164  if (control_byte & 0x04)
2165  {
2166  base_magazine_number |= 0x02;
2167  }
2168  if (control_byte & 0x08)
2169  {
2170  base_magazine_number |= 0x04;
2171  }
2172  }
2173  break;
2174  }
2175  }
2176 
2177  // Now we work out the page number of the reference.
2178  if (base_magazine_number == 0)
2179  {
2180  // Magazine 0 represents pages 0x800 to 0x8ff (0x899 is highest selectable)
2181  page_reference_data_ptr->page_number =
2182  2048 + page_reference_data_ptr->page_offset; // 0x800 + ??
2183  }
2184  else
2185  {
2186  // Magazine 1 represents pages 0x100 to 0x1ff (0x199 is highest selectable)
2187  // This pattern applies for magazines 2 to 7 as well.
2188  page_reference_data_ptr->page_number =
2189  ((U16BIT)base_magazine_number << 8) + page_reference_data_ptr->page_offset;
2190  }
2191 
2192  page_reference_data_ptr->magazine_number = base_magazine_number;
2193 
2194  retval = TRUE;
2195 
2196  // Now we check the validity of the page reference.
2197  switch (reference_type)
2198  {
2199  case PAGE_REFERENCE_TYPE_EDITORIAL_LINK:
2200  {
2201  if (page_reference_data_ptr->page_offset == 0x00ff)
2202  {
2203  retval = FALSE;
2204  }
2205  else if (page_reference_data_ptr->page_sub_code == 0x3f7f)
2206  {
2207  page_reference_data_ptr->page_sub_code = PAGE_SUB_CODE_UNDEFINED;
2208  }
2209  break;
2210  }
2211 
2212  case PAGE_REFERENCE_TYPE_GLOBAL_INDEX:
2213  {
2214  if (page_reference_data_ptr->page_offset == 0x00ff)
2215  {
2216  page_reference_data_ptr->page_number = 0x0100;
2217  page_reference_data_ptr->page_sub_code = PAGE_SUB_CODE_UNDEFINED;
2218  }
2219  else if (page_reference_data_ptr->page_sub_code == 0x3f7f)
2220  {
2221  page_reference_data_ptr->page_sub_code = PAGE_SUB_CODE_UNDEFINED;
2222  }
2223  break;
2224  }
2225 
2226  default:
2227  break;
2228  }
2229  }
2230  }
2231  }
2232 
2233  FUNCTION_FINISH(GetPageReference);
2234 
2235  return(retval);
2236 }
2237 
2251 static BOOLEAN IsPacketQueueingRequired(void)
2252 {
2253  BOOLEAN retval;
2254 
2255  FUNCTION_START(IsPacketQueueingRequired);
2256 
2257  retval = stream_processing_enabled;
2258 
2259  FUNCTION_FINISH(IsPacketQueueingRequired);
2260 
2261  return(retval);
2262 }
2263 
2295 static BOOLEAN GetPacketAddress(U8BIT *packet_number, U8BIT *magazine_number,
2296  U8BIT *teletext_packet_ptr )
2297 {
2298  const S_PACKET_VALIDATION *validation_ptr;
2299  BOOLEAN retval;
2300  U8BIT designation_code;
2301 
2302  FUNCTION_START(GetPacketAddress);
2303 
2304  retval = FALSE;
2305 
2306  if (GetHamming8Byte(teletext_packet_ptr + 1, packet_number))
2307  {
2308  if (GetHamming8Byte(teletext_packet_ptr, magazine_number))
2309  {
2310  // The LSBit of the five-bit packet number is held within the magazine index number.
2311  *packet_number <<= 1;
2312 
2313  if (*magazine_number & 0x08)
2314  {
2315  *packet_number += 1;
2316  }
2317 
2318  *magazine_number &= 0x07;
2319 
2320  if (*packet_number < 32)
2321  {
2322  validation_ptr = packet_validation_array + *packet_number;
2323  if (validation_ptr->is_required == TRUE)
2324  {
2325  if (validation_ptr->has_designation_code == TRUE)
2326  {
2327  // If the packet supports a 'designation code' then this will be the first
2328  // data byte.
2329  if (GetHamming8Byte(teletext_packet_ptr + 2, &designation_code))
2330  {
2331  // Check the designation code is within the range required for this packet type.
2332  if ((designation_code >= validation_ptr->lowest_designation_code) &&
2333  (designation_code <= validation_ptr->highest_designation_code))
2334  {
2335  retval = TRUE;
2336  }
2337  }
2338  }
2339  else
2340  {
2341  retval = TRUE;
2342  }
2343  }
2344  }
2345  DBGPRINT("time=%d pkt_num=%d mg_num=%d rtn=%d", STB_OSGetClockMilliseconds(), *packet_number, *magazine_number, retval);
2346  }
2347  }
2348 
2349  FUNCTION_FINISH(GetPacketAddress);
2350 
2351  return(retval);
2352 }
2353 
2365 static U16BIT GetMagazineIndexFromPageNumber(U16BIT page_number)
2366 {
2367  U16BIT retval;
2368 
2369  FUNCTION_START(GetMagazineIndexFromPageNumber);
2370 
2371  page_number >>= 8;
2372  if (page_number == 8)
2373  {
2374  retval = 0;
2375  }
2376  else
2377  {
2378  retval = page_number;
2379  }
2380 
2381  FUNCTION_FINISH(GetMagazineIndexFromPageNumber);
2382 
2383  return(retval);
2384 }
2385 
2402 static BOOLEAN IsRollingSubCode(U16BIT page_sub_code)
2403 {
2404  U16BIT sub_code_tens, sub_code_units;
2405  BOOLEAN retval;
2406 
2407  FUNCTION_START(IsRollingSubCode);
2408 
2409  retval = FALSE;
2410 
2411  if (page_sub_code != PAGE_SUB_CODE_UNDEFINED)
2412  {
2413  if (!(page_sub_code & 0xff00))
2414  {
2415  sub_code_tens = (page_sub_code & 0x00f0) >> 4;
2416  if (sub_code_tens <= 7)
2417  {
2418  sub_code_units = page_sub_code & 0x000f;
2419  if (sub_code_units <= 9)
2420  {
2421  if ((sub_code_tens != 0) ||
2422  (sub_code_units != 0))
2423  {
2424  retval = TRUE;
2425  }
2426  }
2427  }
2428  }
2429  }
2430 
2431  FUNCTION_FINISH(IsRollingSubCode);
2432 
2433  return(retval);
2434 }
2435 
2464 static void GetBasicPageDisplayInfo(S_PAGE_DISPLAY_INFO *ptr, U8BIT *default_setting,
2465  U8BIT *second_setting, BOOLEAN *boxing_required,
2466  BOOLEAN *header_required, BOOLEAN *body_required,
2467  BOOLEAN *default_row_background_colour_defined,
2468  U8BIT *default_row_background_colour)
2469 {
2470  U16BIT magazine_number;
2471  U32BIT triplet_value;
2472  BOOLEAN default_mapping_defined, second_mapping_defined;
2473  S_PAGE_REFERENCE_DATA page_reference_data;
2474 
2475  FUNCTION_START(GetBasicPageDisplayInfo);
2476 
2477  // Start with default character set designations
2478  if (default_setting != NULL)
2479  {
2480  *default_setting = default_character_set_mapping << 3;
2481  }
2482  if (second_setting != NULL)
2483  {
2484  *second_setting = default_character_set_mapping << 3;
2485  }
2486 
2487  if (boxing_required != NULL)
2488  {
2489  *boxing_required = FALSE;
2490  }
2491  if (header_required != NULL)
2492  {
2493  *header_required = show_header_row;
2494  }
2495  if (body_required != NULL)
2496  {
2497  *body_required = TRUE;
2498  }
2499 
2500  default_mapping_defined = FALSE;
2501  second_mapping_defined = FALSE;
2502 
2503  if (default_row_background_colour_defined != NULL)
2504  {
2505  *default_row_background_colour_defined = FALSE;
2506  }
2507 
2508  // Attempt to get default and secondary GO and G2 sets and national option sub-set designation
2509  // from X/28/0
2510  if (ptr->page_source.specific_data.is_defined[0] == TRUE)
2511  {
2512  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[0][1], &triplet_value) == TRUE)
2513  {
2514  if (default_setting != NULL)
2515  {
2516  *default_setting = (U8BIT)((triplet_value & 0x003f80L) >> 7L);
2517  }
2518  default_mapping_defined = TRUE;
2519 
2520  if (second_setting != NULL)
2521  {
2522  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2523  }
2524 
2525  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[0][4], &triplet_value) == TRUE)
2526  {
2527  if (second_setting != NULL)
2528  {
2529  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2530  }
2531  second_mapping_defined = TRUE;
2532  }
2533  }
2534 
2535  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[0][37], &triplet_value) == TRUE)
2536  {
2537  if (triplet_value & 0x004000L)
2538  {
2539  if (default_row_background_colour_defined != NULL)
2540  {
2541  if (default_row_background_colour != NULL)
2542  {
2543  *default_row_background_colour = (U8BIT)((triplet_value & 0x003e00L) >> 9L);
2544  }
2545  *default_row_background_colour_defined = TRUE;
2546  }
2547  }
2548  }
2549  }
2550 
2551  if (ptr->page_source.specific_data.is_defined[1] == TRUE)
2552  {
2553  if (default_mapping_defined == FALSE)
2554  {
2555  // Attempt to get default and secondary GO and G2 sets and national option sub-set
2556  // designation from X/28/1
2557  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[1][1], &triplet_value) == TRUE)
2558  {
2559  if (default_setting != NULL)
2560  {
2561  *default_setting = (U8BIT)((triplet_value & 0x003f80L) >> 7L);
2562  }
2563  default_mapping_defined = TRUE;
2564 
2565  if (second_setting != NULL)
2566  {
2567  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2568  }
2569 
2570  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[1][4], &triplet_value) == TRUE)
2571  {
2572  if (second_setting != NULL)
2573  {
2574  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2575  }
2576  second_mapping_defined = TRUE;
2577  }
2578  }
2579  }
2580  else if (second_mapping_defined == FALSE)
2581  {
2582  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[1][1], &triplet_value) == TRUE)
2583  {
2584  if (second_setting != NULL)
2585  {
2586  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2587  }
2588 
2589  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[1][4], &triplet_value) == TRUE)
2590  {
2591  if (second_setting != NULL)
2592  {
2593  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2594  }
2595  second_mapping_defined = TRUE;
2596  }
2597  }
2598  }
2599 
2600  if (default_row_background_colour_defined != NULL)
2601  {
2602  if (*default_row_background_colour_defined == FALSE)
2603  {
2604  if (GetHammimg24Value(&ptr->page_source.specific_data.s_data[1][37], &triplet_value) == TRUE)
2605  {
2606  if (triplet_value & 0x004000L)
2607  {
2608  if (default_row_background_colour != NULL)
2609  {
2610  *default_row_background_colour = (U8BIT)((triplet_value & 0x003e00L) >> 9L);
2611  }
2612  *default_row_background_colour_defined = TRUE;
2613  }
2614  }
2615  }
2616  }
2617  }
2618 
2619  if (ptr->mgzn_data.is_defined[0] == TRUE)
2620  {
2621  if (default_mapping_defined == FALSE)
2622  {
2623  // Attempt to get default and secondary GO and G2 sets and national option sub-set
2624  // designation from M/29/0
2625  if (GetHammimg24Value(&ptr->mgzn_data.s_data[0][1], &triplet_value) == TRUE)
2626  {
2627  if (default_setting != NULL)
2628  {
2629  *default_setting = (U8BIT)((triplet_value & 0x003f80L) >> 7L);
2630  }
2631  default_mapping_defined = TRUE;
2632 
2633  if (second_setting != NULL)
2634  {
2635  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2636  }
2637 
2638  if (GetHammimg24Value(&ptr->mgzn_data.s_data[0][4], &triplet_value) == TRUE)
2639  {
2640  if (second_setting != NULL)
2641  {
2642  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2643  }
2644  second_mapping_defined = TRUE;
2645  }
2646  }
2647  }
2648  else if (second_mapping_defined == FALSE)
2649  {
2650  if (GetHammimg24Value(&ptr->mgzn_data.s_data[0][1], &triplet_value) == TRUE)
2651  {
2652  if (second_setting != NULL)
2653  {
2654  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2655  }
2656 
2657  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][4], &triplet_value) == TRUE)
2658  {
2659  if (second_setting != NULL)
2660  {
2661  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2662  }
2663  second_mapping_defined = TRUE;
2664  }
2665  }
2666  }
2667 
2668  if (default_row_background_colour_defined != NULL)
2669  {
2670  if (*default_row_background_colour_defined == FALSE)
2671  {
2672  if (GetHammimg24Value(&ptr->mgzn_data.s_data[0][37], &triplet_value) == TRUE)
2673  {
2674  if (triplet_value & 0x004000L)
2675  {
2676  if (default_row_background_colour != NULL)
2677  {
2678  *default_row_background_colour = (U8BIT)((triplet_value & 0x003e00L) >> 9L);
2679  }
2680  *default_row_background_colour_defined = TRUE;
2681  }
2682  }
2683  }
2684  }
2685  }
2686 
2687  if (ptr->mgzn_data.is_defined[1] == TRUE)
2688  {
2689  if (default_mapping_defined == FALSE)
2690  {
2691  // Attempt to get default and secondary GO and G2 sets and national option sub-set
2692  // designation from M/29/1
2693  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][1], &triplet_value) == TRUE)
2694  {
2695  if (default_setting != NULL)
2696  {
2697  *default_setting = (U8BIT)((triplet_value & 0x003f80L) >> 7L);
2698  }
2699  default_mapping_defined = TRUE;
2700 
2701  if (second_setting != NULL)
2702  {
2703  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2704  }
2705 
2706  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][4], &triplet_value) == TRUE)
2707  {
2708  if (second_setting != NULL)
2709  {
2710  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2711  }
2712  second_mapping_defined = TRUE;
2713  }
2714  }
2715  }
2716  else if (second_mapping_defined == FALSE)
2717  {
2718  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][1], &triplet_value) == TRUE)
2719  {
2720  if (second_setting != NULL)
2721  {
2722  *second_setting = (U8BIT)((triplet_value & 0x03c000L) >> 14L);
2723  }
2724 
2725  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][4], &triplet_value) == TRUE)
2726  {
2727  if (second_setting != NULL)
2728  {
2729  *second_setting |= (U8BIT)((triplet_value & 0x000007L) << 4L);
2730  }
2731  second_mapping_defined = TRUE;
2732  }
2733  }
2734  }
2735 
2736  if (default_row_background_colour_defined != NULL)
2737  {
2738  if (*default_row_background_colour_defined == FALSE)
2739  {
2740  if (GetHammimg24Value(&ptr->mgzn_data.s_data[1][37], &triplet_value) == TRUE)
2741  {
2742  if (triplet_value & 0x004000L)
2743  {
2744  if (default_row_background_colour != NULL)
2745  {
2746  *default_row_background_colour = (U8BIT)((triplet_value & 0x003e00L) >> 9L);
2747  }
2748  *default_row_background_colour_defined = TRUE;
2749  }
2750  }
2751  }
2752  }
2753  }
2754 
2755  // Finally override the default G0 set national option sub-set designation from setting in X/0
2756  // header.
2757  if (ptr->page_source.is_header_defined == TRUE)
2758  {
2759  magazine_number = GetMagazineIndexFromPageNumber(page_display_info.page_number);
2760 
2761  if (GetPageReference(ptr->page_source.header, &page_reference_data,
2762  PAGE_REFERENCE_TYPE_HEADER, magazine_number) == TRUE)
2763  {
2764  if (default_setting != NULL)
2765  {
2766  *default_setting &= 0xf8;
2767  *default_setting |= page_reference_data.national_option_character_subset;
2768  }
2769  }
2770 
2771  ptr->subtitle = page_reference_data.subtitle;
2772 
2773  if ((page_reference_data.newsflash == TRUE) ||
2774  (page_reference_data.subtitle == TRUE))
2775  {
2776  if (boxing_required != NULL)
2777  {
2778  *boxing_required = TRUE;
2779  }
2780  }
2781 
2782  if (page_reference_data.suppress_header == TRUE)
2783  {
2784  if (header_required != NULL)
2785  {
2786  *header_required = FALSE;
2787  }
2788  }
2789 
2790  if (page_reference_data.inhibit_display == TRUE)
2791  {
2792  if (body_required != NULL)
2793  {
2794  *body_required = FALSE;
2795  }
2796  }
2797  }
2798 
2799  FUNCTION_FINISH(GetBasicPageDisplayInfo);
2800 }
2801 
2828 static void GetCharacterPaletteIndexes(S_PAGE_DISPLAY_INFO *display_info_ptr,
2829  U8BIT *foreground_index, U8BIT *background_index,
2830  U8BIT foreground_colour, U8BIT background_colour,
2831  BOOLEAN flashing, BOOLEAN conceal,
2832  BOOLEAN boxing_required, BOOLEAN boxed,
2833  BOOLEAN video_mix_overridden)
2834 {
2835  U8BIT fore_colour, back_colour, effect_mask;
2836  U16BIT index;
2837 
2838  FUNCTION_START(GetCharacterPaletteIndexes);
2839 
2840  if ((boxing_required == TRUE) &&
2841  (boxed == FALSE))
2842  {
2843  // If we are displaying a newsflash/subtitle screen and the current text is not boxed, then
2844  // mark the foreground index to denote that nothing is to be displayed.
2845  *foreground_index = PALETTE_FOREGROUND_UNBOXED;
2846  }
2847  else
2848  {
2849  if (foreground_colour < 8)
2850  {
2851  // Remap the absolute Teletext colour reference to a foreground reservation in the palette.
2852  fore_colour = foreground_colour + PALETTE_FOREGROUND_BLACK;
2853  }
2854  else
2855  {
2856  // The colour reference is invalid - default to white
2857  fore_colour = PALETTE_FOREGROUND_WHITE;
2858  }
2859 
2860  if (background_colour < 8)
2861  {
2862  // Remap the absolute Teletext colour reference to a background reservation in the palette.
2863  back_colour = background_colour + PALETTE_BACKGROUND_BLACK;
2864  }
2865  else
2866  {
2867  // The colour reference is invalid - default to black
2868  back_colour = PALETTE_BACKGROUND_BLACK;
2869  }
2870 
2871  // determine which display attributes result in a 'dynamic' palette requirement.
2872  effect_mask = PALETTE_EFFECT_UNDEFINED;
2873 
2874  if (flashing == TRUE)
2875  {
2876  effect_mask = PALETTE_EFFECT_FLASH;
2877  }
2878  if (conceal == TRUE)
2879  {
2880  effect_mask |= PALETTE_EFFECT_CONCEAL;
2881  }
2882 
2883  // If there is a need for a reserved palette entry...
2884  if (effect_mask != PALETTE_EFFECT_UNDEFINED)
2885  {
2886  for (index = 0; index < NUM_PALETTE_EFFECTS; index++)
2887  {
2888  if (display_info_ptr->palette_attribute_array[index].effect_mask ==
2889  PALETTE_EFFECT_UNDEFINED)
2890  {
2891  // If we have reached the end of the currently allocated reservations, the add a new
2892  // one.
2893  display_info_ptr->palette_attribute_array[index].fore_colour = fore_colour;
2894  display_info_ptr->palette_attribute_array[index].back_colour = back_colour;
2895  display_info_ptr->palette_attribute_array[index].effect_mask = effect_mask;
2896 
2897  if (index < (NUM_PALETTE_EFFECTS - 1))
2898  {
2899  display_info_ptr->palette_attribute_array[index + 1].effect_mask =
2900  PALETTE_EFFECT_UNDEFINED;
2901  }
2902 
2903  fore_colour = index + PALETTE_EFFECT_ORIGIN;
2904  break;
2905  }
2906 
2907 
2908  // If a suitable allocation already exists, then use it.
2909  if ((display_info_ptr->palette_attribute_array[index].fore_colour == fore_colour) &&
2910  (display_info_ptr->palette_attribute_array[index].back_colour == back_colour) &&
2911  (display_info_ptr->palette_attribute_array[index].effect_mask == effect_mask))
2912  {
2913  fore_colour = index + PALETTE_EFFECT_ORIGIN;
2914  break;
2915  }
2916  }
2917  }
2918 
2919  *foreground_index = fore_colour;
2920 
2921  if ((display_info_ptr->video_mix_set == TRUE) &&
2922  (video_mix_overridden == TRUE))
2923  {
2924  if (back_colour == PALETTE_BACKGROUND_BLACK)
2925  {
2926  *background_index = PALETTE_BACKGROUND_BLACK_FIXED;
2927  }
2928  }
2929  else
2930  {
2931  *background_index = back_colour;
2932  }
2933  }
2934 
2935  FUNCTION_FINISH(GetCharacterPaletteIndexes);
2936 }
2937 
2938 static BOOLEAN GetPesPts(U8BIT *data, U8BIT *pts)
2939 {
2940  BOOLEAN retval;
2941 
2942  FUNCTION_START(GetPesPts);
2943 
2944  pts[0] = (data[0] & 0x08) >> 3;
2945  pts[1] = ((data[0] & 0x06) << 5) + ((data[1] & 0xfc) >> 2);
2946  pts[2] = ((data[1] & 0x03) << 6) + ((data[2] & 0xfc) >> 2);
2947  pts[3] = ((data[2] & 0x02) << 6) + ((data[3] & 0xfe) >> 1);
2948  pts[4] = ((data[3] & 0x01) << 7) + ((data[4] & 0xfe) >> 1);
2949 
2950  retval = (data[0] & 0x01) & (data[2] & 0x01) & (data[4] & 0x01);
2951 
2952  FUNCTION_FINISH(GetPesPts);
2953 
2954  return(retval);
2955 }
2956 
2975 static void PESCollectionCallback(U32BIT handle, U8BIT data_identifier, void *data_ptr, U32BIT data_length)
2976 {
2977  FUNCTION_START(PESCollectionCallback);
2978  USE_UNWANTED_PARAM(handle);
2979  USE_UNWANTED_PARAM(data_identifier);
2980 
2981  AddPESDataToQueue(data_ptr, data_length);
2982 
2983  FUNCTION_FINISH(PESCollectionCallback);
2984 }
2985 
2986 static BOOLEAN AddPESDataToQueue(void *data_ptr, U32BIT data_length)
2987 {
2988  BOOLEAN retval;
2989  U16BIT data_remaining;
2990 
2991  // The PES packet header (as defined in BS ISO/IEC 13818-1, Table 2-17 - PES packet) precedes
2992  // one or more Teletext packets in PES data fields
2993  //
2994  // Thus is equivalent to this structure:
2995  //
2996  // typedef struct
2997  // {
2998  // U8BIT start_code_prefix[3]; // This should have values of 0x00, 0x00, 0x01
2999  // U8BIT stream_id; // Thus should be 0xbd, which is 'private_stream_1'.
3000  //
3001  // U8BIT packet_length[2]; // This is a big endian value, hence the byte pair will
3002  // // need conversion.
3003  // // NB - this must be non-zero!
3004  //
3005  // U8BIT padding[2]; // Two irrelevant bytes.
3006  //
3007  // U8BIT header_length; // Offset applied to <header_end_marker> that gives the
3008  // // location of the 'PES data field' block.
3009  // U8BIT header_end_marker;
3010  // }
3011  U8BIT *pes_packet_header_ptr;
3012 
3013  // Within the PES packet is the PES data block which in turn contains 'PES data fields' (as
3014  // defined in ETSI EN 300 706 V1.2.1, section 4.3 - Syntax of PES data field, Table 1: Syntax
3015  // for PES data field) is found all the Teletext packet(s).
3016  //
3017  // Thus is equivalent to these structures:
3018  //
3019  // typedef struct
3020  // {
3021  // U8BIT data_unit_id; // This value is irrelevant.
3022  //
3023  // U8BIT data_unit_length; // This MUST be 0x2c (44 bytes) as it signifies the total
3024  // // length of data represented by the three subsequent elements.
3025  // // This should be 1 + 1 + 42 = 44 bytes!
3026  //
3027  // // These definitions below map to the content of the 'data_field' of the 'PES data field'
3028  //
3029  // U8BIT field_byte;
3030  // // These values should be validated against specified constants as part of the packet
3031  // // validation process.
3032  // U8BIT framing_code;
3033  //
3034  // S_TELETEXT_PACKET teletext_packet;
3035  // }
3036  // S_PES_DATA_FIELD;
3037  //
3038  // typedef struct s_pes_data
3039  // {
3040  // U8BIT data_indentifier; // This should be in the renage 0x10 to 0x1f.
3041  // // This is valid range for PES content relating to EBU Teletext
3042  // // data.
3043  //
3044  // S_PES_DATA_FIELD data_field;
3045  // }
3046  U8BIT *data_identifier_ptr;
3047  U8BIT *pes_data_field_ptr;
3048  U8BIT pts_dts_flags, pts_present;
3049  U8BIT pts[5];
3050  S_COLLATION_QUEUE_ITEM queue_item;
3051 
3052  // These are equivalent to <start_code_prefix> and <stream_id> of the PES packet header
3053  // The valid value of 0xbd denotes this as 'private_stream_1'
3054  static U8BIT pes_packet_header_validator[4] = { 0x00, 0x00, 0x01, 0xbd };
3055 
3056  FUNCTION_START(AddPESDataToQueue);
3057 
3058  USE_UNWANTED_PARAM(data_length);
3059 
3060  retval = FALSE;
3061 
3062  if (IsPacketQueueingRequired() == TRUE)
3063  {
3064  pes_packet_header_ptr = (U8BIT *)data_ptr;
3065 
3066  // Validate the <start_code_prefix> (3 byte signature) and the <stream_id>
3067  if (!memcmp(pes_packet_header_ptr, pes_packet_header_validator, sizeof(pes_packet_header_validator)))
3068  {
3069  // Get pointer to start of PES data content within PES packet - after header.
3070  data_identifier_ptr = pes_packet_header_ptr + *(pes_packet_header_ptr + 8) + 9;
3071 
3072  // Check that data identifier denotes that this PES data is 'EBU data'
3073  if ((*data_identifier_ptr >= 0x10) &&
3074  (*data_identifier_ptr <= 0x1f))
3075  {
3076  /* Extract the PTS from the PES header if it's present */
3077  pts_dts_flags = (pes_packet_header_ptr[7] & 0xc0) >> 6;
3078  pts_present = ((pts_dts_flags & 0x2) >> 1);
3079 
3080  if (pts_present)
3081  {
3082  if (!GetPesPts(&pes_packet_header_ptr[9], pts))
3083  {
3084  // One or more of the 3 marker_bits are not set correctly.
3085  memset(pts, 0x00, 5);
3086  }
3087  }
3088 
3089  // get the packet length, and then subtract the header length.
3090  // This results in the amount of data which constitutes a sequence of
3091  // PES data fields.
3092  data_remaining = (*(pes_packet_header_ptr + 4) << 8) + *(pes_packet_header_ptr + 5) - 4;
3093  data_remaining -= *(pes_packet_header_ptr + 8);
3094 
3095  // Get a pointer to the first PES data field.
3096  pes_data_field_ptr = data_identifier_ptr + 1;
3097 
3098  // Each PES data field has four header bytes, and then 42 bytes of actual Teletext
3099  // packet data.
3100  while (data_remaining >= PES_DATA_FIELD_WIDTH)
3101  {
3102  retval = TRUE;
3103 
3104  // The <data_unit_length> should always be 0x2c, which is 44 bytes.
3105  // The <framing_code> should always be 0xe4.
3106  if ((*(pes_data_field_ptr + 1) == 0x2c) &&
3107  (*(pes_data_field_ptr + 3) == 0xe4))
3108  {
3109  /* Allocate memory for this data packet and write it to the queue */
3110  if ((queue_item.data = STB_GetMemory(PES_DATA_FIELD_WIDTH - 4)) != NULL)
3111  {
3112  memcpy(queue_item.data, pes_data_field_ptr + 4, PES_DATA_FIELD_WIDTH - 4);
3113 
3114  queue_item.pts_present = pts_present;
3115  if (pts_present)
3116  {
3117  memcpy(queue_item.pts, pts, 5);
3118  }
3119 
3120  if (STB_OSWriteQueue(collation_queue, (void *)&queue_item, sizeof(queue_item), TIMEOUT_NOW))
3121  {
3122  queue_count++;
3123  if (queue_count > max_queue_count)
3124  {
3125  max_queue_count = queue_count;
3126  EBU_DBG("%s: max_queue_count=%u\n", __FUNCTION__, max_queue_count);
3127  }
3128  }
3129  else
3130  {
3131  EBU_DBG("%s: Failed to write to collation queue\n", __FUNCTION__);
3132  STB_FreeMemory(queue_item.data);
3133  }
3134  }
3135  }
3136 
3137  // Advance to the next PES data field (if possible)
3138  pes_data_field_ptr += PES_DATA_FIELD_WIDTH;
3139  data_remaining -= PES_DATA_FIELD_WIDTH;
3140  }
3141  }
3142  }
3143  }
3144 
3145  FUNCTION_FINISH(AddPESDataToQueue);
3146 
3147  return(retval);
3148 }
3149 
3150 static void PESCollationTask(void *param)
3151 {
3152  S_COLLATION_QUEUE_ITEM queue_item;
3153 
3154  USE_UNWANTED_PARAM(param);
3155 
3156  while (1)
3157  {
3158  STB_OSSemaphoreWait(collation_start);
3159  collation_started = TRUE;
3160  while (!stop_collation)
3161  {
3162  if (STB_OSReadQueue(collation_queue, &queue_item, sizeof(queue_item), TIMEOUT_NEVER))
3163  {
3164  queue_count--;
3165 
3166  if (queue_item.data != NULL)
3167  {
3168  /* Process the teletext packet, which consists of two leading bytes for the packet and
3169  * magazine identification, and then 40 bytes of packet data */
3170  PerformPESCollation(queue_item.data, queue_item.pts_present, queue_item.pts);
3171 
3172  STB_FreeMemory(queue_item.data);
3173  }
3174  }
3175  }
3176 
3177  STB_OSSemaphoreSignal(collation_stopped);
3178  collation_started = FALSE;
3179  }
3180 }
3181 
3195 static BOOLEAN InitialiseCollation(void)
3196 {
3197  U16BIT i;
3198  BOOLEAN retval;
3199 
3200  FUNCTION_START(InitialiseCollation);
3201 
3202  retval = FALSE;
3203 
3204  // There is currently no way to kill a semaphore, so initialisation is a single-shot affair!
3205 
3206  if (page_request_info.semaphore == NULL)
3207  {
3208  page_request_info.semaphore = STB_OSCreateSemaphore();
3209  }
3210 
3211  if (page_display_info.page_semaphore == NULL)
3212  {
3213  page_display_info.page_semaphore = STB_OSCreateSemaphore();
3214  }
3215  if (page_display_info.page_index_semaphore == NULL)
3216  {
3217  page_display_info.page_index_semaphore = STB_OSCreateSemaphore();
3218  }
3219  if (page_display_info.carousel_page_semaphore == NULL)
3220  {
3221  page_display_info.carousel_page_semaphore = STB_OSCreateSemaphore();
3222  }
3223  if (page_display_info.time_filler_header_data_semaphore == NULL)
3224  {
3225  page_display_info.time_filler_header_data_semaphore = STB_OSCreateSemaphore();
3226  }
3227  if (page_display_info.page_scale_semaphore == NULL)
3228  {
3229  page_display_info.page_scale_semaphore = STB_OSCreateSemaphore();
3230  }
3231 
3232  is_broadcast_service_data_defined[0] = FALSE;
3233  is_broadcast_service_data_defined[1] = FALSE;
3234 
3235  memset(magazine_array, 0, sizeof(S_MAGAZINE_INFO) * 8 );
3236 
3237  // If we have a semaphore (either from just above or a previos call to this function then
3238  // continue with the initialisation of the corresponding task.
3239  if ((page_request_info.semaphore != NULL) &&
3240  (page_display_info.page_semaphore != NULL) &&
3241  (page_display_info.page_index_semaphore != NULL) &&
3242  (page_display_info.carousel_page_semaphore != NULL) &&
3243  (page_display_info.time_filler_header_data_semaphore != NULL) &&
3244  (page_display_info.page_scale_semaphore != NULL))
3245  {
3246  retval = TRUE;
3247  for (i = 0; i != 8; i++)
3248  {
3249  magazine_array[i].m_mutex = STB_OSCreateMutex();
3250  if (magazine_array[i].m_mutex == NULL)
3251  {
3252  retval = FALSE;
3253  DBGPRINT("STB_OSCreateMutex failed");
3254  break;
3255  }
3256  }
3257  }
3258 
3259  FUNCTION_FINISH(InitialiseCollation);
3260 
3261  return(retval);
3262 }
3263 
3279 BOOLEAN PerformPESCollation(U8BIT *data_ptr, BOOLEAN pts_valid, U8BIT *pts)
3280 {
3281  U8BIT packet_number, magazine_number, control_byte;
3282  U8BIT designation_code, magazine_index, format_number;
3283  U32BIT triplet_value;
3284  BOOLEAN retval, update_required;
3285 
3286  FUNCTION_START(PerformPESCollation);
3287 
3288  retval = FALSE;
3289 
3290  CheckPageRequest(pts_valid, pts);
3291 
3292  if (GetPacketAddress(&packet_number, &magazine_number, data_ptr))
3293  {
3294  data_ptr += 2;
3295 
3296  // On the basis of the packet number, determine how the data content should be handled.
3297  if (packet_number == 0)
3298  {
3299  // This is an X/0 packet, which is a page header
3300  // (as defined in ETSI EN 300 706 V1.2.1, section 9.3.1 - Page Header)
3301  //
3302  // Thus is equivalent to this structure:
3303  //
3304  // typedef struct
3305  // {
3306  // // Byte-pair used with the magazine index to genereate a page index.
3307  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3308  // U8BIT units;
3309  // U8BIT tens;
3310  //
3311  // // Page sub-code, and some control bits.
3312  // // (data is Hamming 8/4 protected, sub-code in 13 of sixteen bits 2,4,6,...,30,32)
3313  // // NB - control bits are 'Erase Page', 'Newsflash', and 'Subtitle'.
3314  // union
3315  // {
3316  // U32BIT sub_code;
3317  // U8BIT control_bytes_a[4]; // only control_bytes_a[1] and control_bytes_a[3]
3318  // // have control bit content.
3319  // };
3320  //
3321  // // The remaining control bits.
3322  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3323  // // NB - control bits are 'Suppress Header', 'Update Indicator',
3324  // // 'Interrupted Sequence', 'Inhibit Display', 'Magazine Serial', and
3325  // // 'Nat. Option Char. Subset'.
3326  // U8BIT control_bytes_b[2];
3327  //
3328  // // Character codes for top line after edit index and page index (8 characters)
3329  // // (for each byte, odd partiy coded in MSbit.)
3330  // U8BIT data[32];
3331  // }
3332  // S_PAGE_HEADER;
3333 
3334  // To get to the X/0 header within the Teletext packet, we must skip over the page and
3335  // magazine number byte pair.
3336 
3337  // Before copying the data into the magazine, the existing content is checked and passed on
3338  // to the cache mechanism for further processing - this is achieved by calling
3339  // NotifyPageCollated( ).
3340 
3341  // Get hold of the last control byte
3342  if (GetHamming8Byte(data_ptr + 7, &control_byte) == TRUE)
3343  {
3344  if (control_byte & 0x01)
3345  {
3346  // 'Magazine Serial' mode is enabled.
3347  // When each page header is received, the last fully collated page is passed onto the
3348  // cache - irrespective of it's magazine.
3349 
3350  // Search all the magazines for a previously transmitted page...
3351  for (magazine_index = 0; magazine_index != 8; magazine_index++)
3352  {
3353  // ..if found, pass onto the cacheing interface.
3354  if (magazine_array[magazine_index].m_page.is_header_defined == TRUE)
3355  {
3356  NotifyPageCollated(&magazine_array[magazine_index].m_page, magazine_index,
3357  pts_valid, pts);
3358 
3359  magazine_array[magazine_index].m_page.is_header_defined = FALSE;
3360  break;
3361  }
3362  }
3363  }
3364  else
3365  {
3366  // 'Magazine Serial' mode is disabled.
3367  // When each page header is received, the last page in the SAME magazine is passed
3368  // onto the cache.
3369 
3370  // Pass page onto cache - don't bother clearing the is_header_defined flag,
3371  // as we are about to set it anyway!
3372  if (magazine_array[magazine_number].m_page.is_header_defined == TRUE)
3373  {
3374  NotifyPageCollated(&magazine_array[magazine_number].m_page, magazine_number,
3375  pts_valid, pts);
3376  }
3377  }
3378 
3379  // Copy header packet into allotted space in relevant magazine.
3380  memcpy(magazine_array[magazine_number].m_page.header, data_ptr, MAX_COLUMN);
3381 
3382  magazine_array[magazine_number].m_page.is_header_defined = TRUE;
3383 
3384  if (magazine_array[magazine_number].m_page.display_data_defined_mask)
3385  {
3386  DBGPRINT("reseting mask %#x", magazine_array[magazine_number].m_page.display_data_defined_mask );
3387  }
3388  magazine_array[magazine_number].m_page.display_data_defined_mask = 0;
3389 
3390  magazine_array[magazine_number].m_page.basic_enhancement_data_defined_mask = 0;
3391 
3392  magazine_array[magazine_number].m_page.is_editorial_page_linking_data_defined = FALSE;
3393 
3394  magazine_array[magazine_number].m_page.specific_data.is_defined[0] = FALSE;
3395  magazine_array[magazine_number].m_page.specific_data.is_defined[1] = FALSE;
3396  }
3397  }
3398  else if ((packet_number >= 1) &&
3399  (packet_number <= MAX_ROWS))
3400  {
3401  // These are X/1 to X/25 packets, which contain all the information that is subsequently
3402  // parsed to give a TeleText page display.
3403  // Control codes within the header packet determine the exact nature of some of these
3404  // packets, and the packet content may be inherited by subsequent pages of the 'Erase page'
3405  // control code is not set.
3406  // (as defined in ETSI EN 300 706 V1.2.1, section 9.3.2 - Packets X/1 to X/25)
3407  //
3408  // Thus is equivalent to this structure:
3409  //
3410  // char data[40];
3411 
3412  // To get to the X/25 data within the Teletext packet, we must skip over the page and
3413  // magazine number byte pair.
3414 
3415  // Copy the data packet into allotted space in relevant magazine.
3416  memcpy(magazine_array[magazine_number].m_page.display_data[packet_number], data_ptr, MAX_COLUMN);
3417 
3418  // Set the relevant bit in the definition notification mask.
3419  magazine_array[magazine_number].m_page.display_data_defined_mask |= 1 << packet_number;
3420  }
3421  else if (packet_number == 26)
3422  {
3423  // These are X/26/0 to X/26/15 packets, which are enhanced data.
3424  // (as defined in ETSI EN 300 706 V1.2.1, section 9.3.2 - Packets X/1 to X/25)
3425  //
3426  // Thus is equivalent to this structure:
3427  //
3428  // typedef struct
3429  // {
3430  // // This is the 'Designation Code' used as index for enhancement packet array.
3431  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3432  // U8BIT designation_code;
3433  //
3434  // // 13 triplets, each describing different attributes.
3435  // // (data is Hamming 24/18 protected)
3436  // U8BIT data[39];
3437  // }
3438  // S_PAGE_BASIC_ENHANCEMENT_DATA;
3439 
3440  // To get to the X/26 enhancement data within the Teletext packet, we must skip over the
3441  // page and magazine number byte pair.
3442 
3443  // The first byte is the designation code, which yelids a 4-bit value.
3444  if (GetHamming8Byte(data_ptr, &designation_code) == TRUE)
3445  {
3446  // Copy the enhanced data packet into allotted space in relevant magazine.
3447  memcpy(magazine_array[magazine_number].m_page.basic_enhancement_data[designation_code],
3448  data_ptr, MAX_COLUMN);
3449 
3450  if (designation_code)
3451  {
3452  magazine_array[magazine_number].m_page.basic_enhancement_data_defined_mask |=
3453  1 << designation_code;
3454  }
3455  else
3456  {
3457  magazine_array[magazine_number].m_page.basic_enhancement_data_defined_mask |= 1;
3458  }
3459  }
3460  }
3461  else if (packet_number == 27)
3462  {
3463  // This is the X/27/0 packet, which is editorial page linking data (for FLOF navigations).
3464  // (as defined in ETSI EN 300 706 V1.2.1, section 9.6.1 - Packets X/27/0 to X/27/3 for
3465  // Editoral Linking)
3466  //
3467  // Thus is equivalent to this structure:
3468  //
3469  // typedef struct
3470  // {
3471  // // This is the 'Designation Code' used as index for enhancement packet array.
3472  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3473  // U8BIT designation_code;
3474  //
3475  // // First four links are FastText navigations, sixth is local index page.
3476  // S_EDITORIAL_LINK editorial_link[6];
3477  //
3478  // // Bit 4 determines if packet Y/24 is displayed - this has coloured text for four
3479  // // links.
3480  // U8BIT link_contol_byte;
3481  //
3482  // U16BIT crc;
3483  // }
3484  // S_PAGE_EDITORIAL_LINKING_DATA;
3485  //
3486  // typedef struct
3487  // {
3488  // // Byte-pair used with the magazine index to genereate a page index.
3489  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3490  // U8BIT units;
3491  // U8BIT tens;
3492  //
3493  // // Page sub-code, and some control bits.
3494  // // (data is Hamming 8/4 protected, sub-code in 13 of sixteen bits 2,4,6,...,30,32)
3495  // // NB - control bits are 'Erase Page', 'Newsflash', and 'Subtitle'
3496  // union
3497  // {
3498  // U32BIT sub_code;
3499  // U8BIT magazine_bytes_a[4]; // only magazine_bytes_a[1] and magazine_bytes_a[3]
3500  // // have content.
3501  // };
3502  // }
3503  // S_EDITORIAL_LINK;
3504 
3505 
3506  // To get to the X/27 editorial link data within the Teletext packet, we must skip over the
3507  // page and magazine number byte pair.
3508 
3509  // The first byte is the designation code, which yelids a 4-bit value.
3510  if (GetHamming8Byte(data_ptr, &designation_code) == TRUE)
3511  {
3512  // We are only interested in X/27/0
3513  if (designation_code == 0)
3514  {
3515  // Copy the editorial page linking data packet into allotted space in relevant
3516  // magazine.
3517  memcpy(magazine_array[magazine_number].m_page.editorial_page_linking_data,
3518  data_ptr, MAX_COLUMN);
3519 
3520  magazine_array[magazine_number].m_page.is_editorial_page_linking_data_defined = TRUE;
3521  }
3522  }
3523  }
3524  else if (packet_number == 28)
3525  {
3526  // This is either:
3527  // the X/28/0 Format 1 packet, which is page specific data.
3528  // (as defined in ETSI EN 300 706 V1.2.1, section 9.4.2 - Packets X/28/0 Format 1)
3529  // or
3530  // the X/28/1 packet, which is page specific data.
3531  // (as defined in ETSI EN 300 706 V1.2.1, section 9.4.4 - Packets X/28/1)
3532  //
3533  // typedef struct
3534  // {
3535  // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3536  // U8BIT designation_code;
3537  //
3538  // // 13 triplets, each describing different attributes.
3539  // // (data is Hamming 24/18 protected)
3540  // U8BIT data[39];
3541  // }
3542  // S_PAGE_BASIC_ENHANCEMENT_DATA;
3543 
3544 
3545  // To get to the X/28 page specific data within the Teletext packet, we must skip over the
3546  // page and magazine number byte pair.
3547 
3548  // The first byte is the designation code, which yelids a 4-bit value.
3549  if (GetHamming8Byte(data_ptr, &designation_code) == TRUE)
3550  {
3551  // We are only interested in X/28/0
3552  if (designation_code == 0)
3553  {
3554  if (GetHammimg24Value(data_ptr + 1, &triplet_value) == TRUE)
3555  {
3556  // We are only interested in the page function of type 'Basic Level 1 Teletext
3557  // page (LOP)'
3558  if ((triplet_value & 0x0fL) == 0)
3559  {
3560  // Copy the page specific data packet into allotted space in relevant magazine.
3561  memcpy(magazine_array[magazine_number].m_page.specific_data.s_data[0],
3562  data_ptr, MAX_COLUMN);
3563 
3564  magazine_array[magazine_number].m_page.specific_data.is_defined[0] = TRUE;
3565  }
3566  }
3567  }
3568  // We are only interested in X/28/1
3569  else if (designation_code == 1)
3570  {
3571  // Copy the page specific_data data packet into allotted space in relevant magazine.
3572  memcpy(magazine_array[magazine_number].m_page.specific_data.s_data[1], data_ptr, MAX_COLUMN);
3573 
3574  magazine_array[magazine_number].m_page.specific_data.is_defined[1] = TRUE;
3575  }
3576  }
3577  }
3578  else if (packet_number == 29)
3579  {
3580  // This is either:
3581  // the M/29/0 packet, which is magazine specific_data data.
3582  // [ this has the same format as the X/28/0 Format 1 packet, which is page specific_data data.]
3583  // (as defined in ETSI EN 300 706 V1.2.1, section 9.4.2 - Packets X/28/0 Format 1)
3584  // or
3585  // the M/29/1 packet, which is magazine specific_data data.
3586  // [ this has the same format as the X/28/1 packet, which is page specific_data data. ]
3587  // (as defined in ETSI EN 300 706 V1.2.1, section 9.4.4 - Packets X/28/1)
3588  //
3589  // typedef struct
3590  // {
3591  // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3592  // U8BIT designation_code;
3593  //
3594  // // 13 triplets, each describing different attributes.
3595  // // (data is Hamming 24/18 protected)
3596  // U8BIT data[39];
3597  // }
3598  // S_PAGE_BASIC_ENHANCEMENT_DATA;
3599 
3600 
3601  // To get to the M/29 magazine specific_data data within the Teletext packet, we must skip over
3602  // the page and magazine number byte pair.
3603 
3604  // The first byte is the designation code, which yelids a 4-bit value.
3605  if (GetHamming8Byte(data_ptr, &designation_code) == TRUE)
3606  {
3607  // We are only interested in M/29/0 and M/29/1
3608  if ((designation_code == 0) ||
3609  (designation_code == 1))
3610  {
3611  if (GetHammimg24Value(data_ptr + 1, &triplet_value) == TRUE)
3612  {
3613  // We are only interested in the page function of type 'Basic Level 1 Teletext
3614  // page (LOP)'
3615  if ((triplet_value & 0x0fL) == 0)
3616  {
3617  update_required = FALSE;
3618 
3619  if (magazine_array[magazine_number].m_specific_data.is_defined[designation_code] == TRUE)
3620  {
3621  if (memcmp(magazine_array[magazine_number].m_specific_data.s_data[designation_code],
3622  data_ptr, MAX_COLUMN))
3623  {
3624  update_required = TRUE;
3625  }
3626  }
3627  else
3628  {
3629  update_required = TRUE;
3630  }
3631 
3632  if (update_required == TRUE)
3633  {
3634  // Copy the page specific_data data packet into allotted space in relevant magazine.
3635  memcpy(magazine_array[magazine_number].m_specific_data.s_data[designation_code],
3636  data_ptr, MAX_COLUMN);
3637 
3638  magazine_array[magazine_number].m_specific_data.is_defined[designation_code] = TRUE;
3639 
3640  if (page_display_info.page_number)
3641  {
3642  if (GetMagazineIndexFromPageNumber(page_display_info.page_number) ==
3643  magazine_number)
3644  {
3645  /* Wait until page_display_info is available to be used */
3646  STB_OSSemaphoreWait(page_free_sem);
3647 
3648  STB_OSSemaphoreWait(page_display_info.page_semaphore);
3649 
3650  memcpy(page_display_info.mgzn_data.s_data[designation_code],
3651  data_ptr, MAX_COLUMN);
3652 
3653  page_display_info.mgzn_data.is_defined[designation_code] = TRUE;
3654 
3655  page_display_info.pts_valid = pts_valid;
3656  if (pts_valid)
3657  {
3658  memcpy(page_display_info.page_pts, pts, 5);
3659  EBU_DBG("PageUpdate PTS: 0x%02x%02x%02x%02x%02x", pts[0], pts[1],
3660  pts[2], pts[3], pts[4]);
3661  }
3662 
3663  page_display_info.page_updated = TRUE;
3664 
3665  STB_OSSemaphoreSignal(page_display_info.page_semaphore);
3666  }
3667  }
3668  }
3669  }
3670  }
3671  }
3672  }
3673  }
3674  else if ((packet_number == 30) &&
3675  (magazine_number == 0))
3676  {
3677  // This is either:
3678  // the 8/30 Format 1 and 2 packets, which is page broadcast service data.
3679  // (as defined in ETSI EN 300 706 V1.2.1, section 9.8 - Broadcast Service Data Packets)
3680  //
3681  // typedef struct s_page_broadcast_service_sub_data_format_1
3682  // {
3683  // U16BIT network_identification_code;
3684  //
3685  // U8BIT time_offset_code;
3686  // U8BIT mjd_time[3]; // Modified Julian Date triplet
3687  // U8BIT utc_time[3]; // Universal Time Co-ordinated triplet
3688  //
3689  // U8BIT reserved[4];
3690  // }
3691  // S_PAGE_BROADCAST_SERVICE_SUB_DATA_FORMAT_1;
3692  //
3693  // typedef struct s_page_broadcast_service_sub_data_format_2
3694  // {
3695  // U8BIT program_identification_data[13];
3696  // }
3697  // S_PAGE_BROADCAST_SERVICE_SUB_DATA_FORMAT_2;
3698  //
3699  //
3700  // typedef struct s_page_broadcast_service_data
3701  // {
3702  // // This is the 'Designation Code' used as index for enhancement packet array.
3703  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3704  // U8BIT designation_code;
3705  //
3706  // // Byte-pair used with the magazine index to genereate a page index.
3707  // // (data is Hamming 8/4 protected, data in bits 2,4,6,8)
3708  // U8BIT units;
3709  // U8BIT tens;
3710  //
3711  // // Page sub-code, and some control bits.
3712  // // (data is Hamming 8/4 protected, sub-code in 13 of sixteen bits 2,4,6,...,30,32)
3713  // // NB - control bits are 'Erase Page', 'Newsflash', and 'Subtitle'
3714  // union
3715  // {
3716  // U32BIT sub_code;
3717  // U8BIT magazine_bytes[4]; // only magazine_bytes[1] and magazine_bytes[3] have
3718  // // magazine index content
3719  // };
3720  //
3721  // union
3722  // {
3723  // S_PAGE_BROADCAST_SERVICE_SUB_DATA_FORMAT_1 data_format_1;
3724  // S_PAGE_BROADCAST_SERVICE_SUB_DATA_FORMAT_2 data_format_2;
3725  // };
3726  //
3727  // U8BIT status_display[20];
3728  // }
3729  // S_PAGE_BROADCAST_SERVICE_DATA;
3730 
3731  // To get to the 8/30 page specific_data data within the Teletext packet, we must skip over the
3732  // page and magazine number byte pair.
3733 
3734  // The first byte is the designation code, which yelids a 4-bit value.
3735  if (GetHamming8Byte(data_ptr, &designation_code) == TRUE)
3736  {
3737  // We are only interested in Format 1 and 2 packets, which are represented by the
3738  // designation code pairs 0,1 and 2,3 repectively.
3739  if (designation_code < 4)
3740  {
3741  format_number = designation_code >> 1;
3742 
3743  memcpy(broadcast_service_data[format_number], data_ptr, MAX_COLUMN);
3744  is_broadcast_service_data_defined[format_number] = TRUE;
3745 
3746  if (broadcast_index_page_invocation_required == TRUE)
3747  {
3748  broadcast_index_page_invocation_required = FALSE;
3749  RequestIndexPage();
3750  }
3751  }
3752  }
3753  }
3754  retval = TRUE;
3755  }
3756 
3757  FUNCTION_FINISH(PerformPESCollation);
3758 
3759  return(retval);
3760 }
3761 
3788 static void RequestPage(U16BIT page_number, U16BIT page_sub_code)
3789 {
3790  BOOLEAN confirm_request;
3791 
3792  FUNCTION_START(RequestPage);
3793 
3794  confirm_request = FALSE;
3795 
3796  if (page_request_info.type != REQUEST_TYPE_EXPLICIT)
3797  {
3798  confirm_request = TRUE;
3799  }
3800 
3801  page_number &= CACHE_PAGE_NUMBER_MASK;
3802 
3803  // Only trigger a requested page notification if the requested page is different from the last
3804  // one.
3805  if (page_number != page_request_info.page_number)
3806  {
3807  confirm_request = TRUE;
3808  }
3809 
3810  if (page_sub_code == PAGE_SUB_CODE_UNDEFINED)
3811  {
3812  if (page_request_info.page_sub_code != PAGE_SUB_CODE_UNDEFINED)
3813  {
3814  confirm_request = TRUE;
3815  }
3816  }
3817  else if ((page_sub_code & 0x3f7f) != page_request_info.page_sub_code)
3818  {
3819  page_sub_code &= 0x3f7f;
3820  confirm_request = TRUE;
3821  }
3822 
3823  if (confirm_request == TRUE)
3824  {
3825  STB_OSSemaphoreWait(page_request_info.semaphore);
3826 
3827  page_request_info.type = REQUEST_TYPE_EXPLICIT;
3828 
3829  page_request_info.page_number = page_number;
3830  page_request_info.page_sub_code = page_sub_code;
3831 
3832  page_request_info.pending = TRUE;
3833 
3834  STB_OSSemaphoreSignal(page_request_info.semaphore);
3835  }
3836 
3837  FUNCTION_FINISH(RequestPage);
3838 }
3839 
3853 static void RequestIndexPage(void)
3854 {
3855  FUNCTION_START(RequestIndexPage);
3856 
3857  if (page_request_info.type != REQUEST_TYPE_INDEX)
3858  {
3859  STB_OSSemaphoreWait(page_request_info.semaphore);
3860 
3861  page_request_info.type = REQUEST_TYPE_INDEX;
3862 
3863  page_request_info.pending = TRUE;
3864 
3865  STB_OSSemaphoreSignal(page_request_info.semaphore);
3866  }
3867 
3868  FUNCTION_FINISH(RequestIndexPage);
3869 }
3870 
3889 static void RequestNextPrevious(E_REQUEST_TYPE request_type, BOOLEAN increment)
3890 {
3891  FUNCTION_START(RequestNextPrevious);
3892 
3893  if (page_request_info.type != request_type)
3894  {
3895  // Page request type has changed
3896 
3897  STB_OSSemaphoreWait(page_request_info.semaphore);
3898 
3899  page_request_info.type = request_type;
3900 
3901  // Set the iteration parameter to +1 or -1
3902  if (increment == TRUE)
3903  {
3904  page_request_info.param = 1;
3905  }
3906  else
3907  {
3908  page_request_info.param = -1;
3909  }
3910 
3911  page_request_info.pending = TRUE;
3912 
3913  STB_OSSemaphoreSignal(page_request_info.semaphore);
3914  }
3915  else
3916  {
3917  // Page request type has been repeated
3918 
3919  STB_OSSemaphoreWait(page_request_info.semaphore);
3920 
3921  if (page_request_info.pending == TRUE)
3922  {
3923  // If the previous similar request(s) have not been met then increase the iteration
3924  // parameter accordingly.
3925  if (increment == TRUE)
3926  {
3927  page_request_info.param++;
3928  }
3929  else
3930  {
3931  page_request_info.param--;
3932  }
3933  }
3934  else
3935  {
3936  // If the previous similar request(s) have been met then set the iteration parameter
3937  // to +1 or -1
3938  if (increment == TRUE)
3939  {
3940  page_request_info.param = 1;
3941  }
3942  else
3943  {
3944  page_request_info.param = -1;
3945  }
3946 
3947  page_request_info.pending = TRUE;
3948  }
3949 
3950  STB_OSSemaphoreSignal(page_request_info.semaphore);
3951  }
3952 
3953  FUNCTION_FINISH(RequestNextPrevious);
3954 }
3955 
3971 static void RequestNextAvailablePage(void)
3972 {
3973  FUNCTION_START(RequestNextAvailablePage);
3974 
3975  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_AVAILABLE, TRUE);
3976 
3977  FUNCTION_FINISH(RequestNextAvailablePage);
3978 }
3979 
3995 static void RequestPreviousAvailablePage(void)
3996 {
3997  FUNCTION_START(RequestPreviousAvailablePage);
3998 
3999  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_AVAILABLE, FALSE);
4000 
4001  FUNCTION_FINISH(RequestPreviousAvailablePage);
4002 }
4003 
4018 static void RequestNextVisitedPage(void)
4019 {
4020  FUNCTION_START(RequestNextVisitedPage);
4021 
4022  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_VISITED, TRUE);
4023 
4024  FUNCTION_FINISH(RequestNextVisitedPage);
4025 }
4026 
4041 static void RequestPreviousVisitedPage(void)
4042 {
4043  FUNCTION_START(RequestPreviousVisitedPage);
4044 
4045  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_VISITED, FALSE);
4046 
4047  FUNCTION_FINISH(RequestPreviousVisitedPage);
4048 }
4049 
4062 static void RequestEditorialLinkPage(U16BIT index)
4063 {
4064  FUNCTION_START(RequestEditorialLinkPage);
4065 
4066  if (index < MAX_EDITORIAL_LINKS)
4067  {
4068  if (page_request_info.type != REQUEST_TYPE_EDITORIAL_LINK)
4069  {
4070  STB_OSSemaphoreWait(page_request_info.semaphore);
4071 
4072  page_request_info.type = REQUEST_TYPE_EDITORIAL_LINK;
4073 
4074  page_request_info.param = index;
4075 
4076  page_request_info.pending = TRUE;
4077 
4078  STB_OSSemaphoreSignal(page_request_info.semaphore);
4079  }
4080  else
4081  {
4082  STB_OSSemaphoreWait(page_request_info.semaphore);
4083 
4084  if (page_request_info.param != index)
4085  {
4086  page_request_info.param = index;
4087 
4088  page_request_info.pending = TRUE;
4089  }
4090 
4091  STB_OSSemaphoreSignal(page_request_info.semaphore);
4092  }
4093  }
4094 
4095  FUNCTION_FINISH(RequestEditorialLinkPage);
4096 }
4097 
4114 static void RequestNextSubPage(void)
4115 {
4116  FUNCTION_START(RequestNextSubPage);
4117 
4118  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_SUB, TRUE);
4119 
4120  FUNCTION_FINISH(RequestNextSubPage);
4121 }
4122 
4139 static void RequestPreviousSubPage(void)
4140 {
4141  FUNCTION_START(RequestPreviousSubPage);
4142 
4143  RequestNextPrevious(REQUEST_TYPE_NEXT_PREV_SUB, FALSE);
4144 
4145  FUNCTION_FINISH(RequestPreviousSubPage);
4146 }
4147 
4163 static U16BIT GetMaximumEditorialLinkTiers(void)
4164 {
4165  U16BIT retval;
4166 
4167  FUNCTION_START(GetMaximumEditorialLinkTiers);
4168 
4169  if (caching_method == EBUTT_CACHING_METHOD_NAVIGATION)
4170  {
4171  // For this caching method, we only cache the editorially-linked pages of the currently
4172  // displayed page.
4173  retval = 1;
4174  }
4175  else
4176  {
4177  // For the EBUTT_CACHING_METHOD_NAVIGATION_TREE and EBUTT_CACHING_METHOD_ALL caching method,
4178  // we cache the up to a nominally defined depth of pages from of the currently displayed page.
4179  retval = MAX_EDITORIAL_LINK_TIERS;
4180  }
4181 
4182  FUNCTION_FINISH(GetMaximumEditorialLinkTiers);
4183 
4184  return(retval);
4185 }
4186 
4213 static BOOLEAN FindEditorialLinkRecursive(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
4215  S_EDITORIAL_LINK_CACHE_REQUEST **parent_ptr,
4216  U16BIT page_number)
4217 {
4218  U16BIT link_index;
4219  BOOLEAN retval;
4220  S_EDITORIAL_LINK_CACHE_REQUEST *found_ptr;
4222 
4223  FUNCTION_START(FindEditorialLinkRecursive);
4224 
4225  retval = FALSE;
4226 
4227  // Only perform search if the root item is defined!
4228  if (base_ptr != NULL)
4229  {
4230  // If the root item has a matching page number...
4231  if (base_ptr->page_number == page_number)
4232  {
4233  // ...then optionally return it's reference
4234  if (ptr != NULL)
4235  {
4236  *ptr = base_ptr;
4237  }
4238  retval = TRUE;
4239  }
4240  else
4241  {
4242  // We must now traverse the page's editorial link data looking for child page references.
4243  sub_page_ptr = base_ptr->sub_page_list;
4244  // For each sub-page...
4245  while (sub_page_ptr != NULL)
4246  {
4247  // ...if there are any editorial links...
4248  if (sub_page_ptr->is_parsed == TRUE)
4249  {
4250  // ... then for each link...
4251  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4252  {
4253  // ... find the page item with the matching page number in the entire request tree.
4254  // At this point, the link's sub-code is irrelevant.
4255  // NB - this is a recursive call to this fuction!
4256  if (FindEditorialLinkRecursive(
4257  (S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
4258  &found_ptr, parent_ptr, page_number) == TRUE)
4259  {
4260  // If we have found a page item with a matching page number then optionally
4261  // return it's reference (and it's parent as well)
4262  if (ptr != NULL)
4263  {
4264  *ptr = found_ptr;
4265  }
4266  if (parent_ptr != NULL)
4267  {
4268  if (*parent_ptr == NULL)
4269  {
4270  *parent_ptr = base_ptr;
4271  }
4272  }
4273 
4274  // Changer eturn value to denote a succesful search.
4275  retval = TRUE;
4276  break;
4277  }
4278  }
4279 
4280  // If match found, then stop looking at other links of this sub-page.
4281  if (retval == TRUE)
4282  {
4283  break;
4284  }
4285  }
4286 
4287  // If we are here then no page item exists in the item tree which matches the requuied
4288  // page number, so we must procees with checks of editorial links of other sub-pages.
4289  sub_page_ptr = sub_page_ptr->next_ptr;
4290  }
4291  }
4292  }
4293 
4294  FUNCTION_FINISH(FindEditorialLinkRecursive);
4295 
4296  return(retval);
4297 }
4298 
4324 static BOOLEAN FindEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
4326  S_EDITORIAL_LINK_CACHE_REQUEST **parent_ptr,
4327  U16BIT page_number)
4328 {
4329  BOOLEAN retval;
4330 
4331  FUNCTION_START(FindEditorialLinkPageRequest);
4332 
4333  retval = FALSE;
4334 
4335  // Only perform search if the root item is defined!
4336  if (base_ptr != NULL)
4337  {
4338  if (parent_ptr != NULL)
4339  {
4340  *parent_ptr = NULL;
4341  }
4342 
4343  // If the root item has a matching page number...
4344  if (base_ptr->page_number == page_number)
4345  {
4346  // ...then optionally return it's reference
4347  if (ptr != NULL)
4348  {
4349  *ptr = base_ptr;
4350  }
4351  retval = TRUE;
4352  }
4353  else
4354  {
4355  // Perform a recursive serch for a page request with a matching page number down the entire
4356  // request tree.
4357  if (FindEditorialLinkRecursive(base_ptr, ptr, parent_ptr, page_number) == TRUE)
4358  {
4359  if (parent_ptr != NULL)
4360  {
4361  if (*parent_ptr == NULL)
4362  {
4363  *parent_ptr = base_ptr;
4364  }
4365  }
4366 
4367  retval = TRUE;
4368  }
4369  }
4370  }
4371 
4372  FUNCTION_FINISH(FindEditorialLinkPageRequest);
4373 
4374  return(retval);
4375 }
4376 
4401 static BOOLEAN GetEditorialLink(S_EDITORIAL_LINK_CACHE_REQUEST *base_ptr,
4402  S_EDITORIAL_LINK_CACHE_REQUEST **ptr, U16BIT page_number)
4403 {
4404  U16BIT magazine_number, link_index;
4405  BOOLEAN retval;
4406  S_EDITORIAL_LINK_CACHE_REQUEST *found_ptr;
4408 
4409  FUNCTION_START(GetEditorialLink);
4410 
4411  retval = FALSE;
4412 
4413  // Only perform search if the root item is defined!
4414  if (base_ptr != NULL)
4415  {
4416  // If the root item has a matching page number...
4417  if (base_ptr->page_number == page_number)
4418  {
4419  // ...then optionally return it's reference
4420  if (ptr != NULL)
4421  {
4422  *ptr = base_ptr;
4423  }
4424  retval = TRUE;
4425  }
4426  else
4427  {
4428  magazine_number = GetMagazineIndexFromPageNumber(page_number);
4429 
4430  // We must now traverse the page's editorial link data looking for child page references.
4431  sub_page_ptr = base_ptr->sub_page_list;
4432  // For each sub-page...
4433  while (sub_page_ptr != NULL)
4434  {
4435  // ...if there are any editorial links...
4436  if (sub_page_ptr->is_parsed == TRUE)
4437  {
4438  // ... then for each link...
4439  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4440  {
4441  // ... find the page item with the matching page number in the entire request tree.
4442  // At this point, the link's sub-code is irrelevant.
4443  // NB - this is a recursive call to this fuction!
4444  if (GetEditorialLink((S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
4445  &found_ptr, page_number) == TRUE)
4446  {
4447  // If we have found a page item with a matching page number then optionally
4448  // return it's reference
4449  if (ptr != NULL)
4450  {
4451  *ptr = found_ptr;
4452  }
4453 
4454  // Change return value to denote a succesful search.
4455  retval = TRUE;
4456  break;
4457  }
4458 
4459  if (ptr != NULL)
4460  {
4461  // If no match was found in the tree below, then if any of the page links
4462  // explicitly reference this page number, then a new editorial cache request
4463  // entity will be added to the request tree.
4464  if ((sub_page_ptr->link_page_number[link_index] == page_number) &&
4465  (sub_page_ptr->link[link_index] == NULL))
4466  {
4467  if (base_ptr->tier <= GetMaximumEditorialLinkTiers())
4468  {
4469  *ptr = (S_EDITORIAL_LINK_CACHE_REQUEST *)GetMemory(
4471  while (*ptr == NULL)
4472  {
4473  if (RemoveUnrequestedCacheContent(magazine_number, FALSE) == FALSE)
4474  {
4475  break;
4476  }
4477 
4478  *ptr = (S_EDITORIAL_LINK_CACHE_REQUEST *)GetMemory(
4480  }
4481 
4482  if (*ptr != NULL)
4483  {
4484  (*ptr)->page_number = sub_page_ptr->link_page_number[link_index];
4485  (*ptr)->tier = base_ptr->tier + 1;
4486 
4487  (*ptr)->sub_page_list = NULL;
4488 
4489  sub_page_ptr->link[link_index] = (void *)*ptr;
4490 
4491  retval = TRUE;
4492  break;
4493  }
4494  }
4495  }
4496  }
4497  }
4498 
4499  // If match found, then stop looking at other links of this sub-page.
4500  if (retval == TRUE)
4501  {
4502  break;
4503  }
4504  }
4505 
4506  // If we are here then no page item exists in the item tree which matches the requuied
4507  // page number, so we must procees with checks of editorial links of other sub-pages.
4508  sub_page_ptr = sub_page_ptr->next_ptr;
4509  }
4510  }
4511  }
4512 
4513  FUNCTION_FINISH(GetEditorialLink);
4514 
4515  return(retval);
4516 }
4517 
4537 static BOOLEAN RemoveEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST **base_ptr,
4539 {
4540  U16BIT link_index;
4541  BOOLEAN retval;
4543 
4544  FUNCTION_START(RemoveEditorialLinkPageRequest);
4545 
4546  retval = FALSE;
4547 
4548  // Only perform search if the root item is defined!
4549  if (*base_ptr != NULL)
4550  {
4551  // If the root item is the matching page item...
4552  if (*base_ptr == ptr)
4553  {
4554  // Then simply remove it from the tree by resetting the item tree.
4555  *base_ptr = NULL;
4556  retval = TRUE;
4557  }
4558  else
4559  {
4560  // We must now traverse the page's editorial link data looking for child page references.
4561  sub_page_ptr = (*base_ptr)->sub_page_list;
4562  // For each sub-page...
4563  while (sub_page_ptr != NULL)
4564  {
4565  // ...if there are any editorial links...
4566  if (sub_page_ptr->is_parsed == TRUE)
4567  {
4568  // ... then for each link...
4569  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4570  {
4571  // ... that is defined...
4572  if (sub_page_ptr->link[link_index] != NULL)
4573  {
4574  // ... find the supplied page item in the entire request tree.
4575  // At this point, the link's sub-code is irrelevant.
4576  // NB - this is a recursive call to this fuction!
4577  if (RemoveEditorialLinkPageRequest(
4578  (S_EDITORIAL_LINK_CACHE_REQUEST **)&sub_page_ptr->link[link_index],
4579  ptr) == TRUE)
4580  {
4581  // Change return value to denote a succesful search and removal.
4582  retval = TRUE;
4583  break;
4584  }
4585  }
4586  }
4587 
4588  // If match found, then stop looking at other links of this sub-page.
4589  if (retval == TRUE)
4590  {
4591  break;
4592  }
4593  }
4594 
4595  // If we are here then no page item exists in the item tree which matches the requuied
4596  // page item, so we must procees with checks of editorial links of other sub-pages.
4597  sub_page_ptr = sub_page_ptr->next_ptr;
4598  }
4599  }
4600  }
4601 
4602  FUNCTION_FINISH(RemoveEditorialLinkPageRequest);
4603 
4604  return(retval);
4605 }
4606 
4627 static BOOLEAN GetSubPageEditorialLinks(S_CACHE_SUBPAGE *sub_page_ptr,
4628  U16BIT *page_number_link_array,
4629  U16BIT *page_sub_code_link_array,
4630  U16BIT max_num_links, U16BIT magazine_number)
4631 {
4632  U16BIT link_index;
4633  BOOLEAN retval;
4634  S_PAGE_REFERENCE_DATA page_reference_data;
4635  U8BIT *link_ptr;
4636 
4637  FUNCTION_START(GetSubPageEditorialLinks);
4638 
4639  retval = FALSE;
4640 
4641  // Check of collated teletext data of the sub-page actually contains editorial link content.
4642  if (sub_page_ptr->collated_data.is_editorial_page_linking_data_defined == TRUE)
4643  {
4644  // Sets the link data block pointer up to just after the designation codee byte.
4645  link_ptr = &sub_page_ptr->collated_data.editorial_page_linking_data[1];
4646 
4647  // For each editorial page link required in the arrays...
4648  for (link_index = 0; link_index < max_num_links; link_index++)
4649  {
4650  // ...if we can decode the link data block...
4651  if (GetPageReference(link_ptr, &page_reference_data, PAGE_REFERENCE_TYPE_EDITORIAL_LINK,
4652  magazine_number) == TRUE)
4653  {
4654  // ...then populate the array items.
4655  *page_number_link_array = page_reference_data.page_number;
4656  *page_sub_code_link_array = page_reference_data.page_sub_code;
4657 
4658  retval = TRUE;
4659  }
4660  else
4661  {
4662  // ...otherwise mark the array item as undefined.
4663  *page_number_link_array = 0;
4664  *page_sub_code_link_array = 0;
4665  }
4666 
4667  // Advance our array pointers.
4668  page_number_link_array++;
4669  page_sub_code_link_array++;
4670  // Move the link data block pointer to the next editorial link
4671  link_ptr += 6;
4672  }
4673  }
4674 
4675  FUNCTION_FINISH(GetSubPageEditorialLinks);
4676 
4677  return(retval);
4678 }
4679 
4695 static BOOLEAN CreateEditorialLinkPageRequest(S_EDITORIAL_LINK_CACHE_REQUEST **ptr,
4696  U16BIT page_number, U16BIT sub_code)
4697 {
4698  U16BIT magazine_number;
4699  BOOLEAN retval;
4700  BOOLEAN is_found;
4701  S_CACHE_PAGE *page_ptr;
4702  S_CACHE_SUBPAGE *subpage_ptr;
4703  S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *request_sub_page_ptr;
4704 
4705  FUNCTION_START(CreateEditorialLinkPageRequest);
4706 
4707  retval = FALSE;
4708 
4709  magazine_number = GetMagazineIndexFromPageNumber(page_number);
4710 
4712  while (*ptr == NULL)
4713  {
4714  if (RemoveUnrequestedCacheContent(magazine_number, FALSE) == FALSE)
4715  {
4716  break;
4717  }
4718 
4720  }
4721 
4722  if (*ptr != NULL)
4723  {
4724  (*ptr)->page_number = page_number;
4725  (*ptr)->tier = 0;
4726  (*ptr)->sub_page_list = NULL;
4727 
4728  //... and locate mathcing page in cache.
4729  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
4730  page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
4731  while (page_ptr != NULL)
4732  {
4733  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == page_number)
4734  {
4735  subpage_ptr = page_ptr->subpage_ptr;
4736  is_found = FALSE;
4737 
4738  while (subpage_ptr != NULL)
4739  {
4740  if (subpage_ptr->sub_code == sub_code)
4741  {
4742  is_found = TRUE;
4743  }
4744 
4745  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
4747  while (request_sub_page_ptr == NULL)
4748  {
4749  if (RemoveUnrequestedCacheContent(magazine_number, TRUE) == FALSE)
4750  {
4751  break;
4752  }
4753 
4754  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
4756  }
4757 
4758  if (request_sub_page_ptr != NULL)
4759  {
4760  if (GetSubPageEditorialLinks(subpage_ptr, request_sub_page_ptr->link_page_number,
4761  request_sub_page_ptr->link_sub_code,
4762  MAX_EDITORIAL_LINKS, magazine_number) == TRUE)
4763  {
4764  request_sub_page_ptr->sub_code = subpage_ptr->sub_code;
4765  memset(request_sub_page_ptr->link, 0, sizeof(void *) * MAX_EDITORIAL_LINKS);
4766  request_sub_page_ptr->is_parsed = TRUE;
4767  request_sub_page_ptr->next_ptr = (*ptr)->sub_page_list;
4768  (*ptr)->sub_page_list = request_sub_page_ptr;
4769  }
4770  else
4771  {
4772  STB_FreeMemory(request_sub_page_ptr);
4773  }
4774  }
4775 
4776  subpage_ptr = subpage_ptr->next_ptr;
4777  }
4778 
4779  if ((is_found == FALSE) &&
4780  (sub_code != PAGE_SUB_CODE_UNDEFINED))
4781  {
4782  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
4784  while (request_sub_page_ptr == NULL)
4785  {
4786  if (RemoveUnrequestedCacheContent(magazine_number, TRUE) == FALSE)
4787  {
4788  break;
4789  }
4790 
4791  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
4793  }
4794 
4795  if (request_sub_page_ptr != NULL)
4796  {
4797  request_sub_page_ptr->sub_code = sub_code;
4798  request_sub_page_ptr->is_parsed = FALSE;
4799  request_sub_page_ptr->next_ptr = (*ptr)->sub_page_list;
4800  (*ptr)->sub_page_list = request_sub_page_ptr;
4801  }
4802  }
4803 
4804  break;
4805  }
4806 
4807  page_ptr = page_ptr->next_ptr;
4808  }
4809  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
4810 
4811 
4812  retval = TRUE;
4813  }
4814 
4815  FUNCTION_FINISH(CreateEditorialLinkPageRequest);
4816 
4817  return(retval);
4818 }
4819 
4832 static void ReTierEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST *ptr, U16BIT tier)
4833 {
4834  U16BIT link_index;
4836 
4837  FUNCTION_START(ReTierEditorialLinkPageRequests);
4838 
4839  if (ptr != NULL)
4840  {
4841  tier++;
4842  ptr->tier = tier;
4843 
4844  sub_page_ptr = ptr->sub_page_list;
4845  while (sub_page_ptr != NULL)
4846  {
4847  if (sub_page_ptr->is_parsed == TRUE)
4848  {
4849  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4850  {
4851  if (sub_page_ptr->link[link_index] != NULL)
4852  {
4853  ReTierEditorialLinkPageRequests((S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index], tier);
4854  }
4855  }
4856  }
4857 
4858  sub_page_ptr = sub_page_ptr->next_ptr;
4859  }
4860  }
4861 
4862  FUNCTION_FINISH(ReTierEditorialLinkPageRequests);
4863 }
4864 
4878 static void KillEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST **base_ptr)
4879 {
4880  U16BIT link_index;
4882  S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *next_sub_page_ptr;
4883 
4884  FUNCTION_START(KillEditorialLinkPageRequests);
4885 
4886  if (base_ptr != NULL)
4887  {
4888  if (*base_ptr != NULL)
4889  {
4890  sub_page_ptr = (*base_ptr)->sub_page_list;
4891  while (sub_page_ptr != NULL)
4892  {
4893  if (sub_page_ptr->is_parsed == TRUE)
4894  {
4895  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4896  {
4897  KillEditorialLinkPageRequests((S_EDITORIAL_LINK_CACHE_REQUEST **)&sub_page_ptr->link[link_index]);
4898  }
4899  }
4900 
4901  next_sub_page_ptr = sub_page_ptr->next_ptr;
4902 
4903  STB_FreeMemory(sub_page_ptr);
4904 
4905  sub_page_ptr = next_sub_page_ptr;
4906  }
4907 
4908  STB_FreeMemory(*base_ptr);
4909 
4910  *base_ptr = NULL;
4911  }
4912  }
4913 
4914  FUNCTION_FINISH(KillEditorialLinkPageRequests);
4915 }
4916 
4929 static void UpdateEditorialLinkPageRequestRecursive(S_EDITORIAL_LINK_CACHE_REQUEST *ptr,
4930  U16BIT tier)
4931 {
4932  U16BIT link_index;
4934  S_EDITORIAL_LINK_CACHE_REQUEST *other_ptr;
4935  S_EDITORIAL_LINK_CACHE_REQUEST *parent_ptr;
4936 
4937  FUNCTION_START(UpdateEditorialLinkPageRequestRecursive);
4938 
4939  tier++;
4940  ptr->tier = tier;
4941 
4942  RemoveEditorialLinkPageRequest(&editorial_link_request_root, ptr);
4943 
4944  sub_page_ptr = ptr->sub_page_list;
4945  while (sub_page_ptr != NULL)
4946  {
4947  if (sub_page_ptr->is_parsed == TRUE)
4948  {
4949  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
4950  {
4951  if (sub_page_ptr->link[link_index] == NULL)
4952  {
4953  // Attempt to set this link pointer with equivalent editorial link request in
4954  // original list.
4955  // NB - the relevant link pointer will be updated if the editorial link is found.
4956  if (FindEditorialLinkPageRequest(editorial_link_request_root,
4957  (S_EDITORIAL_LINK_CACHE_REQUEST **)&sub_page_ptr->link[link_index],
4958  NULL, sub_page_ptr->link_page_number[link_index]) == TRUE)
4959  {
4960  // As we are inserting an editorial link in the new tree, we will have to adjust
4961  // it's tier value (which also goes for all it's child links)
4962  ReTierEditorialLinkPageRequests(
4963  (S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
4964  tier);
4965 
4966  // If found, then call function recursively.
4967  // NB - The first thing that will happen is the removal of the newly copied link
4968  // from the original list!
4969  UpdateEditorialLinkPageRequestRecursive(
4970  (S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
4971  tier);
4972  }
4973  // Attempt to find the equivalent editorial link request in our new list.
4974  else if (FindEditorialLinkPageRequest(temp_editorial_link_request_root, &other_ptr,
4975  &parent_ptr,
4976  sub_page_ptr->link_page_number[link_index]) == TRUE)
4977  {
4978  // If found then check if it is placed at a higher tier postion.
4979  if (parent_ptr != NULL)
4980  {
4981  if (parent_ptr->tier > tier)
4982  {
4983  // It's at a higher tier position, so move it to this new location, and
4984  // recursively adjust it's child links.
4985  RemoveEditorialLinkPageRequest(&parent_ptr, other_ptr);
4986 
4987  // As we are inserting it in a new postion, we will have to adjust it's tier
4988  // value (which also goes for all it's child links)
4989  ReTierEditorialLinkPageRequests(other_ptr, tier);
4990 
4991  sub_page_ptr->link[link_index] = other_ptr;
4992 
4993  UpdateEditorialLinkPageRequestRecursive(
4994  (S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
4995  tier);
4996  }
4997  }
4998  else
4999  {
5000  sub_page_ptr->link[link_index] = NULL;
5001  }
5002  }
5003  else
5004  {
5005  sub_page_ptr->link[link_index] = NULL;
5006  }
5007  }
5008  else
5009  {
5010  UpdateEditorialLinkPageRequestRecursive(
5011  (S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index],
5012  tier);
5013  }
5014  }
5015  }
5016 
5017  sub_page_ptr = sub_page_ptr->next_ptr;
5018  }
5019 
5020  FUNCTION_FINISH(UpdateEditorialLinkPageRequestRecursive);
5021 }
5022 
5035 static void UpdateEditorialLinkPageRequest(U16BIT page_number, U16BIT sub_code)
5036 {
5038 
5039  FUNCTION_START(UpdateEditorialLinkPageRequest);
5040 
5041  // Attempt to find cache of editorial page links associated witht the supplied page number.
5042  if (FindEditorialLinkPageRequest(editorial_link_request_root, &ptr, NULL, page_number) == TRUE)
5043  {
5044  // If found, and already at root of tree, then nothin needs to be done.
5045  if (ptr == editorial_link_request_root)
5046  {
5047  ptr = NULL;
5048  }
5049  }
5050  else
5051  {
5052  // If not found, then create new request record for this page number
5053  if (CreateEditorialLinkPageRequest(&ptr, page_number, sub_code) == FALSE)
5054  {
5055  ptr = NULL;
5056  }
5057  }
5058 
5059  // If we have a non-root cache request for the supplied page number...
5060  if (ptr != NULL)
5061  {
5062  // Then set as the root of our temporary request tree
5063  temp_editorial_link_request_root = ptr;
5064 
5065  // and recursivley populate this temporary tree with items from the first that
5066  // are required.
5067  UpdateEditorialLinkPageRequestRecursive(ptr, 0);
5068 
5069  // Now kill remianing items in original tree
5070  KillEditorialLinkPageRequests(&editorial_link_request_root);
5071 
5072  // And replace the original tree with the newly collated temporary tree
5073  editorial_link_request_root = temp_editorial_link_request_root;
5074  temp_editorial_link_request_root = NULL;
5075  }
5076 
5077  FUNCTION_FINISH(UpdateEditorialLinkPageRequest);
5078 }
5079 
5080 static void SetPageFlag( U16BIT page_num, U16BIT flag )
5081 {
5082  S_CACHE_PAGE *page_ptr;
5083  S_MAGAZINE_INFO *mgzn_ptr;
5084 
5085  mgzn_ptr = magazine_array + GetMagazineIndexFromPageNumber(page_num);
5086  STB_OSMutexLock( mgzn_ptr->m_mutex );
5087  page_ptr = mgzn_ptr->m_cache_page_ptr;
5088  while (page_ptr != NULL)
5089  {
5090  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == page_num)
5091  {
5092  page_ptr->page_number |= flag;
5093  break;
5094  }
5095  page_ptr = page_ptr->next_ptr;
5096  }
5097  STB_OSMutexUnlock( mgzn_ptr->m_mutex );
5098 }
5099 
5100 static void UnsetPageFlag( U16BIT page_num, U16BIT flag )
5101 {
5102  S_CACHE_PAGE *page_ptr;
5103  S_MAGAZINE_INFO *mgzn_ptr;
5104 
5105  mgzn_ptr = magazine_array + GetMagazineIndexFromPageNumber(page_num);
5106  STB_OSMutexLock( mgzn_ptr->m_mutex );
5107  page_ptr = mgzn_ptr->m_cache_page_ptr;
5108  while (page_ptr != NULL)
5109  {
5110  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == page_num)
5111  {
5112  page_ptr->page_number &= ~flag;
5113  break;
5114  }
5115  page_ptr = page_ptr->next_ptr;
5116  }
5117  STB_OSMutexUnlock( mgzn_ptr->m_mutex );
5118 }
5119 
5131 static void FlagEditorialLinkPageRequests(S_EDITORIAL_LINK_CACHE_REQUEST *ptr)
5132 {
5133  U16BIT link_index;
5135 
5136  FUNCTION_START(FlagEditorialLinkPageRequests);
5137 
5138  if (ptr != NULL)
5139  {
5140  SetPageFlag( ptr->page_number, CACHE_PAGE_FLOF_REQUESTED );
5141 
5142  sub_page_ptr = ptr->sub_page_list;
5143  while (sub_page_ptr != NULL)
5144  {
5145  if (sub_page_ptr->is_parsed == TRUE)
5146  {
5147  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
5148  {
5149  FlagEditorialLinkPageRequests((S_EDITORIAL_LINK_CACHE_REQUEST *)sub_page_ptr->link[link_index]);
5150  }
5151  }
5152 
5153  sub_page_ptr = sub_page_ptr->next_ptr;
5154  }
5155  }
5156 
5157  FUNCTION_FINISH(FlagEditorialLinkPageRequests);
5158 }
5159 
5172 static void DeterminePageEditorialLinks(S_EDITORIAL_LINK_CACHE_REQUEST *ptr,
5173  S_CACHE_SUBPAGE *subpage_ptr)
5174 {
5175  U16BIT magazine_number, link_index;
5176  BOOLEAN is_found;
5177  S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *request_sub_page_ptr;
5178  S_CACHE_PAGE *page_ptr;
5180 
5181  FUNCTION_START(DeterminePageEditorialLinks);
5182 
5183  if ((ptr != NULL) &&
5184  (ptr->tier <= GetMaximumEditorialLinkTiers()))
5185  {
5186  request_sub_page_ptr = ptr->sub_page_list;
5187  while (request_sub_page_ptr != NULL)
5188  {
5189  if (request_sub_page_ptr->sub_code == subpage_ptr->sub_code)
5190  {
5191  break;
5192  }
5193  request_sub_page_ptr = request_sub_page_ptr->next_ptr;
5194  }
5195 
5196  magazine_number = GetMagazineIndexFromPageNumber(ptr->page_number);
5197 
5198  if (request_sub_page_ptr == NULL)
5199  {
5200  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
5202  while (request_sub_page_ptr == NULL)
5203  {
5204  if (RemoveUnrequestedCacheContent(magazine_number, FALSE) == FALSE)
5205  {
5206  break;
5207  }
5208 
5209  request_sub_page_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST_SUB_PAGE *)GetMemory(
5211  }
5212 
5213  if (request_sub_page_ptr != NULL)
5214  {
5215  request_sub_page_ptr->sub_code = subpage_ptr->sub_code;
5216  request_sub_page_ptr->is_parsed = FALSE;
5217  request_sub_page_ptr->next_ptr = ptr->sub_page_list;
5218  ptr->sub_page_list = request_sub_page_ptr;
5219  }
5220  }
5221 
5222  if (request_sub_page_ptr != NULL)
5223  {
5224  if (request_sub_page_ptr->is_parsed == FALSE)
5225  {
5226  if (GetSubPageEditorialLinks(subpage_ptr, request_sub_page_ptr->link_page_number,
5227  request_sub_page_ptr->link_sub_code, MAX_EDITORIAL_LINKS,
5228  magazine_number) == TRUE)
5229  {
5230  memset(request_sub_page_ptr->link, 0, sizeof(void *) * MAX_EDITORIAL_LINKS);
5231  request_sub_page_ptr->is_parsed = TRUE;
5232 
5233  for (link_index = 0; link_index < MAX_EDITORIAL_LINKS; link_index++)
5234  {
5235  if (request_sub_page_ptr->link_page_number[link_index] != 0)
5236  {
5237  // Find page in cache
5238 
5239  is_found = FALSE;
5240 
5241  // ...determine the relevant magazine
5242  magazine_number = GetMagazineIndexFromPageNumber(request_sub_page_ptr->link_page_number[link_index]);
5243 
5244  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
5245  //... and locate mathcing page in cache.
5246  page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
5247  while (page_ptr != NULL)
5248  {
5249  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) ==
5250  request_sub_page_ptr->link_page_number[link_index])
5251  {
5252  subpage_ptr = page_ptr->subpage_ptr;
5253 
5254  while (subpage_ptr != NULL)
5255  {
5256  if ((subpage_ptr->sub_code == request_sub_page_ptr->link_sub_code[link_index]) ||
5257  (request_sub_page_ptr->link_sub_code[link_index] == PAGE_SUB_CODE_UNDEFINED))
5258  {
5259  is_found = TRUE;
5260  break;
5261  }
5262 
5263  subpage_ptr = subpage_ptr->next_ptr;
5264  }
5265 
5266  if (is_found == TRUE)
5267  {
5268  break;
5269  }
5270  }
5271 
5272  page_ptr = page_ptr->next_ptr;
5273  }
5274  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
5275 
5276  if (is_found == TRUE)
5277  {
5278  if (FindEditorialLinkPageRequest(editorial_link_request_root, NULL, NULL,
5279  request_sub_page_ptr->link_page_number[link_index]) == FALSE)
5280  {
5281  // No page request in editorial link tree
5282  new_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST *)GetMemory(
5284  while (new_ptr == NULL)
5285  {
5286  if (RemoveUnrequestedCacheContent(magazine_number, FALSE) == FALSE)
5287  {
5288  break;
5289  }
5290 
5291  new_ptr = (S_EDITORIAL_LINK_CACHE_REQUEST *)GetMemory(
5293  }
5294 
5295  if (new_ptr != NULL)
5296  {
5297  new_ptr->page_number =
5298  request_sub_page_ptr->link_page_number[link_index];
5299  new_ptr->tier = ptr->tier + 1;
5300 
5301  new_ptr->sub_page_list = NULL;
5302 
5303  request_sub_page_ptr->link[link_index] = (void *)new_ptr;
5304 
5305  DeterminePageEditorialLinks(new_ptr, subpage_ptr);
5306  }
5307  }
5308  }
5309  }
5310  }
5311  }
5312  }
5313  }
5314  }
5315 
5316  FUNCTION_FINISH(DeterminePageEditorialLinks);
5317 }
5318 
5333 static BOOLEAN SearchRequestArray(U16BIT *array_ptr, U16BIT array_size, BOOLEAN find_highest,
5334  U16BIT **return_array_ptr)
5335 {
5336  U16BIT index, found_page_number;
5337  BOOLEAN retval;
5338 
5339  FUNCTION_START(SearchRequestArray);
5340 
5341  retval = FALSE;
5342 
5343  if (find_highest)
5344  {
5345  found_page_number = 0;
5346  }
5347  else
5348  {
5349  found_page_number = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
5350  }
5351 
5352  for (index = 0; index < array_size; index++)
5353  {
5354  if (find_highest)
5355  {
5356  if (array_ptr[index] > found_page_number)
5357  {
5358  found_page_number = array_ptr[index];
5359  *return_array_ptr = &array_ptr[index];
5360  retval = TRUE;
5361  }
5362  }
5363  else
5364  {
5365  if (array_ptr[index] < found_page_number)
5366  {
5367  found_page_number = array_ptr[index];
5368  *return_array_ptr = &array_ptr[index];
5369  retval = TRUE;
5370  }
5371  }
5372  }
5373 
5374  if (retval == FALSE)
5375  {
5376  *return_array_ptr = &array_ptr[0];
5377  }
5378 
5379  FUNCTION_FINISH(SearchRequestArray);
5380 
5381  return(retval);
5382 }
5383 
5396 static BOOLEAN SearchPreviousRequestArray(BOOLEAN find_highest, U16BIT **return_array_ptr)
5397 {
5398  BOOLEAN retval;
5399 
5400  FUNCTION_START(SearchPreviousRequestArray);
5401 
5402  retval = SearchRequestArray(previous_cache_request_array, NUM_PREVIOUS_CACHE_REQUESTS, find_highest, return_array_ptr);
5403 
5404  FUNCTION_FINISH(SearchPreviousRequestArray);
5405 
5406  return(retval);
5407 }
5408 
5421 static BOOLEAN SearchNextRequestArray(BOOLEAN find_highest, U16BIT **return_array_ptr)
5422 {
5423  U16BIT index;
5424  BOOLEAN retval;
5425 
5426  FUNCTION_START(SearchNextRequestArray);
5427 
5428  if (next_cache_request_array[0] == 0)
5429  {
5430  for (index = 0; index < NUM_NEXT_CACHE_REQUESTS; index++)
5431  {
5432  next_cache_request_array[index] = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
5433  }
5434  }
5435 
5436  retval = SearchRequestArray(next_cache_request_array, NUM_NEXT_CACHE_REQUESTS, find_highest,
5437  return_array_ptr);
5438 
5439  FUNCTION_FINISH(SearchNextRequestArray);
5440 
5441  return(retval);
5442 }
5443 
5455 static BOOLEAN IsInPreviousRequestArray(U16BIT page_number)
5456 {
5457  U16BIT index;
5458  BOOLEAN retval;
5459 
5460  FUNCTION_START(IsInPreviousRequestArray);
5461 
5462  retval = FALSE;
5463 
5464  for (index = 0; index < NUM_PREVIOUS_CACHE_REQUESTS; index++)
5465  {
5466  if (previous_cache_request_array[index] == page_number)
5467  {
5468  retval = TRUE;
5469  break;
5470  }
5471  }
5472 
5473  FUNCTION_FINISH(IsInPreviousRequestArray);
5474 
5475  return(retval);
5476 }
5477 
5489 static BOOLEAN IsInNextRequestArray(U16BIT page_number)
5490 {
5491  U16BIT index;
5492  BOOLEAN retval;
5493 
5494  FUNCTION_START(IsInNextRequestArray);
5495 
5496  retval = FALSE;
5497 
5498  if (next_cache_request_array[0] == 0)
5499  {
5500  for (index = 0; index < NUM_NEXT_CACHE_REQUESTS; index++)
5501  {
5502  next_cache_request_array[index] = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
5503  }
5504  }
5505 
5506  for (index = 0; index < NUM_NEXT_CACHE_REQUESTS; index++)
5507  {
5508  if (next_cache_request_array[index] == page_number)
5509  {
5510  retval = TRUE;
5511  break;
5512  }
5513  }
5514 
5515  FUNCTION_FINISH(IsInNextRequestArray);
5516 
5517  return(retval);
5518 }
5519 
5532 static BOOLEAN GetGlobalIndexPage(U16BIT *page_number, U16BIT *page_sub_code)
5533 {
5534  BOOLEAN retval;
5535  S_PAGE_REFERENCE_DATA page_reference_data;
5536 
5537  FUNCTION_START(GetGlobalIndexPage);
5538 
5539  retval = FALSE;
5540 
5541  if (is_broadcast_service_data_defined[0] == TRUE)
5542  {
5543  if (GetPageReference(&broadcast_service_data[0][1], &page_reference_data,
5544  PAGE_REFERENCE_TYPE_GLOBAL_INDEX, 0) == TRUE)
5545  {
5546  retval = TRUE;
5547  }
5548  }
5549 
5550  if (retval == FALSE)
5551  {
5552  if (is_broadcast_service_data_defined[1] == TRUE)
5553  {
5554  if (GetPageReference(&broadcast_service_data[1][1], &page_reference_data,
5555  PAGE_REFERENCE_TYPE_GLOBAL_INDEX, 0) == TRUE)
5556  {
5557  retval = TRUE;
5558  }
5559  }
5560  }
5561 
5562  if (retval == TRUE)
5563  {
5564  *page_number = page_reference_data.page_number;
5565  *page_sub_code = page_reference_data.page_sub_code;
5566  }
5567 
5568  FUNCTION_FINISH(GetGlobalIndexPage);
5569 
5570  return(retval);
5571 }
5572 
5585 static BOOLEAN GetIndexPage(U16BIT *page_number, U16BIT *page_sub_code)
5586 {
5587  U16BIT magazine_number;
5588  BOOLEAN retval;
5589  S_PAGE_REFERENCE_DATA page_reference_data;
5590 
5591  FUNCTION_START(GetIndexPage);
5592 
5593  retval = FALSE;
5594 
5595  // Check to see if there is a sixth editorial link defined within the currently displayed page.
5596  // This will be in the X/27/0 packet.
5597  if (page_display_info.page_number)
5598  {
5599  if (page_display_info.page_source.is_editorial_page_linking_data_defined == TRUE)
5600  {
5601  magazine_number = GetMagazineIndexFromPageNumber(page_display_info.page_number);
5602 
5603  if (GetPageReference(&page_display_info.page_source.editorial_page_linking_data[31],
5604  &page_reference_data,
5605  PAGE_REFERENCE_TYPE_EDITORIAL_LINK, magazine_number) == TRUE)
5606  {
5607  *page_number = page_reference_data.page_number;
5608  *page_sub_code = page_reference_data.page_sub_code;
5609 
5610  retval = TRUE;
5611  }
5612  }
5613  }
5614 
5615  if (retval == FALSE)
5616  {
5617  retval = GetGlobalIndexPage(page_number, page_sub_code);
5618  }
5619 
5620  FUNCTION_FINISH(GetIndexPage);
5621 
5622  return(retval);
5623 }
5624 
5637 static BOOLEAN GetAvailablePage(U16BIT *page_number, S16BIT page_increment)
5638 {
5639  U8BIT flag;
5640  U16BIT page_tens, page_units, magazine_number, num_page_tests, page_offset;
5641  BOOLEAN retval;
5642 
5643  FUNCTION_START(GetAvailablePage);
5644 
5645  retval = FALSE;
5646 
5647  if (page_number != NULL)
5648  {
5649  magazine_number = GetMagazineIndexFromPageNumber(*page_number);
5650 
5651  page_tens = (*page_number & 0x00f0) >> 4;
5652  page_units = *page_number & 0x000f;
5653 
5654  num_page_tests = 0;
5655 
5656  while ((page_increment != 0) &&
5657  (num_page_tests < 800))
5658  {
5659  if (page_increment > 0)
5660  {
5661  if (page_units == 9)
5662  {
5663  page_units = 0;
5664 
5665  if (page_tens == 9)
5666  {
5667  page_tens = 0;
5668 
5669  if (magazine_number == 7)
5670  {
5671  magazine_number = 0;
5672  }
5673  else
5674  {
5675  magazine_number++;
5676  }
5677  }
5678  else
5679  {
5680  page_tens++;
5681  }
5682  }
5683  else
5684  {
5685  page_units++;
5686  }
5687  }
5688  else
5689  {
5690  if (page_units == 0)
5691  {
5692  page_units = 9;
5693 
5694  if (page_tens == 0)
5695  {
5696  page_tens = 9;
5697 
5698  if (magazine_number == 0)
5699  {
5700  magazine_number = 7;
5701  }
5702  else
5703  {
5704  magazine_number--;
5705  }
5706  }
5707  else
5708  {
5709  page_tens--;
5710  }
5711  }
5712  else
5713  {
5714  page_units--;
5715  }
5716  }
5717 
5718  page_offset = (page_tens << 4) + page_units;
5719 
5720  flag = magazine_array[magazine_number].m_cache_valid_page_array[page_offset >> 3] & 1 <<
5721  (page_offset & 0x07);
5722 
5723  if (flag)
5724  {
5725  if (page_increment > 0)
5726  {
5727  page_increment--;
5728  }
5729  else
5730  {
5731  page_increment++;
5732  }
5733 
5734  if (page_increment == 0)
5735  {
5736  if (magazine_number == 0)
5737  {
5738  *page_number = 0x800 + page_offset;
5739  }
5740  else
5741  {
5742  *page_number = (magazine_number << 8) + page_offset;
5743  }
5744 
5745  retval = TRUE;
5746  break;
5747  }
5748  }
5749 
5750  num_page_tests++;
5751  }
5752  }
5753 
5754  FUNCTION_FINISH(GetAvailablePage);
5755 
5756  return(retval);
5757 }
5758 
5772 static BOOLEAN GetVisitedPage(U16BIT *page_number, U16BIT *page_sub_code, S16BIT page_increment)
5773 {
5774  BOOLEAN retval;
5775 
5776  FUNCTION_START(GetVisitedPage);
5777 
5778  USE_UNWANTED_PARAM(page_sub_code);
5779 
5780  retval = FALSE;
5781 
5782  while (page_increment != 0)
5783  {
5784  if (page_increment > 0)
5785  {
5786  if (GetNextPageFromHistory(page_number) == FALSE)
5787  {
5788  break;
5789  }
5790  page_increment--;
5791  }
5792  else
5793  {
5794  if (GetPreviousPageFromHistory(page_number) == FALSE)
5795  {
5796  break;
5797  }
5798  page_increment++;
5799  }
5800 
5801  retval = TRUE;
5802  }
5803 
5804  FUNCTION_FINISH(GetVisitedPage);
5805 
5806  return(retval);
5807 }
5808 
5822 static BOOLEAN GetEditorialLinkPage(U16BIT *page_number, U16BIT *page_sub_code, U16BIT link_index)
5823 {
5824  U16BIT magazine_number;
5825  BOOLEAN retval;
5826  S_PAGE_REFERENCE_DATA page_reference_data;
5827  U8BIT *link_ptr;
5828 
5829  FUNCTION_START(GetEditorialLinkPage);
5830 
5831  retval = FALSE;
5832 
5833  // Check of collated teletext data of the sub-page actually contains editorial link content.
5834  if (page_display_info.page_source.is_editorial_page_linking_data_defined == TRUE)
5835  {
5836  // Sets the link data block pointer up to just after the designation codee byte.
5837  link_ptr = &page_display_info.page_source.editorial_page_linking_data[1];
5838 
5839  link_ptr += link_index * 6;
5840 
5841  magazine_number = GetMagazineIndexFromPageNumber(page_display_info.page_number);
5842 
5843  // ...if we can decode the link data block...
5844  if (GetPageReference(link_ptr, &page_reference_data, PAGE_REFERENCE_TYPE_EDITORIAL_LINK,
5845  magazine_number) == TRUE)
5846  {
5847  // ...then populate the array items.
5848  *page_number = page_reference_data.page_number;
5849  *page_sub_code = page_reference_data.page_sub_code;
5850 
5851  retval = TRUE;
5852  }
5853  }
5854 
5855  FUNCTION_FINISH(GetEditorialLinkPage);
5856 
5857  return(retval);
5858 }
5859 
5874 static BOOLEAN GetSubPage(U16BIT *new_page_sub_code, U16BIT current_page_number,
5875  U16BIT current_page_sub_code, S16BIT page_increment)
5876 {
5877  BOOLEAN retval;
5878  U16BIT magazine_number, num_sub_pages, ref_index1, ref_index2;
5879  S_CACHE_PAGE *page_ptr;
5880  S_CACHE_SUBPAGE *subpage_ptr;
5881  S_CACHE_SUBPAGE *temp_sub_page_ref;
5882  S_CACHE_SUBPAGE **sub_page_ref_array;
5883 
5884  FUNCTION_START(GetSubPage);
5885 
5886  retval = FALSE;
5887 
5888  if (IsRollingSubCode(current_page_sub_code) == TRUE)
5889  {
5890  magazine_number = GetMagazineIndexFromPageNumber(current_page_number);
5891 
5892  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
5893 
5894  page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
5895 
5896  while (page_ptr != NULL)
5897  {
5898  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == current_page_number)
5899  {
5900  num_sub_pages = 0;
5901  subpage_ptr = page_ptr->subpage_ptr;
5902  while (subpage_ptr != NULL)
5903  {
5904  if (IsRollingSubCode(subpage_ptr->sub_code) == TRUE)
5905  {
5906  num_sub_pages++;
5907  }
5908  subpage_ptr = subpage_ptr->next_ptr;
5909  }
5910 
5911  if (num_sub_pages < 2)
5912  {
5913  break;
5914  }
5915 
5916  sub_page_ref_array = (S_CACHE_SUBPAGE **)GetMemory(num_sub_pages *
5917  sizeof(S_CACHE_SUBPAGE *));
5918  if (sub_page_ref_array == NULL)
5919  {
5920  break;
5921  }
5922 
5923  ref_index1 = 0;
5924  subpage_ptr = page_ptr->subpage_ptr;
5925  while (subpage_ptr != NULL)
5926  {
5927  if (IsRollingSubCode(subpage_ptr->sub_code) == TRUE)
5928  {
5929  sub_page_ref_array[ref_index1] = subpage_ptr;
5930  ref_index1++;
5931  }
5932  subpage_ptr = subpage_ptr->next_ptr;
5933  }
5934 
5935  for (ref_index1 = 0; ref_index1 < (num_sub_pages - 1); ref_index1++)
5936  {
5937  for (ref_index2 = ref_index1 + 1; ref_index2 < num_sub_pages; ref_index2++)
5938  {
5939  if (sub_page_ref_array[ref_index1]->sub_code >
5940  sub_page_ref_array[ref_index2]->sub_code)
5941  {
5942  temp_sub_page_ref = sub_page_ref_array[ref_index1];
5943  sub_page_ref_array[ref_index1] = sub_page_ref_array[ref_index2];
5944  sub_page_ref_array[ref_index2] = temp_sub_page_ref;
5945  }
5946  }
5947  }
5948 
5949  for (ref_index1 = 0; ref_index1 < num_sub_pages; ref_index1++)
5950  {
5951  if (sub_page_ref_array[ref_index1]->sub_code == current_page_sub_code)
5952  {
5953  if (page_increment > 0)
5954  {
5955  ref_index1 += (U16BIT)page_increment;
5956  }
5957  else
5958  {
5959  ref_index1 += num_sub_pages - ((U16BIT)-page_increment % num_sub_pages);
5960  }
5961 
5962  ref_index1 %= num_sub_pages;
5963 
5964  *new_page_sub_code = sub_page_ref_array[ref_index1]->sub_code;
5965  retval = TRUE;
5966  break;
5967  }
5968  }
5969 
5970  STB_FreeMemory(sub_page_ref_array);
5971 
5972  // If we have been anable to allocate memory for a temporary ordered buffer, then this
5973  // contingency code is used to return an unsorted sub-code reference.
5974  if (retval == FALSE)
5975  {
5976  // Firstly, find current sub-code reference in the page's link-list.
5977  subpage_ptr = page_ptr->subpage_ptr;
5978  while (subpage_ptr != NULL)
5979  {
5980  if (subpage_ptr->sub_code == current_page_sub_code)
5981  {
5982  break;
5983  }
5984  subpage_ptr = subpage_ptr->next_ptr;
5985  }
5986 
5987  if (subpage_ptr != NULL)
5988  {
5989  // If found, then look for next compatible sub-code.
5990  subpage_ptr = subpage_ptr->next_ptr;
5991 
5992  while (subpage_ptr != NULL)
5993  {
5994  if (IsRollingSubCode(subpage_ptr->sub_code) == TRUE)
5995  {
5996  *new_page_sub_code = subpage_ptr->sub_code;
5997  retval = TRUE;
5998  break;
5999  }
6000  subpage_ptr = subpage_ptr->next_ptr;
6001  }
6002 
6003  if (subpage_ptr == NULL)
6004  {
6005  // If not found, then we have reached the end of the link-list, so continue
6006  // search from start.
6007  subpage_ptr = page_ptr->subpage_ptr;
6008 
6009  while (subpage_ptr != NULL)
6010  {
6011  if (subpage_ptr->sub_code == current_page_sub_code)
6012  {
6013  // We have done a full traversal of the link-list, so quit.
6014  break;
6015  }
6016 
6017  if (IsRollingSubCode(subpage_ptr->sub_code) == TRUE)
6018  {
6019  *new_page_sub_code = subpage_ptr->sub_code;
6020  retval = TRUE;
6021  break;
6022  }
6023  subpage_ptr = subpage_ptr->next_ptr;
6024  }
6025  }
6026  }
6027  }
6028 
6029  break;
6030  }
6031 
6032  page_ptr = page_ptr->next_ptr;
6033  }
6034  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
6035  }
6036 
6037  FUNCTION_FINISH(GetSubPage);
6038 
6039  return(retval);
6040 }
6041 
6053 static void DriverReset(void)
6054 {
6055  U16BIT magazine_number;
6056  S_CACHE_PAGE *page_ptr;
6057  S_CACHE_PAGE *next_page_ptr;
6058  S_CACHE_SUBPAGE *subpage_ptr;
6059  S_CACHE_SUBPAGE *next_subpage_ptr;
6060 
6061  FUNCTION_START(DriverReset);
6062 
6063  DBGPRINT(" ****** CLEARING DATA ****** ");
6064 
6065  for (magazine_number = 0; magazine_number != 8; magazine_number++)
6066  {
6067  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
6068 
6069  page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
6070 
6071  while (page_ptr != NULL)
6072  {
6073  subpage_ptr = page_ptr->subpage_ptr;
6074  while (subpage_ptr != NULL)
6075  {
6076  next_subpage_ptr = subpage_ptr->next_ptr;
6077 
6078  STB_FreeMemory(subpage_ptr);
6079 
6080  subpage_ptr = next_subpage_ptr;
6081  }
6082 
6083  next_page_ptr = page_ptr->next_ptr;
6084 
6085  STB_FreeMemory(page_ptr);
6086 
6087  page_ptr = next_page_ptr;
6088  }
6089 
6090  memset(magazine_array[magazine_number].m_cache_valid_page_array, 0, 32);
6091 
6092  magazine_array[magazine_number].m_cache_page_ptr = NULL;
6093 
6094  magazine_array[magazine_number].m_specific_data.is_defined[0] = FALSE;
6095  magazine_array[magazine_number].m_specific_data.is_defined[1] = FALSE;
6096 
6097  memset( &magazine_array[magazine_number].m_page, 0x00, sizeof(S_MAGAZINE_PAGE));
6098 
6099  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
6100  }
6101 
6102  is_broadcast_service_data_defined[0] = FALSE;
6103  is_broadcast_service_data_defined[1] = FALSE;
6104 
6105  page_history_lwm = 0;
6106  page_history_hwm = 0;
6107  page_history_mwm = 0;
6108  page_history_request_page_number = 0xffff;
6109 
6110  history_cache_reset_requested = TRUE;
6111  editorial_link_cache_reset_requested = TRUE;
6112 
6113  page_control_info.state = PAGE_CONTROL_STATE_IDLE;
6114  page_control_info.reveal_required = FALSE;
6115 
6116  page_control_info.clear_required = FALSE;
6117 
6118  page_display_info.page_number = 0;
6119  page_display_info.page_sub_code = 0;
6120  page_display_info.subtitle = FALSE;
6121  page_display_info.pts_valid = FALSE;
6122  page_display_info.time_offset = 0;
6123 
6124  /* Reset the character map and page source header otherwise the index row (0) from a previous channel may be displayed */
6125  memset( page_display_info.character_map, 0x00, sizeof(page_display_info.character_map));
6126  memset( &page_display_info.page_source, 0x00, sizeof(S_MAGAZINE_PAGE));
6127 
6128  /* display copy is also cleared to prevent obsolete data being displayed */
6129  page_display_copy.page_number = 0;
6130  page_display_copy.page_sub_code = 0;
6131  page_display_copy.subtitle = FALSE;
6132  page_display_copy.pts_valid = FALSE;
6133  page_display_copy.time_offset = 0;
6134 
6135  memset( page_display_copy.character_map, 0x00, sizeof(page_display_copy.character_map));
6136  memset( &page_display_copy.page_source, 0x00, sizeof(S_MAGAZINE_PAGE));
6137 
6138  subtitle_timeout = 0;
6139 
6140  FUNCTION_FINISH(DriverReset);
6141 }
6142 
6154 static void CheckPageRequest(BOOLEAN pts_valid, U8BIT *pts)
6155 {
6156  S_CACHE_PAGE *page_ptr;
6157  S_CACHE_SUBPAGE *subpage_ptr;
6158  S_HISTORY_CACHE_REQUEST *history_ptr;
6159  S_HISTORY_CACHE_REQUEST *prev_history_ptr;
6160  U16BIT magazine_index, page_number, page_sub_code, item_count;
6161  BOOLEAN update_cache_requests;
6162  U8BIT index;
6163 
6164  FUNCTION_START(CheckPageRequest);
6165 
6166  update_cache_requests = FALSE;
6167 
6168  STB_OSSemaphoreWait(page_request_info.semaphore);
6169 
6170  if (page_request_info.pending == TRUE)
6171  {
6172  page_request_info.pending = FALSE;
6173 
6174  switch (page_request_info.type)
6175  {
6176  case REQUEST_TYPE_EXPLICIT:
6177  {
6178  page_request_info.target_page_number = page_request_info.page_number;
6179  page_request_info.target_page_sub_code = page_request_info.page_sub_code;
6180  update_cache_requests = TRUE;
6181 
6182  NotifyRequestToPageHistory(page_request_info.target_page_number);
6183  break;
6184  }
6185  case REQUEST_TYPE_INDEX:
6186  {
6187  if (GetIndexPage(&page_request_info.target_page_number,
6188  &page_request_info.target_page_sub_code) == TRUE)
6189  {
6190  update_cache_requests = TRUE;
6191 
6192  NotifyRequestToPageHistory(page_request_info.target_page_number);
6193  }
6194  break;
6195  }
6196  case REQUEST_TYPE_NEXT_PREV_AVAILABLE:
6197  {
6198  page_request_info.target_page_sub_code = PAGE_SUB_CODE_UNDEFINED;
6199 
6200  if (page_request_info.target_page_number == 0)
6201  {
6202  // No page requested prior to this request, so next/prev availibility will have to
6203  // be w.r.t the displayed page.
6204 
6205  if (!page_display_info.page_number)
6206  {
6207  // If there is no diplsayed page, then we cannot do anything more.
6208  break;
6209  }
6210 
6211  page_request_info.target_page_number = page_display_info.page_number;
6212  }
6213 
6214  if (GetAvailablePage(&page_request_info.target_page_number,
6215  page_request_info.param) == TRUE)
6216  {
6217  NotifyRequestToPageHistory(page_request_info.target_page_number);
6218 
6219  update_cache_requests = TRUE;
6220  }
6221 
6222  break;
6223  }
6224  case REQUEST_TYPE_NEXT_PREV_VISITED:
6225  {
6226  if (GetVisitedPage(&page_request_info.target_page_number,
6227  &page_request_info.target_page_sub_code,
6228  page_request_info.param) == TRUE)
6229  {
6230  update_cache_requests = TRUE;
6231  }
6232  break;
6233  }
6234  case REQUEST_TYPE_EDITORIAL_LINK:
6235  {
6236  if (page_display_info.page_number)
6237  {
6238  if (GetEditorialLinkPage(&page_request_info.target_page_number,
6239  &page_request_info.target_page_sub_code,
6240  page_request_info.param) == TRUE)
6241  {
6242  NotifyRequestToPageHistory(page_request_info.target_page_number);
6243 
6244  update_cache_requests = TRUE;
6245  }
6246  }
6247  break;
6248  }
6249  case REQUEST_TYPE_NEXT_PREV_SUB:
6250  {
6251  if (page_display_info.page_number)
6252  {
6253  if (GetSubPage(&page_request_info.target_page_sub_code, page_display_info.page_number,
6254  page_display_info.page_sub_code,
6255  page_request_info.param) == TRUE)
6256  {
6257  page_request_info.target_page_number = page_display_info.page_number;
6258  update_cache_requests = TRUE;
6259  }
6260  }
6261  break;
6262  }
6263  case REQUEST_TYPE_CANCEL:
6264  {
6265  page_request_info.target_page_number = page_display_info.page_number;
6266  page_request_info.target_page_sub_code = page_display_info.page_sub_code;
6267 
6268  NotifyRequestToPageHistory(0xffff);
6269  break;
6270  }
6271  default:
6272  {
6273  page_request_info.pending = FALSE;
6274  break;
6275  }
6276  }
6277  }
6278 
6279  STB_OSSemaphoreSignal(page_request_info.semaphore);
6280 
6281  if (previousnext_cache_reset_requested == TRUE)
6282  {
6283  for (index = 0; index < NUM_PREVIOUS_CACHE_REQUESTS; index++)
6284  {
6285  previous_cache_request_array[index] = 0;
6286  }
6287  for (index = 0; index < NUM_NEXT_CACHE_REQUESTS; index++)
6288  {
6289  next_cache_request_array[index] = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
6290  }
6291 
6292  previousnext_cache_reset_requested = FALSE;
6293  }
6294 
6295  if (history_cache_reset_requested == TRUE)
6296  {
6297  while (history_cache_request_list != NULL)
6298  {
6299  history_ptr = history_cache_request_list->next_ptr;
6300 
6301  STB_FreeMemory(history_cache_request_list);
6302 
6303  history_cache_request_list = history_ptr;
6304  }
6305 
6306  update_cache_requests = TRUE;
6307 
6308  history_cache_reset_requested = FALSE;
6309  }
6310 
6311  if (editorial_link_cache_reset_requested == TRUE)
6312  {
6313  KillEditorialLinkPageRequests(&editorial_link_request_root);
6314 
6315  update_cache_requests = TRUE;
6316 
6317  editorial_link_cache_reset_requested = FALSE;
6318  }
6319 
6320  if (update_cache_requests == TRUE)
6321  {
6322  page_number = page_request_info.target_page_number;
6323  page_sub_code = page_request_info.target_page_sub_code;
6324 
6325  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
6326 
6327  page_display_info.page_index_digit[0] = ((page_number & 0x0f00) >> 8) + PAGE_INDEX_DIGIT_0;
6328  page_display_info.page_index_digit[1] = ((page_number & 0x00f0) >> 4) + PAGE_INDEX_DIGIT_0;
6329  page_display_info.page_index_digit[2] = (page_number & 0x000f) + PAGE_INDEX_DIGIT_0;
6330 
6331  page_display_info.page_index_updated = TRUE;
6332 
6333  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
6334 
6335  // Determine the relevant magazine
6336  magazine_index = GetMagazineIndexFromPageNumber(page_number);
6337 
6338  STB_OSMutexLock( magazine_array[magazine_index].m_mutex );
6339 
6340  //... and locate matching page in cache.
6341  page_ptr = magazine_array[magazine_index].m_cache_page_ptr;
6342  while (page_ptr != NULL)
6343  {
6344  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == page_number)
6345  {
6346  if (page_sub_code == PAGE_SUB_CODE_UNDEFINED)
6347  {
6348  if (page_ptr->latest_subpage_ptr != NULL)
6349  {
6350  NotifyDisplayUpdate(&page_ptr->latest_subpage_ptr->collated_data, magazine_index,
6351  page_number, page_ptr->latest_subpage_ptr->sub_code, FALSE, pts_valid, pts);
6352  break;
6353  }
6354  }
6355  else
6356  {
6357  subpage_ptr = page_ptr->subpage_ptr;
6358 
6359  while (subpage_ptr != NULL)
6360  {
6361  if (subpage_ptr->sub_code == page_sub_code)
6362  {
6363  NotifyDisplayUpdate(&subpage_ptr->collated_data, magazine_index, page_number,
6364  page_sub_code, FALSE, pts_valid, pts);
6365  break;
6366  }
6367 
6368  subpage_ptr = subpage_ptr->next_ptr;
6369  }
6370 
6371  if (subpage_ptr != NULL)
6372  {
6373  break;
6374  }
6375  }
6376  }
6377 
6378  page_ptr = page_ptr->next_ptr;
6379  }
6380  STB_OSMutexUnlock( magazine_array[magazine_index].m_mutex );
6381 
6382  //----------------------------------------------------------------------------------
6383  // Clearing flags
6384  //----------------------------------------------------------------------------------
6385 
6386  // Go through all pages in cache clearing each page's relevant flags.
6387  for (magazine_index = 0; magazine_index != 8; magazine_index++)
6388  {
6389  STB_OSMutexLock( magazine_array[magazine_index].m_mutex );
6390  page_ptr = magazine_array[magazine_index].m_cache_page_ptr;
6391 
6392  while (page_ptr != NULL)
6393  {
6394  page_ptr->page_number &= ~(CACHE_PAGE_FLOF_REQUESTED |
6395  CACHE_PAGE_HISTORY_REQUESTED |
6396  CACHE_PAGE_LOCKED);
6397 
6398  page_ptr = page_ptr->next_ptr;
6399  }
6400  STB_OSMutexUnlock( magazine_array[magazine_index].m_mutex );
6401  }
6402 
6403  //----------------------------------------------------------------------------------
6404  // Request history link-list maintainance
6405  //----------------------------------------------------------------------------------
6406 
6407  // Search for a match for this page number in the requested page history.
6408  // This is done to advance an existing record to the top of the link-list, which
6409  // represents the most recently made requests.
6410  history_ptr = history_cache_request_list;
6411  prev_history_ptr = NULL;
6412  item_count = 0;
6413 
6414  while (history_ptr != NULL)
6415  {
6416  item_count++;
6417 
6418  // If we find the page number somewhere in the history link-list...
6419  if (history_ptr->page_number == page_number)
6420  {
6421  // then assuming it's not the top-most item...
6422  if (history_ptr != history_cache_request_list)
6423  {
6424  // we remove it from it's present position within the link-list...
6425  prev_history_ptr->next_ptr = history_ptr->next_ptr;
6426  break;
6427  }
6428  }
6429 
6430  // No match found yet, so advance to next link-list item.
6431  prev_history_ptr = history_ptr;
6432  history_ptr = history_ptr->next_ptr;
6433  }
6434 
6435  switch (caching_method)
6436  {
6437  case EBUTT_CACHING_METHOD_HISTORY:
6438  case EBUTT_CACHING_METHOD_NAVIGATION:
6439  case EBUTT_CACHING_METHOD_NAVIGATION_TREE:
6440  case EBUTT_CACHING_METHOD_ALL:
6441  {
6442  // If the requested page is not found in the link-list (i.e. has not been requested in
6443  // recent history)
6444  // Then we must attempt to either add a new record to the link-list, or relocate the
6445  // tail (oldest) record at the top of the link-list, and modify this one.
6446  if (history_ptr == NULL)
6447  {
6448  if (item_count < MAX_HISTORY_CACHE_REQUESTS)
6449  {
6450  history_ptr = (S_HISTORY_CACHE_REQUEST *)GetMemory(sizeof(S_HISTORY_CACHE_REQUEST));
6451  while (history_ptr == NULL)
6452  {
6453  // Determine the relevant magazine
6454  magazine_index = GetMagazineIndexFromPageNumber(page_number);
6455 
6456  if (RemoveUnrequestedCacheContent(magazine_index, FALSE) == FALSE)
6457  {
6458  break;
6459  }
6460 
6461  history_ptr = (S_HISTORY_CACHE_REQUEST *)GetMemory(sizeof(S_HISTORY_CACHE_REQUEST));
6462  }
6463  }
6464 
6465  // If either allcation of a new item failed, or was blocked because the link-list
6466  // already has too many records ...
6467  if (history_ptr == NULL)
6468  {
6469  if (history_cache_request_list != NULL)
6470  {
6471  if (history_cache_request_list->next_ptr == NULL)
6472  {
6473  // If there is a single record in the history, then just modify this one.
6474  history_cache_request_list->page_number = page_number;
6475  }
6476  else
6477  {
6478  // Find the last record in the link-list...
6479  history_ptr = history_cache_request_list;
6480  prev_history_ptr = NULL;
6481  while (history_ptr->next_ptr != NULL)
6482  {
6483  prev_history_ptr = history_ptr;
6484  history_ptr = history_ptr->next_ptr;
6485  }
6486 
6487  if (prev_history_ptr != NULL)
6488  {
6489  // we remove it from it's end position within the link-list
6490  prev_history_ptr->next_ptr = NULL;
6491  }
6492  }
6493  }
6494  }
6495  }
6496  break;
6497  }
6498 
6499  default:
6500  break;
6501  }
6502 
6503  // If we have a valid pointer here, then we must populate it with the latest
6504  // page request, and add it to the top of the link-list.
6505  if ((history_ptr != NULL) &&
6506  (history_ptr != history_cache_request_list))
6507  {
6508  history_ptr->page_number = page_number;
6509  history_ptr->next_ptr = history_cache_request_list;
6510  history_cache_request_list = history_ptr;
6511  }
6512 
6513  // Finally, go through each item in the page request link-list, and if the relevant
6514  // record is found within the page case, then set the CACHE_PAGE_HISTORY_REQUESTED flag to
6515  // donote this.
6516  history_ptr = history_cache_request_list;
6517  // For each page request...
6518  while (history_ptr != NULL)
6519  {
6520  SetPageFlag( history_ptr->page_number, CACHE_PAGE_HISTORY_REQUESTED );
6521 
6522  history_ptr = history_ptr->next_ptr;
6523  }
6524 
6525  //----------------------------------------------------------------------------------
6526  // Request FLOF tree maintainance
6527  //----------------------------------------------------------------------------------
6528 
6529  switch (caching_method)
6530  {
6531  case EBUTT_CACHING_METHOD_NAVIGATION:
6532  case EBUTT_CACHING_METHOD_NAVIGATION_TREE:
6533  case EBUTT_CACHING_METHOD_ALL:
6534  {
6535  // Look for editorial link request item representing this page and reposition at top
6536  // of request tree if necessary. In doing this, all editorial link items within the
6537  // tree are repositioned w.r.t the new root item if possible.
6538  UpdateEditorialLinkPageRequest(page_number, page_sub_code);
6539 
6540  // Then go through all items left in tree, and mark corresponding existing cahced pages
6541  // accordingly.
6542  FlagEditorialLinkPageRequests(editorial_link_request_root);
6543 
6544  break;
6545  }
6546 
6547  default:
6548  break;
6549  }
6550 
6551  SetPageFlag( page_number, CACHE_PAGE_LOCKED );
6552 
6553  if (page_display_info.page_number)
6554  {
6555  SetPageFlag( page_display_info.page_number, CACHE_PAGE_LOCKED );
6556  }
6557  }
6558 
6559  FUNCTION_FINISH(CheckPageRequest);
6560 }
6561 
6574 static BOOLEAN RemoveCachePage(U16BIT magazine_number, U16BIT mask)
6575 {
6576  BOOLEAN retval;
6577  S_CACHE_PAGE *page_ptr;
6578  S_CACHE_PAGE *last_page_ptr;
6579  S_CACHE_PAGE *search_page_ptr;
6580  S_CACHE_PAGE *search_last_page_ptr;
6581  S_CACHE_SUBPAGE *subpage_ptr;
6582  S_CACHE_SUBPAGE *temp_subpage_ptr;
6583 
6584  FUNCTION_START(RemoveCachePage);
6585 
6586  retval = FALSE;
6587 
6588  // Search for last page in cache link-list with no caching flags set.
6589  search_page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
6590  search_last_page_ptr = NULL;
6591  page_ptr = NULL;
6592  last_page_ptr = NULL;
6593 
6594  while (search_page_ptr != NULL)
6595  {
6596  if (!(search_page_ptr->page_number & ~(CACHE_PAGE_NUMBER_MASK | mask)))
6597  {
6598  page_ptr = search_page_ptr;
6599  last_page_ptr = search_last_page_ptr;
6600  break;
6601  }
6602  search_last_page_ptr = search_page_ptr;
6603  search_page_ptr = search_page_ptr->next_ptr;
6604  }
6605 
6606  if (page_ptr != NULL)
6607  {
6608  // Firstly free all the subpages.
6609  subpage_ptr = page_ptr->subpage_ptr;
6610  while (subpage_ptr != NULL)
6611  {
6612  temp_subpage_ptr = subpage_ptr->next_ptr;
6613 
6614  STB_FreeMemory(subpage_ptr);
6615 
6616  subpage_ptr = temp_subpage_ptr;
6617  }
6618 
6619  if (last_page_ptr == NULL)
6620  {
6621  magazine_array[magazine_number].m_cache_page_ptr = page_ptr->next_ptr;
6622  }
6623  else
6624  {
6625  last_page_ptr->next_ptr = page_ptr->next_ptr;
6626  }
6627 
6628  // Now we can free the removed cache page.
6629  STB_FreeMemory(page_ptr);
6630 
6631  retval = TRUE;
6632  }
6633 
6634  FUNCTION_FINISH(RemoveCachePage);
6635 
6636  return(retval);
6637 }
6638 
6650 static BOOLEAN RemoveUnrequestedCachePage(U16BIT magazine_number)
6651 {
6652  BOOLEAN retval;
6653  S_CACHE_PAGE *page_ptr;
6654  S_CACHE_PAGE *last_page_ptr;
6655  S_CACHE_PAGE *search_page_ptr;
6656  S_CACHE_PAGE *search_last_page_ptr;
6657  S_CACHE_SUBPAGE *subpage_ptr;
6658  S_CACHE_SUBPAGE *temp_subpage_ptr;
6659 
6660  FUNCTION_START(RemoveUnrequestedCachePage);
6661 
6662  retval = FALSE;
6663 
6664  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
6665 
6666  // Search for last page in cache link-list with no caching flags set.
6667  search_page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
6668  search_last_page_ptr = NULL;
6669  page_ptr = NULL;
6670  last_page_ptr = NULL;
6671 
6672  while (search_page_ptr != NULL)
6673  {
6674  if (!(search_page_ptr->page_number & ~CACHE_PAGE_NUMBER_MASK))
6675  {
6676  page_ptr = search_page_ptr;
6677  last_page_ptr = search_last_page_ptr;
6678  break;
6679  }
6680  search_last_page_ptr = search_page_ptr;
6681  search_page_ptr = search_page_ptr->next_ptr;
6682  }
6683 
6684  if (page_ptr != NULL)
6685  {
6686  // Firstly free all the subpages.
6687  subpage_ptr = page_ptr->subpage_ptr;
6688  while (subpage_ptr != NULL)
6689  {
6690  temp_subpage_ptr = subpage_ptr->next_ptr;
6691 
6692  STB_FreeMemory(subpage_ptr);
6693 
6694  subpage_ptr = temp_subpage_ptr;
6695  }
6696 
6697  if (last_page_ptr == NULL)
6698  {
6699  magazine_array[magazine_number].m_cache_page_ptr = page_ptr->next_ptr;
6700  }
6701  else
6702  {
6703  last_page_ptr->next_ptr = page_ptr->next_ptr;
6704  }
6705 
6706  // Now we can free the removed cache page.
6707  STB_FreeMemory(page_ptr);
6708 
6709  retval = TRUE;
6710  }
6711 
6712  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
6713 
6714  FUNCTION_FINISH(RemoveUnrequestedCachePage);
6715 
6716  return(retval);
6717 }
6718 
6731 static BOOLEAN RemoveCacheContent(U16BIT magazine_number, BOOLEAN exclude_magazine)
6732 {
6733  U16BIT mask_index, offset, mgzn_ndx;
6734  BOOLEAN retval;
6735 
6736  FUNCTION_START(RemoveCacheContent);
6737 
6738  retval = FALSE;
6739 
6740  for (mask_index = 0; (mask_index != 8) && (retval == FALSE); mask_index++)
6741  {
6742  if (exclude_magazine == FALSE)
6743  {
6744  retval = RemoveCachePage(magazine_number, cache_removal_priority_mask_array[mask_index]);
6745  }
6746 
6747  for (offset = 1; retval == FALSE && offset != 8; offset++)
6748  {
6749  mgzn_ndx = (magazine_number + offset) % 8;
6750  STB_OSMutexLock( magazine_array[mgzn_ndx].m_mutex );
6751  retval = RemoveCachePage(mgzn_ndx, cache_removal_priority_mask_array[mask_index]);
6752  STB_OSMutexUnlock( magazine_array[mgzn_ndx].m_mutex );
6753  }
6754  }
6755 
6756  FUNCTION_FINISH(RemoveCacheContent);
6757 
6758  return(retval);
6759 }
6760 
6773 static BOOLEAN RemoveUnrequestedCacheContent(U16BIT magazine_number, BOOLEAN exclude_magazine)
6774 {
6775  U16BIT magazine_offset;
6776  BOOLEAN retval;
6777 
6778  FUNCTION_START(RemoveUnrequestedCacheContent);
6779 
6780  retval = FALSE;
6781 
6782  if (exclude_magazine == FALSE)
6783  {
6784  retval = RemoveUnrequestedCachePage(magazine_number);
6785  }
6786 
6787  for (magazine_offset = 1; retval == FALSE && magazine_offset != 8; magazine_offset++)
6788  {
6789  retval = RemoveUnrequestedCachePage((magazine_number + magazine_offset) % 8);
6790  }
6791 
6792  FUNCTION_FINISH(RemoveUnrequestedCacheContent);
6793 
6794  return(retval);
6795 }
6796 
6797 #if 0
6798 
6809 static void RemoveAllCacheContent(void)
6810 {
6811  U16BIT magazine_number;
6812  S_CACHE_PAGE *page_ptr;
6813  S_CACHE_PAGE *next_page_ptr;
6814  S_CACHE_SUBPAGE *subpage_ptr;
6815  S_CACHE_SUBPAGE *next_subpage_ptr;
6816 
6817  FUNCTION_START(RemoveAllCacheContent);
6818 
6819  for (magazine_number = 0; magazine_number != 8; magazine_number++)
6820  {
6821  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
6822 
6823  page_ptr = magazine_array[magazine_number].m_cache_page_ptr;
6824 
6825  while (page_ptr != NULL)
6826  {
6827  subpage_ptr = page_ptr->subpage_ptr;
6828  while (subpage_ptr != NULL)
6829  {
6830  next_subpage_ptr = subpage_ptr->next_ptr;
6831 
6832  STB_FreeMemory(subpage_ptr);
6833 
6834  subpage_ptr = next_subpage_ptr;
6835  }
6836 
6837  next_page_ptr = page_ptr->next_ptr;
6838 
6839  STB_FreeMemory(page_ptr);
6840 
6841  page_ptr = next_page_ptr;
6842  }
6843 
6844  memset(magazine_array[magazine_number].m_cache_valid_page_array, 0, sizeof(U8BIT) * 32);
6845  magazine_array[magazine_number].m_cache_page_ptr = NULL;
6846 
6847  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
6848  }
6849 
6850  FUNCTION_FINISH(RemoveAllCacheContent);
6851 }
6852 
6853 #endif
6854 
6870 static void NotifyDisplayUpdate(S_MAGAZINE_PAGE *collated_page_ptr, U16BIT magazine_number,
6871  U16BIT page_number, U16BIT page_sub_code, BOOLEAN update_clock, BOOLEAN pts_valid, U8BIT *pts)
6872 {
6873  U16BIT index;
6874 
6875  FUNCTION_START(NotifyDisplayUpdate);
6876 
6877  // If we are about to display a page, then there is no need to continue search for the
6878  // broadcaster-defined index page. We may have collated page 100 (which we ask for by default,
6879  // or the operator may have manually chosen a page themseleves.
6880  broadcast_index_page_invocation_required = FALSE;
6881 
6882  NotifyDisplayToPageHistory(page_number);
6883 
6884  DBGPRINT("%03x:%04x\n", page_number, page_sub_code);
6885 
6886  /* Wait until page_display_info is available to be used */
6887  STB_OSSemaphoreWait(page_free_sem);
6888 
6889  STB_OSSemaphoreWait(page_display_info.page_semaphore);
6890 
6891  memcpy(&page_display_info.page_source, collated_page_ptr, sizeof(S_MAGAZINE_PAGE));
6892 
6893  if (page_display_info.page_number)
6894  {
6895  if (GetMagazineIndexFromPageNumber(page_display_info.page_number) != magazine_number)
6896  {
6897  STB_OSMutexLock( magazine_array[magazine_number].m_mutex );
6898 
6899  for (index = 0; index != 2; index++)
6900  {
6901  if (magazine_array[magazine_number].m_specific_data.is_defined[index] == TRUE)
6902  {
6903  memcpy(page_display_info.mgzn_data.s_data[index],
6904  magazine_array[magazine_number].m_specific_data.s_data[index], MAX_COLUMN);
6905 
6906  page_display_info.mgzn_data.is_defined[index] = TRUE;
6907  }
6908  }
6909 
6910  STB_OSMutexUnlock( magazine_array[magazine_number].m_mutex );
6911  }
6912  }
6913 
6914  if ((page_display_info.page_number != page_number) ||
6915  (page_display_info.page_sub_code != page_sub_code))
6916  {
6917  page_display_info.reveal_set = FALSE;
6918  }
6919 
6920  page_display_info.clear_set = FALSE;
6921  page_control_info.clear_required = FALSE;
6922  page_display_info.clear_required = FALSE;
6923 
6924  page_display_info.page_number = page_number;
6925  page_display_info.page_sub_code = page_sub_code;
6926 
6927  page_display_info.page_clock_valid = update_clock;
6928 
6929  page_display_info.pts_valid = pts_valid;
6930  if (pts_valid)
6931  {
6932  memcpy(page_display_info.page_pts, pts, 5);
6933  }
6934 
6935  page_display_info.page_updated = TRUE;
6936 
6937  STB_OSSemaphoreSignal(page_display_info.page_semaphore);
6938 
6939  if (!show_header_row)
6940  {
6941  subtitle_timeout = STB_OSGetClockMilliseconds();
6942  DBGPRINT("set Subtitle Timeout @ %lu", subtitle_timeout);
6943  }
6944 
6945  FUNCTION_FINISH(NotifyDisplayUpdate);
6946 }
6947 
6960 static void CheckPageCaching(S_MAGAZINE_PAGE *collated_page_ptr, S_PAGE_REFERENCE_DATA *reference_data_ptr,
6961  BOOLEAN pts_valid, U8BIT *pts)
6962 {
6963  U16BIT flag, index, page_sub_code, magazine_index, num_unrequested_pages;
6964  BOOLEAN caching_required;
6965  BOOLEAN caching_successful;
6966  U16BIT *next_request_array_ptr;
6967  U16BIT *previous_request_array_ptr;
6968  S_CACHE_PAGE *page_ptr;
6969  S_CACHE_SUBPAGE *subpage_ptr;
6970  S_EDITORIAL_LINK_CACHE_REQUEST *editorial_link_ptr;
6971  S_HISTORY_CACHE_REQUEST *history_ptr;
6972 
6973  FUNCTION_START(CheckPageCaching);
6974 
6975  flag = 0;
6976  caching_required = FALSE;
6977  editorial_link_ptr = NULL;
6978 
6979  if ((caching_method == EBUTT_CACHING_METHOD_NAVIGATION) ||
6980  (caching_method == EBUTT_CACHING_METHOD_NAVIGATION_TREE) ||
6981  (caching_method == EBUTT_CACHING_METHOD_ALL))
6982  {
6983  if (GetEditorialLink(editorial_link_request_root, &editorial_link_ptr,
6984  reference_data_ptr->page_number) == TRUE)
6985  {
6986  flag = CACHE_PAGE_FLOF_REQUESTED;
6987  caching_required = TRUE;
6988  }
6989  }
6990 
6991  if ((caching_method == EBUTT_CACHING_METHOD_HISTORY) ||
6992  (caching_method == EBUTT_CACHING_METHOD_NAVIGATION) ||
6993  (caching_method == EBUTT_CACHING_METHOD_NAVIGATION_TREE) ||
6994  (caching_method == EBUTT_CACHING_METHOD_ALL))
6995  {
6996  history_ptr = history_cache_request_list;
6997  // For each page request...
6998  while (history_ptr != NULL)
6999  {
7000  if (history_ptr->page_number == reference_data_ptr->page_number)
7001  {
7002  flag |= CACHE_PAGE_HISTORY_REQUESTED;
7003  caching_required = TRUE;
7004  break;
7005  }
7006 
7007  history_ptr = history_ptr->next_ptr;
7008  }
7009  }
7010 
7011  for (index = 0; index < NUM_PREVIOUS_CACHE_REQUESTS; index++)
7012  {
7013  if (previous_cache_request_array[index] == reference_data_ptr->page_number)
7014  {
7015  flag |= CACHE_PAGE_PREVNEXT_REQUESTED;
7016  caching_required = TRUE;
7017  break;
7018  }
7019  }
7020 
7021  if (page_display_info.page_number)
7022  {
7023  if (page_display_info.page_number != next_prev_page_number)
7024  {
7025  do
7026  {
7027  // Find lowest page number in request next array
7028  SearchNextRequestArray(FALSE, &next_request_array_ptr);
7029 
7030  // If it's greater than the displayed page then no modification to the array is
7031  // required, as all the array records are still greater than the displayed page.
7032  if (page_display_info.page_number < *next_request_array_ptr)
7033  {
7034  // exit loop
7035  break;
7036  }
7037 
7038  // If the displayed page is in the array, then remove it.
7039  if (page_display_info.page_number == *next_request_array_ptr)
7040  {
7041  // First see if the relevant record exists in the page cache.
7042  // If found, then remove relevant flag,
7043  UnsetPageFlag( *next_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7044 
7045  // Clear the item in the next array
7046  *next_request_array_ptr = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
7047  }
7048  else
7049  {
7050  // If we are here then the array record is lower than the request page number.
7051  // In this case we will transfer the array record to the previous request array.
7052 
7053  // Find lowest element
7054  SearchPreviousRequestArray(FALSE, &previous_request_array_ptr);
7055 
7056  if (*previous_request_array_ptr != 0)
7057  {
7058  // First see if the relevant record exists in the page cache.
7059  // If found, then remove relevant flag,
7060  UnsetPageFlag( *previous_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7061  }
7062 
7063  // Transfer the page request from the next array to the previous array
7064  *previous_request_array_ptr = *next_request_array_ptr;
7065  // Clear the item in the next array
7066  *next_request_array_ptr = INVALID_PREVNEXT_CACHE_PAGE_NUMBER;
7067  }
7068  }
7069  while (1);
7070 
7071  do
7072  {
7073  // Find highest page number in request previous array
7074  SearchPreviousRequestArray(TRUE, &previous_request_array_ptr);
7075 
7076  // If it's less than the displayed page then no modification to the array is
7077  // required, as all the array records are still less than the displayed page.
7078  if (page_display_info.page_number > *previous_request_array_ptr)
7079  {
7080  break;
7081  }
7082 
7083  // If the displayed page is in the array, then remove it.
7084  if (page_display_info.page_number == *previous_request_array_ptr)
7085  {
7086  // First see if the relevant record exists in the page cache.
7087  // If found, then remove relevant flag,
7088  UnsetPageFlag( *previous_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7089 
7090  // Clear the item in the previous array
7091  *previous_request_array_ptr = 0;
7092  }
7093  else
7094  {
7095  // If we are here then the array record is higher than the request page number.
7096  // In this case we will transfer the array record to the next request array.
7097 
7098  // Find highest element
7099  SearchNextRequestArray(TRUE, &next_request_array_ptr);
7100 
7101  if (*next_request_array_ptr != INVALID_PREVNEXT_CACHE_PAGE_NUMBER)
7102  {
7103  // First see if the relevant record exists in the page cache.
7104  // If found, then remove relevant flag,
7105  UnsetPageFlag( *next_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7106  }
7107 
7108  // Transfer the page request from the previous array to the next array
7109  *next_request_array_ptr = *previous_request_array_ptr;
7110  // Clear the item in the previous array
7111  *previous_request_array_ptr = 0;
7112  }
7113  }
7114  while (1);
7115 
7116  next_prev_page_number = page_display_info.page_number;
7117  }
7118 
7119  if (reference_data_ptr->page_number > page_display_info.page_number)
7120  {
7121  // Find highest page number in request next array
7122  SearchNextRequestArray(TRUE, &next_request_array_ptr);
7123 
7124  if (reference_data_ptr->page_number < *next_request_array_ptr)
7125  {
7126  if (IsInNextRequestArray(reference_data_ptr->page_number) == FALSE)
7127  {
7128  if (*next_request_array_ptr != INVALID_PREVNEXT_CACHE_PAGE_NUMBER)
7129  {
7130  UnsetPageFlag( *next_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7131  }
7132 
7133  *next_request_array_ptr = reference_data_ptr->page_number;
7134 
7135  SetPageFlag( *next_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7136  }
7137  }
7138  }
7139  else if (reference_data_ptr->page_number < page_display_info.page_number)
7140  {
7141  // Find lowest page number in request previous array
7142  SearchPreviousRequestArray(FALSE, &previous_request_array_ptr);
7143 
7144  if (reference_data_ptr->page_number > *previous_request_array_ptr)
7145  {
7146  if (IsInPreviousRequestArray(reference_data_ptr->page_number) == FALSE)
7147  {
7148  if (*previous_request_array_ptr != 0)
7149  {
7150  UnsetPageFlag( *previous_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7151  }
7152 
7153  *previous_request_array_ptr = reference_data_ptr->page_number;
7154 
7155  SetPageFlag( *previous_request_array_ptr, CACHE_PAGE_PREVNEXT_REQUESTED );
7156  }
7157  }
7158  }
7159  }
7160 
7161  for (index = 0; index < NUM_NEXT_CACHE_REQUESTS; index++)
7162  {
7163  if (next_cache_request_array[index] == reference_data_ptr->page_number)
7164  {
7165  flag |= CACHE_PAGE_PREVNEXT_REQUESTED;
7166  caching_required = TRUE;
7167  break;
7168  }
7169  }
7170 
7171  if (caching_method == EBUTT_CACHING_METHOD_ALL)
7172  {
7173  caching_required = TRUE;
7174  }
7175 
7176  // As soon as a requested page arrives, update/add it's content to the cache and immediately lock
7177  // it. We will subsequently invoke a display update.
7178  // Similarily, this code will execute when the page arrives on the carousel repeatedly thereafter.
7179  if (page_request_info.target_page_number == reference_data_ptr->page_number)
7180  {
7181  flag |= CACHE_PAGE_LOCKED;
7182  caching_required = TRUE;
7183  }
7184 
7185  // This is done just in case we are in a transitional period when the currently displayed page
7186  // is updated whilst we are waiting for a newly requested page.
7187  // In this circumstance we will not invoke a display update, but merely lock the page in the
7188  // cache.
7189  if (page_display_info.page_number == reference_data_ptr->page_number)
7190  {
7191  flag |= CACHE_PAGE_LOCKED;
7192  }
7193 
7194  if (caching_required == TRUE)
7195  {
7196  // ...determine the relevant magazine
7197  magazine_index = GetMagazineIndexFromPageNumber(reference_data_ptr->page_number);
7198 
7199  caching_successful = FALSE;
7200 
7201  if (GetHamming8DoubleWord(collated_page_ptr->header + 2, &page_sub_code) == TRUE)
7202  {
7203  page_sub_code &= 0x3f7f;
7204 
7205  STB_OSMutexLock( magazine_array[magazine_index].m_mutex );
7206 
7207  //... and locate mathcing page in cache.
7208  page_ptr = magazine_array[magazine_index].m_cache_page_ptr;
7209  while (page_ptr != NULL)
7210  {
7211  // If the page already exists in the cache...
7212  if ((page_ptr->page_number & CACHE_PAGE_NUMBER_MASK) == reference_data_ptr->page_number)
7213  {
7214  // update it's flags and sub-page content.
7215  page_ptr->page_number &= CACHE_PAGE_NUMBER_MASK;
7216  page_ptr->page_number |= flag;
7217 
7218  subpage_ptr = page_ptr->subpage_ptr;
7219 
7220  while (subpage_ptr != NULL)
7221  {
7222  if (subpage_ptr->sub_code == page_sub_code)
7223  {
7224  if (reference_data_ptr->erase_page == TRUE)
7225  {
7226  memcpy(&subpage_ptr->collated_data, collated_page_ptr,
7227  sizeof(S_MAGAZINE_PAGE));
7228  }
7229  else
7230  {
7231  memcpy(subpage_ptr->collated_data.header, collated_page_ptr->header, MAX_COLUMN);
7232  subpage_ptr->collated_data.is_header_defined = TRUE;
7233 
7234  for (index = 1; index != MAX_ROWS; index++)
7235  {
7236  if (collated_page_ptr->display_data_defined_mask & (1 << index))
7237  {
7238  memcpy(subpage_ptr->collated_data.display_data[index],
7239  collated_page_ptr->display_data[index], MAX_COLUMN);
7240  subpage_ptr->collated_data.display_data_defined_mask |= 1 << index;
7241  }
7242  }
7243 
7244  for (index = 0; index != 16; index++)
7245  {
7246  if (collated_page_ptr->basic_enhancement_data_defined_mask & (1 << index))
7247  {
7248  memcpy(subpage_ptr->collated_data.basic_enhancement_data[index],
7249  collated_page_ptr->basic_enhancement_data[index], MAX_COLUMN);
7250  subpage_ptr->collated_data.basic_enhancement_data_defined_mask |=
7251  1 << index;
7252  }
7253  }
7254 
7255  if (collated_page_ptr->is_editorial_page_linking_data_defined == TRUE)
7256  {
7257  memcpy(subpage_ptr->collated_data.editorial_page_linking_data,
7258  collated_page_ptr->editorial_page_linking_data, MAX_COLUMN);
7259  subpage_ptr->collated_data.is_editorial_page_linking_data_defined = TRUE;
7260  }
7261 
7262  for (index = 0; index != 2; index++)
7263  {
7264  if (collated_page_ptr->specific_data.is_defined[index] == TRUE)
7265  {
7266  memcpy(subpage_ptr->collated_data.specific_data.s_data[index],
7267  collated_page_ptr->specific_data.s_data[index], MAX_COLUMN);
7268  subpage_ptr->collated_data.specific_data.is_defined[index] = TRUE;
7269  }
7270  }
7271  }
7272 
7273  page_ptr->latest_subpage_ptr = subpage_ptr;
7274 
7275  DeterminePageEditorialLinks(editorial_link_ptr, subpage_ptr);
7276 
7277  caching_successful = TRUE;
7278  break;
7279  }
7280 
7281  subpage_ptr = subpage_ptr->next_ptr;
7282  }
7283 
7284  if (subpage_ptr == NULL)
7285  {
7286  subpage_ptr = (S_CACHE_SUBPAGE *)GetMemory(sizeof(S_CACHE_SUBPAGE));
7287  while (subpage_ptr == NULL)
7288  {
7289  // Remove old cache page(s) if no memory available!
7290  if (RemoveCacheContent(magazine_index, TRUE) == FALSE)
7291  {
7292  break;
7293  }
7294  subpage_ptr = (S_CACHE_SUBPAGE *)GetMemory(sizeof(S_CACHE_SUBPAGE));
7295  }
7296 
7297  if (subpage_ptr != NULL)
7298  {
7299  subpage_ptr->sub_code = page_sub_code;
7300  memcpy(&subpage_ptr->collated_data, collated_page_ptr,
7301  sizeof(S_MAGAZINE_PAGE));
7302  subpage_ptr->next_ptr = page_ptr->subpage_ptr;
7303 
7304  page_ptr->subpage_ptr = subpage_ptr;
7305  page_ptr->latest_subpage_ptr = subpage_ptr;
7306 
7307  DeterminePageEditorialLinks(editorial_link_ptr, subpage_ptr);
7308 
7309  caching_successful = TRUE;
7310  }
7311  }
7312 
7313  break;
7314  }
7315 
7316  page_ptr = page_ptr->next_ptr;
7317  }
7318 
7319  if (page_ptr == NULL)
7320  {
7321  // Add new page AND subpage here....
7322  // NB - remove old page if no memory available!
7323  page_ptr = (S_CACHE_PAGE *)GetMemory(sizeof(S_CACHE_PAGE));
7324  while (page_ptr == NULL)
7325  {
7326  // Remove old cache page(s) if no memory available!
7327  if (RemoveCacheContent(magazine_index, FALSE) == FALSE)
7328  {
7329  break;
7330  }
7331  page_ptr = (S_CACHE_PAGE *)GetMemory(sizeof(S_CACHE_PAGE));
7332  }
7333 
7334  if (page_ptr != NULL)
7335  {
7336  page_ptr->page_number = reference_data_ptr->page_number | flag;
7337 
7338  subpage_ptr = (S_CACHE_SUBPAGE *)GetMemory(sizeof(S_CACHE_SUBPAGE));
7339  while (subpage_ptr == NULL)
7340  {
7341  // Remove old cache page(s) if no memory available!
7342  if (RemoveCacheContent(magazine_index, TRUE) == FALSE)
7343  {
7344  break;
7345  }
7346  subpage_ptr = (S_CACHE_SUBPAGE *)GetMemory(sizeof(S_CACHE_SUBPAGE));
7347  }
7348 
7349  if (subpage_ptr != NULL)
7350  {
7351  subpage_ptr->sub_code = page_sub_code;
7352  memcpy(&subpage_ptr->collated_data, collated_page_ptr, sizeof(S_MAGAZINE_PAGE));
7353  subpage_ptr->next_ptr = NULL;
7354 
7355  page_ptr->subpage_ptr = subpage_ptr;
7356  page_ptr->latest_subpage_ptr = subpage_ptr;
7357 
7358  page_ptr->next_ptr = magazine_array[magazine_index].m_cache_page_ptr;
7359 
7360  magazine_array[magazine_index].m_cache_page_ptr = page_ptr;
7361 
7362  caching_successful = TRUE;
7363  }
7364  else
7365  {
7366  STB_FreeMemory(page_ptr);
7367  }
7368  }
7369  }
7370 
7371  STB_OSMutexUnlock( magazine_array[magazine_index].m_mutex );
7372  }
7373 
7374  if (caching_successful == TRUE)
7375  {
7376  if (page_display_info.page_number == reference_data_ptr->page_number)
7377  {
7378  // We have just updated cache for currently displayed page.
7379 
7380  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
7381  {
7382  // When page is held, we only prompt for a display update when the currently
7383  // displayed sub-page is refreshed in the cache.
7384  if (page_display_info.page_sub_code == page_sub_code)
7385  {
7386  NotifyDisplayUpdate(collated_page_ptr, magazine_index,
7387  reference_data_ptr->page_number, page_sub_code, TRUE, pts_valid, pts);
7388  }
7389  }
7390  else
7391  {
7392  if (page_control_info.state != PAGE_CONTROL_STATE_INPUT)
7393  {
7394  if (page_request_info.target_page_number == reference_data_ptr->page_number)
7395  {
7396  // When display is not held, then we always prompt for a display update
7397  // as each sub-page is refreshed in the cache.
7398  if (page_display_info.page_sub_code != page_sub_code)
7399  {
7400  if ((IsRollingSubCode(page_display_info.page_sub_code) == TRUE) &&
7401  (collated_page_ptr->display_data_defined_mask != 0))
7402  {
7403  NotifyDisplayUpdate(collated_page_ptr, magazine_index,
7404  reference_data_ptr->page_number, page_sub_code, TRUE, pts_valid, pts);
7405  }
7406  }
7407  else
7408  {
7409  if (collated_page_ptr->display_data_defined_mask != 0)
7410  {
7411  NotifyDisplayUpdate(collated_page_ptr, magazine_index,
7412  reference_data_ptr->page_number, page_sub_code, TRUE, pts_valid, pts);
7413  }
7414  }
7415  }
7416  }
7417  }
7418  }
7419  else
7420  {
7421  // We have just updated cache for page that is not currently displayed.
7422 
7423  if (page_request_info.target_page_number == reference_data_ptr->page_number)
7424  {
7425  // This page is curently requested as the display page!
7426  NotifyDisplayUpdate(collated_page_ptr, magazine_index,
7427  reference_data_ptr->page_number, page_sub_code, TRUE, pts_valid, pts);
7428  }
7429  }
7430  }
7431 
7432  //Lastly, check that not too many unrequested pages are cached for each magazine.
7433  if (caching_method != EBUTT_CACHING_METHOD_ALL)
7434  {
7435  for (magazine_index = 0; magazine_index != 8; magazine_index++)
7436  {
7437  STB_OSMutexLock( magazine_array[magazine_index].m_mutex );
7438  page_ptr = magazine_array[magazine_index].m_cache_page_ptr;
7439  num_unrequested_pages = 0;
7440 
7441  while (page_ptr != NULL)
7442  {
7443  if (!(page_ptr->page_number & ~CACHE_PAGE_NUMBER_MASK))
7444  {
7445  num_unrequested_pages++;
7446  }
7447 
7448  page_ptr = page_ptr->next_ptr;
7449  }
7450  STB_OSMutexUnlock( magazine_array[magazine_index].m_mutex );
7451 
7452  while (num_unrequested_pages > 10)
7453  {
7454  if (RemoveUnrequestedCachePage(magazine_index) == FALSE)
7455  {
7456  break;
7457  }
7458 
7459  num_unrequested_pages--;
7460  }
7461  }
7462  }
7463  }
7464 
7465  FUNCTION_FINISH(CheckPageCaching);
7466 }
7467 
7480 static void CheckTimeFillingPacket(S_MAGAZINE_PAGE *collated_page_ptr, U16BIT page_number)
7481 {
7482  FUNCTION_START(CheckTimeFillingPacket);
7483 
7484  // Page is 'Time Filling Header' page, which is used to update the display of real-time clock.
7485 
7486  if ((page_display_info.page_number & 0x0f00) == (page_number & 0x0f00))
7487  {
7488  STB_OSSemaphoreWait(page_display_info.time_filler_header_data_semaphore);
7489 
7490  memcpy(page_display_info.time_filler_header_data, &collated_page_ptr->header[8], 32);
7491 
7492  page_display_info.clock_updated = TRUE;
7493 
7494  STB_OSSemaphoreSignal(page_display_info.time_filler_header_data_semaphore);
7495  }
7496 
7497  FUNCTION_FINISH(CheckTimeFillingPacket);
7498 }
7499 
7511 static void CheckHeaderClockContent(S_MAGAZINE_PAGE *collated_page_ptr)
7512 {
7513  FUNCTION_START(CheckHeaderClockContent);
7514 
7515  if (memcmp(&page_display_info.time_filler_header_data[24], &collated_page_ptr->header[32], 8))
7516  {
7517  STB_OSSemaphoreWait(page_display_info.time_filler_header_data_semaphore);
7518 
7519  memcpy(page_display_info.time_filler_header_data, &collated_page_ptr->header[8], 32);
7520 
7521  page_display_info.clock_updated = TRUE;
7522 
7523  STB_OSSemaphoreSignal(page_display_info.time_filler_header_data_semaphore);
7524  }
7525 
7526  FUNCTION_FINISH(CheckHeaderClockContent);
7527 }
7528 
7543 static void NotifyRequestToPageHistory(U16BIT page_number)
7544 {
7545  FUNCTION_START(NotifyRequestToPageHistory);
7546 
7547  page_history_request_page_number = page_number;
7548 
7549  FUNCTION_FINISH(NotifyRequestToPageHistory);
7550 }
7551 
7564 static U16BIT MoveHistoryMarker(U16BIT marker, BOOLEAN advance)
7565 {
7566  FUNCTION_START(MoveHistoryMarker);
7567 
7568  if (advance == TRUE)
7569  {
7570  marker++;
7571  if (marker >= MAX_PAGE_HISTORY)
7572  {
7573  marker = 0;
7574  }
7575  }
7576  else
7577  {
7578  if (marker == 0)
7579  {
7580  marker = MAX_PAGE_HISTORY - 1;
7581  }
7582  else
7583  {
7584  marker--;
7585  }
7586  }
7587 
7588  FUNCTION_FINISH(MoveHistoryMarker);
7589 
7590  return(marker);
7591 }
7592 
7608 static void NotifyDisplayToPageHistory(U16BIT page_number)
7609 {
7610  FUNCTION_START(NotifyDisplayToPageHistory);
7611 
7612  // NB - if prior calls have been made to GetPreviousPageFromHistory() then we will reset the
7613  // high-water-mark to a new position, potentially reducing the page history.
7614 
7615  if (page_number == page_history_request_page_number)
7616  {
7617  // If the page number being displayed is as a result of an explicit request, then we add
7618  // the page number to the history.
7619  page_history_array[page_history_hwm] = page_number;
7620 
7621  // Advance the high-water-mark
7622  page_history_hwm = MoveHistoryMarker(page_history_hwm, TRUE);
7623 
7624  // If we have collided with the low-water-mark, then force it's advancement, thus losing
7625  // oldest record in history.
7626  if (page_history_hwm == page_history_lwm)
7627  {
7628  page_history_lwm = MoveHistoryMarker(page_history_lwm, TRUE);
7629  }
7630  // Now adjsut the middle water-mark.
7631  page_history_mwm = page_history_hwm;
7632 
7633  // Reset the requested page record.
7634  page_history_request_page_number = 0xffff;
7635  }
7636 
7637  FUNCTION_FINISH(NotifyDisplayToPageHistory);
7638 }
7639 
7651 static BOOLEAN GetPreviousPageFromHistory(U16BIT *page_number)
7652 {
7653  U16BIT temp_mwm;
7654  BOOLEAN retval;
7655 
7656  FUNCTION_START(GetPreviousPageFromHistory);
7657 
7658  retval = FALSE;
7659 
7660  if (page_history_hwm != page_history_lwm)
7661  {
7662  temp_mwm = MoveHistoryMarker(page_history_mwm, FALSE);
7663 
7664  if (temp_mwm != page_history_lwm)
7665  {
7666  temp_mwm = MoveHistoryMarker(temp_mwm, FALSE);
7667 
7668  *page_number = page_history_array[temp_mwm];
7669 
7670  page_history_mwm = MoveHistoryMarker(temp_mwm, TRUE);
7671 
7672  retval = TRUE;
7673  }
7674  }
7675 
7676  FUNCTION_FINISH(GetPreviousPageFromHistory);
7677 
7678  return(retval);
7679 }
7680 
7692 static BOOLEAN GetNextPageFromHistory(U16BIT *page_number)
7693 {
7694  BOOLEAN retval;
7695 
7696  FUNCTION_START(GetNextPageFromHistory);
7697 
7698  retval = FALSE;
7699 
7700  if (page_history_mwm != page_history_hwm)
7701  {
7702  *page_number = page_history_array[page_history_mwm];
7703 
7704  page_history_mwm = MoveHistoryMarker(page_history_mwm, TRUE);
7705 
7706  retval = TRUE;
7707  }
7708 
7709  FUNCTION_FINISH(GetNextPageFromHistory);
7710 
7711  return(retval);
7712 }
7713 
7737 static void NotifyPageCollated(S_MAGAZINE_PAGE *collated_page_ptr, U8BIT magazine_number,
7738  BOOLEAN pts_valid, U8BIT *pts)
7739 {
7740  BOOLEAN update_carousel_display;
7741  S_PAGE_REFERENCE_DATA page_reference_data;
7742 
7743  FUNCTION_START(NotifyPageCollated);
7744 
7745  if (GetPageReference(collated_page_ptr->header, &page_reference_data, PAGE_REFERENCE_TYPE_HEADER,
7746  magazine_number) == TRUE)
7747  {
7748  if (page_reference_data.page_offset == 0xff)
7749  {
7750  if (page_reference_data.page_sub_code <= 0x3f7e)
7751  {
7752  CheckTimeFillingPacket(collated_page_ptr, page_reference_data.page_number);
7753  }
7754  }
7755  else
7756  {
7757 #ifdef EBU_DEBUG
7758  if ((page_display_info.page_number >> 8) == magazine_number)
7759  {
7760  EBU_DBG("PageCollated: #=%03x:%04x, display_data_defined=0x%08x",
7761  page_reference_data.page_number, page_reference_data.page_sub_code,
7762  collated_page_ptr->display_data_defined_mask);
7763  }
7764 #endif
7765 
7766  CheckHeaderClockContent(collated_page_ptr);
7767 
7768  // Mark the relevant bit in the byte array used to represent each of the 256 pages
7769  // within this magazine.
7770  magazine_array[magazine_number].m_cache_valid_page_array[page_reference_data.page_offset >> 3] |=
7771  1 << (page_reference_data.page_offset & 0x07);
7772 
7773  // Check if the 'Interrupted Sequnce' mode is cleared.
7774  // If so, then the displayed page index record for this magazine is updated.
7775  if (page_reference_data.interrupted_sequence == FALSE)
7776  {
7777  if (page_control_info.state != PAGE_CONTROL_STATE_HOLD)
7778  {
7779  update_carousel_display = FALSE;
7780 
7781  if (page_request_info.target_page_number)
7782  {
7783  if (page_request_info.target_page_sub_code == PAGE_SUB_CODE_UNDEFINED)
7784  {
7785  if (page_request_info.target_page_number != page_display_info.page_number)
7786  {
7787  if (page_reference_data.magazine_serial == TRUE)
7788  {
7789  update_carousel_display = TRUE;
7790  }
7791  else
7792  {
7793  if (GetMagazineIndexFromPageNumber(page_reference_data.page_number) ==
7794  GetMagazineIndexFromPageNumber(page_request_info.target_page_number))
7795  {
7796  update_carousel_display = TRUE;
7797  }
7798  }
7799  }
7800  }
7801  else
7802  {
7803  if ((page_request_info.target_page_number != page_display_info.page_number) ||
7804  (page_request_info.target_page_sub_code != page_display_info.page_sub_code))
7805  {
7806  if (page_reference_data.magazine_serial == TRUE)
7807  {
7808  update_carousel_display = TRUE;
7809  }
7810  else
7811  {
7812  if (GetMagazineIndexFromPageNumber(page_reference_data.page_number) ==
7813  GetMagazineIndexFromPageNumber(page_request_info.target_page_number))
7814  {
7815  update_carousel_display = TRUE;
7816  }
7817  }
7818  }
7819  }
7820  }
7821  else
7822  {
7823  update_carousel_display = TRUE;
7824  }
7825 
7826  if (update_carousel_display == TRUE && show_header_row == TRUE)
7827  {
7828  STB_OSSemaphoreWait(page_display_info.carousel_page_semaphore);
7829 
7830  page_display_info.carousel_page_number = page_reference_data.page_number;
7831 
7832  if (collated_page_ptr->is_header_defined == TRUE)
7833  {
7834  memcpy(page_display_info.carousel_page_header, collated_page_ptr->header, MAX_COLUMN);
7835  }
7836  page_display_info.carousel_page_updated = TRUE;
7837 
7838  STB_OSSemaphoreSignal(page_display_info.carousel_page_semaphore);
7839  }
7840  }
7841  }
7842 
7843  CheckPageCaching(collated_page_ptr, &page_reference_data, pts_valid, pts);
7844  }
7845  }
7846 
7847  FUNCTION_FINISH(NotifyPageCollated);
7848 }
7849 
7862 static BOOLEAN InitialiseDisplayTask(void)
7863 {
7864  BOOLEAN retval;
7865 
7866  FUNCTION_START(InitialiseDisplayTask);
7867 
7868  retval = FALSE;
7869 
7870  if (display_task_semaphore == NULL)
7871  {
7872  display_task_semaphore = STB_OSCreateSemaphore();
7873  }
7874  if (display_task_semaphore != NULL)
7875  {
7876  STB_OSSemaphoreWait(display_task_semaphore);
7877 
7878  display_task_ptr = STB_OSCreateTask(DisplayUpdateTask, NULL, DISPLAY_TASK_STACK_SIZE,
7879  DISPLAY_TASK_PRIORITY, (U8BIT *)"EBUTT_DISPLAY");
7880  if (display_task_ptr)
7881  {
7882  retval = TRUE;
7883  }
7884  }
7885 
7886  FUNCTION_FINISH(InitialiseDisplayTask);
7887 
7888  return(retval);
7889 }
7890 
7903 static void KillDisplayTask(void)
7904 {
7905  FUNCTION_START(KillDisplayTask);
7906 
7907  if (display_task_ptr != NULL)
7908  {
7909  STB_OSSemaphoreWait(display_task_semaphore);
7910 
7911  STB_OSDestroyTask(display_task_ptr);
7912  display_task_ptr = NULL;
7913  }
7914 
7915  FUNCTION_FINISH(KillDisplayTask);
7916 }
7917 
7930 static BOOLEAN IsNationalOptionSubsetIndex(U8BIT character_index, U8BIT *subset_offset)
7931 {
7932  U8BIT option_subset;
7933  BOOLEAN retval;
7934 
7935  FUNCTION_START(IsNationalOptionSubsetIndex);
7936 
7937  retval = FALSE;
7938 
7939  if ((character_index >= 0x20) &&
7940  (character_index <= 0x7f))
7941  {
7942  option_subset = option_subset_array[character_index - 0x20];
7943 
7944  if (option_subset)
7945  {
7946  *subset_offset = subset_offset_array[option_subset];
7947 
7948  retval = TRUE;
7949  }
7950  }
7951 
7952  FUNCTION_FINISH(IsNationalOptionSubsetIndex);
7953 
7954  return(retval);
7955 }
7956 
7971 static void GetTripletFields(U32BIT triplet_value, U8BIT *address, U8BIT *mode, U8BIT *data)
7972 {
7973  FUNCTION_START(GetTripletFields);
7974 
7975  *address = (U8BIT) (triplet_value & 0x00003fL);
7976  *mode = (U8BIT)((triplet_value & 0x0007c0L) >> 6L);
7977  *data = (U8BIT)((triplet_value & 0x03f800L) >> 11L);
7978 
7979  FUNCTION_FINISH(GetTripletFields);
7980 }
7981 
7996 static void DecodeTeletextPageBody(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN enforce_header_display)
7997 {
7998  U8BIT foreground_colour, background_colour, foreground_index, background_index;
7999  U8BIT default_mapping, second_mapping, hold_mosaics_char;
8000  U8BIT subset_offset, current_source_char, previous_source_char;
8001  U8BIT default_row_background_colour;
8002  U8BIT triplet_address, triplet_mode, triplet_data;
8003  U16BIT row, column, last_column;
8004  U16BIT packet_index, triplet_index, font_index, character_offset, diacritic_offset, equivalence_index;
8005  U32BIT triplet_value;
8006  U8BIT *source_data_ptr;
8007  U8BIT *triplet_ptr;
8008  BOOLEAN double_height, flashing, concealed, boxed, boxing_required;
8009  BOOLEAN mosaic_enabled, contiguous_mosaic_enabled, hold_mosaic_enabled;
8010  BOOLEAN header_required, body_required, valid_row;
8011  BOOLEAN default_row_background_colour_defined, double_height_in_previous_line, terminated;
8012  const S_CHARACTER_SET_MAPPING *default_mapping_ptr;
8013  const S_CHARACTER_SET_MAPPING *second_mapping_ptr;
8014  const S_CHARACTER_SET_MAPPING *current_mapping_ptr;
8015  S_TELETEXT_CHARACTER *destination_data_ptr;
8016 
8017  static const U8BIT diacritic_substitution_offset[16] = { 0, 0x30, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20,
8018  0x20, 0x30, 0, 0x20, 0, 0, 0, 0x30 };
8019 
8020  FUNCTION_START(DecodeTeletextPageBody);
8021 
8022  current_mapping_ptr = NULL;
8023 
8024  // Get the default and second character font set mappings for this page.
8025  GetBasicPageDisplayInfo(display_info_ptr, &default_mapping, &second_mapping, &boxing_required,
8026  &header_required, &body_required,
8027  &default_row_background_colour_defined,
8028  &default_row_background_colour);
8029 
8030  default_mapping_ptr = &character_set_mapping_array[default_mapping];
8031  if (second_mapping == 0xff)
8032  {
8033  second_mapping_ptr = NULL;
8034  }
8035  else
8036  {
8037  second_mapping_ptr = &character_set_mapping_array[second_mapping];
8038  }
8039 
8040  display_info_ptr->render_required = TRUE;
8041 
8042  if ((boxing_required || !show_header_row) && (page_control_info.state == PAGE_CONTROL_STATE_IDLE))
8043  {
8044  display_info_ptr->screen_colour = PALETTE_BACKGROUND_TRANSPARENT;
8045  }
8046  else
8047  {
8048  display_info_ptr->screen_colour = PALETTE_BACKGROUND_BLACK;
8049  }
8050 
8051  display_info_ptr->clear_screen = TRUE;
8052 
8053  display_info_ptr->palette_update_required = TRUE;
8054 
8055  double_height_in_previous_line = FALSE;
8056 
8057  display_info_ptr->palette_attribute_array[0].effect_mask = PALETTE_EFFECT_UNDEFINED;
8058  display_info_ptr->palette_alias_array[0].fore_colour = PALETTE_BACKGROUND_TRANSPARENT;
8059 
8060  for (row = 0; row <= 24; row++)
8061  {
8062  valid_row = FALSE;
8063 
8064  if (row == 0)
8065  {
8066  if (display_info_ptr->page_source.is_header_defined == TRUE)
8067  {
8068  if ((header_required == TRUE) ||
8069  (enforce_header_display == TRUE))
8070  {
8071  valid_row = TRUE;
8072  }
8073  }
8074  }
8075  else
8076  {
8077  if ((double_height_in_previous_line == FALSE) &&
8078  (body_required == TRUE) &&
8079  (display_info_ptr->page_source.display_data_defined_mask & (1 << row)))
8080  {
8081  valid_row = TRUE;
8082  }
8083  }
8084 
8085  if (valid_row == TRUE)
8086  {
8087  display_info_ptr->valid_row[row] = TRUE;
8088  display_info_ptr->render_row[row] = TRUE;
8089 
8090  // We are displaying a new row of characters, so set all the status flags to their
8091  // default settings.
8092  current_mapping_ptr = default_mapping_ptr;
8093 
8094  if (row == 0)
8095  {
8096  if (boxing_required == TRUE)
8097  {
8098  for (column = 0; column != 8; column++)
8099  {
8100  display_info_ptr->character_map[0][column].foreground_index = PALETTE_FOREGROUND_UNBOXED;
8101  }
8102  }
8103  else
8104  {
8105  for (column = 0; column != 8; column++)
8106  {
8107  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK;
8108  }
8109  }
8110 
8111  column = 8;
8112  if (display_info_ptr->page_clock_valid == TRUE)
8113  {
8114  last_column = 39;
8115  }
8116  else
8117  {
8118  last_column = 31;
8119  }
8120  }
8121  else
8122  {
8123  column = 0;
8124  last_column = 39;
8125  }
8126  foreground_colour = 7;
8127  if (default_row_background_colour_defined == TRUE)
8128  {
8129  background_colour = default_row_background_colour;
8130  }
8131  else
8132  {
8133  background_colour = 0;
8134  }
8135 
8136  double_height = FALSE;
8137  flashing = FALSE;
8138  concealed = FALSE;
8139  boxed = FALSE;
8140  mosaic_enabled = FALSE;
8141  contiguous_mosaic_enabled = TRUE;
8142  hold_mosaic_enabled = FALSE;
8143  hold_mosaics_char = 0; // white-space
8144  previous_source_char = 0;
8145 
8146  GetCharacterPaletteIndexes(display_info_ptr,
8147  &foreground_index, &background_index,
8148  foreground_colour, background_colour,
8149  flashing, concealed,
8150  boxing_required, boxed, FALSE);
8151 
8152  if (row == 0)
8153  {
8154  source_data_ptr = &display_info_ptr->page_source.header[8];
8155  destination_data_ptr = &display_info_ptr->character_map[row][8];
8156  }
8157  else
8158  {
8159  source_data_ptr = display_info_ptr->page_source.display_data[row];
8160  destination_data_ptr = display_info_ptr->character_map[row];
8161  }
8162 
8163 
8164  while (column <= last_column)
8165  {
8166  // Default setting for the caracter map entry.
8167  if (mosaic_enabled == TRUE)
8168  {
8169  if (hold_mosaic_enabled == TRUE)
8170  {
8171  destination_data_ptr->info = (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
8172  hold_mosaics_char;
8173  }
8174  else
8175  {
8176  destination_data_ptr->info = FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8;
8177  }
8178 
8179  if (contiguous_mosaic_enabled == FALSE)
8180  {
8181  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
8182  }
8183  }
8184  else
8185  {
8186  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
8187  {
8188  destination_data_ptr->info = FONT_INDEX_LATIN_G0_SET << 8;
8189  }
8190  else
8191  {
8192  destination_data_ptr->info = current_mapping_ptr->G0_index << 8;
8193  }
8194  }
8195 
8196  if (double_height == TRUE)
8197  {
8198  destination_data_ptr->info |= TELETEXT_CHARACTER_DOUBLE_HEIGHT;
8199  }
8200 
8201  destination_data_ptr->diacritic_info = 0;
8202 
8203  destination_data_ptr->foreground_index = foreground_index;
8204  destination_data_ptr->background_index = background_index;
8205 
8206  if (GetParity7Byte(*source_data_ptr, &current_source_char) == TRUE)
8207  {
8208  switch (current_source_char & 0x70)
8209  {
8210  case 0x00: // Standard spacing attributes
8211  {
8212  switch (current_source_char & 0x0f)
8213  {
8214  case 0x08: // Flash ("set after")
8215  {
8216  flashing = TRUE;
8217  GetCharacterPaletteIndexes(display_info_ptr,
8218  &foreground_index, &background_index,
8219  foreground_colour, background_colour,
8220  flashing, concealed,
8221  boxing_required, boxed, FALSE);
8222 
8223  display_info_ptr->flash_required = TRUE;
8224  break;
8225  }
8226  case 0x09: // Steady ("set at")
8227  {
8228  flashing = FALSE;
8229  GetCharacterPaletteIndexes(display_info_ptr,
8230  &foreground_index, &background_index,
8231  foreground_colour, background_colour,
8232  flashing, concealed,
8233  boxing_required, boxed, FALSE);
8234 
8235  destination_data_ptr->foreground_index = foreground_index;
8236  break;
8237  }
8238  case 0x0a: // End Box ("set after")
8239  {
8240  if ((boxing_required == TRUE) &&
8241  (boxed == TRUE))
8242  {
8243  boxed = FALSE;
8244  GetCharacterPaletteIndexes(display_info_ptr,
8245  &foreground_index, &background_index,
8246  foreground_colour, background_colour,
8247  flashing, concealed,
8248  boxing_required, boxed, FALSE);
8249  }
8250  break;
8251  }
8252  case 0x0b: // Start Box ("set after")
8253  {
8254  if ((boxing_required == TRUE) &&
8255  (boxed == FALSE))
8256  {
8257  if (previous_source_char == 0x0b)
8258  {
8259  boxed = TRUE;
8260  GetCharacterPaletteIndexes(display_info_ptr,
8261  &foreground_index, &background_index,
8262  foreground_colour, background_colour,
8263  flashing, concealed,
8264  boxing_required, boxed, FALSE);
8265  }
8266  }
8267  break;
8268  }
8269  case 0x0c: // Normal Size ("set at")
8270  {
8271  if (double_height == TRUE)
8272  {
8273  double_height = FALSE;
8274  destination_data_ptr->info &= ~TELETEXT_CHARACTER_DOUBLE_HEIGHT;
8275 
8276  hold_mosaics_char = 0; // white-space
8277  }
8278  break;
8279  }
8280  case 0x0d: // Double Height ("set after")
8281  {
8282  if (double_height == FALSE)
8283  {
8284  if ((row > 0) && (row < 24))
8285  {
8286  double_height = TRUE;
8287  double_height_in_previous_line = TRUE;
8288  }
8289  hold_mosaics_char = 0; // white-space
8290  }
8291  break;
8292  }
8293  case 0x0e: // Double Width ("set after")
8294  case 0x0f: // Double Size ("set after")
8295  {
8296  // Ignored by this decoder!
8297  break;
8298  }
8299  default: // 0x00 to 0x07 - Alpha Black to Alpha White ("set after")
8300  {
8301  foreground_colour = current_source_char & 0x07;
8302  concealed = FALSE;
8303  mosaic_enabled = FALSE;
8304  hold_mosaic_enabled = FALSE;
8305  hold_mosaics_char = 0; // white-space
8306 
8307  GetCharacterPaletteIndexes(display_info_ptr,
8308  &foreground_index, &background_index,
8309  foreground_colour, background_colour,
8310  flashing, concealed,
8311  boxing_required, boxed, FALSE);
8312  break;
8313  }
8314  }
8315  break;
8316  }
8317  case 0x10:
8318  {
8319  switch (current_source_char & 0x0f)
8320  {
8321  case 0x08: // Conceal ("set at")
8322  {
8323  concealed = TRUE;
8324  GetCharacterPaletteIndexes(display_info_ptr,
8325  &foreground_index, &background_index,
8326  foreground_colour, background_colour,
8327  flashing, concealed,
8328  boxing_required, boxed, FALSE);
8329 
8330  destination_data_ptr->foreground_index = foreground_index;
8331 
8332  display_info_ptr->reveal_available = TRUE;
8333  break;
8334  }
8335  case 0x09: // Contiguous Mosiac Graphics ("set at")
8336  {
8337  contiguous_mosaic_enabled = TRUE;
8338 
8339  destination_data_ptr->info &= ~TELETEXT_CHARACTER_SEPERATED_MOSAIC;
8340  break;
8341  }
8342  case 0x0a: // Seperated Mosiac Graphics ("set at")
8343  {
8344  contiguous_mosaic_enabled = FALSE;
8345 
8346  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
8347  break;
8348  }
8349  case 0x0b: // ASCII 0x1b - ESC charecter used to toggle between default and
8350  // second G0 sets.
8351  {
8352  if (second_mapping_ptr != NULL)
8353  {
8354  if (current_mapping_ptr == default_mapping_ptr)
8355  {
8356  current_mapping_ptr = second_mapping_ptr;
8357  }
8358  else
8359  {
8360  current_mapping_ptr = default_mapping_ptr;
8361  }
8362  }
8363  break;
8364  }
8365  case 0x0c: // Black Background ("set at")
8366  {
8367  if (default_row_background_colour_defined == TRUE)
8368  {
8369  background_colour = default_row_background_colour;
8370  }
8371  else
8372  {
8373  background_colour = 0;
8374  }
8375 
8376  GetCharacterPaletteIndexes(display_info_ptr,
8377  &foreground_index, &background_index,
8378  foreground_colour, background_colour,
8379  flashing, concealed,
8380  boxing_required, boxed, FALSE);
8381 
8382  // NB - the forcground colour is also set here in case a new flashing or
8383  // conceal attrubute has been genereated.
8384  destination_data_ptr->foreground_index = foreground_index;
8385  destination_data_ptr->background_index = background_index;
8386  break;
8387  }
8388  case 0x0d: // New Background ("set at")
8389  {
8390  background_colour = foreground_colour;
8391 
8392  GetCharacterPaletteIndexes(display_info_ptr,
8393  &foreground_index, &background_index,
8394  foreground_colour, background_colour,
8395  flashing, concealed,
8396  boxing_required, boxed, FALSE);
8397 
8398  // NB - the forcground colour is also set here in case a new flashing or
8399  // conceal attrubute has been genereated.
8400  destination_data_ptr->foreground_index = foreground_index;
8401  destination_data_ptr->background_index = background_index;
8402  break;
8403  }
8404  case 0x0e: // Hold Mosaics ("set at")
8405  {
8406  if (hold_mosaic_enabled == FALSE)
8407  {
8408  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8409  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
8410  destination_data_ptr->info |= (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
8411  hold_mosaics_char;
8412 
8413  hold_mosaic_enabled = TRUE;
8414  }
8415  break;
8416  }
8417  case 0x0f: // Release Mosaics ("set after")
8418  {
8419  if (mosaic_enabled == TRUE)
8420  {
8421  hold_mosaic_enabled = FALSE;
8422  }
8423  break;
8424  }
8425  default: // 0x0 to 0x07 - Mosaic Black to Mosaic White ("set after")
8426  {
8427  foreground_colour = current_source_char & 0x07;
8428  concealed = FALSE;
8429  mosaic_enabled = TRUE;
8430 
8431  GetCharacterPaletteIndexes(display_info_ptr,
8432  &foreground_index, &background_index,
8433  foreground_colour, background_colour,
8434  flashing, concealed,
8435  boxing_required, boxed, FALSE);
8436  break;
8437  }
8438  }
8439  break;
8440  }
8441  default: // 0x20 to 0x7f - Font character
8442  {
8443  destination_data_ptr->info &= ~TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
8444  destination_data_ptr->info |= current_source_char - 0x20;
8445 
8446  if (mosaic_enabled == TRUE)
8447  {
8448  if (((current_source_char & 0x70) == 0x40) ||
8449  ((current_source_char & 0x70) == 0x50))
8450  {
8451  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
8452  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
8453  {
8454  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8455  TELETEXT_CHARACTER_BITMAP_INDEX_MASK |
8456  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
8457 
8458  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
8459 
8460  destination_data_ptr->info |= subset_offset +
8461  current_mapping_ptr->national_option_subset_index;
8462  }
8463  else
8464  {
8465  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8466  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
8467 
8468  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
8469  {
8470  destination_data_ptr->info |= FONT_INDEX_LATIN_G0_SET << 8;
8471  }
8472  else
8473  {
8474  destination_data_ptr->info |= current_mapping_ptr->G0_index << 8;
8475  }
8476  }
8477  }
8478  else
8479  {
8480  hold_mosaics_char = current_source_char - 0x20;
8481  }
8482  }
8483  else
8484  {
8485  if ((current_mapping_ptr->G0_index == FONT_INDEX_LATIN_G0_SET) ||
8486  (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED))
8487  {
8488  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
8489  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
8490  {
8491  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8492  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
8493 
8494  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
8495 
8496  destination_data_ptr->info |= subset_offset +
8497  current_mapping_ptr->national_option_subset_index;
8498  }
8499  }
8500  }
8501 
8502  break;
8503  }
8504  }
8505  }
8506 
8507  previous_source_char = current_source_char;
8508  source_data_ptr++;
8509  destination_data_ptr++;
8510  column++;
8511  }
8512 
8513  if (row == 0)
8514  {
8515  if (boxing_required == FALSE)
8516  {
8517  for (column = last_column + 1; column != MAX_COLUMN; column++)
8518  {
8519  display_info_ptr->character_map[0][column].foreground_index =
8520  display_info_ptr->character_map[0][31].foreground_index;
8521  display_info_ptr->character_map[0][column].background_index =
8522  display_info_ptr->character_map[0][31].background_index;
8523  }
8524  }
8525  }
8526  }
8527  else
8528  {
8529  if (double_height_in_previous_line == TRUE)
8530  {
8531  for (column = 0; column != MAX_COLUMN; column++)
8532  {
8533  display_info_ptr->character_map[row][column].info = 0;
8534  display_info_ptr->character_map[row][column].foreground_index =
8535  display_info_ptr->character_map[row - 1][column].foreground_index;
8536  display_info_ptr->character_map[row][column].background_index =
8537  display_info_ptr->character_map[row - 1][column].background_index;
8538  }
8539 
8540  display_info_ptr->valid_row[row] = TRUE;
8541  display_info_ptr->render_row[row] = TRUE;
8542 
8543  double_height_in_previous_line = FALSE;
8544  }
8545  else
8546  {
8547  DBGPRINT("Clear row %d [%d,%d]", row, display_info_ptr->valid_row[row], display_info_ptr->render_row[row]);
8548  // No data for this row, so clear it.
8549  display_info_ptr->valid_row[row] = FALSE;
8550  }
8551  }
8552  }
8553 
8554  row = 0;
8555  column = 0;
8556  terminated = FALSE;
8557 
8558  if (display_info_ptr->page_source.basic_enhancement_data_defined_mask)
8559  {
8560  for (packet_index = 0; (packet_index != 16) && (terminated == FALSE); packet_index++)
8561  {
8562  if (display_info_ptr->page_source.basic_enhancement_data_defined_mask & (1 << packet_index))
8563  {
8564  triplet_ptr = &display_info_ptr->page_source.basic_enhancement_data[packet_index][1];
8565 
8566  for (triplet_index = 0; (triplet_index != 13) && (terminated == FALSE); triplet_index++)
8567  {
8568  if (GetHammimg24Value((void *)triplet_ptr, &triplet_value) == TRUE)
8569  {
8570  GetTripletFields(triplet_value, &triplet_address, &triplet_mode, &triplet_data);
8571 
8572  if (triplet_address >= MAX_COLUMN)
8573  {
8574  // Row address group
8575  switch (triplet_mode)
8576  {
8577  case 4: // Set Active Position
8578  {
8579  if (triplet_address == MAX_COLUMN)
8580  {
8581  row = 24;
8582  }
8583  else
8584  {
8585  row = triplet_address - MAX_COLUMN;
8586  }
8587  if (triplet_data < MAX_COLUMN)
8588  {
8589  column = triplet_data;
8590  }
8591  break;
8592  }
8593  case 7: // Address Display Row 0
8594  {
8595  row = 0;
8596  column = 0;
8597  break;
8598  }
8599  case 31: // Termination Marker
8600  {
8601  terminated = TRUE;
8602  break;
8603  }
8604  }
8605  }
8606  else
8607  {
8608  // Column address group
8609  switch (triplet_mode)
8610  {
8611  case 1: // Block Mosaic Character from the G1 set
8612  {
8613  column = triplet_address;
8614 
8615  if ((row != 0) ||
8616  (column >= 8))
8617  {
8618  if (triplet_data >= 0x20)
8619  {
8620  if (((triplet_data & 0x70) == 0x40) ||
8621  ((triplet_data & 0x70) == 0x50))
8622  {
8623  // Uses character from gurrent G0 set, so nothing to do here!
8624  }
8625  else
8626  {
8627  destination_data_ptr = &display_info_ptr->character_map[row][column];
8628 
8629  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8630  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
8631 
8632  destination_data_ptr->info |= FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8;
8633  destination_data_ptr->info |= triplet_data - 0x20;
8634  }
8635  }
8636  }
8637  break;
8638  }
8639  case 2: // Line Drawing or Smoothed Mosaic Character from the G3 set
8640  {
8641  column = triplet_address;
8642 
8643  if ((row != 0) ||
8644  (column >= 8))
8645  {
8646  if (triplet_data >= 0x20)
8647  {
8648  if ((triplet_data != 0x6e) &&
8649  (triplet_data != 0x6f) &&
8650  (triplet_data != 0x7e) &&
8651  (triplet_data != 0x7f))
8652  {
8653  destination_data_ptr = &display_info_ptr->character_map[row][column];
8654 
8655  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8656  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
8657 
8658  destination_data_ptr->info |= FONT_INDEX_G3_SMOOTH_MOSAICS_LINE_DRAWING_SET << 8;
8659  destination_data_ptr->info |= triplet_data - 0x20;
8660  }
8661  }
8662  }
8663  break;
8664  }
8665  case 9: // Character from the current G0 Set
8666  {
8667  column = triplet_address;
8668 
8669  if (triplet_data >= 0x20)
8670  {
8671  destination_data_ptr = &display_info_ptr->character_map[row][column];
8672 
8673  destination_data_ptr->info &= ~TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
8674 
8675  destination_data_ptr->info |= triplet_data - 0x20;
8676  }
8677  break;
8678  }
8679  case 15: // Character from the G2 Supplimentary Set
8680  {
8681  column = triplet_address;
8682 
8683  if (triplet_data >= 0x20)
8684  {
8685  destination_data_ptr = &display_info_ptr->character_map[row][column];
8686 
8687  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
8688  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
8689 
8690  if (current_mapping_ptr->G2_index == FONT_INDEX_UNDEFINED)
8691  {
8692  destination_data_ptr->info |= FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET << 8;
8693  }
8694  else
8695  {
8696  destination_data_ptr->info |= current_mapping_ptr->G2_index << 8;
8697  }
8698  destination_data_ptr->info |= triplet_data - 0x20;
8699  }
8700  break;
8701  }
8702  default:
8703  {
8704  if (triplet_mode >= 16)
8705  {
8706  column = triplet_address;
8707 
8708  destination_data_ptr = &display_info_ptr->character_map[row][column];
8709 
8710  destination_data_ptr->info &= ~TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
8711 
8712  if (triplet_mode == 16)
8713  {
8714  if (triplet_data == 0x2a)
8715  {
8716  font_index = (destination_data_ptr->info & TELETEXT_CHARACTER_FONT_INDEX_MASK) >> 8;
8717 
8718  if ((font_index == FONT_INDEX_LATIN_G0_SET) ||
8719  (font_index == FONT_INDEX_CYRILLIC_G0_SET_OPTION_1_SERBIAN_CROATIAN) ||
8720  (font_index == FONT_INDEX_CYRILLIC_G0_SET_OPTION_2_RUSSIAN_BULGARIAN) ||
8721  (font_index == FONT_INDEX_CYRILLIC_G0_SET_OPTION_3_UKRANIAN) ||
8722  (font_index == FONT_INDEX_GREEK_G0_SET) ||
8723  (font_index == FONT_INDEX_ARABIC_G0_SET) ||
8724  (font_index == FONT_INDEX_HEBREW_G0_SET))
8725  {
8726  destination_data_ptr->info &= ~TELETEXT_CHARACTER_FONT_INDEX_MASK;
8727 
8728  destination_data_ptr->info |= FONT_INDEX_LATIN_G0_SET << 8;
8729 
8730  destination_data_ptr->info |= 0x20; // '*' changed to '@'
8731  }
8732  else
8733  {
8734  destination_data_ptr->info |= 0x0a;
8735  }
8736 
8737  destination_data_ptr->diacritic_info = 0;
8738  }
8739  else if (triplet_data >= 0x20)
8740  {
8741  destination_data_ptr->info |= triplet_data - 0x20;
8742 
8743  destination_data_ptr->diacritic_info = 0;
8744  }
8745  }
8746  else
8747  {
8748  if (triplet_data >= 0x20)
8749  {
8750  font_index = (destination_data_ptr->info & TELETEXT_CHARACTER_FONT_INDEX_MASK) >> 8;
8751  character_offset = triplet_data - 0x20;
8752  diacritic_offset = triplet_mode - 16;
8753 
8754  for (equivalence_index = 0; diacritic_equivalent_array[equivalence_index].font_index != FONT_INDEX_UNDEFINED; equivalence_index++)
8755  {
8756  if ((diacritic_equivalent_array[equivalence_index].font_index == font_index) &&
8757  (diacritic_equivalent_array[equivalence_index].character_offset == character_offset) &&
8758  (diacritic_equivalent_array[equivalence_index].diacritic_offset == diacritic_offset))
8759  {
8760  destination_data_ptr->info &= ~TELETEXT_CHARACTER_FONT_INDEX_MASK;
8761 
8762  destination_data_ptr->info |= diacritic_equivalent_array[equivalence_index].alternative_font_index << 8;
8763 
8764  destination_data_ptr->info |= diacritic_equivalent_array[equivalence_index].alternative_character_offset;
8765 
8766  destination_data_ptr->diacritic_info = 0;
8767  break;
8768  }
8769  }
8770 
8771  if (diacritic_equivalent_array[equivalence_index].font_index == FONT_INDEX_UNDEFINED)
8772  {
8773  if ((diacritic_substitutions_avaialable == TRUE) &&
8774  (diacritic_substitution_offset[diacritic_offset] != 0))
8775  {
8776  for (equivalence_index = 0; diacritic_substitution_array[equivalence_index].font_index != FONT_INDEX_UNDEFINED; equivalence_index++)
8777  {
8778  if ((diacritic_substitution_array[equivalence_index].font_index == font_index) &&
8779  (diacritic_substitution_array[equivalence_index].character_offset == character_offset))
8780  {
8781  destination_data_ptr->info &= ~TELETEXT_CHARACTER_FONT_INDEX_MASK;
8782 
8783  destination_data_ptr->info |= FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8;
8784 
8785  destination_data_ptr->info |= diacritic_substitution_offset[diacritic_offset] +
8786  diacritic_substitution_array[equivalence_index].alternative_character_offset;
8787 
8788  if (current_mapping_ptr->G2_index == FONT_INDEX_UNDEFINED)
8789  {
8790  destination_data_ptr->diacritic_info = FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET << 8;
8791  }
8792  else
8793  {
8794  destination_data_ptr->diacritic_info = current_mapping_ptr->G2_index << 8;
8795  }
8796  destination_data_ptr->diacritic_info |= 0x20 + diacritic_offset;
8797  break;
8798  }
8799  }
8800  }
8801  }
8802 
8803  if (diacritic_substitution_array[equivalence_index].font_index == FONT_INDEX_UNDEFINED)
8804  {
8805  destination_data_ptr->info |= character_offset;
8806 
8807  if (current_mapping_ptr->G2_index == FONT_INDEX_UNDEFINED)
8808  {
8809  destination_data_ptr->diacritic_info = FONT_INDEX_LATIN_G2_SUPPLIMENTARY_SET << 8;
8810  }
8811  else
8812  {
8813  destination_data_ptr->diacritic_info = current_mapping_ptr->G2_index << 8;
8814  }
8815  destination_data_ptr->diacritic_info |= 0x20 + diacritic_offset;
8816  }
8817  }
8818  }
8819  }
8820  break;
8821  }
8822  }
8823  }
8824  }
8825 
8826  triplet_ptr += 3;
8827  }
8828  }
8829  }
8830  }
8831 
8832  FUNCTION_FINISH(DecodeTeletextPageBody);
8833 }
8834 
8847 static void DecodeTeletextPageNumber(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN video_mix_overridden)
8848 {
8849  U16BIT column;
8850  BOOLEAN default_row_background_colour_defined;
8851  U8BIT default_row_background_colour;
8852  BOOLEAN set_background;
8853 
8854  static U8BIT index_digit_mapping[17] =
8855  {
8856  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
8857  0X21, 0X22, 0X23, 0X24, 0X25, 0X26,
8858  0x0d
8859  };
8860 
8861  FUNCTION_START(DecodeTeletextPageNumber);
8862 
8863  GetBasicPageDisplayInfo(display_info_ptr, NULL, NULL, NULL, NULL, NULL,
8864  &default_row_background_colour_defined,
8865  &default_row_background_colour);
8866 
8867  display_info_ptr->render_required = TRUE;
8868 
8869  if (display_info_ptr->page_index_held == TRUE)
8870  {
8871  for (column = 0; column != 8; column++)
8872  {
8873  display_info_ptr->character_map[0][column].info = FONT_INDEX_LATIN_G0_SET << 8;
8874  display_info_ptr->character_map[0][column].foreground_index = PALETTE_FOREGROUND_RED;
8875  if (default_row_background_colour_defined == TRUE)
8876  {
8877  display_info_ptr->character_map[0][column].background_index = default_row_background_colour;
8878  }
8879  else
8880  {
8881  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK;
8882  }
8883 
8884  display_info_ptr->character_map[0][2].info |= 0x28;
8885  display_info_ptr->character_map[0][3].info |= 0x2f;
8886  display_info_ptr->character_map[0][4].info |= 0x2c;
8887  display_info_ptr->character_map[0][5].info |= 0x24;
8888 
8889  display_info_ptr->palette_update_required = TRUE;
8890  }
8891  }
8892  else
8893  {
8894  for (column = 0; column != 8; column++)
8895  {
8896  display_info_ptr->character_map[0][column].info = FONT_INDEX_LATIN_G0_SET << 8;
8897  display_info_ptr->character_map[0][column].foreground_index = PALETTE_FOREGROUND_WHITE;
8898  if ((display_info_ptr->video_mix_set == TRUE) &&
8899  (video_mix_overridden == TRUE))
8900  {
8901  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK_FIXED;
8902  }
8903  else
8904  {
8905  if (default_row_background_colour_defined == TRUE)
8906  {
8907  display_info_ptr->character_map[0][column].background_index = default_row_background_colour;
8908  }
8909  else
8910  {
8911  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK;
8912  }
8913  }
8914  }
8915 
8916  for (column = 0; column != 3; column++)
8917  {
8918  display_info_ptr->character_map[0][column + 3].info |= index_digit_mapping[display_info_ptr->page_index_digit[column] - PAGE_INDEX_DIGIT_0];
8919  }
8920  }
8921 
8922  /*
8923  * If the header is blank, except for the index number and this is the first time it is being
8924  * displayed the header will be incorrectly transparent and showing the video. Check to see
8925  * if there is any data in the display page or it's copy. If there isn't set the background
8926  * colour to be the index's background colour (so if black, it's black. If transparent it's
8927  * transparent etc.)
8928  */
8929  set_background = TRUE;
8930  for (column = 8; column != MAX_COLUMN; column++)
8931  {
8932  if ((display_info_ptr->character_map[0][column].info != 0x00) &&
8933  (page_display_info.character_map[0][column].info != 0x00))
8934  {
8935  set_background = FALSE;
8936  }
8937  }
8938  if (set_background != FALSE)
8939  {
8940  for (column = 8; column != MAX_COLUMN; column++)
8941  {
8942  display_info_ptr->character_map[0][column].foreground_index = display_info_ptr->character_map[0][0].foreground_index;
8943  display_info_ptr->character_map[0][column].background_index = display_info_ptr->character_map[0][0].background_index;
8944  }
8945  }
8946 
8947  display_info_ptr->valid_row[0] = TRUE;
8948  display_info_ptr->render_row[0] = TRUE;
8949 
8950  FUNCTION_FINISH(DecodeTeletextPageNumber);
8951 }
8952 
8964 static void DecodeTeletextCarouselHeader(S_PAGE_DISPLAY_INFO *display_info_ptr)
8965 {
8966  U8BIT foreground_colour, background_colour, foreground_index, background_index;
8967  U8BIT default_mapping, second_mapping, hold_mosaics_char;
8968  U8BIT subset_offset, current_source_char;
8969  U8BIT default_row_background_colour;
8970  U16BIT column;
8971  U8BIT *source_data_ptr;
8972  BOOLEAN flashing, concealed;
8973  BOOLEAN mosaic_enabled, contiguous_mosaic_enabled, hold_mosaic_enabled;
8974  BOOLEAN default_row_background_colour_defined;
8975  const S_CHARACTER_SET_MAPPING *default_mapping_ptr;
8976  const S_CHARACTER_SET_MAPPING *second_mapping_ptr;
8977  const S_CHARACTER_SET_MAPPING *current_mapping_ptr;
8978  S_TELETEXT_CHARACTER *destination_data_ptr;
8979 
8980  FUNCTION_START(DecodeTeletextCarouselHeader);
8981 
8982  // Get the default and second character font set mappings for this page.
8983  GetBasicPageDisplayInfo(display_info_ptr, &default_mapping, &second_mapping, NULL,
8984  NULL, NULL,
8985  &default_row_background_colour_defined,
8986  &default_row_background_colour);
8987 
8988  default_mapping_ptr = &character_set_mapping_array[default_mapping];
8989  if (second_mapping == 0xff)
8990  {
8991  second_mapping_ptr = NULL;
8992  }
8993  else
8994  {
8995  second_mapping_ptr = &character_set_mapping_array[second_mapping];
8996  }
8997 
8998  display_info_ptr->render_required = TRUE;
8999  display_info_ptr->palette_update_required = TRUE;
9000 
9001  display_info_ptr->valid_row[0] = TRUE;
9002  display_info_ptr->render_row[0] = TRUE;
9003 
9004  // We are displaying a new row of characters, so set all the status flags to their
9005  // default settings.
9006  current_mapping_ptr = default_mapping_ptr;
9007 
9008  foreground_colour = 2;
9009  if (default_row_background_colour_defined == TRUE)
9010  {
9011  background_colour = default_row_background_colour;
9012  }
9013  else
9014  {
9015  background_colour = 0;
9016  }
9017 
9018  flashing = FALSE;
9019  concealed = FALSE;
9020  mosaic_enabled = FALSE;
9021  contiguous_mosaic_enabled = TRUE;
9022  hold_mosaic_enabled = FALSE;
9023  hold_mosaics_char = 0; // white-space
9024 
9025  GetCharacterPaletteIndexes(display_info_ptr,
9026  &foreground_index, &background_index,
9027  foreground_colour, background_colour,
9028  flashing, concealed,
9029  FALSE, FALSE, TRUE);
9030 
9031  source_data_ptr = &display_info_ptr->carousel_page_header[8];
9032  destination_data_ptr = &display_info_ptr->character_map[0][8];
9033 
9034  for (column = 8; column != MAX_COLUMN; column++)
9035  {
9036  // Default setting for the caracter map entry.
9037  if (mosaic_enabled == TRUE)
9038  {
9039  if (hold_mosaic_enabled == TRUE)
9040  {
9041  destination_data_ptr->info = (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
9042  hold_mosaics_char;
9043  }
9044  else
9045  {
9046  destination_data_ptr->info = FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8;
9047  }
9048 
9049  if (contiguous_mosaic_enabled == FALSE)
9050  {
9051  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9052  }
9053  }
9054  else
9055  {
9056  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
9057  {
9058  destination_data_ptr->info = FONT_INDEX_LATIN_G0_SET << 8;
9059  }
9060  else
9061  {
9062  destination_data_ptr->info = current_mapping_ptr->G0_index << 8;
9063  }
9064  }
9065 
9066  destination_data_ptr->foreground_index = foreground_index;
9067  destination_data_ptr->background_index = background_index;
9068 
9069  if (GetParity7Byte(*source_data_ptr, &current_source_char) == TRUE)
9070  {
9071  switch (current_source_char & 0x70)
9072  {
9073  case 0x00: // Standard spacing attributes
9074  {
9075  switch (current_source_char & 0x0f)
9076  {
9077  case 0x08: // Flash ("set after")
9078  {
9079  flashing = TRUE;
9080  GetCharacterPaletteIndexes(display_info_ptr,
9081  &foreground_index, &background_index,
9082  foreground_colour, background_colour,
9083  flashing, concealed,
9084  FALSE, FALSE, TRUE);
9085  break;
9086  }
9087  case 0x09: // Steady ("set at")
9088  {
9089  flashing = FALSE;
9090  GetCharacterPaletteIndexes(display_info_ptr,
9091  &foreground_index, &background_index,
9092  foreground_colour, background_colour,
9093  flashing, concealed,
9094  FALSE, FALSE, TRUE);
9095 
9096  destination_data_ptr->foreground_index = foreground_index;
9097  break;
9098  }
9099  case 0x0a: // End Box ("set after")
9100  {
9101  break;
9102  }
9103  case 0x0b: // Start Box ("set after")
9104  {
9105  break;
9106  }
9107  case 0x0c: // Normal Size ("set at")
9108  {
9109  hold_mosaics_char = 0; // white-space
9110  break;
9111  }
9112  case 0x0d: // Double Height ("set after")
9113  {
9114  hold_mosaics_char = 0; // white-space
9115  break;
9116  }
9117  case 0x0e: // Double Width ("set after")
9118  case 0x0f: // Double Size ("set after")
9119  {
9120  // Ignored by this decoder!
9121  break;
9122  }
9123  default: // 0x00 to 0x07 - Alpha Black to Alpha White ("set after")
9124  {
9125  foreground_colour = current_source_char & 0x07;
9126  concealed = FALSE;
9127  mosaic_enabled = FALSE;
9128  hold_mosaic_enabled = FALSE;
9129  hold_mosaics_char = 0; // white-space
9130 
9131  GetCharacterPaletteIndexes(display_info_ptr,
9132  &foreground_index, &background_index,
9133  foreground_colour, background_colour,
9134  flashing, concealed,
9135  FALSE, FALSE, TRUE);
9136  break;
9137  }
9138  }
9139  break;
9140  }
9141  case 0x10:
9142  {
9143  switch (current_source_char & 0x0f)
9144  {
9145  case 0x08: // Conceal ("set at")
9146  {
9147  concealed = TRUE;
9148  GetCharacterPaletteIndexes(display_info_ptr,
9149  &foreground_index, &background_index,
9150  foreground_colour, background_colour,
9151  flashing, concealed,
9152  FALSE, FALSE, TRUE);
9153 
9154  destination_data_ptr->foreground_index = foreground_index;
9155  break;
9156  }
9157  case 0x09: // Contiguous Mosiac Graphics ("set at")
9158  {
9159  contiguous_mosaic_enabled = TRUE;
9160 
9161  destination_data_ptr->info &= ~TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9162  break;
9163  }
9164  case 0x0a: // Seperated Mosiac Graphics ("set at")
9165  {
9166  contiguous_mosaic_enabled = FALSE;
9167 
9168  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9169  break;
9170  }
9171  case 0x0b: // ASCII 0x1b - ESC charecter used to toggle between default and
9172  // second G0 sets.
9173  {
9174  if (second_mapping_ptr != NULL)
9175  {
9176  if (current_mapping_ptr == default_mapping_ptr)
9177  {
9178  current_mapping_ptr = second_mapping_ptr;
9179  }
9180  else
9181  {
9182  current_mapping_ptr = default_mapping_ptr;
9183  }
9184  }
9185  break;
9186  }
9187  case 0x0c: // Black Background ("set at")
9188  {
9189  if (default_row_background_colour_defined == TRUE)
9190  {
9191  background_colour = default_row_background_colour;
9192  }
9193  else
9194  {
9195  background_colour = 0;
9196  }
9197 
9198  GetCharacterPaletteIndexes(display_info_ptr,
9199  &foreground_index, &background_index,
9200  foreground_colour, background_colour,
9201  flashing, concealed,
9202  FALSE, FALSE, TRUE);
9203 
9204  // NB - the forcground colour is also set here in case a new flashing or
9205  // conceal attrubute has been genereated.
9206  destination_data_ptr->foreground_index = foreground_index;
9207  destination_data_ptr->background_index = background_index;
9208  break;
9209  }
9210  case 0x0d: // New Background ("set at")
9211  {
9212  background_colour = foreground_colour;
9213 
9214  GetCharacterPaletteIndexes(display_info_ptr,
9215  &foreground_index, &background_index,
9216  foreground_colour, background_colour,
9217  flashing, concealed,
9218  FALSE, FALSE, TRUE);
9219 
9220  // NB - the forcground colour is also set here in case a new flashing or
9221  // conceal attrubute has been genereated.
9222  destination_data_ptr->foreground_index = foreground_index;
9223  destination_data_ptr->background_index = background_index;
9224  break;
9225  }
9226  case 0x0e: // Hold Mosaics ("set at")
9227  {
9228  if (mosaic_enabled == FALSE)
9229  {
9230  if (hold_mosaic_enabled == FALSE)
9231  {
9232  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9233  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
9234  destination_data_ptr->info |= (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
9235  hold_mosaics_char;
9236 
9237  hold_mosaic_enabled = TRUE;
9238  }
9239  }
9240  break;
9241  }
9242  case 0x0f: // Release Mosaics ("set after")
9243  {
9244  if (mosaic_enabled == TRUE)
9245  {
9246  hold_mosaic_enabled = FALSE;
9247  }
9248  break;
9249  }
9250  default: // 0x0 to 0x07 - Mosaic Black to Mosaic White ("set after")
9251  {
9252  foreground_colour = current_source_char & 0x07;
9253  concealed = FALSE;
9254  mosaic_enabled = TRUE;
9255 
9256  GetCharacterPaletteIndexes(display_info_ptr,
9257  &foreground_index, &background_index,
9258  foreground_colour, background_colour,
9259  flashing, concealed,
9260  FALSE, FALSE, TRUE);
9261  break;
9262  }
9263  }
9264  break;
9265  }
9266  default: // 0x20 to 0x7f - Font character
9267  {
9268  destination_data_ptr->info &= ~TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
9269  destination_data_ptr->info |= current_source_char - 0x20;
9270 
9271  if (mosaic_enabled == TRUE)
9272  {
9273  if (((current_source_char & 0x70) == 0x40) ||
9274  ((current_source_char & 0x70) == 0x50))
9275  {
9276  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
9277  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
9278  {
9279  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9280  TELETEXT_CHARACTER_BITMAP_INDEX_MASK |
9281  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
9282 
9283  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
9284 
9285  destination_data_ptr->info |= subset_offset +
9286  current_mapping_ptr->national_option_subset_index;
9287  }
9288  else
9289  {
9290  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9291  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
9292 
9293  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
9294  {
9295  destination_data_ptr->info |= FONT_INDEX_LATIN_G0_SET << 8;
9296  }
9297  else
9298  {
9299  destination_data_ptr->info |= current_mapping_ptr->G0_index << 8;
9300  }
9301  }
9302  }
9303  else
9304  {
9305  hold_mosaics_char = current_source_char - 0x20;
9306  }
9307  }
9308  else
9309  {
9310  if ((current_mapping_ptr->G0_index == FONT_INDEX_LATIN_G0_SET) ||
9311  (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED))
9312  {
9313  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
9314  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
9315  {
9316  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9317  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
9318 
9319  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
9320 
9321  destination_data_ptr->info |= subset_offset +
9322  current_mapping_ptr->national_option_subset_index;
9323  }
9324  }
9325  }
9326  break;
9327  }
9328  }
9329  }
9330 
9331  source_data_ptr++;
9332  destination_data_ptr++;
9333  }
9334 
9335  if (display_info_ptr->character_map[0][8].background_index == PALETTE_BACKGROUND_BLACK_FIXED)
9336  {
9337  for (column = 0; column != 8; column++)
9338  {
9339  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK_FIXED;
9340  }
9341  for (column = 32; column != MAX_COLUMN; column++)
9342  {
9343  display_info_ptr->character_map[0][column].background_index = PALETTE_BACKGROUND_BLACK_FIXED;
9344  }
9345  }
9346 
9347  FUNCTION_FINISH(DecodeTeletextCarouselHeader);
9348 }
9349 
9362 static void DecodeTeletextClock(S_PAGE_DISPLAY_INFO *display_info_ptr, BOOLEAN video_mix_overridden)
9363 {
9364  U8BIT foreground_colour, background_colour, foreground_index, background_index;
9365  U8BIT default_mapping, second_mapping, hold_mosaics_char;
9366  U8BIT subset_offset, current_source_char;
9367  U8BIT default_row_background_colour;
9368  U16BIT column;
9369  U8BIT *source_data_ptr;
9370  BOOLEAN flashing, concealed, header_required;
9371  BOOLEAN mosaic_enabled, contiguous_mosaic_enabled, hold_mosaic_enabled;
9372  BOOLEAN default_row_background_colour_defined;
9373  const S_CHARACTER_SET_MAPPING *default_mapping_ptr;
9374  const S_CHARACTER_SET_MAPPING *second_mapping_ptr;
9375  const S_CHARACTER_SET_MAPPING *current_mapping_ptr;
9376  S_TELETEXT_CHARACTER *destination_data_ptr;
9377 
9378  FUNCTION_START(DecodeTeletextClock);
9379 
9380  // Get the default and second character font set mappings for this page.
9381  GetBasicPageDisplayInfo(display_info_ptr, &default_mapping, &second_mapping, NULL,
9382  &header_required, NULL,
9383  &default_row_background_colour_defined,
9384  &default_row_background_colour);
9385 
9386  if (header_required == TRUE)
9387  {
9388  default_mapping_ptr = &character_set_mapping_array[default_mapping];
9389  if (second_mapping == 0xff)
9390  {
9391  second_mapping_ptr = NULL;
9392  }
9393  else
9394  {
9395  second_mapping_ptr = &character_set_mapping_array[second_mapping];
9396  }
9397 
9398  display_info_ptr->render_required = TRUE;
9399  display_info_ptr->palette_update_required = TRUE;
9400 
9401  display_info_ptr->valid_row[0] = TRUE;
9402  display_info_ptr->render_row[0] = TRUE;
9403 
9404  // We are displaying a new row of characters, so set all the status flags to their
9405  // default settings.
9406  current_mapping_ptr = default_mapping_ptr;
9407 
9408  foreground_colour = 2;
9409  background_colour = 0;
9410 
9411  flashing = FALSE;
9412  concealed = FALSE;
9413  mosaic_enabled = FALSE;
9414  contiguous_mosaic_enabled = TRUE;
9415  hold_mosaic_enabled = FALSE;
9416  hold_mosaics_char = 0; // white-space
9417 
9418  GetCharacterPaletteIndexes(display_info_ptr,
9419  &foreground_index, &background_index,
9420  foreground_colour, background_colour,
9421  flashing, concealed,
9422  FALSE, FALSE, video_mix_overridden);
9423 
9424  source_data_ptr = &display_info_ptr->time_filler_header_data[24];
9425  destination_data_ptr = &display_info_ptr->character_map[0][32];
9426 
9427  for (column = 32; column != MAX_COLUMN; column++)
9428  {
9429  // Default setting for the caracter map entry.
9430  if (mosaic_enabled == TRUE)
9431  {
9432  if (hold_mosaic_enabled == TRUE)
9433  {
9434  destination_data_ptr->info = (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
9435  hold_mosaics_char;
9436  }
9437  else
9438  {
9439  destination_data_ptr->info = FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8;
9440  }
9441 
9442  if (contiguous_mosaic_enabled == FALSE)
9443  {
9444  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9445  }
9446  }
9447  else
9448  {
9449  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
9450  {
9451  destination_data_ptr->info = FONT_INDEX_LATIN_G0_SET << 8;
9452  }
9453  else
9454  {
9455  destination_data_ptr->info = current_mapping_ptr->G0_index << 8;
9456  }
9457  }
9458 
9459  if (GetParity7Byte(*source_data_ptr, &current_source_char) == TRUE)
9460  {
9461  switch (current_source_char & 0x70)
9462  {
9463  case 0x00: // Standard spacing attributes
9464  {
9465  switch (current_source_char & 0x0f)
9466  {
9467  case 0x08: // Flash ("set after")
9468  {
9469  flashing = TRUE;
9470  GetCharacterPaletteIndexes(display_info_ptr,
9471  &foreground_index, &background_index,
9472  foreground_colour, background_colour,
9473  flashing, concealed,
9474  FALSE, FALSE, video_mix_overridden);
9475  break;
9476  }
9477  case 0x09: // Steady ("set at")
9478  {
9479  flashing = FALSE;
9480  GetCharacterPaletteIndexes(display_info_ptr,
9481  &foreground_index, &background_index,
9482  foreground_colour, background_colour,
9483  flashing, concealed,
9484  FALSE, FALSE, video_mix_overridden);
9485 
9486  destination_data_ptr->foreground_index = foreground_index;
9487  break;
9488  }
9489  case 0x0a: // End Box ("set after")
9490  {
9491  break;
9492  }
9493  case 0x0b: // Start Box ("set after")
9494  {
9495  break;
9496  }
9497  case 0x0c: // Normal Size ("set at")
9498  {
9499  break;
9500  }
9501  case 0x0d: // Double Height ("set after")
9502  {
9503  break;
9504  }
9505  case 0x0e: // Double Width ("set after")
9506  case 0x0f: // Double Size ("set after")
9507  {
9508  // Ignored by this decoder!
9509  break;
9510  }
9511  default: // 0x00 to 0x07 - Alpha Black to Alpha White ("set after")
9512  {
9513  // foreground_colour = current_source_char & 0x07;
9514  // concealed = FALSE;
9515  // mosaic_enabled = FALSE;
9516  // hold_mosaic_enabled = FALSE;
9517  //
9518  // GetCharacterPaletteIndexes(display_info_ptr,
9519  // &foreground_index, &background_index,
9520  // foreground_colour, background_colour,
9521  // flashing, concealed,
9522  // FALSE, FALSE, video_mix_overridden);
9523  break;
9524  }
9525  }
9526  break;
9527  }
9528  case 0x10:
9529  {
9530  switch (current_source_char & 0x0f)
9531  {
9532  case 0x08: // Conceal ("set at")
9533  {
9534  concealed = TRUE;
9535  GetCharacterPaletteIndexes(display_info_ptr,
9536  &foreground_index, &background_index,
9537  foreground_colour, background_colour,
9538  flashing, concealed,
9539  FALSE, FALSE, video_mix_overridden);
9540 
9541  destination_data_ptr->foreground_index = foreground_index;
9542  break;
9543  }
9544  case 0x09: // Contiguous Mosiac Graphics ("set at")
9545  {
9546  contiguous_mosaic_enabled = TRUE;
9547 
9548  destination_data_ptr->info &= ~TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9549  break;
9550  }
9551  case 0x0a: // Seperated Mosiac Graphics ("set at")
9552  {
9553  contiguous_mosaic_enabled = FALSE;
9554 
9555  destination_data_ptr->info |= TELETEXT_CHARACTER_SEPERATED_MOSAIC;
9556  break;
9557  }
9558  case 0x0b: // ASCII 0x1b - ESC charecter used to toggle between default and
9559  // second G0 sets.
9560  {
9561  if (second_mapping_ptr != NULL)
9562  {
9563  if (current_mapping_ptr == default_mapping_ptr)
9564  {
9565  current_mapping_ptr = second_mapping_ptr;
9566  }
9567  else
9568  {
9569  current_mapping_ptr = default_mapping_ptr;
9570  }
9571  }
9572  break;
9573  }
9574  case 0x0c: // Black Background ("set at")
9575  {
9576  // if(default_row_background_colour_defined == TRUE)
9577  // {
9578  // background_colour = default_row_background_colour;
9579  // }
9580  // else
9581  // {
9582  // background_colour = 0;
9583  // }
9584  //
9585  // GetCharacterPaletteIndexes(display_info_ptr,
9586  // &foreground_index, &background_index,
9587  // foreground_colour, background_colour,
9588  // flashing, concealed,
9589  // FALSE, FALSE, video_mix_overridden);
9590 
9591  // NB - the forcground colour is also set here in case a new flashing or
9592  // conceal attrubute has been genereated.
9593  // destination_data_ptr->foreground_index = foreground_index;
9594  // destination_data_ptr->background_index = background_index;
9595  break;
9596  }
9597  case 0x0d: // New Background ("set at")
9598  {
9599  // background_colour = foreground_colour;
9600  //
9601  // GetCharacterPaletteIndexes(display_info_ptr,
9602  // &foreground_index, &background_index,
9603  // foreground_colour, background_colour,
9604  // flashing, concealed,
9605  // FALSE, FALSE, video_mix_overridden);
9606  //
9607  // // NB - the forcground colour is also set here in case a new flashing or
9608  // // conceal attrubute has been genereated.
9609  // destination_data_ptr->foreground_index = foreground_index;
9610  // destination_data_ptr->background_index = background_index;
9611  break;
9612  }
9613  case 0x0e: // Hold Mosaics ("set at")
9614  {
9615  if (mosaic_enabled == FALSE)
9616  {
9617  if (hold_mosaic_enabled == FALSE)
9618  {
9619  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9620  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
9621  destination_data_ptr->info |= (FONT_INDEX_G1_BLOCK_MOSAICS_SET << 8) +
9622  hold_mosaics_char;
9623 
9624  hold_mosaic_enabled = TRUE;
9625  }
9626  }
9627  break;
9628  }
9629  case 0x0f: // Release Mosaics ("set after")
9630  {
9631  if (mosaic_enabled == TRUE)
9632  {
9633  hold_mosaic_enabled = FALSE;
9634  }
9635  break;
9636  }
9637  default: // 0x0 to 0x07 - Mosaic Black to Mosaic White ("set after")
9638  {
9639  // foreground_colour = current_source_char & 0x07;
9640  // concealed = FALSE;
9641  // mosaic_enabled = TRUE;
9642  //
9643  // GetCharacterPaletteIndexes(display_info_ptr,
9644  // &foreground_index, &background_index,
9645  // foreground_colour, background_colour,
9646  // flashing, concealed,
9647  // FALSE, FALSE, video_mix_overridden);
9648  break;
9649  }
9650  }
9651  break;
9652  }
9653  default: // 0x20 to 0x7f - Font character
9654  {
9655  destination_data_ptr->info |= current_source_char - 0x20;
9656 
9657  if (mosaic_enabled == TRUE)
9658  {
9659  if (((current_source_char & 0x70) == 0x40) ||
9660  ((current_source_char & 0x70) == 0x50))
9661  {
9662  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
9663  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
9664  {
9665  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9666  TELETEXT_CHARACTER_BITMAP_INDEX_MASK |
9667  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
9668 
9669  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
9670 
9671  destination_data_ptr->info |= subset_offset +
9672  current_mapping_ptr->national_option_subset_index;
9673  }
9674  else
9675  {
9676  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9677  TELETEXT_CHARACTER_SEPERATED_MOSAIC);
9678 
9679  if (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED)
9680  {
9681  destination_data_ptr->info |= FONT_INDEX_LATIN_G0_SET << 8;
9682  }
9683  else
9684  {
9685  destination_data_ptr->info |= current_mapping_ptr->G0_index << 8;
9686  }
9687  }
9688  }
9689  }
9690  else
9691  {
9692  if ((current_mapping_ptr->G0_index == FONT_INDEX_LATIN_G0_SET) ||
9693  (current_mapping_ptr->G0_index == FONT_INDEX_UNDEFINED))
9694  {
9695  if ((IsNationalOptionSubsetIndex(current_source_char, &subset_offset) == TRUE) &&
9696  (current_mapping_ptr->national_option_subset_index != NATIONALITY_INDEX_UNDEFINED))
9697  {
9698  destination_data_ptr->info &= ~(TELETEXT_CHARACTER_FONT_INDEX_MASK |
9699  TELETEXT_CHARACTER_BITMAP_INDEX_MASK);
9700 
9701  destination_data_ptr->info |= FONT_INDEX_NATIONAL_OPTION_SUBSET << 8;
9702 
9703  destination_data_ptr->info |= subset_offset +
9704  current_mapping_ptr->national_option_subset_index;
9705  }
9706  }
9707  }
9708  break;
9709  }
9710  }
9711  }
9712 
9713  source_data_ptr++;
9714  destination_data_ptr++;
9715  }
9716  }
9717 
9718  FUNCTION_FINISH(DecodeTeletextClock);
9719 }
9720 
9736 static void GetAliasedColourIndexes(S_TELETEXT_CHARACTER *character_ptr, U8BIT *bitmap_ptr,
9737  U8BIT *aliased_foreground_index, U8BIT *aliased_background_index,
9738  S_PAGE_DISPLAY_INFO *display_info_ptr)
9739 {
9740  U16BIT effect_index, alias_index, max_aliases;
9741 
9742  FUNCTION_START(GetAliasedColourIndexes);
9743 
9744  *aliased_foreground_index = character_ptr->foreground_index;
9745  *aliased_background_index = character_ptr->background_index;
9746 
9747  if (*bitmap_ptr & 4)
9748  {
9749  for (effect_index = 0; effect_index != NUM_PALETTE_EFFECTS; effect_index++)
9750  {
9751  if (display_info_ptr->palette_attribute_array[effect_index].effect_mask ==
9752  PALETTE_EFFECT_UNDEFINED)
9753  {
9754  break;
9755  }
9756  }
9757 
9758  if (effect_index != NUM_PALETTE_EFFECTS)
9759  {
9760  max_aliases = (NUM_PALETTE_EFFECTS - effect_index) / 2;
9761 
9762  for (alias_index = 0; alias_index < max_aliases; alias_index++)
9763  {
9764  if (display_info_ptr->palette_alias_array[alias_index].fore_colour ==
9765  PALETTE_BACKGROUND_TRANSPARENT)
9766  {
9767  display_info_ptr->palette_alias_array[alias_index].fore_colour =
9768  character_ptr->foreground_index;
9769  display_info_ptr->palette_alias_array[alias_index].back_colour =
9770  character_ptr->background_index;
9771 
9772  if (alias_index < (max_aliases - 1))
9773  {
9774  display_info_ptr->palette_alias_array[alias_index + 1].fore_colour =
9775  PALETTE_BACKGROUND_TRANSPARENT;
9776  }
9777 
9778  *aliased_foreground_index = PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2);
9779  *aliased_background_index =
9780  PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2) + 1;
9781 
9782  break;
9783  }
9784 
9785  if ((display_info_ptr->palette_alias_array[alias_index].fore_colour ==
9786  character_ptr->foreground_index) &&
9787  (display_info_ptr->palette_alias_array[alias_index].back_colour ==
9788  character_ptr->background_index))
9789  {
9790  *aliased_foreground_index = PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2);
9791  *aliased_background_index =
9792  PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2) + 1;
9793 
9794  break;
9795  }
9796  }
9797  }
9798  }
9799 
9800  FUNCTION_FINISH(GetAliasedColourIndexes);
9801 }
9802 
9819 static void RenderCharacter(U16BIT x, U16BIT y, U16BIT x_scalar, U16BIT y_scalar,
9820  S_TELETEXT_CHARACTER *character_ptr, S_PAGE_DISPLAY_INFO *display_info_ptr)
9821 {
9822  U8BIT row_index, column_index, repeat_index;
9823  U8BIT aliased_foreground_index, aliased_background_index;
9824  U16BIT font_index, bitmap_index, output_row_increment, output_repeat_increment;
9825  BOOLEAN render_done;
9826  U8BIT *output_row_ptr;
9827  U8BIT *output_column_ptr;
9828  U8BIT *output_repeat_ptr;
9829  U8BIT *bitmap_ptr;
9830  U8BIT *diacritic_bitmap_ptr;
9831  U8BIT pixel_colour;
9832 
9833  FUNCTION_START(RenderCharacter);
9834 
9835  render_done = FALSE;
9836 
9837  if (character_ptr->foreground_index == PALETTE_FOREGROUND_UNBOXED)
9838  {
9839  if (character_ptr->info & TELETEXT_CHARACTER_DOUBLE_HEIGHT)
9840  {
9841  y_scalar *= 2;
9842  }
9843  DBGPRINT("x=%d,y=%d", x, y);
9844  STB_OSDRegionFillRect( ttxt_osd_region, x, y,
9845  ebutt_font_ptr->character_width * x_scalar,
9846  ebutt_font_ptr->character_height * y_scalar,
9847  PALETTE_BACKGROUND_TRANSPARENT );
9848 
9849  render_done = TRUE;
9850  }
9851  else
9852  {
9853  font_index = (character_ptr->info & TELETEXT_CHARACTER_FONT_INDEX_MASK) >> 8;
9854 
9855  if (font_index != FONT_INDEX_NO_BITMAP)
9856  {
9857  if (font_index != FONT_INDEX_NATIONAL_OPTION_SUBSET)
9858  {
9859  bitmap_ptr = ebutt_font_ptr->font_table_set_ptr[font_index];
9860  }
9861  else
9862  {
9863  bitmap_ptr = ebutt_font_ptr->font_table_option_subset_ptr;
9864  }
9865 
9866  if (bitmap_ptr != NULL)
9867  {
9868  bitmap_index = character_ptr->info & TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
9869 
9870  bitmap_ptr += ebutt_font_ptr->character_width * ebutt_font_ptr->character_height *
9871  bitmap_index;
9872 
9873  GetAliasedColourIndexes(character_ptr, bitmap_ptr,
9874  &aliased_foreground_index, &aliased_background_index,
9875  display_info_ptr);
9876 
9877  if (character_ptr->diacritic_info)
9878  {
9879  font_index = (character_ptr->diacritic_info & TELETEXT_CHARACTER_FONT_INDEX_MASK) >> 8;
9880 
9881  diacritic_bitmap_ptr = ebutt_font_ptr->font_table_set_ptr[font_index];
9882 
9883  if (diacritic_bitmap_ptr != NULL)
9884  {
9885  bitmap_index = character_ptr->diacritic_info & TELETEXT_CHARACTER_BITMAP_INDEX_MASK;
9886 
9887  diacritic_bitmap_ptr += ebutt_font_ptr->character_width *
9888  ebutt_font_ptr->character_height * bitmap_index;
9889  }
9890  }
9891  else
9892  {
9893  diacritic_bitmap_ptr = NULL;
9894  }
9895 
9896  memset(display_char_buffer, character_ptr->background_index, display_char_buffer_size);
9897 
9898  if (character_ptr->info & TELETEXT_CHARACTER_DOUBLE_HEIGHT)
9899  {
9900  y_scalar *= 2;
9901  }
9902 
9903  output_row_ptr = display_char_buffer;
9904 
9905  output_row_increment = ebutt_font_ptr->character_width * x_scalar * y_scalar;
9906  output_repeat_increment = ebutt_font_ptr->character_width * x_scalar;
9907 
9908  for (row_index = 0; row_index != ebutt_font_ptr->character_height; row_index++)
9909  {
9910  output_column_ptr = output_row_ptr;
9911 
9912  if (character_ptr->info & TELETEXT_CHARACTER_SEPERATED_MOSAIC)
9913  {
9914  if (ebutt_font_ptr->seperator_row_mask & (1L << (U32BIT)row_index))
9915  {
9916  output_row_ptr += output_row_increment;
9917  bitmap_ptr += ebutt_font_ptr->character_width;
9918  if (diacritic_bitmap_ptr != NULL)
9919  {
9920  diacritic_bitmap_ptr += ebutt_font_ptr->character_width;
9921  }
9922  continue;
9923  }
9924  }
9925 
9926  for (column_index = 0; column_index != ebutt_font_ptr->character_width;
9927  column_index++)
9928  {
9929  if (character_ptr->info & TELETEXT_CHARACTER_SEPERATED_MOSAIC)
9930  {
9931  if (ebutt_font_ptr->seperator_column_mask & (1L << (U32BIT)column_index))
9932  {
9933  output_column_ptr += x_scalar;
9934  bitmap_ptr++;
9935  if (diacritic_bitmap_ptr != NULL)
9936  {
9937  diacritic_bitmap_ptr++;
9938  }
9939  continue;
9940  }
9941  }
9942 
9943  if ((*bitmap_ptr) & 1)
9944  {
9945  output_repeat_ptr = output_column_ptr;
9946 
9947  if (*bitmap_ptr == 3)
9948  {
9949  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
9950  {
9951  memset(output_repeat_ptr, character_ptr->foreground_index, x_scalar);
9952 
9953  *output_repeat_ptr = aliased_foreground_index;
9954 
9955  output_repeat_ptr += output_repeat_increment;
9956  }
9957  }
9958  else
9959  {
9960  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
9961  {
9962  memset(output_repeat_ptr, character_ptr->foreground_index, x_scalar);
9963 
9964  output_repeat_ptr += output_repeat_increment;
9965  }
9966  }
9967  }
9968  else
9969  {
9970  if (*bitmap_ptr == 2)
9971  {
9972  output_repeat_ptr = output_column_ptr;
9973  pixel_colour = aliased_background_index;
9974 
9975  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
9976  {
9977  *output_repeat_ptr = pixel_colour;
9978 
9979  output_repeat_ptr += output_repeat_increment;
9980  }
9981  }
9982  }
9983 
9984  if (diacritic_bitmap_ptr != NULL)
9985  {
9986  if ((*diacritic_bitmap_ptr) & 1)
9987  {
9988  output_repeat_ptr = output_column_ptr;
9989 
9990  if ((*diacritic_bitmap_ptr == 3) &&
9991  (*output_repeat_ptr != character_ptr->foreground_index))
9992  {
9993  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
9994  {
9995  memset(output_repeat_ptr, character_ptr->foreground_index, x_scalar);
9996 
9997  *output_repeat_ptr = aliased_foreground_index;
9998 
9999  output_repeat_ptr += output_repeat_increment;
10000  }
10001  }
10002  else
10003  {
10004  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
10005  {
10006  memset(output_repeat_ptr, character_ptr->foreground_index, x_scalar);
10007 
10008  output_repeat_ptr += output_repeat_increment;
10009  }
10010  }
10011  }
10012  else
10013  {
10014  output_repeat_ptr = output_column_ptr;
10015 
10016  if ((*diacritic_bitmap_ptr == 2) &&
10017  (*output_repeat_ptr != character_ptr->foreground_index))
10018  {
10019  pixel_colour = aliased_background_index;
10020 
10021  for (repeat_index = 0; repeat_index != y_scalar; repeat_index++)
10022  {
10023  *output_repeat_ptr = pixel_colour;
10024 
10025  output_repeat_ptr += output_repeat_increment;
10026  }
10027  }
10028  }
10029  }
10030 
10031  output_column_ptr += x_scalar;
10032  bitmap_ptr++;
10033  if (diacritic_bitmap_ptr != NULL)
10034  {
10035  diacritic_bitmap_ptr++;
10036  }
10037  }
10038 
10039  output_row_ptr += output_row_increment;
10040  }
10041  DBGPRINT("x=%d y=%d c=%c", x, y, bitmap_index ? bitmap_index + 0x20 : 176);
10042  STB_OSDDrawBitmapInRegion(ttxt_osd_region, x, y, output_repeat_increment,
10043  ebutt_font_ptr->character_height * y_scalar, display_char_buffer, FALSE);
10044 
10045  render_done = TRUE;
10046  }
10047  }
10048  }
10049 
10050  if (render_done == FALSE)
10051  {
10052  if (character_ptr->info & TELETEXT_CHARACTER_DOUBLE_HEIGHT)
10053  {
10054  y_scalar *= 2;
10055  }
10056  DBGPRINT("x=%d,y=%d", x, y);
10057  STB_OSDRegionFillRect( ttxt_osd_region, x, y,
10058  ebutt_font_ptr->character_width * x_scalar,
10059  ebutt_font_ptr->character_height * y_scalar,
10060  character_ptr->background_index );
10061  }
10062 
10063  FUNCTION_FINISH(RenderCharacter);
10064 }
10065 
10082 static U32BIT GetRGBSetting(BOOLEAN tranparency_required, U8BIT transparency_level,
10083  BOOLEAN red_required, BOOLEAN green_required, BOOLEAN blue_required,
10084  U8BIT gun_intensity)
10085 {
10086  U32BIT retval;
10087 
10088  FUNCTION_START(GetRGBSetting);
10089 
10090  if (tranparency_required == TRUE)
10091  {
10092  retval = (U32BIT)transparency_level << 24L;
10093  }
10094  else
10095  {
10096  retval = 0;
10097  }
10098 
10099  if (red_required == TRUE)
10100  {
10101  retval |= (U32BIT)gun_intensity << 16L;
10102  }
10103 
10104  if (green_required == TRUE)
10105  {
10106  retval |= (U32BIT)gun_intensity << 8L;
10107  }
10108 
10109  if (blue_required == TRUE)
10110  {
10111  retval |= (U32BIT)gun_intensity;
10112  }
10113 
10114  FUNCTION_FINISH(GetRGBSetting);
10115 
10116  return(retval);
10117 }
10118 
10132 static U32BIT GetRGBRamping(U32BIT fore_colour, U32BIT back_colour, U32BIT foreground_sixteenths)
10133 {
10134  U8BIT index;
10135  U32BIT retval, gun_mask, fore_gun_value, back_gun_value, temp;
10136 
10137  FUNCTION_START(GetRGBRamping);
10138 
10139  retval = 0;
10140  gun_mask = 0x00ff0000L;
10141 
10142  for (index = 0; index != 3; index++)
10143  {
10144  fore_gun_value = fore_colour & gun_mask;
10145  back_gun_value = back_colour & gun_mask;
10146 
10147  if (fore_gun_value >= back_gun_value)
10148  {
10149  temp = (fore_gun_value * foreground_sixteenths) + (back_gun_value *
10150  (16 - foreground_sixteenths));
10151  }
10152  else
10153  {
10154  temp = (back_gun_value * (16 - foreground_sixteenths)) +
10155  (fore_gun_value * foreground_sixteenths);
10156  }
10157  temp >>= 4;
10158 
10159  retval |= temp & gun_mask;
10160 
10161  gun_mask >>= 8;
10162  }
10163 
10164  FUNCTION_FINISH(GetRGBRamping);
10165 
10166  return(retval);
10167 }
10168 
10180 static void RenderDisplay(S_PAGE_DISPLAY_INFO *display_info_ptr)
10181 {
10182  U8BIT fore_colour_index, back_colour_index;
10183  U16BIT row_index, y, y_scalar, column_index, x, character_width, character_height;
10184  U16BIT effect_index, alias_index, max_aliases;
10185  U16BIT display_zoom_scalar, display_start_row, display_num_rows;
10186  U32BIT alias_colour_value;
10187  S_TELETEXT_CHARACTER *character_ptr;
10188  U8BIT stc[5];
10189  U32BIT pts_timestamp;
10190  U32BIT stc_timestamp;
10191  BOOLEAN render_required;
10192 
10193  static U32BIT normal_palette_array[PALETTE_EFFECT_ORIGIN];
10194  static U32BIT mixed_palette_array[PALETTE_EFFECT_ORIGIN];
10195  static U8BIT gun_intensity;
10196  static U8BIT antialias_level;
10197  static U8BIT transparency_level;
10198 
10199  FUNCTION_START(RenderDisplay);
10200 
10201  display_zoom_scalar = display_info_ptr->page_scale_zoom_scalar;
10202  display_start_row = display_info_ptr->page_scale_start_row;
10203  display_num_rows = display_info_ptr->page_scale_num_rows;
10204  if (display_start_row == 0 && !show_header_row)
10205  {
10206  display_start_row++;
10207  display_num_rows--;
10208  }
10209 
10210  render_required = FALSE;
10211 
10212  if (display_info_ptr->render_required == TRUE)
10213  {
10214 #ifdef EBU_DEBUG
10215  if (display_info_ptr->clear_screen || display_info_ptr->render_row[display_start_row + 1])
10216  {
10217  EBU_PRINT("RenderDisplay: start=%u, num=%u, clear=%u\n", display_start_row, display_num_rows,
10218  display_info_ptr->clear_screen);
10219 
10220  EBU_PRINT(" valid =");
10221  for (row_index = display_start_row; row_index < (display_start_row + display_num_rows);
10222  row_index++)
10223  {
10224  EBU_PRINT("%c", display_info_ptr->valid_row[row_index] ? '1' : '0');
10225  }
10226  EBU_PRINT("\n");
10227  EBU_PRINT(" render=");
10228  for (row_index = display_start_row; row_index < (display_start_row + display_num_rows);
10229  row_index++)
10230  {
10231  EBU_PRINT("%c", display_info_ptr->render_row[row_index] ? '1' : '0');
10232  }
10233  EBU_PRINT("\n");
10234  }
10235 #endif
10236 
10237  if (display_info_ptr->subtitle && display_info_ptr->pts_valid)
10238  {
10239  /* Work out whether there's anything to render */
10240  if (!display_info_ptr->clear_set)
10241  {
10242  for (row_index = display_start_row;
10243  (row_index != (display_start_row + display_num_rows)) && !render_required; row_index++)
10244  {
10245  if ((display_info_ptr->valid_row[row_index] == TRUE) &&
10246  (display_info_ptr->render_row[row_index] == TRUE))
10247  {
10248  render_required = TRUE;
10249  }
10250  }
10251  }
10252 
10253  if (render_required)
10254  {
10255  pts_timestamp = (display_info_ptr->page_pts[0] << 24) + (display_info_ptr->page_pts[1] << 16) +
10256  (display_info_ptr->page_pts[2] << 8) + display_info_ptr->page_pts[3];
10257 
10258  STB_AVGetSTC(STB_DPGetPathVideoDecoder(teletext_path), stc);
10259  stc_timestamp = (stc[0] << 24) + (stc[1] << 16) + (stc[2] << 8) + stc[3];
10260 
10261  if ((stc[0] == 0) && (display_info_ptr->page_pts[0] == 1))
10262  {
10263  /* Top bit of STC isn't present so make sure PTS doesn't have it set either */
10264  EBU_DBG("Clearing top bit of PTS 0x%08lx, STC=0x%08lx", pts_timestamp, stc_timestamp);
10265  pts_timestamp &= 0x00ffffff;
10266  }
10267  else if ((stc[0] == 1) && (display_info_ptr->page_pts[0] == 0))
10268  {
10269  /* Top bit of STC is present so make sure PTS has it set too */
10270  EBU_DBG("Setting top bit of PTS 0x%08lx, STC=0x%08lx", pts_timestamp, stc_timestamp);
10271  pts_timestamp |= 0x01000000;
10272  }
10273 
10274  if (display_info_ptr->time_offset == 0)
10275  {
10276  /* Some broadcasters present PTS values that are completely different to the STC,
10277  * so a large difference needs to be detected and an offset value calculated */
10278  if ((stc_timestamp != 0) && (pts_timestamp != 0))
10279  {
10280  display_info_ptr->time_offset = (S32BIT)((pts_timestamp - stc_timestamp) & 0xffffff00);
10281  if ((display_info_ptr->time_offset < -0x10000) || (display_info_ptr->time_offset > 0x10000))
10282  {
10283  EBU_DBG("Using offset 0x%08lx, PTS 0x%08lx, STC 0x%08lx",
10284  display_info_ptr->time_offset, pts_timestamp, stc_timestamp);
10285 
10286  pts_timestamp -= display_info_ptr->time_offset;
10287  }
10288  else
10289  {
10290  display_info_ptr->time_offset = 0;
10291  }
10292  }
10293  }
10294  else
10295  {
10296  pts_timestamp -= display_info_ptr->time_offset;
10297  }
10298 
10299  /* Wait to update the display */
10300  do
10301  {
10302  STB_AVGetSTC(STB_DPGetPathVideoDecoder(teletext_path), stc);
10303  stc_timestamp = (stc[0] << 24) + (stc[1] << 16) + (stc[2] << 8) + stc[3];
10304 
10305  if ((stc_timestamp < pts_timestamp) && !stop_teletext)
10306  {
10307  EBU_DBG("Wait to display..., PTS=0x%08lx, STC=0x%08lx", pts_timestamp, stc_timestamp);
10308  STB_OSTaskDelay(100);
10309  }
10310  }
10311  while ((stc_timestamp < pts_timestamp) && !stop_teletext);
10312 
10313  EBU_DBG("Display now: PTS=0x%08lx, STC=0x%08lx", pts_timestamp, stc_timestamp);
10314  }
10315  }
10316 
10317  /* Hide the region before drawing into it */
10318  STB_OSDHideRegion(ttxt_osd_region);
10319 
10320  if (display_info_ptr->clear_screen == TRUE)
10321  {
10322  if (display_info_ptr->clear_set == TRUE)
10323  {
10324  STB_OSDFillRegion( ttxt_osd_region, PALETTE_BACKGROUND_TRANSPARENT );
10325  }
10326  else
10327  {
10328  STB_OSDFillRegion( ttxt_osd_region, display_info_ptr->screen_colour );
10329  }
10330 
10331  display_info_ptr->clear_screen = FALSE;
10332  }
10333 
10334  if (ebutt_font_ptr != NULL)
10335  {
10336  character_width = ebutt_font_ptr->character_width * display_x_scalar;
10337 
10338  y_scalar = display_y_scalar * display_zoom_scalar;
10339 
10340  character_height = ebutt_font_ptr->character_height * y_scalar;
10341 
10342  y = display_margin_top;
10343 
10344  if (display_info_ptr->clear_set == TRUE)
10345  {
10346  character_ptr = &display_info_ptr->character_map[0][2];
10347 
10348  x = display_margin_left;
10349  x += character_width * 2;
10350 
10351  for (column_index = 2; column_index != 6; column_index++)
10352  {
10353  RenderCharacter(x, y, display_x_scalar, y_scalar, character_ptr, display_info_ptr);
10354  x += character_width;
10355  character_ptr++;
10356  }
10357  }
10358  else
10359  {
10360 #ifdef EBU_DEBUG
10361  EBU_PRINT("%s: ", __FUNCTION__);
10362 #endif
10363  for (row_index = display_start_row; row_index != (display_start_row + display_num_rows);
10364  row_index++)
10365  {
10366  if ((display_info_ptr->valid_row[row_index] == TRUE) &&
10367  (display_info_ptr->render_row[row_index] == TRUE))
10368  {
10369  character_ptr = &display_info_ptr->character_map[row_index][0];
10370 
10371  x = display_margin_left;
10372 
10373  for (column_index = 0; column_index != MAX_COLUMN; column_index++)
10374  {
10375  if (row_index > 0)
10376  {
10377  if ((display_info_ptr->valid_row[row_index - 1] == TRUE) &&
10378  (display_info_ptr->character_map[row_index - 1][column_index].info &
10379  TELETEXT_CHARACTER_DOUBLE_HEIGHT))
10380  {
10381  x += character_width;
10382  character_ptr++;
10383  continue;
10384  }
10385  }
10386 
10387 #ifdef EBU_DEBUG
10388  if ((character_ptr->info & 0xff) < 0x5f)
10389  EBU_PRINT("%c", (character_ptr->info & 0xff) + 0x20);
10390 #endif
10391  RenderCharacter(x, y, display_x_scalar, y_scalar, character_ptr, display_info_ptr);
10392  x += character_width;
10393  character_ptr++;
10394  }
10395 
10396  display_info_ptr->render_row[row_index] = FALSE;
10397  }
10398 
10399  y += character_height;
10400  }
10401 #ifdef EBU_DEBUG
10402  EBU_PRINT("\n");
10403 #endif
10404  }
10405  }
10406 
10407  display_info_ptr->render_required = FALSE;
10408  }
10409 
10410  if (gun_intensity != current_gun_intensity)
10411  {
10412  gun_intensity = current_gun_intensity;
10413 
10414  normal_palette_array[PALETTE_BACKGROUND_TRANSPARENT] =
10415  GetRGBSetting(TRUE, current_transparency_level, FALSE, FALSE, FALSE, 0);
10416  normal_palette_array[PALETTE_BACKGROUND_BLACK_FIXED] =
10417  GetRGBSetting(FALSE, 0, FALSE, FALSE, FALSE, 0);
10418 
10419  normal_palette_array[PALETTE_BACKGROUND_BLACK] =
10420  GetRGBSetting(FALSE, 0, FALSE, FALSE, FALSE, 0);
10421  normal_palette_array[PALETTE_BACKGROUND_RED] =
10422  GetRGBSetting(FALSE, 0, TRUE, FALSE, FALSE, gun_intensity);
10423  normal_palette_array[PALETTE_BACKGROUND_GREEN] =
10424  GetRGBSetting(FALSE, 0, FALSE, TRUE, FALSE, gun_intensity);
10425  normal_palette_array[PALETTE_BACKGROUND_YELLOW] =
10426  GetRGBSetting(FALSE, 0, TRUE, TRUE, FALSE, gun_intensity);
10427  normal_palette_array[PALETTE_BACKGROUND_BLUE] =
10428  GetRGBSetting(FALSE, 0, FALSE, FALSE, TRUE, gun_intensity);
10429  normal_palette_array[PALETTE_BACKGROUND_MAGENTA] =
10430  GetRGBSetting(FALSE, 0, TRUE, FALSE, TRUE, gun_intensity);
10431  normal_palette_array[PALETTE_BACKGROUND_CYAN] =
10432  GetRGBSetting(FALSE, 0, FALSE, TRUE, TRUE, gun_intensity);
10433  normal_palette_array[PALETTE_BACKGROUND_WHITE] =
10434  GetRGBSetting(FALSE, 0, TRUE, TRUE, TRUE, gun_intensity);
10435 
10436  normal_palette_array[PALETTE_FOREGROUND_BLACK] =
10437  normal_palette_array[PALETTE_BACKGROUND_BLACK];
10438  normal_palette_array[PALETTE_FOREGROUND_RED] =
10439  normal_palette_array[PALETTE_BACKGROUND_RED];
10440  normal_palette_array[PALETTE_FOREGROUND_GREEN] =
10441  normal_palette_array[PALETTE_BACKGROUND_GREEN];
10442  normal_palette_array[PALETTE_FOREGROUND_YELLOW] =
10443  normal_palette_array[PALETTE_BACKGROUND_YELLOW];
10444  normal_palette_array[PALETTE_FOREGROUND_BLUE] =
10445  normal_palette_array[PALETTE_BACKGROUND_BLUE];
10446  normal_palette_array[PALETTE_FOREGROUND_MAGENTA] =
10447  normal_palette_array[PALETTE_BACKGROUND_MAGENTA];
10448  normal_palette_array[PALETTE_FOREGROUND_CYAN] =
10449  normal_palette_array[PALETTE_BACKGROUND_CYAN];
10450  normal_palette_array[PALETTE_FOREGROUND_WHITE] =
10451  normal_palette_array[PALETTE_BACKGROUND_WHITE];
10452 
10453  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT] =
10454  GetRGBSetting(TRUE, current_transparency_level, FALSE, FALSE, FALSE, 0);
10455  mixed_palette_array[PALETTE_BACKGROUND_BLACK_FIXED] =
10456  GetRGBSetting(FALSE, 0, FALSE, FALSE, FALSE, 0);
10457 
10458  mixed_palette_array[PALETTE_BACKGROUND_BLACK] =
10459  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10460  mixed_palette_array[PALETTE_BACKGROUND_RED] =
10461  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10462  mixed_palette_array[PALETTE_BACKGROUND_GREEN] =
10463  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10464  mixed_palette_array[PALETTE_BACKGROUND_YELLOW] =
10465  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10466  mixed_palette_array[PALETTE_BACKGROUND_BLUE] =
10467  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10468  mixed_palette_array[PALETTE_BACKGROUND_MAGENTA] =
10469  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10470  mixed_palette_array[PALETTE_BACKGROUND_CYAN] =
10471  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10472  mixed_palette_array[PALETTE_BACKGROUND_WHITE] =
10473  mixed_palette_array[PALETTE_BACKGROUND_TRANSPARENT];
10474 
10475  mixed_palette_array[PALETTE_FOREGROUND_BLACK] =
10476  normal_palette_array[PALETTE_FOREGROUND_BLACK];
10477  mixed_palette_array[PALETTE_FOREGROUND_RED] =
10478  normal_palette_array[PALETTE_FOREGROUND_RED];
10479  mixed_palette_array[PALETTE_FOREGROUND_GREEN] =
10480  normal_palette_array[PALETTE_FOREGROUND_GREEN];
10481  mixed_palette_array[PALETTE_FOREGROUND_YELLOW] =
10482  normal_palette_array[PALETTE_FOREGROUND_YELLOW];
10483  mixed_palette_array[PALETTE_FOREGROUND_BLUE] =
10484  normal_palette_array[PALETTE_FOREGROUND_BLUE];
10485  mixed_palette_array[PALETTE_FOREGROUND_MAGENTA] =
10486  normal_palette_array[PALETTE_FOREGROUND_MAGENTA];
10487  mixed_palette_array[PALETTE_FOREGROUND_CYAN] =
10488  normal_palette_array[PALETTE_FOREGROUND_CYAN];
10489  mixed_palette_array[PALETTE_FOREGROUND_WHITE] =
10490  normal_palette_array[PALETTE_FOREGROUND_WHITE];
10491 
10492  display_info_ptr->palette_update_required = TRUE;
10493  }
10494 
10495  if (antialias_level != current_antialias_level)
10496  {
10497  antialias_level = current_antialias_level;
10498 
10499  display_info_ptr->palette_update_required = TRUE;
10500  }
10501 
10502  if (transparency_level != current_transparency_level)
10503  {
10504  transparency_level = current_transparency_level;
10505 
10506  display_info_ptr->palette_update_required = TRUE;
10507  }
10508 
10509  if (palette_reset_required == TRUE)
10510  {
10511  if (display_info_ptr->video_mix_set == TRUE)
10512  {
10513  memcpy(display_info_ptr->palette_array, mixed_palette_array,
10514  PALETTE_EFFECT_ORIGIN * sizeof(U32BIT));
10515  }
10516  else
10517  {
10518  memcpy(display_info_ptr->palette_array, normal_palette_array,
10519  PALETTE_EFFECT_ORIGIN * sizeof(U32BIT));
10520  }
10521 
10522  STB_OSDSetRGBPalette( ttxt_osd_region, display_info_ptr->palette_array );
10523 
10524  palette_reset_required = FALSE;
10525  }
10526 
10527  if (display_info_ptr->palette_update_required == TRUE)
10528  {
10529  if (display_info_ptr->video_mix_set == TRUE)
10530  {
10531  memcpy(display_info_ptr->palette_array, mixed_palette_array,
10532  PALETTE_EFFECT_ORIGIN * sizeof(U32BIT));
10533  }
10534  else
10535  {
10536  memcpy(display_info_ptr->palette_array, normal_palette_array,
10537  PALETTE_EFFECT_ORIGIN * sizeof(U32BIT));
10538  }
10539 
10540  for (effect_index = 0; effect_index < NUM_PALETTE_EFFECTS; effect_index++)
10541  {
10542  if (display_info_ptr->palette_attribute_array[effect_index].effect_mask ==
10543  PALETTE_EFFECT_UNDEFINED)
10544  {
10545  break;
10546  }
10547 
10548  display_info_ptr->palette_array[effect_index + PALETTE_EFFECT_ORIGIN] =
10549  display_info_ptr->palette_array[display_info_ptr->palette_attribute_array[effect_index].fore_colour];
10550  display_info_ptr->palette_attribute_array[effect_index].fore_colour_used = TRUE;
10551 
10552  if (display_info_ptr->palette_attribute_array[effect_index].effect_mask & PALETTE_EFFECT_CONCEAL)
10553  {
10554  if (display_info_ptr->reveal_set == TRUE)
10555  {
10556  if (display_info_ptr->palette_attribute_array[effect_index].effect_mask & PALETTE_EFFECT_FLASH)
10557  {
10558  if (display_info_ptr->flash_set == FALSE)
10559  {
10560  display_info_ptr->palette_array[effect_index + PALETTE_EFFECT_ORIGIN] =
10561  display_info_ptr->palette_array[display_info_ptr->palette_attribute_array[effect_index].back_colour];
10562  display_info_ptr->palette_attribute_array[effect_index].fore_colour_used = FALSE;
10563  }
10564  }
10565  }
10566  else
10567  {
10568  display_info_ptr->palette_array[effect_index + PALETTE_EFFECT_ORIGIN] =
10569  display_info_ptr->palette_array[display_info_ptr->palette_attribute_array[effect_index].back_colour];
10570  display_info_ptr->palette_attribute_array[effect_index].fore_colour_used = FALSE;
10571  }
10572  }
10573  else if (display_info_ptr->palette_attribute_array[effect_index].effect_mask & PALETTE_EFFECT_FLASH)
10574  {
10575  if (display_info_ptr->flash_set == FALSE)
10576  {
10577  display_info_ptr->palette_array[effect_index + PALETTE_EFFECT_ORIGIN] =
10578  display_info_ptr->palette_array[display_info_ptr->palette_attribute_array[effect_index].back_colour];
10579  display_info_ptr->palette_attribute_array[effect_index].fore_colour_used = FALSE;
10580  }
10581  }
10582  }
10583 
10584  if (effect_index != NUM_PALETTE_EFFECTS)
10585  {
10586  max_aliases = (NUM_PALETTE_EFFECTS - effect_index) / 2;
10587 
10588  for (alias_index = 0; alias_index < max_aliases; alias_index++)
10589  {
10590  if (display_info_ptr->palette_alias_array[alias_index].fore_colour ==
10591  PALETTE_BACKGROUND_TRANSPARENT)
10592  {
10593  break;
10594  }
10595 
10596  fore_colour_index = display_info_ptr->palette_alias_array[alias_index].fore_colour;
10597  back_colour_index = display_info_ptr->palette_alias_array[alias_index].back_colour;
10598 
10599  if (fore_colour_index >= PALETTE_EFFECT_ORIGIN)
10600  {
10601  if (display_info_ptr->palette_attribute_array[fore_colour_index - PALETTE_EFFECT_ORIGIN].fore_colour_used == TRUE)
10602  {
10603  fore_colour_index = display_info_ptr->palette_attribute_array[fore_colour_index - PALETTE_EFFECT_ORIGIN].fore_colour;
10604  }
10605  else
10606  {
10607  fore_colour_index = display_info_ptr->palette_attribute_array[fore_colour_index - PALETTE_EFFECT_ORIGIN].back_colour;
10608  }
10609  }
10610 
10611  if (display_info_ptr->palette_array[back_colour_index] & 0xff000000L)
10612  {
10613  display_info_ptr->palette_array[PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2)] =
10614  display_info_ptr->palette_array[fore_colour_index];
10615  display_info_ptr->palette_array[PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2) + 1] =
10616  display_info_ptr->palette_array[back_colour_index];
10617  }
10618  else
10619  {
10620  alias_colour_value = GetRGBRamping(display_info_ptr->palette_array[fore_colour_index],
10621  display_info_ptr->palette_array[back_colour_index],
10622  16L - (U32BIT)antialias_level);
10623 
10624  display_info_ptr->palette_array[PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2)] = alias_colour_value;
10625 
10626  alias_colour_value = GetRGBRamping(display_info_ptr->palette_array[fore_colour_index],
10627  display_info_ptr->palette_array[back_colour_index],
10628  (U32BIT)antialias_level);
10629 
10630  display_info_ptr->palette_array[PALETTE_EFFECT_ORIGIN + effect_index + (alias_index * 2) + 1] = alias_colour_value;
10631  }
10632  }
10633  }
10634 
10635 
10636  STB_OSDSetRGBPalette( ttxt_osd_region, display_info_ptr->palette_array );
10637 
10638  display_info_ptr->palette_update_required = FALSE;
10639  }
10640 
10641  if (!is_visible)
10642  {
10644  //STB_OSDSetRegionDisplaySize(SD_WIDTH, SD_HEIGHT);
10645  is_visible = TRUE;
10646  }
10647 
10648  if (!stop_teletext)
10649  {
10650  if (render_required)
10651  {
10652  /* Need to set a new time for the subtitle timeout as the display of it is being delayed */
10653  subtitle_timeout = STB_OSGetClockMilliseconds();
10654 
10655  EBU_DBG("Start subtitle timeout @ %lu", subtitle_timeout);
10656  }
10657 
10658  STB_OSDShowRegion(ttxt_osd_region);
10660  }
10661 
10662  FUNCTION_FINISH(RenderDisplay);
10663 }
10664 
10682 static void PerformDisplayUpdate(void)
10683 {
10684  U16BIT row_index;
10685  BOOLEAN enforce_header_display;
10686  BOOLEAN override_header_backcolor;
10687 
10688  static U16BIT flash_counter;
10689 
10690  FUNCTION_START(PerformDisplayUpdate);
10691 
10692  enforce_header_display = FALSE;
10693 
10694  /* If the drivers have been reset ensure that the copy is cleared to prevent obsolete data being displayed */
10695  if (page_display_info.video_mix_required != page_control_info.video_mix_required)
10696  {
10697  page_display_info.video_mix_required = page_control_info.video_mix_required;
10698 
10699  page_display_info.video_mix_set = !page_display_info.video_mix_set;
10700  }
10701 
10702  if (page_display_copy.video_mix_set != page_display_info.video_mix_set)
10703  {
10704  page_display_copy.video_mix_set = page_display_info.video_mix_set;
10705 
10706  page_display_copy.palette_update_required = TRUE;
10707  }
10708 
10709  if (page_display_info.clear_required != page_control_info.clear_required)
10710  {
10711  page_display_info.clear_required = page_control_info.clear_required;
10712 
10713  page_display_info.clear_set = !page_display_info.clear_set;
10714  }
10715 
10716  if (page_display_copy.clear_set != page_display_info.clear_set)
10717  {
10718  page_display_copy.clear_set = page_display_info.clear_set;
10719 
10720  if (page_display_copy.clear_set == TRUE)
10721  {
10722  page_display_copy.render_required = TRUE;
10723  page_display_copy.clear_screen = TRUE;
10724  }
10725  else
10726  {
10727  if (page_display_info.page_number)
10728  {
10729  page_display_info.page_updated = TRUE;
10730  }
10731  }
10732  }
10733 
10734  override_header_backcolor = FALSE;
10735  if (show_header_row)
10736  {
10737  STB_OSSemaphoreWait(page_display_info.carousel_page_semaphore);
10738 
10739  if (page_display_info.carousel_page_updated == TRUE)
10740  {
10741  page_display_copy.carousel_page_number = page_display_info.carousel_page_number;
10742 
10743  memcpy(&page_display_copy.carousel_page_header, &page_display_info.carousel_page_header, MAX_COLUMN);
10744 
10745  page_display_info.carousel_page_updated = FALSE;
10746 
10747  STB_OSSemaphoreSignal(page_display_info.carousel_page_semaphore);
10748 
10749  DecodeTeletextCarouselHeader(&page_display_copy);
10750 
10751  override_header_backcolor = TRUE;
10752  enforce_header_display = TRUE;
10753  }
10754  else
10755  {
10756  STB_OSSemaphoreSignal(page_display_info.carousel_page_semaphore);
10757  }
10758  }
10759 
10760  STB_OSSemaphoreWait(page_display_info.page_semaphore);
10761 
10762  if (page_display_info.page_updated == TRUE)
10763  {
10764  page_display_copy.page_number = page_display_info.page_number;
10765  page_display_copy.page_sub_code = page_display_info.page_sub_code;
10766 
10767  memcpy(&page_display_copy.page_source, &page_display_info.page_source, sizeof(S_MAGAZINE_PAGE));
10768  memcpy(&page_display_copy.mgzn_data, &page_display_info.mgzn_data, sizeof(S_SPECIFIC_DATA));
10769 
10770  page_display_copy.page_clock_valid = page_display_info.page_clock_valid;
10771 
10772  page_display_info.page_updated = FALSE;
10773 
10774  STB_OSSemaphoreSignal(page_display_info.page_semaphore);
10775 
10776  page_display_copy.flash_set = TRUE;
10777  page_display_copy.flash_required = FALSE;
10778 
10779  page_display_copy.reveal_available = FALSE;
10780 
10781  DecodeTeletextPageBody(&page_display_copy, enforce_header_display);
10782 
10783  override_header_backcolor = FALSE;
10784  }
10785  else
10786  {
10787  STB_OSSemaphoreSignal(page_display_info.page_semaphore);
10788  }
10789 
10790  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
10791 
10792  if (page_display_info.page_index_updated == TRUE)
10793  {
10794  memcpy(&page_display_copy.page_index_digit, &page_display_info.page_index_digit,
10795  sizeof(E_PAGE_INDEX_DIGIT) * 3);
10796 
10797  page_display_copy.page_index_held = page_display_info.page_index_held;
10798 
10799  page_display_info.page_index_updated = FALSE;
10800 
10801  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
10802 
10803  if (show_header_row)
10804  {
10805  if ((override_header_backcolor == TRUE) ||
10806  (page_control_info.state == PAGE_CONTROL_STATE_INPUT))
10807  {
10808  DecodeTeletextPageNumber(&page_display_copy, TRUE);
10809  }
10810  else
10811  {
10812  DecodeTeletextPageNumber(&page_display_copy, FALSE);
10813  }
10814  }
10815  }
10816  else
10817  {
10818  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
10819  }
10820 
10821  STB_OSSemaphoreWait(page_display_info.time_filler_header_data_semaphore);
10822 
10823  if (page_display_info.clock_updated == TRUE)
10824  {
10825  memcpy(&page_display_copy.time_filler_header_data, &page_display_info.time_filler_header_data, 32);
10826 
10827  page_display_info.clock_updated = FALSE;
10828 
10829  STB_OSSemaphoreSignal(page_display_info.time_filler_header_data_semaphore);
10830 
10831  DecodeTeletextClock(&page_display_copy, override_header_backcolor);
10832  }
10833  else
10834  {
10835  STB_OSSemaphoreSignal(page_display_info.time_filler_header_data_semaphore);
10836  }
10837 
10838  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
10839 
10840  if (page_display_info.page_scale_params_defined == FALSE)
10841  {
10842  page_display_copy.page_scale_zoom_scalar = 1;
10843  page_display_copy.page_scale_start_row = 0;
10844  page_display_copy.page_scale_num_rows = MAX_ROWS;
10845  }
10846  else
10847  {
10848  page_display_copy.page_scale_zoom_scalar = page_display_info.page_scale_zoom_scalar;
10849  page_display_copy.page_scale_start_row = page_display_info.page_scale_start_row;
10850  page_display_copy.page_scale_num_rows = page_display_info.page_scale_num_rows;
10851  }
10852 
10853  if (page_display_info.page_rescaled == TRUE)
10854  {
10855  page_display_info.page_rescaled = FALSE;
10856 
10857  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
10858 
10859  for (row_index = page_display_copy.page_scale_start_row;
10860  row_index < (page_display_copy.page_scale_start_row + page_display_copy.page_scale_num_rows);
10861  row_index++)
10862  {
10863  page_display_copy.render_row[row_index] = page_display_copy.valid_row[row_index];
10864  }
10865 
10866  page_display_copy.render_required = TRUE;
10867  page_display_copy.clear_screen = TRUE;
10868  }
10869  else
10870  {
10871  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
10872  }
10873 
10874  if (page_display_copy.flash_required == TRUE)
10875  {
10876  flash_counter++;
10877  if (flash_counter == 3)
10878  {
10879  page_display_copy.flash_set = !page_display_copy.flash_set;
10880  page_display_copy.palette_update_required = TRUE;
10881 
10882  flash_counter = 0;
10883  }
10884  }
10885 
10886  if (page_display_copy.reveal_available == TRUE)
10887  {
10888  if (page_display_info.reveal_required != page_control_info.reveal_required)
10889  {
10890  page_display_info.reveal_required = page_control_info.reveal_required;
10891 
10892  page_display_info.reveal_set = !page_display_info.reveal_set;
10893  }
10894 
10895  if (page_display_copy.reveal_set != page_display_info.reveal_set)
10896  {
10897  page_display_copy.reveal_set = page_display_info.reveal_set;
10898 
10899  page_display_copy.palette_update_required = TRUE;
10900  }
10901  }
10902 
10903  page_display_copy.pts_valid = page_display_info.pts_valid;
10904  if (page_display_copy.pts_valid)
10905  {
10906  memcpy(page_display_copy.page_pts, page_display_info.page_pts, 5);
10907  }
10908 
10909  if (page_display_copy.render_required)
10910  {
10911  /* page_display_info is now free to accept the next page */
10912  STB_OSSemaphoreSignal(page_free_sem);
10913 
10914  RenderDisplay(&page_display_copy);
10915  }
10916 
10917  FUNCTION_FINISH(PerformDisplayUpdate);
10918 }
10919 
10920 static BOOLEAN InitialiseDisplay(void)
10921 {
10922  U8BIT *bitmap_ptr;
10923  U16BIT ch_width, ch_height;
10924  BOOLEAN retval;
10925 
10926  FUNCTION_START(InitialiseDisplay);
10927 
10928  retval = FALSE;
10929  ch_width = (U16BIT)ebutt_font_ptr->character_width;
10930  ch_height = (U16BIT)ebutt_font_ptr->character_height;
10931 
10932  ttxt_osd_region = STB_OSDCreateRegion( SD_WIDTH, SD_HEIGHT, 8 /*bit colour*/ );
10933 
10934  if (ttxt_osd_region != NULL)
10935  {
10936  STB_OSDSetRegionDisplaySize(SD_WIDTH, SD_HEIGHT);
10937 
10938  display_margin_left = (SD_WIDTH - (ch_width * display_x_scalar * MAX_COLUMN)) / 2;
10939  display_margin_top = (SD_HEIGHT - (ch_height * display_y_scalar * MAX_ROWS)) / 2;
10940 
10941  // initialise region colour
10942  STB_OSDFillRegion( ttxt_osd_region, PALETTE_BACKGROUND_TRANSPARENT );
10943 
10944  display_char_buffer_size = ch_width * ch_height * display_x_scalar * display_y_scalar *
10945  MAX_DISPLAY_ZOOM_SCALAR * 2;
10946 
10947  if (display_char_buffer != NULL)
10948  {
10949  STB_FreeMemory(display_char_buffer_origin);
10950 
10951  display_char_buffer = NULL;
10952  }
10953 
10954  // NB - we have a character rendering buffer that has a hidden additional six bytes at
10955  // the head of it's allocation. DO NOT TAMPER WITH THIS!!
10956  // In a standard build these header bytes are unused, and their existance effects
10957  // nothing.
10958  // In a TTDEMO build, they are used to display the bitmap content in an emulation.
10959  display_char_buffer_origin = (U8BIT *)STB_GetMemory(display_char_buffer_size + 6);
10960  if (display_char_buffer_origin != NULL)
10961  {
10962  display_char_buffer = display_char_buffer_origin + 6;
10963 
10964  diacritic_substitutions_avaialable = FALSE;
10965 
10966  // Check to see of anything has been defined for G1 block mosaic character 0x40
10967  // (i.e. a table offset of 0x20).
10968  // If anything is detected at this reserved (and nominally empty) location, then we
10969  // will assume that there are character/diacritic substitutions defined here.
10970 
10971  bitmap_ptr = ebutt_font_ptr->font_table_set_ptr[FONT_INDEX_G1_BLOCK_MOSAICS_SET];
10972 
10973  if (bitmap_ptr != NULL)
10974  {
10975  bitmap_ptr += ch_width * ch_height * 0x20;
10976 
10977  memset(display_char_buffer, 0, display_char_buffer_size);
10978 
10979  if (memcmp(bitmap_ptr, display_char_buffer, ch_width * ch_height))
10980  {
10981  diacritic_substitutions_avaialable = TRUE;
10982  }
10983  }
10984  retval = TRUE;
10985  }
10986  }
10987 
10988  FUNCTION_FINISH(InitialiseDisplay);
10989 
10990  return(retval);
10991 }
10992 
11008 static void DisplayUpdateTask(void *unwanted_ptr)
11009 {
11010  FUNCTION_START(DisplayUpdateTask);
11011 
11012  USE_UNWANTED_PARAM(unwanted_ptr);
11013 
11014  if (InitialiseDisplay())
11015  {
11016  // Run forever
11017  while (1)
11018  {
11019  STB_OSSemaphoreWait(display_task_semaphore);
11020 
11021  if ((subtitle_timeout != 0) && (STB_OSGetClockDiff(subtitle_timeout) > SUBTITLE_TIMEOUT))
11022  {
11023  EBU_DBG("%s: Subtitle timeout @ %lu", __FUNCTION__, STB_OSGetClockMilliseconds());
11024 
11025  DriverReset();
11026 
11027  STB_OSDFillRegion( ttxt_osd_region, PALETTE_BACKGROUND_TRANSPARENT );
11029  }
11030 
11031  PerformDisplayUpdate();
11032 
11033  STB_OSSemaphoreSignal(display_task_semaphore);
11034 
11035  STB_OSTaskDelay(100);
11036  }
11037  }
11038 
11039  FUNCTION_FINISH(DisplayUpdateTask);
11040 }
11041 
11042 //---global function definitions-----------------------------------------------
11043 
11062 {
11063  BOOLEAN retval;
11064 
11065  FUNCTION_START(STB_EBUTT_Initialise);
11066 
11067  retval = FALSE;
11068 
11069  if (is_initialised == FALSE)
11070  {
11071  if (InitialiseCollation() == TRUE)
11072  {
11073  if (InitialiseDisplayTask() == TRUE)
11074  {
11075  pes_collection_callback_handle =
11076  STB_RegisterPesCollectionCallback(PESCollectionCallback, 0x10, 0x1f);
11077  if (pes_collection_callback_handle)
11078  {
11079  is_initialised = TRUE;
11080 
11081  retval = TRUE;
11082  }
11083  else
11084  {
11085  KillDisplayTask();
11086  }
11087  }
11088  }
11089 
11090  /* Create the resources for the collation task */
11091  page_free_sem = STB_OSCreateSemaphore();
11092  collation_start = STB_OSCreateSemaphore();
11093  collation_stopped = STB_OSCreateSemaphore();
11094 
11095  collation_queue = STB_OSCreateQueue(sizeof(S_COLLATION_QUEUE_ITEM), COLLATION_QUEUE_SIZE);
11096 
11097  if ((collation_start != NULL) && (collation_stopped != NULL) && (collation_queue != NULL))
11098  {
11099  /* Initially grab both semaphores */
11100  STB_OSSemaphoreWait(collation_start);
11101  STB_OSSemaphoreWait(collation_stopped);
11102 
11103  stop_collation = FALSE;
11104  queue_count = 0;
11105  max_queue_count = 0;
11106  collation_started = FALSE;
11107 
11108  STB_OSCreateTask(PESCollationTask, NULL, DISPLAY_TASK_STACK_SIZE, DISPLAY_TASK_PRIORITY,
11109  (U8BIT *)"EBUTT_Collate");
11110  }
11111  }
11112 
11113  FUNCTION_FINISH(STB_EBUTT_Initialise);
11114 
11115  return(retval);
11116 }
11117 
11132 void STB_EBUTT_Kill(U8BIT path)
11133 {
11134  FUNCTION_START(STB_EBUTT_Kill);
11135 
11136  if (is_initialised == TRUE)
11137  {
11138  STB_EBUTT_Hide();
11139  STB_EBUTT_Stop(path, TRUE);
11140 
11141  STB_UnregisterPesCollectionCallback(pes_collection_callback_handle);
11142 
11143  if (display_char_buffer != NULL)
11144  {
11145  STB_FreeMemory(display_char_buffer_origin);
11146 
11147  display_char_buffer = NULL;
11148  }
11149 
11150  is_initialised = FALSE;
11151  }
11152 
11153  FUNCTION_FINISH(STB_EBUTT_Kill);
11154 }
11155 
11156 /*!**************************************************************************
11157  * @brief Allows teletext PES data packets to be injected by an external module,
11158  * which will be decoded and displayed.
11159  * @param data_ptr - pointer to first whole PES packet data
11160  * @param data_length - number of bytes of data provided
11161  * @return TRUE if the data is valid EBU teletext PES data, FALSE otherwise
11162  ****************************************************************************/
11163 BOOLEAN STB_EBUTT_InjectData(U8BIT *data_ptr, U32BIT data_length)
11164 {
11165  BOOLEAN retval;
11166  U16BIT pes_size;
11167 
11168  FUNCTION_START(STB_EBUTT_InjectData);
11169 
11170  retval = FALSE;
11171 
11172  if ((data_ptr != NULL) && (data_length > 5))
11173  {
11174  retval = TRUE;
11175 
11176  /* Handle each PES packet one at a time */
11177  while (retval && (data_length > 5))
11178  {
11179  /* Find the size of the PES packet, which is +6 to allow for the header and size fields */
11180  pes_size = (*(data_ptr + 4) << 8) + *(data_ptr + 5) + 6;
11181 
11182  if (data_length >= pes_size)
11183  {
11184  /* Enough data has been provided, so add it to the processing queue */
11185  retval = AddPESDataToQueue(data_ptr, pes_size);
11186 
11187  data_length -= pes_size;
11188  data_ptr += pes_size;
11189  }
11190  else
11191  {
11192  retval = FALSE;
11193  }
11194  }
11195  }
11196 
11197  FUNCTION_FINISH(STB_EBUTT_InjectData);
11198 
11199  return(retval);
11200 }
11201 
11222 void STB_EBUTT_Start(U8BIT path, U16BIT text_pid, U8BIT magazine, U8BIT page)
11223 {
11224  FUNCTION_START(STB_EBUTT_Start);
11225 
11226  if (is_initialised == TRUE)
11227  {
11228  STB_ChangePesCollectionPID(path, text_pid);
11229 
11230  STB_OSSemaphoreWait(page_request_info.semaphore);
11231 
11232  page_request_info.type = REQUEST_TYPE_EXPLICIT;
11233 
11234  if (magazine == 0)
11235  {
11236  page_request_info.page_number = 0x800 + page;
11237  }
11238  else
11239  {
11240  page_request_info.page_number = (magazine << 8) + page;
11241  }
11242 
11243  page_request_info.page_sub_code = PAGE_SUB_CODE_UNDEFINED;
11244 
11245  page_request_info.pending = TRUE;
11246 
11247  STB_OSSemaphoreSignal(page_request_info.semaphore);
11248 
11249  teletext_path = path;
11250  broadcast_index_page_invocation_required = TRUE;
11251  show_header_row = FALSE;
11252  subtitle_timeout = 0;
11253  stop_teletext = FALSE;
11254 
11255  stream_processing_enabled = TRUE;
11256 
11257  stop_collation = FALSE;
11258 
11259  /* Start the collation task */
11260  STB_OSSemaphoreSignal(collation_start);
11261  }
11262 
11263  FUNCTION_FINISH(STB_EBUTT_Start);
11264 }
11265 
11266 void STB_EBUTT_Stop(U8BIT path, BOOLEAN reset_cache)
11267 {
11268  S_COLLATION_QUEUE_ITEM queue_item;
11269 
11270  FUNCTION_START(STB_EBUTT_Stop);
11271 
11272  if (is_initialised == TRUE)
11273  {
11274  stop_teletext = TRUE;
11275 
11276  STB_ChangePesCollectionPID(path, 0);
11277 
11278  stream_processing_enabled = FALSE;
11279  if (reset_cache)
11280  {
11281  DriverReset();
11282 
11283  /* Don't wait if the collation task has already been requested to stop */
11284  if (!stop_collation && collation_started)
11285  {
11286  /* Signal the collation task to stop */
11287  stop_collation = TRUE;
11288 
11289  /* Write an empty item to the queue to ensure the task isn't blocked
11290  * from seeing the request to stop */
11291  queue_item.data = NULL;
11292  if (STB_OSWriteQueue(collation_queue, &queue_item, sizeof(queue_item), TIMEOUT_NOW))
11293  {
11294  queue_count++;
11295  }
11296 
11297  /* Wait for the task to indicate it's stopped */
11298  if (!STB_OSSemaphoreWaitTimeout(collation_stopped, 200))
11299  {
11300  /* Task hasn't stopped yet so is probably blocked waiting for page display info */
11301  STB_OSSemaphoreSignal(page_free_sem);
11302 
11303  STB_OSSemaphoreWait(collation_stopped);
11304  }
11305  }
11306 
11307  queue_count = 0;
11308  max_queue_count = 0;
11309 
11310  /* Now clear any items on the queue */
11311  while (STB_OSReadQueue(collation_queue, &queue_item, sizeof(queue_item), TIMEOUT_NOW))
11312  {
11313  if (queue_item.data != NULL)
11314  {
11315  STB_FreeMemory(queue_item.data);
11316  }
11317  }
11318 
11319  if (is_shown == TRUE && is_initialised == TRUE)
11320  {
11321  /* STB_EBUTT_Hide has NOT been called */
11322  STB_OSDFillRegion( ttxt_osd_region, PALETTE_BACKGROUND_TRANSPARENT );
11324  }
11325  }
11326  }
11327 
11328  FUNCTION_FINISH(STB_EBUTT_Stop);
11329 }
11330 
11356 BOOLEAN STB_EBUTT_Show(E_EBUTT_CHARACTER_SET_DESIGNATION character_set_designation,
11357  BOOLEAN navigate_to_index_page, BOOLEAN show_header)
11358 {
11359  BOOLEAN retval;
11360 
11361  FUNCTION_START(STB_EBUTT_Show);
11362 
11363  retval = FALSE;
11364 
11365  if ((is_initialised == TRUE) &&
11366  (is_shown == FALSE))
11367  {
11368  broadcast_index_page_invocation_required = navigate_to_index_page;
11369  show_header_row = show_header;
11370 
11371  default_character_set_mapping = (U8BIT)character_set_designation;
11372 
11373  page_control_info.video_mix_required = FALSE;
11374  page_control_info.clear_required = FALSE;
11375 
11376  STB_OSSemaphoreSignal(display_task_semaphore);
11377 
11378  palette_reset_required = TRUE;
11379 
11380  is_shown = TRUE;
11381  is_visible = FALSE;
11382  stop_teletext = FALSE;
11383  retval = TRUE;
11384  }
11385 
11386  FUNCTION_FINISH(STB_EBUTT_Show);
11387 
11388  return(retval);
11389 }
11390 
11403 void STB_EBUTT_Hide(void)
11404 {
11405  FUNCTION_START(STB_EBUTT_Hide);
11406 
11407  if ((is_initialised == TRUE) &&
11408  (is_shown == TRUE))
11409  {
11410  stop_teletext = TRUE;
11411 
11412  STB_OSSemaphoreWait(display_task_semaphore);
11413 
11414  STB_OSDFillRegion( ttxt_osd_region, PALETTE_BACKGROUND_TRANSPARENT );
11415 
11416  if (is_visible)
11417  {
11418  STB_OSDHideRegion( ttxt_osd_region );
11420  is_visible = FALSE;
11421  }
11422 
11424 
11425  is_shown = FALSE;
11426  }
11427 
11428  FUNCTION_FINISH(STB_EBUTT_Hide);
11429 }
11430 
11443 void STB_EBUTT_SetCacheMethod(E_EBUTT_CACHING_METHOD ebutt_caching_method)
11444 {
11445  FUNCTION_START(STB_EBUTT_SetCacheMethod);
11446 
11447  switch (ebutt_caching_method)
11448  {
11449  case EBUTT_CACHING_METHOD_PREVIOUS_NEXT:
11450  {
11451  // An nominal number of pages in the carousel numbering sequence that are close to the
11452  // currently displayed page are cached.
11453  // The minimal amount of memory allocation is required for this simple caching.
11454  history_cache_reset_requested = TRUE;
11455 
11456  caching_method = EBUTT_CACHING_METHOD_PREVIOUS_NEXT;
11457  break;
11458  }
11459 
11460  case EBUTT_CACHING_METHOD_HISTORY:
11461  {
11462  // As for EBUTT_CACHING_METHOD_PREVIOUS_NEXT, but also...
11463  // Previously visited pages are cached, up to a nominal limit.
11464  // The allows for easy travelral of a chain of recently visited pages.
11465  // Some memory allocation is required for this caching.
11466  editorial_link_cache_reset_requested = TRUE;
11467 
11468  caching_method = EBUTT_CACHING_METHOD_HISTORY;
11469  break;
11470  }
11471 
11472  case EBUTT_CACHING_METHOD_NAVIGATION:
11473  {
11474  // As for EBUTT_CACHING_METHOD_HISTORY, but also...
11475  // The FLOF (or FastText) page navigation links are cached for the
11476  // currently displayed page.
11477  // More complex memory allocation is required for this caching.
11478  editorial_link_cache_reset_requested = TRUE;
11479 
11480  caching_method = EBUTT_CACHING_METHOD_NAVIGATION;
11481  break;
11482  }
11483 
11484  case EBUTT_CACHING_METHOD_NAVIGATION_TREE:
11485  {
11486  // As for EBUTT_CACHING_METHOD_NAVIGATION, but also...
11487  // The pages defined in a tree of navigation links to the currently
11488  // displayed page are cached.
11489  // Complex memory allocation is required for this caching.
11490 
11491  caching_method = EBUTT_CACHING_METHOD_NAVIGATION_TREE;
11492  break;
11493  }
11494 
11495  case EBUTT_CACHING_METHOD_ALL:
11496  {
11497  // All TeleText carousel content is cached - offers optimal performance.
11498  // Significant amounts of memory allocation are required for this caching.
11499  caching_method = EBUTT_CACHING_METHOD_ALL;
11500  break;
11501  }
11502 
11503  default: // EBUTT_CACHING_METHOD_NONE
11504  {
11505  // No caching is performed - only presently displayed page and optionally next requested
11506  // page information is held in the system.
11507  history_cache_reset_requested = TRUE;
11508  editorial_link_cache_reset_requested = TRUE;
11509 
11510  caching_method = EBUTT_CACHING_METHOD_NONE;
11511  break;
11512  }
11513  }
11514 
11515  FUNCTION_FINISH(STB_EBUTT_SetCacheMethod);
11516 }
11517 
11531 void STB_EBUTT_NotifyEvent(E_EBUTT_EVENT event_type)
11532 {
11533  U16BIT page_number, index;
11534  BOOLEAN reset_state;
11535 
11536  FUNCTION_START(STB_EBUTT_NotifyEvent);
11537 
11538  if (is_initialised == TRUE)
11539  {
11540  reset_state = TRUE;
11541 
11542  switch (event_type)
11543  {
11544  // These are the four FastText shortcuts, usually represented by red, green,
11545  // yellow and blue keys on the handset.
11546  case EBUTT_EVENT_QUICK_NAVIGATE_1:
11547  case EBUTT_EVENT_QUICK_NAVIGATE_2:
11548  case EBUTT_EVENT_QUICK_NAVIGATE_3:
11549  case EBUTT_EVENT_QUICK_NAVIGATE_4:
11550  {
11551  RequestEditorialLinkPage((U16BIT)(event_type - EBUTT_EVENT_QUICK_NAVIGATE_1));
11552  break;
11553  }
11554  // The ten numeric keys used to input page indexes.
11555  case EBUTT_EVENT_0:
11556  case EBUTT_EVENT_1:
11557  case EBUTT_EVENT_2:
11558  case EBUTT_EVENT_3:
11559  case EBUTT_EVENT_4:
11560  case EBUTT_EVENT_5:
11561  case EBUTT_EVENT_6:
11562  case EBUTT_EVENT_7:
11563  case EBUTT_EVENT_8:
11564  case EBUTT_EVENT_9:
11565  {
11566  if (page_control_info.state != PAGE_CONTROL_STATE_INPUT)
11567  {
11568  if ((event_type != EBUTT_EVENT_0) &&
11569  (event_type != EBUTT_EVENT_9))
11570  {
11571  page_control_info.page_digit[0] = (U8BIT)(event_type - EBUTT_EVENT_0);
11572  page_control_info.page_digit_offset = 1;
11573 
11574  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11575 
11576  page_display_info.page_index_digit[0] = page_control_info.page_digit[0] +
11577  PAGE_INDEX_DIGIT_0;
11578  page_display_info.page_index_digit[1] = PAGE_INDEX_DIGIT_UNDEFINED;
11579  page_display_info.page_index_digit[2] = PAGE_INDEX_DIGIT_UNDEFINED;
11580 
11581  page_display_info.page_index_updated = TRUE;
11582  page_display_info.page_index_held = FALSE;
11583 
11584  page_control_info.state = PAGE_CONTROL_STATE_INPUT;
11585 
11586  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11587 
11588  reset_state = FALSE;
11589  }
11590  }
11591  else
11592  {
11593  page_control_info.page_digit[page_control_info.page_digit_offset] =
11594  (U8BIT)(event_type - EBUTT_EVENT_0);
11595 
11596  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11597 
11598  page_display_info.page_index_digit[page_control_info.page_digit_offset] =
11599  page_control_info.page_digit[page_control_info.page_digit_offset] +
11600  PAGE_INDEX_DIGIT_0;
11601 
11602  page_display_info.page_index_updated = TRUE;
11603 
11604  page_control_info.page_digit_offset++;
11605 
11606  if (page_control_info.page_digit_offset == 3)
11607  {
11608  page_control_info.state = PAGE_CONTROL_STATE_IDLE;
11609 
11610  for (index = 0, page_number = 0; index < 3; index++)
11611  {
11612  page_number <<= 4;
11613  page_number += (U16BIT)page_control_info.page_digit[index];
11614  }
11615 
11616  RequestPage(page_number, PAGE_SUB_CODE_UNDEFINED);
11617  }
11618  else
11619  {
11620  reset_state = FALSE;
11621  }
11622 
11623  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11624  }
11625  break;
11626  }
11627 
11628  // This is the home key, which returns to the nominated index page for this
11629  // service.
11630  case EBUTT_EVENT_INDEXPAGE:
11631  {
11632  RequestIndexPage();
11633  break;
11634  }
11635  // These are used to quickly increment/decrement the page index.
11636  case EBUTT_EVENT_NEXTPAGE:
11637  {
11638  RequestNextAvailablePage();
11639  break;
11640  }
11641  case EBUTT_EVENT_PREVIOUSPAGE:
11642  {
11643  RequestPreviousAvailablePage();
11644  break;
11645  }
11646  // These are used to navigate the sub-pages when in 'hold' mode.
11647  case EBUTT_EVENT_NEXTSUBPAGE:
11648  {
11649  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
11650  {
11651  RequestNextSubPage();
11652 
11653  reset_state = FALSE;
11654  }
11655  break;
11656  }
11657  case EBUTT_EVENT_PREVIOUSSUBPAGE:
11658  {
11659  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
11660  {
11661  RequestPreviousSubPage();
11662 
11663  reset_state = FALSE;
11664  }
11665  break;
11666  }
11667  // These are used to traverse the page history (if caching requested).
11668  case EBUTT_EVENT_BACKPAGE:
11669  {
11670  RequestPreviousVisitedPage();
11671  break;
11672  }
11673  case EBUTT_EVENT_FORWARDPAGE:
11674  {
11675  RequestNextVisitedPage();
11676  break;
11677  }
11678  // This is used to toggle hold on the current page.
11679  case EBUTT_EVENT_HOLD:
11680  {
11681  if (page_control_info.clear_required == FALSE)
11682  {
11683  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
11684  {
11685  page_control_info.state = PAGE_CONTROL_STATE_IDLE;
11686 
11687  STB_OSSemaphoreWait(page_request_info.semaphore);
11688 
11689  page_request_info.target_page_sub_code = PAGE_SUB_CODE_UNDEFINED;
11690 
11691  page_request_info.pending = FALSE;
11692 
11693  STB_OSSemaphoreSignal(page_request_info.semaphore);
11694 
11695  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11696 
11697  page_number = page_display_info.page_number;
11698  if (page_number == 0)
11699  {
11700  page_number = page_request_info.target_page_number;
11701  }
11702 
11703  page_display_info.page_index_digit[0] =
11704  ((page_number & 0x0f00) >> 8) + PAGE_INDEX_DIGIT_0;
11705  page_display_info.page_index_digit[1] =
11706  ((page_number & 0x00f0) >> 4) + PAGE_INDEX_DIGIT_0;
11707  page_display_info.page_index_digit[2] =
11708  (page_number & 0x000f) + PAGE_INDEX_DIGIT_0;
11709 
11710  page_display_info.page_index_updated = TRUE;
11711  page_display_info.page_index_held = FALSE;
11712 
11713  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11714  }
11715  else
11716  {
11717  page_control_info.state = PAGE_CONTROL_STATE_HOLD;
11718 
11719  STB_OSSemaphoreWait(page_request_info.semaphore);
11720 
11721  // Cancel and pending page request
11722  page_request_info.type = REQUEST_TYPE_CANCEL;
11723 
11724  page_request_info.pending = TRUE;
11725 
11726  STB_OSSemaphoreSignal(page_request_info.semaphore);
11727 
11728 
11729  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11730 
11731  // Force display task to redisplay the page number - now we are in 'hold' mode, the
11732  // display task will show an icon accordingly.
11733  page_display_info.page_index_updated = TRUE;
11734  page_display_info.page_index_held = TRUE;
11735 
11736  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11737  }
11738  }
11739 
11740  reset_state = FALSE;
11741 
11742  break;
11743  }
11744  // Reveal hidden page content (as defined in EBU specification)
11745  case EBUTT_EVENT_REVEAL:
11746  {
11747  page_control_info.reveal_required = !page_control_info.reveal_required;
11748  reset_state = FALSE;
11749  break;
11750  }
11751  // This key toggles 'clear' mode (page hidden until updated)
11752  case EBUTT_EVENT_CLEAR:
11753  {
11754  page_control_info.clear_required = !page_control_info.clear_required;
11755 
11756  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
11757  {
11758  page_control_info.state = PAGE_CONTROL_STATE_IDLE;
11759 
11760  STB_OSSemaphoreWait(page_request_info.semaphore);
11761 
11762  page_request_info.target_page_sub_code = PAGE_SUB_CODE_UNDEFINED;
11763 
11764  page_request_info.pending = FALSE;
11765 
11766  STB_OSSemaphoreSignal(page_request_info.semaphore);
11767 
11768  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11769 
11770  page_display_info.page_index_updated = TRUE;
11771  page_display_info.page_index_held = FALSE;
11772 
11773  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11774  }
11775 
11776  reset_state = FALSE;
11777  break;
11778  }
11779  // Used to toggle transparent background ('video mix' mode)
11780  case EBUTT_EVENT_MIX_VIDEO:
11781  {
11782  page_control_info.video_mix_required = !page_control_info.video_mix_required;
11783  reset_state = FALSE;
11784  break;
11785  }
11786  // Used to toggle double height top / double-height bottom / normal height display.
11787  case EBUTT_EVENT_DOUBLE_HEIGHT:
11788  {
11789  if (page_display_info.page_scale_params_defined == FALSE)
11790  {
11791  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11792  page_display_info.page_scale_status = PAGE_SCALE_STATUS_ZOOM_TOP;
11793  page_display_info.page_scale_start_row = 0;
11794  page_display_info.page_scale_num_rows = 13;
11795  page_display_info.page_scale_zoom_scalar = 2;
11796  page_display_info.page_rescaled = TRUE;
11797  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11798 
11799  page_display_info.page_scale_params_defined = TRUE;
11800  }
11801  else
11802  {
11803  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11804  switch (page_display_info.page_scale_status)
11805  {
11806  case PAGE_SCALE_STATUS_NORMAL:
11807  {
11808  page_display_info.page_scale_status = PAGE_SCALE_STATUS_ZOOM_TOP;
11809  page_display_info.page_scale_start_row = 0;
11810  page_display_info.page_scale_num_rows = 13;
11811  page_display_info.page_scale_zoom_scalar = 2;
11812  page_display_info.page_rescaled = TRUE;
11813  break;
11814  }
11815  case PAGE_SCALE_STATUS_ZOOM_TOP:
11816  {
11817  if (page_display_info.page_scale_start_row == 0)
11818  {
11819  page_display_info.page_scale_status = PAGE_SCALE_STATUS_ZOOM_BOTTOM;
11820  page_display_info.page_scale_start_row = 13;
11821  page_display_info.page_scale_num_rows = 12;
11822  page_display_info.page_scale_zoom_scalar = 2;
11823  page_display_info.page_rescaled = TRUE;
11824  }
11825  else
11826  {
11827  page_display_info.page_scale_status = PAGE_SCALE_STATUS_NORMAL;
11828  page_display_info.page_scale_start_row = 0;
11829  page_display_info.page_scale_num_rows = MAX_ROWS;
11830  page_display_info.page_scale_zoom_scalar = 1;
11831  page_display_info.page_rescaled = TRUE;
11832  }
11833  break;
11834  }
11835  case PAGE_SCALE_STATUS_ZOOM_BOTTOM:
11836  {
11837  page_display_info.page_scale_status = PAGE_SCALE_STATUS_NORMAL;
11838  page_display_info.page_scale_start_row = 0;
11839  page_display_info.page_scale_num_rows = MAX_ROWS;
11840  page_display_info.page_scale_zoom_scalar = 1;
11841  page_display_info.page_rescaled = TRUE;
11842  break;
11843  }
11844  }
11845  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11846  }
11847 
11848  reset_state = FALSE;
11849  break;
11850  }
11851  // Functional enhancement may offer finer scrolling of double-height display.
11852  case EBUTT_EVENT_DOUBLE_SCROLL_UP:
11853  {
11854  if (page_display_info.page_scale_params_defined == FALSE)
11855  {
11856  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11857  page_display_info.page_scale_status = PAGE_SCALE_STATUS_NORMAL;
11858  page_display_info.page_scale_start_row = 0;
11859  page_display_info.page_scale_num_rows = MAX_ROWS;
11860  page_display_info.page_scale_zoom_scalar = 1;
11861  page_display_info.page_rescaled = FALSE;
11862  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11863 
11864  page_display_info.page_scale_params_defined = TRUE;
11865  }
11866  else
11867  {
11868  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11869  switch (page_display_info.page_scale_status)
11870  {
11871  case PAGE_SCALE_STATUS_NORMAL:
11872  {
11873  break;
11874  }
11875  case PAGE_SCALE_STATUS_ZOOM_TOP:
11876  case PAGE_SCALE_STATUS_ZOOM_BOTTOM:
11877  {
11878  if (page_display_info.page_scale_start_row > 0)
11879  {
11880  page_display_info.page_scale_start_row--;
11881  page_display_info.page_rescaled = TRUE;
11882  }
11883  break;
11884  }
11885  }
11886  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11887  }
11888 
11889  reset_state = FALSE;
11890  break;
11891  }
11892  case EBUTT_EVENT_DOUBLE_SCROLL_DOWN:
11893  {
11894  if (page_display_info.page_scale_params_defined == FALSE)
11895  {
11896  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11897  page_display_info.page_scale_status = PAGE_SCALE_STATUS_NORMAL;
11898  page_display_info.page_scale_start_row = 0;
11899  page_display_info.page_scale_num_rows = MAX_ROWS;
11900  page_display_info.page_scale_zoom_scalar = 1;
11901  page_display_info.page_rescaled = FALSE;
11902  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11903 
11904  page_display_info.page_scale_params_defined = TRUE;
11905  }
11906  else
11907  {
11908  STB_OSSemaphoreWait(page_display_info.page_scale_semaphore);
11909  switch (page_display_info.page_scale_status)
11910  {
11911  case PAGE_SCALE_STATUS_NORMAL:
11912  {
11913  break;
11914  }
11915  case PAGE_SCALE_STATUS_ZOOM_TOP:
11916  case PAGE_SCALE_STATUS_ZOOM_BOTTOM:
11917  {
11918  if ((page_display_info.page_scale_start_row +
11919  page_display_info.page_scale_num_rows) < MAX_ROWS)
11920  {
11921  page_display_info.page_scale_start_row++;
11922  page_display_info.page_rescaled = TRUE;
11923  }
11924  break;
11925  }
11926  }
11927  STB_OSSemaphoreSignal(page_display_info.page_scale_semaphore);
11928  }
11929 
11930  reset_state = FALSE;
11931  break;
11932  }
11933  // Used to initiate/cancel 'timer' mode (clear and re-display page at set time)
11934  case EBUTT_EVENT_TIMER:
11935  {
11936  reset_state = FALSE;
11937  break;
11938  }
11939  }
11940 
11941  if (reset_state == TRUE)
11942  {
11943  page_control_info.state = PAGE_CONTROL_STATE_IDLE;
11944 
11945  STB_OSSemaphoreWait(page_display_info.page_index_semaphore);
11946 
11947  // Force display task to redisplay the page number
11948  page_display_info.page_index_updated = TRUE;
11949  page_display_info.page_index_held = FALSE;
11950 
11951  STB_OSSemaphoreSignal(page_display_info.page_index_semaphore);
11952  }
11953  }
11954 
11955  FUNCTION_FINISH(STB_EBUTT_NotifyEvent);
11956 }
11957 
11972 {
11973  FUNCTION_START(STB_EBUTT_NotifyServiceChange);
11974 
11975  DriverReset();
11976 
11977  FUNCTION_FINISH(STB_EBUTT_NotifyServiceChange);
11978 }
11979 
11992 void STB_EBUTT_SetDisplayBrightness(U8BIT gun_intensity)
11993 {
11994  FUNCTION_START(STB_EBUTT_SetDisplayBrightness);
11995 
11996  if (gun_intensity < 127)
11997  {
11998  current_gun_intensity = 127;
11999  }
12000  else
12001  {
12002  current_gun_intensity = gun_intensity;
12003  }
12004 
12005  FUNCTION_FINISH(STB_EBUTT_SetDisplayBrightness);
12006 }
12007 
12020 {
12021  FUNCTION_START(STB_EBUTT_IncreaseDisplayBrightness);
12022 
12023  if (current_gun_intensity <= 247)
12024  {
12025  current_gun_intensity += 8;
12026  }
12027 
12028  FUNCTION_FINISH(STB_EBUTT_IncreaseDisplayBrightness);
12029 }
12030 
12031 void STB_EBUTT_DecreaseDisplayBrightness(void)
12032 {
12033  FUNCTION_START(STB_EBUTT_DecreaseDisplayBrightness);
12034 
12035  if (current_gun_intensity >= 135)
12036  {
12037  current_gun_intensity -= 8;
12038  }
12039 
12040  FUNCTION_FINISH(STB_EBUTT_DecreaseDisplayBrightness);
12041 }
12042 
12056 void STB_EBUTT_SetDisplayAntiAliasing(U8BIT antialias_level)
12057 {
12058  FUNCTION_START(STB_EBUTT_SetDisplayAntiAliasing);
12059 
12060  if (antialias_level > 8)
12061  {
12062  current_antialias_level = 8;
12063  }
12064  else
12065  {
12066  current_antialias_level = antialias_level;
12067  }
12068 
12069  FUNCTION_FINISH(STB_EBUTT_SetDisplayAntiAliasing);
12070 }
12071 
12084 {
12085  FUNCTION_START(STB_EBUTT_IncreaseDisplayAntiAliasing);
12086 
12087  if (current_antialias_level < 8)
12088  {
12089  current_antialias_level++;
12090  }
12091 
12092  FUNCTION_FINISH(STB_EBUTT_IncreaseDisplayAntiAliasing);
12093 }
12094 
12095 void STB_EBUTT_DecreaseDisplayAntiAliasing(void)
12096 {
12097  FUNCTION_START(STB_EBUTT_DecreaseDisplayAntiAliasing);
12098 
12099  if (current_antialias_level > 0)
12100  {
12101  current_antialias_level--;
12102  }
12103 
12104  FUNCTION_FINISH(STB_EBUTT_DecreaseDisplayAntiAliasing);
12105 }
12106 
12119 void STB_EBUTT_SetDisplayMixTransparency(U8BIT transparency_level)
12120 {
12121  FUNCTION_START(STB_EBUTT_SetDisplayMixTransparency);
12122 
12123  if (transparency_level < 31)
12124  {
12125  current_transparency_level = 31;
12126  }
12127  else
12128  {
12129  current_transparency_level = ((transparency_level - 31) & 0xf8) + 31;
12130  }
12131 
12132  FUNCTION_FINISH(STB_EBUTT_SetDisplayMixTransparency);
12133 }
12134 
12147 {
12149 
12150  if (current_transparency_level < 248)
12151  {
12152  current_transparency_level += 8;
12153  }
12154  else
12155  {
12156  current_transparency_level = 255;
12157  }
12158 
12160 }
12161 
12162 void STB_EBUTT_DecreaseDisplayMixTransparency(void)
12163 {
12164  FUNCTION_START(STB_EBUTT_DecreaseDisplayMixTransparency);
12165 
12166  if (current_transparency_level > 38)
12167  {
12168  current_transparency_level -= 8;
12169  }
12170  else
12171  {
12172  current_transparency_level = 31;
12173  }
12174 
12175  FUNCTION_FINISH(STB_EBUTT_DecreaseDisplayMixTransparency);
12176 }
12177 
12192 {
12193  BOOLEAN retval;
12194 
12195  FUNCTION_START(STB_EBUTT_IsDisplayHeld);
12196 
12197  if (page_control_info.state == PAGE_CONTROL_STATE_HOLD)
12198  {
12199  retval = TRUE;
12200  }
12201  else
12202  {
12203  retval = FALSE;
12204  }
12205 
12206  FUNCTION_FINISH(STB_EBUTT_IsDisplayHeld);
12207 
12208  return(retval);
12209 }
12210 
12225 {
12226  BOOLEAN retval;
12227 
12228  FUNCTION_START(STB_EBUTT_IsDisplayDoubleHeight);
12229 
12230  if (page_display_info.page_scale_status == PAGE_SCALE_STATUS_NORMAL)
12231  {
12232  retval = FALSE;
12233  }
12234  else
12235  {
12236  retval = TRUE;
12237  }
12238 
12239  FUNCTION_FINISH(STB_EBUTT_IsDisplayDoubleHeight);
12240 
12241  return(retval);
12242 }
12243 
12244 //*****************************************************************************
12245 // End of file
12246 //*****************************************************************************
12247 
BOOLEAN STB_EBUTT_Initialise(void)
This must be called to invoke the EBU TeleText driver module before all other functionality can be ac...
Definition: stbebutt.c:11061
void STB_EBUTT_SetDisplayAntiAliasing(U8BIT antialias_level)
Called to adjust the display anti-aliasing level of the Teletext pages. This is used to control &#39;flic...
Definition: stbebutt.c:12056
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void STB_EBUTT_SetDisplayMixTransparency(U8BIT transparency_level)
Called to adjust the display video-mix transparency level of the Teletext pages.
Definition: stbebutt.c:12119
BOOLEAN STB_EBUTT_IsDisplayDoubleHeight(void)
Called to ascertain whether the present page is in &#39;double height&#39; mode or not. Thus function is usef...
Definition: stbebutt.c:12224
U32BIT STB_OSGetClockDiff(U32BIT timestamp)
Get Difference between Given Time and Current Time.
Header file - macros and function prototypes for public use.
void * STB_OSCreateSemaphore(void)
Create a Semaphore.
void STB_EBUTT_IncreaseDisplayBrightness(void)
Called to adjust the display brightness (colour intensity) of the Teletext pages. ...
Definition: stbebutt.c:12019
void STB_OSDUpdateRegions(void)
Updates the display of all subtitle regions.
Header file - Function prototypes for OSD control.
void STB_EBUTT_IncreaseDisplayAntiAliasing(void)
Called to adjust the display anti-aliasing level of the Teletext pages.
Definition: stbebutt.c:12083
BOOLEAN STB_EBUTT_Show(E_EBUTT_CHARACTER_SET_DESIGNATION character_set_designation, BOOLEAN navigate_to_index_page, BOOLEAN show_header)
Called to initiate continuous display of TeleText page content. This will result in either the index ...
Definition: stbebutt.c:11356
void STB_AVGetSTC(U8BIT path, U8BIT stc[5])
Returns the current 33-bit System Time Clock from the PCR PES. On some systems, this information may ...
U8BIT STB_DPGetPathVideoDecoder(U8BIT path)
Returns the video decoder ID acquired by the given decode path.
Definition: stbdpc.c:1757
void STB_OSDFillRegion(void *handle, U8BIT colour)
Fill a region with a colour.
BOOLEAN STB_OSSemaphoreWaitTimeout(void *semaphore, U16BIT timeout)
Wait on Semaphore for Set Time Period in an Attempt to Acquire.
Header file - Function prototypes for A/V control.
void STB_EBUTT_Hide(void)
Called to halt the continuous display of TeleText page content, and to clear the relevant area of the...
Definition: stbebutt.c:11403
void STB_EBUTT_Kill(U8BIT path)
This is the accompanying function to STB_EBUTT_Initialise( ), and is called to shut-down the EBU Tele...
Definition: stbebutt.c:11132
void STB_OSSemaphoreSignal(void *semaphore)
Signal a Semaphore to Release it by decrementing its counter.
void STB_ChangePesCollectionPID(U8BIT path, U16BIT text_pid)
Changes the PID that the DMX is using to gather data on.
Definition: stbpes.c:467
void STB_OSDSetRGBPalette(void *handle, U32BIT *trgb)
Sets the RGB palette for the given region. This function is used for Teletext.
BOOLEAN STB_OSDDisableUIRegion(void)
Disables (makes invisible) the OSD. This function needs to be implemented on platforms that cannot di...
U32BIT STB_RegisterPesCollectionCallback(void(*callback_function)(U32BIT, U8BIT, void *, U32BIT), U8BIT lowest_data_identifier, U8BIT highest_data_identifier)
Used to register a callback function that will receive specific PES data packets. In theory...
Definition: stbpes.c:537
void STB_OSDestroyTask(void *task)
Delete Task must be called upon termination of each task as it frees all OS specific resources alloca...
void STB_OSMutexUnlock(void *mutex)
Unlock a mutex (a.k.a. &#39;leave&#39;, &#39;signal&#39; or &#39;release&#39;)
void STB_OSSemaphoreWait(void *semaphore)
Wait on Semaphore Indefinity or Until Released.
void STB_OSDShowRegion(void *handle)
Makes a region visible.
void STB_EBUTT_SetCacheMethod(E_EBUTT_CACHING_METHOD ebutt_caching_method)
Called to define the strategy used to determine what page content is to be displayed form the TeleTex...
Definition: stbebutt.c:11443
void STB_OSDDrawBitmapInRegion(void *handle, U16BIT x, U16BIT y, U16BIT w, U16BIT h, U8BIT *bitmap, BOOLEAN non_modifying_colour)
Draw a bitmap in a specified region.
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
BOOLEAN STB_EBUTT_InjectData(U8BIT *data_ptr, U32BIT data_length)
Allows teletext PES data packets to be injected by an external module, which will be decoded and disp...
Definition: stbebutt.c:11163
Header file - EBU Teletext driver.
U8BIT STB_MEMSysRAMUsed(void)
Returns the amount of available system memory consumed.
Debug functions header file.
void STB_OSMutexLock(void *mutex)
Lock a mutex (a.k.a. &#39;enter&#39;, &#39;wait&#39; or &#39;get&#39;).
BOOLEAN PerformPESCollation(U8BIT *packet_ptr, BOOLEAN pts_valid, U8BIT *pts)
This process is called to service the queue populated with Teletext packets by the PES collectiom cal...
Definition: stbebutt.c:3279
Header file - Function prototypes for NVM and Heap.
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_EBUTT_NotifyEvent(E_EBUTT_EVENT event_type)
Called whenever a TeleText-specific event being invoked. This is used to pass relevant user input to ...
Definition: stbebutt.c:11531
void * STB_OSDCreateRegion(U16BIT width, U16BIT height, U8BIT depth)
Creates a new OSD region (for subtitling)
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.
void STB_OSDSetRegionDisplaySize(U16BIT width, U16BIT height)
Should be called to set the size of the display so that SD subtitles can be scaled correctly for an H...
Header file - Function prototypes for heap memory.
void STB_EBUTT_SetDisplayBrightness(U8BIT gun_intensity)
Called to adjust the display brightness (colour intensity) of the Teletext pages. ...
Definition: stbebutt.c:11992
void * STB_OSCreateMutex(void)
Create a mutex.
void STB_EBUTT_Start(U8BIT path, U16BIT text_pid, U8BIT magazine, U8BIT page)
These functions are called to control whether received TeleText data is processed. Using this functionality ensures that the process of collating page information can be halted when processing resources are a consideration. It is envisaged that some implementations may wish only to collate TeleText content only when the display is being shown, whilst other designs may which to cache significant page content as a background process. Abstracting this functionality from the initialisation routines gives the option to support both solution types.
Definition: stbebutt.c:11222
void STB_OSDHideRegion(void *handle)
Makes a region invisible.
BOOLEAN STB_OSReadQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Read a message from a queue.
void STB_OSDRegionFillRect(void *handle, U16BIT left, U16BIT top, U16BIT width, U16BIT height, U8BIT colour)
Fill the rectangle within the given region with the given colour.
void STB_UnregisterPesCollectionCallback(U32BIT handle)
Used to un-register a callback function that will receive specific PES data packets.
Definition: stbpes.c:602
void STB_OSTaskDelay(U16BIT timeout)
Delay Task for Specifed Time Period.
Header file - Function prototypes for PES collection task.
BOOLEAN STB_OSDEnableUIRegion(void)
Disables (makes invisible) the OSD. This function needs to be implemented on platforms that cannot di...
void STB_EBUTT_NotifyServiceChange(void)
Called whenever the application permits a TV/Radio service change during a TeleText display session...
Definition: stbebutt.c:11971
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
BOOLEAN STB_EBUTT_IsDisplayHeld(void)
Called to ascertain whether the present page is in &#39;hold&#39; mode or not. Thus function is useful when a...
Definition: stbebutt.c:12191
#define DBGPRINT(...)
Definition: dbgfuncs.h:74
void STB_EBUTT_IncreaseDisplayMixTransparency(void)
Called to adjust the display video-mix transparency level of the Teletext pages.
Definition: stbebutt.c:12146