3 #include <stdint.h>
4 #include <limits.h> //INT_MAX
6 #include "ioData.h"
7 #include "iobuff.h"
9 //#include "ioDataLoc.h"
11 #include <ti/sysbios/hal/Cache.h>
13 #define IODATA_NUM_MEM_ALLOCS 1
14 #define IODATA_INST_ALIGN 3
16 #define IODATA_NUM_BYTES_BITSTREAM 2
17 #define IODATA_NUM_BYTES_PCMSAMPLE 4
19 #define IODATA_ELEMENT_SIZE_DEF IODATA_NUM_BYTES_BITSTREAM
21 #define TRUE 1
22 #define FALSE 0
24 #define IODATA_SYNC_PC_MASK 0x1F
25 #define IODATA_SYNC_SUBTYPE_MASK 0x700
26 #define IODATA_SYNC_SUBTYPE_SHIFT 8
27 #define IODATA_SYNC_SUBTYPE_DTSHD 0x11
28 #define IODATA_SYNC_DDP 0x15
29 #define IODATA_SYNC_THD 0x16
31 #define IODATA_MIN_NUM_ZEROS_BEFORE_PA 2
32 #define IODATA_PREAMBLE_MAX_LEN 8 // TBD
33 #define IODATA_HEADER_LENGTH_IEC 4
34 #define IODATA_HEADER_CHECK_LENGTH_IEC 2 // For IEC, only look at 2 words to check SYNC.
36 #define IEC_PA ((uint_least16_t) 0xF872)
37 #define IEC_PB ((uint_least16_t) 0x4E1F)
38 #define DTS16_SYNC_A ((uint_least16_t) 0x7FFE)
39 #define DTS16_SYNC_B ((uint_least16_t) 0x8001)
40 #define DTS16_SYNC_C ((uint_least16_t) 0xFC00)
41 #define DTS14_SYNC_A ((uint_least16_t) 0x1FFF)
42 #define DTS14_SYNC_B ((uint_least16_t) 0xE800)
43 #define DTS14_SYNC_C ((uint_least16_t) 0x07F0)
45 #define DTS_BURST_TYPE_I 0x008B
46 #define DTS_BURST_TYPE_II 0x018C
47 #define DTS_BURST_TYPE_III 0x028D
48 #define DTS_BURST_TYPE_IV 0x0491
50 #define DTS_BURST_TYPE_IV_CBR 0x02
51 #define DTS_BURST_TYPE_IV_LBR 0x03
52 #define DTS_BURST_TYPE_IV_HBR 0x04
54 #define min(a, b) (((a) < (b)) ? (a) : (b))
55 #define max(a, b) (((a) > (b)) ? (a) : (b))
57 //IBMODE
58 enum
59 {
60 IBMODE_DEFAULT = 0,
61 IBMODE_NO_ZERORUNRESTART = 1,
62 IBMODE_NO_ZERORUN = 2
63 };
65 enum {
66 AUTODET_RESET = 0,
67 AUTODET_SYNC_SEARCH_INITIAL,
68 AUTODET_SYNC_SEARCH_PCM,
69 AUTODET_SYNC_CHECK_ONGOING
70 };
72 // scanState
73 enum
74 {
75 SCANNED_NONE,
76 SCANNED_IEC_PA,
77 SCANNED_IEC_PB,
78 SCANNED_IEC_PC,
79 SCANNED_IEC_PD,
80 SCANNED_DTS14_SYNC_A,
81 SCANNED_DTS14_SYNC_B,
82 SCANNED_DTS14_SYNC_C,
83 SCANNED_DTS14_SYNC_D,
84 SCANNED_DTS16_SYNC_A,
85 SCANNED_DTS16_SYNC_B,
86 SCANNED_DTS16_SYNC_C
87 };
89 typedef struct autoDet_s {
90 int_least32_t frameLength;
91 int_least32_t timeOutCntr;
92 uint_least32_t zeroCount;
93 uint_least32_t numElementsRcvd;
94 uint_least32_t distToFrameEnd;
96 uint_least16_t preambleRef[IODATA_PREAMBLE_MAX_LEN];
97 uint_least16_t preambleBuf[IODATA_PREAMBLE_MAX_LEN];
98 int_fast32_t preambleInd;
99 uint8_t headerLength;
100 uint8_t headerCheckLen;
102 uint_least16_t scanState;
103 uint_least16_t checkState;
105 int8_t ibMode;
106 int8_t timeOutStarted;
107 int8_t preambleStartsPrevBuf;
108 int8_t syncDetected;
109 int8_t syncLost;
110 int8_t completeFrameRcvd;
111 uint_least16_t syncState;
112 uint_least16_t bitStreamInfo;
113 uint_least16_t *bitStreamSyncPtr;
114 uint_least16_t *frameDataStartTemp;
115 uint_least16_t *frameDataStartConfirm;
116 } autoDet_t;
118 typedef struct ioDataDebug_s {
119 uint_least32_t numFramesRcvd;
120 uint_least32_t numBuffUnderflow;
121 uint_least32_t numSyncLost;
123 } ioDataDebug_t;
125 typedef struct ioDataInst_s {
126 autoDet_t autoDet;
127 ioDataDebug_t dbgStats;
128 uint_least16_t autoDetState;
129 uint_least16_t *IECframeLengths;
130 uint_least16_t frameLengthPCM;
131 uint_least16_t frameLengthDef;
132 //uint_least32_t frameLength; // frame length: number of elements in a frame
133 uint_least32_t numElementsRead; // number of elements to read from input buffer
134 uint_least32_t distToFrameEnd;
135 int8_t elementSize;
136 ioBuffHandle_t ioBuffHandle;
137 uint_least32_t zeroRunTrigger;
138 uint_least32_t zeroRunRestart;
139 int_least32_t timeOutCntr;
140 uint_least32_t unknownSourceTimeOut;
142 uint_least16_t *frameDataStart;
143 size_t frameDataSize;
144 uint8_t deliverZeros;
145 uint8_t ioBuffUnderFlow;
146 void *buff1;
147 void *buff2;
148 size_t size1;
149 size_t size2;
151 } ioDataInst_t;
154 // TODO: put this data structure somewhere, or use ioDataNumAlloc & ioDataAlloc to
155 // dynamically allocate memory.
156 //ioDataInst_t ioDataInst;
158 void autoDetection(ioDataInst_t * pIoDataInst);
159 void autoDetReset(ioDataInst_t * pIoDataInst);
163 /*******************************************************************************
164 * API function: ioDataNumAlloc
165 * Returns the maximum number of memory allocation requests that ioDataAlloc()
166 * requires.
167 *******************************************************************************/
168 int ioDataNumAlloc(void)
169 {
170 return (IODATA_NUM_MEM_ALLOCS);
171 } /* ioDataNumAlloc */
173 /*******************************************************************************
174 * API function: ioDataAlloc
175 * Returns a table of memory records that describe the size, alignment, type
176 * and memory space of all buffers required by I/O DATA component.
177 *******************************************************************************/
178 int ioDataAlloc(lib_mem_rec_t *mem_tbl)
179 {
180 mem_tbl[0].size = sizeof(ioDataInst_t);
181 mem_tbl[0].alignment = IODATA_INST_ALIGN;
182 mem_tbl[0].type = LIB_PMEM_SLOW;
183 mem_tbl[0].base = NULL;
185 return (IODATA_NO_ERR);
186 } /* ioDataAlloc */
188 /*******************************************************************************
189 * API function: ioDataCreate
190 * Create an I/O DATA instance.
191 *******************************************************************************/
192 int ioDataCreate(ioDataHandle_t *handle, const lib_mem_rec_t *mem_tbl)
193 {
194 ioDataInst_t *inst;
196 if( (mem_tbl[0].size < sizeof(ioDataInst_t))
197 ||libChkAlign(mem_tbl[0].base, IODATA_INST_ALIGN) ) {
198 // to add: check memory type
199 return (IODATA_ERR_MEMORY);
200 }
202 inst = (ioDataInst_t *)mem_tbl[0].base;
204 *handle = (ioDataHandle_t)inst;
206 return (IODATA_NO_ERR);
207 } /* ioDataCreate */
209 /*=============================================================================
210 * API function: this function initializes I/O data processing.
211 =============================================================================*/
212 int ioDataInit(ioDataHandle_t handle, ioDataParam_t *cfgParams)
213 {
214 ioDataInst_t *pIoDataInst = (ioDataInst_t *)handle;
216 if(cfgParams == NULL) {
217 return (IODATA_ERR_BAD_PARAMS);
218 }
220 pIoDataInst->ioBuffHandle = cfgParams->ioBuffHandle;
221 pIoDataInst->IECframeLengths = cfgParams->frameLengthsIEC;
222 pIoDataInst->frameLengthPCM = cfgParams->frameLengthPCM;
223 pIoDataInst->frameLengthDef = cfgParams->frameLengthDef;
224 pIoDataInst->autoDet.ibMode = cfgParams->ibMode;
225 pIoDataInst->zeroRunRestart = cfgParams->zeroRunRestart;
226 pIoDataInst->zeroRunTrigger = cfgParams->zeroRunTrigger;
227 pIoDataInst->unknownSourceTimeOut = cfgParams->unknownSourceTimeOut*2;
228 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_INITIAL;
229 pIoDataInst->dbgStats.numSyncLost = 0;
230 pIoDataInst->ioBuffUnderFlow = FALSE;
232 autoDetReset(pIoDataInst);
234 return IODATA_NO_ERR;
235 } /* ioDataInit */
238 /*=============================================================================
239 * API function: main function of I/O DATA component processing.
240 =============================================================================*/
241 int ioDataProcess(ioDataHandle_t ioDataHandle)
242 {
243 void *buff1, *buff2;
244 size_t size1, size2;
245 int status;
246 ioDataInst_t *pIoDataInst = (ioDataInst_t *)ioDataHandle;
248 // Get read pointers (or sub-buffers) of the input buffer
249 status = ioBuffGetReadPtrs(pIoDataInst->ioBuffHandle,
250 pIoDataInst->numElementsRead*pIoDataInst->elementSize,
251 &buff1, &size1, &buff2, &size2);
252 if(status == IOBUFF_ERR_UNDERFLOW) {
253 pIoDataInst->ioBuffUnderFlow = TRUE;
254 pIoDataInst->dbgStats.numBuffUnderflow += 1;
256 /* skip processing since there is no enough data to process */
257 return IODATA_ERR_IOBUF_UNDERFLOW;
258 }
260 // Store read pointers and sizes to instance for auto-detection to read
261 pIoDataInst->ioBuffUnderFlow = FALSE;
262 pIoDataInst->buff1 = buff1;
263 pIoDataInst->buff2 = buff2;
264 pIoDataInst->size1 = size1;
265 pIoDataInst->size2 = size2;
267 autoDetection(pIoDataInst);
269 return IODATA_NO_ERR;
270 } /* ioDataProcess */
273 /*=============================================================================
274 * API function - this function marks the sub-buffers provided by I/O BUFF as
275 * read complete. It makes API call to the associated I/O BUFF component to mark
276 * the data as reading completed.
277 =============================================================================*/
278 int ioDataReadComplete(ioDataHandle_t ioDataHandle)
279 {
280 ioDataInst_t *pIoDataInst = (ioDataInst_t *)ioDataHandle;
282 // If the associated I/O buffer underflows, i.e. no enough data to read, do not
283 // call I/O BUFF API to mark read complete.
284 if(pIoDataInst->ioBuffUnderFlow) {
285 return IODATA_ERR_IOBUF_UNDERFLOW;
286 }
288 ioBuffReadComplete(pIoDataInst->ioBuffHandle, pIoDataInst->buff1, pIoDataInst->size1);
290 if(pIoDataInst->buff2 != NULL) {
291 ioBuffReadComplete(pIoDataInst->ioBuffHandle, pIoDataInst->buff2, pIoDataInst->size2);
292 }
294 return IODATA_NO_ERR;
295 } /* ioDataReadComplete */
298 /*=============================================================================
299 * API function - this function allows framework to dynamically control I/O data
300 * component or get information from it.
301 =============================================================================*/
302 int ioDataControl(ioDataHandle_t ioDataHandle, ioDataCtl_t *ioDataCtl)
303 {
304 ioBuffInfo_t ioBuffInfo;
306 ioDataInst_t *pIoDataInst = (ioDataInst_t *)ioDataHandle;
308 switch (ioDataCtl->code)
309 {
311 // case IODATA_CTL_SET_ELEMENT_SIZE:
312 // pIoDataInst->elementSize = ioDataCtl->param.frameInfo.elementSize;
313 // break;
315 case IODATA_CTL_SET_PCM_FRAME_LENGTH:
316 pIoDataInst->numElementsRead = pIoDataInst->frameLengthPCM = ioDataCtl->param.frameLengthPcm;
317 break;
319 case IODATA_CTL_GET_INPBUFFINFO:
320 ioBuffGetInfo(pIoDataInst->ioBuffHandle, &ioBuffInfo);
321 ioDataCtl->param.dataReadInfo.buffBase = ioBuffInfo.base;
322 ioDataCtl->param.dataReadInfo.buffSize = ioBuffInfo.size;
323 ioDataCtl->param.dataReadInfo.startAddress = pIoDataInst->frameDataStart;
324 ioDataCtl->param.dataReadInfo.frameSize = pIoDataInst->frameDataSize;
325 break;
327 case IODATA_CTL_GET_AUTODET_STATUS:
328 ioDataCtl->param.autoDetStats.syncState = pIoDataInst->autoDet.syncState;
329 ioDataCtl->param.autoDetStats.deliverZeros = pIoDataInst->deliverZeros;
330 ioDataCtl->param.autoDetStats.bitStreamInfo = pIoDataInst->autoDet.bitStreamInfo;
331 break;
332 /*
333 case IODATA_CTL_GET_STEAM_INFO:
334 break;
335 */
336 default:
337 break;
338 }
340 return IODATA_NO_ERR;
341 } /* ioDataControl */
343 //========== internal functions - to be moved to a different file ==========
344 void autoDetSyncScan(ioDataInst_t * pIoDataInst);
345 void autoDetSyncCheck(ioDataInst_t * pIoDataInst);
346 void syncScan(void *buff, size_t size, int8_t elementSize, autoDet_t *pDet);
347 void syncCheck(void *buff, size_t size, int8_t elementSize, autoDet_t *pDet);
348 void syncCheckInit(ioDataInst_t * pIoDataInst);
349 void syncScanPcmInit(ioDataInst_t * pIoDataInst);
351 /*=============================================================================
352 * Main function of auto-detection of the I/O DATA component.
353 =============================================================================*/
354 void autoDetection(ioDataInst_t * pIoDataInst)
355 {
356 switch(pIoDataInst->autoDetState)
357 {
358 case AUTODET_SYNC_SEARCH_INITIAL:
359 /* Search for SYNC the first time */
360 autoDetSyncScan(pIoDataInst);
362 if(pIoDataInst->autoDet.syncDetected) {
363 syncCheckInit(pIoDataInst); // prepare for SYNC checking in subsequent frames
365 pIoDataInst->autoDet.frameDataStartConfirm = pIoDataInst->autoDet.frameDataStartTemp;
366 pIoDataInst->autoDet.syncState = IODATA_SYNC_ONE; // found SYNC once and to be verified
367 pIoDataInst->autoDetState = AUTODET_SYNC_CHECK_ONGOING;
368 }
369 /* Check time out counter if SYNC is not found:
370 - if autoDet.timeOutStarted == FALSE (no non-zero data has been received), look at pIoDataInst->timeOutCntr
371 - if autoDet.timeOutStarted == TRUE, look at pIoDataInst->autoDet.timeOutCntr
372 */
373 else if( ((!pIoDataInst->autoDet.timeOutStarted) && (pIoDataInst->timeOutCntr <= 0))
374 || (pIoDataInst->autoDet.timeOutCntr <= 0) ) {
375 /* Time out, decide whether to reset or go to PCM */
376 if ( (pIoDataInst->autoDet.ibMode == IBMODE_DEFAULT)
377 &&(pIoDataInst->autoDet.zeroCount >= pIoDataInst->zeroRunRestart) ) {
378 /* Reset if zero-run is long enough */
379 autoDetReset(pIoDataInst);
380 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_INITIAL;
381 }
382 else {
383 // inform decoder where to read PCM data
384 pIoDataInst->frameDataStart = pIoDataInst->buff1;
385 pIoDataInst->frameDataSize = pIoDataInst->size1;
386 if(pIoDataInst->buff2 != NULL) {
387 pIoDataInst->frameDataSize += pIoDataInst->size2;
388 }
390 // Go to PCM scanning - to play out PCM and keep scanning for SYNC
391 syncScanPcmInit(pIoDataInst);
392 pIoDataInst->autoDet.syncState = IODATA_SYNC_PCM;
393 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_PCM;
394 }
395 }
396 break;
398 case AUTODET_SYNC_SEARCH_PCM:
399 /* Search for SYNC while PCM is played out */
400 autoDetSyncScan(pIoDataInst);
402 /* Check if SYNC is detected or there is zero-run */
403 if(pIoDataInst->autoDet.syncDetected) {
404 autoDetReset(pIoDataInst);
405 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_INITIAL;
406 }
407 else {
408 // inform decoder where to read PCM data
409 pIoDataInst->frameDataStart = pIoDataInst->buff1;
410 pIoDataInst->frameDataSize = pIoDataInst->frameLengthPCM*pIoDataInst->elementSize;
412 pIoDataInst->deliverZeros = FALSE;
414 if(pIoDataInst->autoDet.ibMode == IBMODE_DEFAULT) {
415 if(pIoDataInst->autoDet.zeroCount >= pIoDataInst->zeroRunTrigger) {
416 pIoDataInst->deliverZeros = TRUE;
417 }
419 if(pIoDataInst->autoDet.zeroCount >= pIoDataInst->zeroRunRestart) {
420 /* Reset if zero-run is long enough */
421 autoDetReset(pIoDataInst);
422 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_INITIAL;
423 }
424 }
425 else if(pIoDataInst->autoDet.ibMode == IBMODE_NO_ZERORUNRESTART) {
426 if(pIoDataInst->autoDet.zeroCount >= pIoDataInst->zeroRunTrigger) {
427 pIoDataInst->deliverZeros = TRUE;
428 }
429 }
430 else {
431 // ibMode = IBMODE_NO_ZERORUN. Stay in this state and do nothing
432 }
433 }
435 break;
437 case AUTODET_SYNC_CHECK_ONGOING:
438 autoDetSyncCheck(pIoDataInst);
440 /* Check if a full frame has been received and if so, check if SYNC is maintained */
441 if(pIoDataInst->autoDet.completeFrameRcvd) {
442 if(pIoDataInst->autoDet.syncDetected) {
443 pIoDataInst->autoDet.syncState = IODATA_SYNC_BITSTREAM;
444 pIoDataInst->autoDet.completeFrameRcvd = FALSE;
446 // Inform decoder to read data from the beginning of current frame (after the preamble)
447 // Note: this address could be 1-word pass the end of input buffer and therefore needs
448 // to be wrapped around by ioBuffWrapPointer().
449 pIoDataInst->frameDataStart = ioBuffWrapPointer(pIoDataInst->ioBuffHandle,
450 pIoDataInst->autoDet.frameDataStartConfirm);
451 pIoDataInst->frameDataSize = pIoDataInst->autoDet.frameLength*pIoDataInst->elementSize;
453 // Store the beginning address of data in current frame (not including the preamble)
454 pIoDataInst->autoDet.frameDataStartConfirm = pIoDataInst->autoDet.frameDataStartTemp;
455 pIoDataInst->dbgStats.numFramesRcvd += 1;
457 // re-initialize for SYNC check
458 syncCheckInit(pIoDataInst);
459 }
460 else {
461 pIoDataInst->dbgStats.numSyncLost += 1; // what else needs to be done???
462 autoDetReset(pIoDataInst);
463 pIoDataInst->autoDetState = AUTODET_SYNC_SEARCH_INITIAL;
464 pIoDataInst->autoDet.syncState = IODATA_SYNC_NONE;
465 }
466 }
467 else {
468 ; //pIoDataInst->autoDet.syncState = IODATA_SYNC_CHECK;
469 }
470 break;
472 default: break;
473 }
475 } /* autoDetection */
477 /*=============================================================================
478 * This function resets auto-detection.
479 =============================================================================*/
480 void autoDetReset(ioDataInst_t * pIoDataInst)
481 {
482 pIoDataInst->deliverZeros = FALSE;
483 pIoDataInst->autoDet.zeroCount = 0;
484 pIoDataInst->autoDet.syncState = IODATA_SYNC_NONE;
485 pIoDataInst->autoDet.scanState = SCANNED_NONE;
486 pIoDataInst->autoDet.timeOutStarted = FALSE;
487 pIoDataInst->autoDet.syncDetected = FALSE;
488 pIoDataInst->autoDet.timeOutCntr = pIoDataInst->unknownSourceTimeOut;
489 //pIoDataInst->autoDet.timeOutCntr = pIoDataInst->unknownSourceTimeOut*20;
490 pIoDataInst->numElementsRead = pIoDataInst->frameLengthDef;
491 pIoDataInst->elementSize = IODATA_ELEMENT_SIZE_DEF;
493 pIoDataInst->timeOutCntr = pIoDataInst->unknownSourceTimeOut;
494 //pIoDataInst->timeOutCntr = pIoDataInst->unknownSourceTimeOut*20;
495 pIoDataInst->dbgStats.numFramesRcvd = 0;
496 pIoDataInst->dbgStats.numBuffUnderflow = 0;
497 } /* autoDetReset */
499 /*=============================================================================
500 * This function re-initializes auto-detection for scanning SYNC in PCM data
501 =============================================================================*/
502 void syncScanPcmInit(ioDataInst_t * pIoDataInst)
503 {
504 //pIoDataInst->deliverZeros = FALSE;
505 //pIoDataInst->autoDet.zeroCount = 0;
506 //pIoDataInst->autoDet.scanState = SCANNED_NONE;
507 //pIoDataInst->autoDet.timeOutStarted = FALSE;
508 //pIoDataInst->autoDet.syncDetected = FALSE;
509 //pIoDataInst->autoDet.timeOutCntr = pIoDataInst->unknownSourceTimeOut*2;
510 //pIoDataInst->autoDet.timeOutCntr = pIoDataInst->unknownSourceTimeOut*20;
511 pIoDataInst->numElementsRead = pIoDataInst->frameLengthPCM;
512 //pIoDataInst->timeOutCntr = pIoDataInst->unknownSourceTimeOut*2;
513 //pIoDataInst->timeOutCntr = pIoDataInst->unknownSourceTimeOut*20;
514 pIoDataInst->elementSize = IODATA_NUM_BYTES_PCMSAMPLE;
515 } /* syncScanPcmInit */
517 /*=============================================================================
518 * Initialization for checking sync in subsequent bitstream frames.
519 =============================================================================*/
520 void syncCheckInit(ioDataInst_t * pIoDataInst)
521 {
522 int i;
523 uint_least16_t pc = pIoDataInst->autoDet.bitStreamInfo & IODATA_SYNC_PC_MASK;
525 pIoDataInst->autoDet.frameLength = pIoDataInst->IECframeLengths[pc];
526 pIoDataInst->autoDet.distToFrameEnd = pIoDataInst->autoDet.frameLength
527 - pIoDataInst->autoDet.numElementsRcvd;
529 //#ifdef ADJUST_XFER_SIZE_AFTER_AUTODET
530 #if 1
531 // Adjust the read size such that next read will contain the preamble of next
532 // frame at the end of the read. For first frame after SYNC is detected, the
533 // read size will be smaller than frame size. For subsequent frames, the read
534 // size will be equal to the frame size.
535 pIoDataInst->numElementsRead = pIoDataInst->autoDet.distToFrameEnd
536 + pIoDataInst->autoDet.headerLength;
537 #endif
539 pIoDataInst->autoDet.preambleStartsPrevBuf = FALSE;
540 pIoDataInst->autoDet.completeFrameRcvd = FALSE;
541 pIoDataInst->autoDet.syncDetected = FALSE;
542 pIoDataInst->autoDet.preambleInd = 0;
544 for(i=0; i<pIoDataInst->autoDet.headerLength; i++)
545 {
546 pIoDataInst->autoDet.preambleBuf[i] = 0x0;
547 }
548 } /* syncCheckInit */
551 /*=============================================================================
552 * This function scans for sync word (preamble) in the input buffer while
553 * checking for time out. It calls subroutine syncScan to scan the data.
554 *
555 * The read pointer(s) to the input buffer and the read sizes are provided by
556 * the I/O BUFF component and stored in auto-detection instance. The read
557 * pointers are also refered as sub-buffers.
558 *
559 * NOte: Since the input buffer may wrapp around, there may be two sub-buffers,
560 * one at the end of the input buffer and the other at the beginning,
561 * provided to auto-detection. In this case, syncScan subroutine will be
562 * called twice.
563 =============================================================================*/
564 void autoDetSyncScan(ioDataInst_t * pIoDataInst)
565 {
566 /* scan first sub-buffer for sync */
567 if((pIoDataInst->buff1 != NULL) && (pIoDataInst->size1 != 0)) {
568 syncScan(pIoDataInst->buff1, pIoDataInst->size1, pIoDataInst->elementSize,
569 &pIoDataInst->autoDet);
570 pIoDataInst->timeOutCntr -= pIoDataInst->size1/pIoDataInst->elementSize;
571 }
573 /* check if sync word is found in the first sub-buffer */
574 if(pIoDataInst->autoDet.syncDetected) {
575 /* skip scanning second sub-buffer if sync is detected */
576 if((pIoDataInst->buff2 != NULL) && (pIoDataInst->size2 != 0)) {
577 /* update the number of received elements in current frame */
578 pIoDataInst->autoDet.numElementsRcvd += pIoDataInst->size2;
579 }
580 }
581 else if((pIoDataInst->buff2 != NULL) && (pIoDataInst->size2 != 0)) {
582 /* scan second sub-buffer if there are two sub-buffers */
583 syncScan(pIoDataInst->buff2, pIoDataInst->size2, pIoDataInst->elementSize,
584 &pIoDataInst->autoDet);
585 pIoDataInst->timeOutCntr -= pIoDataInst->size2/pIoDataInst->elementSize;
586 }
587 } /* ioDataAutoDetSyncScan */
589 /*=============================================================================
590 * This function scans for sync word (preamble) in the provided sub-buffer.
591 =============================================================================*/
592 void syncScan(void *buff, size_t size, int8_t elementSize, autoDet_t *pDet)
593 {
594 uint_least16_t *pbuf;
595 int i, stride, scanCount, zeroCount;
596 uint_least16_t scanState;
597 uint_least16_t *syncPtr;
599 pbuf = (uint_least16_t *)buff;
601 /* check element size */
602 if (elementSize == IODATA_NUM_BYTES_PCMSAMPLE) {
603 /* skip every other 16-bit number and only look at MSB of PCM samples */
604 stride = IODATA_NUM_BYTES_PCMSAMPLE / sizeof(uint_least16_t);
605 pbuf += 1;
606 }
607 else {
608 stride = 1;
609 }
611 /* get ready for scanning */
612 scanCount = 0;
613 zeroCount = pDet->zeroCount;
614 scanState = pDet->scanState;
616 /* check if part of the sync words (preamble) are found in previous call */
617 if(scanState != SCANNED_NONE) {
618 /* count this sub-buffer in the number of received elements in current frame */
619 pDet->numElementsRcvd += size/sizeof(uint_least16_t);
620 }
622 /* scan until out of available data or sync is found */
623 for (i=0; i < size/elementSize; i+=stride) {
624 uint_least16_t tail = pbuf[i];
626 if (scanState == SCANNED_NONE) {
627 if (tail == IEC_PA) {
628 /* make sure there are some zeros before PA. */
629 if (zeroCount >= IODATA_MIN_NUM_ZEROS_BEFORE_PA) {
630 scanState = SCANNED_IEC_PA;
631 syncPtr = &pbuf[i]; /* mark the position of PA */
632 }
633 }
635 if(scanState != SCANNED_NONE) {
636 /* Found first sync word. Save its address */
637 pDet->bitStreamSyncPtr = syncPtr;
639 /* number of elements in current frame that have been received
640 * in this sub-buffer, including the preamble (sync words). */
641 pDet->numElementsRcvd = size/sizeof(uint_least16_t) - i;
642 pDet->preambleRef[0] = tail; /* save this word for sync check */
643 }
645 /* update zero count and prevent wrap around */
646 zeroCount = min (zeroCount+1,INT_MAX - 1);
647 if (tail != 0x0000) {
648 zeroCount = 0;
649 }
651 // don't start counting until we get the first non-zero
652 // sample while UNKNOWN. Note we don't have to worry
653 // about the other scanCount increments since these
654 // only occur after the first non-zero sample.
655 //
656 // so don't count unless one of the following is true:
657 // . the last sample was non-zero
658 // . we are already started counting (in this call)
659 // . we started counting in an earlier scanForSync (timeout has changed)
660 //if (scanCount || (tail != 0x0000) || pDet->timeOutStarted) {
661 // scanCount += 1;
662 //}
664 if (tail != 0x0000) {
665 scanCount += 1;
666 pDet->timeOutStarted = TRUE;
667 }
668 else if (scanCount || pDet->timeOutStarted) {
669 scanCount += 1;
670 }
671 else {
672 // don't increment scanCount
673 }
675 continue;
676 }
678 // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
680 switch (scanState) {
682 case SCANNED_IEC_PA:
683 if (tail == IEC_PB) {
684 scanState = SCANNED_IEC_PB;
685 scanCount += 1;
686 pDet->preambleRef[1] = tail; /* save this word for sync check */
687 }
688 else {
689 scanState = SCANNED_NONE;
690 }
691 break;
693 case SCANNED_IEC_PB:
694 // Update scanCount here since, at this point, we are confident that
695 // this is a proper IEC stream. Regardless if we ignore it our not.
696 // Therefore we want to properly signal that this data has been scanned.
697 scanCount += 1;
699 // check for IEC pause packets at this time and if required ignore them.
700 // By construction we are guaranteed to have tail=PC at this time.
701 if ((pDet->ibMode == IBMODE_NO_ZERORUNRESTART) ||
702 (pDet->ibMode == IBMODE_NO_ZERORUN)) {
703 if ( ((tail&0x1F) == 0) || ((tail&0x1F) == 3)) {
704 scanState = SCANNED_NONE;
705 break;
706 }
707 }
709 // fall through to SCANNED_IEC_PC:
710 pDet->preambleRef[2] = tail; /* save this word for sync check */
711 pDet->bitStreamInfo = tail;
712 scanState = SCANNED_IEC_PC;
713 break;
715 case SCANNED_IEC_PC:
716 //pDevExt->headerSize = IEC_HEADER_SIZE;
717 pDet->preambleRef[3] = tail; /* save this word for sync check */
718 pDet->headerLength = IODATA_HEADER_LENGTH_IEC;
719 pDet->headerCheckLen = IODATA_HEADER_CHECK_LENGTH_IEC;
720 scanState = SCANNED_IEC_PD;
722 break;
724 case SCANNED_IEC_PD:
725 // wait untill full header is received
726 pDet->syncDetected = TRUE;
727 pDet->frameDataStartTemp = &pbuf[i];
729 break;
731 } /* switch */
733 if(pDet->syncDetected) {
734 break; // break from for loop
735 }
736 } /* for */
738 pDet->zeroCount = zeroCount;
739 pDet->scanState = scanState;
740 if (pDet->timeOutCntr > scanCount) {
741 pDet->timeOutCntr -= scanCount;
742 }
743 else {
744 pDet->timeOutCntr = 0;
745 }
747 } /* syncScan */
750 /*=============================================================================
751 * This function checks for sync word (preamble) at the expected location in the
752 * input buffer. Similar to ioDataAutoDetSyncScan, it looks into two sub-buffers
753 * when the input buffer wraps around.
754 *
755 =============================================================================*/
756 void autoDetSyncCheck(ioDataInst_t * pIoDataInst)
757 {
758 // look into first sub-buffer for preamble
759 if((pIoDataInst->buff1 != NULL) && (pIoDataInst->size1 != 0)) {
760 syncCheck(pIoDataInst->buff1, pIoDataInst->size1, pIoDataInst->elementSize,
761 &pIoDataInst->autoDet);
762 }
764 // check if first sub-buffer contains the expected preamble
765 if(pIoDataInst->autoDet.syncDetected) {
766 // skip second sub-buffer if first sub-buffer contains the expected preamble */
767 if((pIoDataInst->buff2 != NULL) && (pIoDataInst->size2 != 0)) {
768 // update the number of received elements in current frame
769 pIoDataInst->autoDet.numElementsRcvd += pIoDataInst->size2;
770 }
771 }
772 else if((pIoDataInst->buff2 != NULL) && (pIoDataInst->size2 != 0)) {
773 // look into second sub-buffer if there are two sub-buffers
774 syncCheck(pIoDataInst->buff2, pIoDataInst->size2, pIoDataInst->elementSize,
775 &pIoDataInst->autoDet);
776 }
777 } /* autoDetSyncCheck */
780 /*=============================================================================
781 * This function scans checks for sync word (preamble) in the provided sub-buffer.
782 =============================================================================*/
783 void syncCheck(void *buff, size_t size, int8_t elementSize, autoDet_t *pDet)
784 {
785 uint_least16_t *pbuf;
786 int i, diff, restOfPreamble;
787 uint_least32_t numElements;
789 pbuf = (uint_least16_t *)buff;
790 numElements = size / elementSize; // number of elements in provided sub-buffer
792 // Check if the preamble already starts from the sub-buffer in previous call
793 if(pDet->preambleStartsPrevBuf) {
794 // Calculate number of preamble words in this sub-buffer
795 restOfPreamble = pDet->headerLength - pDet->preambleInd;
797 // Save the preamble words for sync check
798 for(i=0; i<restOfPreamble; i++)
799 {
800 pDet->preambleBuf[pDet->preambleInd++] = pbuf[i];
801 }
803 // Starts counting elements for next sync check
804 pDet->frameDataStartTemp = &pbuf[i]; // starting address of data in next frame
805 pDet->numElementsRcvd += numElements; // number of received elements
806 pDet->preambleStartsPrevBuf = FALSE; // reset flag
807 }
808 else {
809 // Preamble hasn't started from the sub-buffer in previous call.
810 // Check if this frame ends in this sub-buffer:
811 // distToFrameEnd: distance from beginning of this sub-buffer to frame end
812 // numElements: number of elements in this sub-buffer
813 if(pDet->distToFrameEnd < numElements) {
814 // Preamble of next frame is in this sub-buffer, either full or partial.
815 // First distToFrameEnd elements in the sub-buffer are the end of current
816 // frame. Preamble of next frame starts from pbuf[pDet->distToFrameEnd].
817 if(pDet->distToFrameEnd <= (numElements-pDet->headerLength)) {
818 // All the preamble words are in this sub-buffer
819 for(i=pDet->distToFrameEnd; i<pDet->distToFrameEnd+pDet->headerLength; i++)
820 {
821 // Save preamble words for sync check
822 pDet->preambleBuf[pDet->preambleInd++] = pbuf[i];
823 }
825 // Store the starting address of data in next frame.
826 // Note: &pbuf[i] could be 1 word pass the input buffer end if
827 // the last word of preamble happens to be at the end of
828 // the input buffer. In this case, this address needs to
829 // be wrapped around to the beginning of input buffer.
830 pDet->frameDataStartTemp = &pbuf[i];
831 }
832 else {
833 // Only partial preamble is in this sub-buffer.
834 // The preamble spans across this sub-buffer and next.
835 for(i=pDet->distToFrameEnd; i<numElements; i++)
836 {
837 pDet->preambleBuf[pDet->preambleInd++] = pbuf[i];
838 }
839 pDet->preambleStartsPrevBuf = TRUE;
840 }
842 // Starts counting elements for next sync check
843 pDet->numElementsRcvd = numElements - pDet->distToFrameEnd;
844 }
845 else {
846 // Current frame doesn't end here.
847 // Preamble of next frame is not in this sub-buffer
848 pDet->distToFrameEnd -= numElements;
849 }
850 }
852 // Check if full preamble of next frame has been received
853 if(pDet->preambleInd == pDet->headerLength) {
854 pDet->completeFrameRcvd = TRUE;
856 // Check if the preamble matches the reference.
857 diff = 0;
858 for(i=0; i<pDet->headerCheckLen; i++)
859 {
860 diff += pDet->preambleBuf[i] - pDet->preambleRef[i];
861 }
863 // SYNC is maintained if preamble matches reference
864 if(diff == 0) {
865 pDet->syncDetected = TRUE;
866 }
867 else {
868 pDet->syncDetected = FALSE;
869 }
871 // Reset index for next preamble check
872 //pDet->preambleInd = 0;
873 }
874 } /* syncCheck */
877 /* nothing past this point */