Fixed frame length discrepancy between ASIT and decoder.
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / io / ioData.c
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)
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)
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)
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)
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);
233   
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)
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)
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)
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)
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;
397     
398     case AUTODET_SYNC_SEARCH_PCM:
399       /* Search for SYNC while PCM is played out */
400       autoDetSyncScan(pIoDataInst);
401       
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;
413         
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       }
434       
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;
471     
472     default: break;
473   }
475 } /* autoDetection */
477 /*=============================================================================
478  * This function resets auto-detection.
479  =============================================================================*/
480 void autoDetReset(ioDataInst_t * pIoDataInst)
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)
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)
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)
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)
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)
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)
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 */