/** @file DHL_PSI_Impl.c @brief PSI implementation Copyright 2006~2010 Digital STREAM Technology, Inc. All Rights Reserved */ #include "DHL_OSAL.h" #include "DHL_DBG.h" #include "DHL_PSI.h" #include "DHL_PSI_Priv.h" #include "DHL_UTL.h" #include "bsettop_smessage.h" //#include ////#include //DHL_MODULE("*psi", 0); #if COMMENT ___Util_Mem_Func___(){} #endif #define SECTION_TID 0 /* TID index */ #define SECTION_LEN_HI 1 /* length hi index */ #define SECTION_LEN_LO 2 /* length lo index */ #define SECTION_TID_EXT_HI 3 /* Table ID extension high index*/ #define SECTION_TID_EXT_LO 4 /* Table ID extension low index */ #define SECTION_VERSION 5 /* version number index */ #define SECTION_NUM 6 /* section number index */ #define SECTION_NUM_LAST 7 /* last section number index */ #define SECTION_HEADER_LENGTH 8 /* number of bytes in section header */ #define SECTION_LEN_MASK 0x0FFF /* length bit mask */ #define SECTION_VERSION_MASK 0x3E /* version number bit mask */ #define SECTION_VERSION_SHIFT 1 /* version number bit shift */ #define PSI_GET_TID(hdr) ((hdr)[SECTION_TID]) #define PSI_GET_PRIV_INDI(hdr) ((hdr)[SECTION_LEN_HI]&0x8) #define PSI_GET_LEN(hdr) ((((hdr)[SECTION_LEN_HI]&0xF)<<8)+(hdr)[SECTION_LEN_LO]) #define PSI_GET_VER(hdr) (((hdr)[SECTION_VERSION]&SECTION_VERSION_MASK)>>SECTION_VERSION_SHIFT) #define PSI_GET_NUM(hdr) ((hdr)[SECTION_NUM]) #define PSI_GET_LAST_NUM(hdr) ((hdr)[SECTION_NUM_LAST]) void *dhl_psi_alloc_memory(UINT32 size, UINT32 flags) { void *p; p = DHL_OS_Malloc(size); if (p && (flags & DHL_PSI_MEMORY_CLEAR)) memset(p, 0, size); return p; } void dhl_psi_free_memory(void *block) { DHL_OS_Free((void**)&block); } static UINT32 p_get_data_crc(UINT8 *data, UINT32 len) { UINT32 crc; DHL_ASSERT(len >= 4, "p_get_data_crc: data too small!"); data += (len - 4); crc = ((*data) << 24) | ((*(data+1)) << 16) | ((*(data+2)) << 8) | *(data+3); return(crc); } #if COMMENT ____Config____(){} #endif #if COMMENT ____Types____(){} #endif #if COMMENT ____Macros____(){} #endif #define DHL_PSIDescriptorSize(nelem) (sizeof(tDHL_PSI_DataArray) + \ ((nelem)-DYNARRAY_SECTPTR)*sizeof(UINT8 *)) #if COMMENT ____Variables____(){} #endif #if COMMENT ____Debug____(){} #endif static char *psi_tid_str(UINT8 t) { static char buf[10]; return (t)==0x00 ? "pat" : \ (t)==0x02 ? "pmt" : \ (t)==0xC7 ? "mgt" : \ (t)==0xC8 ? "tvt" : \ (t)==0xC9 ? "cvt" : \ (t)==0xCA ? "rrt" : \ (t)==0xCB ? "eit" : \ (t)==0xCC ? "ett" : \ (t)==0xCD ? "stt" : \ (t)==0xD8 ? "eas" : \ (sprintf(buf, "x%02x", t), buf); } #if COMMENT ____ProcPSI____(){} #endif void dhl_psi_free_data_array(tDHL_PSI_DataArray *psi) { int i; for(i=0; inumSections; i++) { if (psi->sectPtr[i]) dhl_psi_free_memory(psi->sectPtr[i]); } dhl_psi_free_memory(psi); } void dhl_psi_set_filter_value(tDHL_PSI_Filter *pFilter, tDHL_FilterAttr attrType, UINT32 value) { switch(attrType) { #if 1//BRCM case eFILTERATTR_TID : pFilter->mask[0]=0x0; pFilter->coef[0]=(value&0xff); break; case eFILTERATTR_CURNEXTINDICATOR : pFilter->mask[5]=(UINT8)~0x1; pFilter->coef[5]|=(value&0x1); break; case eFILTERATTR_TIDEXTENSION : //case eFILTERATTR_SOURCEID : //case eFILTERATTR_BOTHFIELD : pFilter->mask[3]=0x0; pFilter->mask[4]=0x0; pFilter->coef[3]=(value>>8)&0xff; pFilter->coef[4]=(value&0xff); break; case eFILTERATTR_TOPFIELD : pFilter->mask[3]=0x0; pFilter->coef[3]=(value&0xff); break; case eFILTERATTR_BOTTOMFIELD : pFilter->mask[4]=0x0; pFilter->coef[4]=(value&0xff); break; case eFILTERATTR_ETMID : pFilter->mask[9]=0x0; pFilter->mask[10]=0x0; pFilter->mask[11]=0x0; pFilter->mask[12]=0x0; pFilter->coef[9]=(value>>24)&0xff; pFilter->coef[10]=(value>>16)&0xff; pFilter->coef[11]=(value>>8)&0xff; pFilter->coef[12]=(value&0xff); break; case eFILTERATTR_FIRSTPAYLOAD : // it is for checking protocol version. should be 8. pFilter->mask[8]=0x0; pFilter->coef[8]=(value&0xff); break; case eFILTERATTR_VERSION : pFilter->excl[5]=(UINT8)~0x3e; pFilter->coef[5]|=(value<<1)&0x3e; break; #else case eFILTERATTR_TID : pFilter->mask[0]=pFilter->mode[0]=0xff; pFilter->data[0]=(value&0xff); break; case eFILTERATTR_CURNEXTINDICATOR : pFilter->mask[5]=pFilter->mode[5]=(UINT8)0x1; pFilter->data[5]|=(value&0x1); break; case eFILTERATTR_TIDEXTENSION : //case eFILTERATTR_SOURCEID : //case eFILTERATTR_BOTHFIELD : pFilter->mask[3]=pFilter->mode[3]=0xff; pFilter->mask[4]=pFilter->mode[4]=0xff; pFilter->data[3]=(value>>8)&0xff; pFilter->data[4]=(value&0xff); break; case eFILTERATTR_TOPFIELD : pFilter->mask[3]=pFilter->mode[3]=0xff; pFilter->data[3]=(value&0xff); break; case eFILTERATTR_BOTTOMFIELD : pFilter->mask[4]=pFilter->mode[4]=0xff; pFilter->data[4]=(value&0xff); break; case eFILTERATTR_ETMID : pFilter->mask[9]=pFilter->mode[9]=0xff; pFilter->mask[10]=pFilter->mode[10]=0xff; pFilter->mask[11]=pFilter->mode[11]=0xff; pFilter->mask[12]=pFilter->mode[12]=0xff; pFilter->data[9]=(value>>24)&0xff; pFilter->data[10]=(value>>16)&0xff; pFilter->data[11]=(value>>8)&0xff; pFilter->data[12]=(value&0xff); break; case eFILTERATTR_FIRSTPAYLOAD : // it is for checking protocol version. should be 8. pFilter->mask[8]=pFilter->mode[8]=0xff; pFilter->data[8]=(value&0xff); break; case eFILTERATTR_VERSION : pFilter->mask[5]=(UINT8)0x3e; pFilter->mode[5]=(UINT8)0;//~0x3e; pFilter->data[5]|=(value<<1)&0x3e; break; #endif default : return; } // pFilter->attrCoef|=attrType; return; } #if DST_SW_FILTERING DHL_RESULT check_sw_filter(tDHL_PSI_Filter* pFilter, UINT8* buf, int len) { // UINT8 data, mask, mode; // ÇÊÅÍÀÇ data, mask, mode // UINT8 filter; int i; // len °ª 13º¸´Ù ÀÛÀºÁö üũ if (len < FILTER_MAX_BYTE) return DHL_FAIL; for(i = 0 ; i < FILTER_MAX_BYTE; i++) { #if 1//BRCM // match mask if (((~pFilter->mask[i]) & pFilter->coef[i]) != ((~pFilter->mask[i]) & buf[i])) { return FALSE; // 'FALSE' means 'not matched' } // exclude mask if ((pFilter->excl[i] != 0xff) && ((~pFilter->excl[i]) & pFilter->coef[i]) == ((~pFilter->excl[i]) & buf[i])) { return FALSE; // 'FALSE' means 'not matched' } #else if(pFilter->mask[i] == 0x00) // mask°ªÀÌ 0ÀÌ¸é ºñ±³ÇÏÁö ¾ÊÀ½ continue; data = pFilter->data[i]; mask = pFilter->mask[i]; mode = pFilter->mode[i]; // equal filtering validity check filter = mask & mode; if (filter != 0 && (buf[i] & filter) != (data & filter)) return DHL_FAIL; // not equal filtering validity check filter = (mask & ~mode); if (filter != 0 && (buf[i] & filter) == (data & filter)) return DHL_FAIL; #endif } return DHL_OK; } #endif tDHL_PSI_Event dhl_psi_post_data_received(tDHL_PSI_FiltCtl *pFltCtl, UINT8 *pdata, int len, int *procLen) { BOOL useCRC; tDHL_PSI_DataArray *desc=NULL; tDHL_PSI_Event event = ePSIEVENT_NOEVENT; UINT8 *buffer=NULL; int sectionNumber; int maxSections; int version; *procLen = PSI_GET_LEN(pdata) + 3; // ÀÔ·ÂµÈ ¼½¼Ç µ¥ÀÌÅÍÀÇ ±æÀ̰¡ ¼½¼Ç ³» section length°ªº¸´Ù ÀÛÀº °æ¿ì ¿¡·¯ if (len < *procLen) { // event = ePSIEVENT_SYNCERR; // SYNCERR ´Â ´Ù¸¥ ¿ëµµ·Î »ç¿ëµÇ´Ï ePSIEVENT_NOEVENT ¸®Åϵǵµ·Ï ÇÏÀÚ. *procLen = len; goto label_exit; } #if DST_CRC_RECHECK if (pdata[SECTION_LEN_HI]&0x80) { // section syntax indicator if (DHL_UTL_CalcCRC32(0xffffffff, pdata, *procLen) != 0) { printf( "section crc err!!\n"); goto label_exit; } } #endif #if DST_SW_FILTERING if(pFltCtl->pFltData == NULL) { printf( "sw section filter data ptr(pFltData) is NULL!!\n"); goto label_exit; } if(check_sw_filter(pFltCtl->pFltData, pdata, *procLen) != DHL_OK) { //printf( "sw section filter detected error!!\n"); goto label_exit; } #endif version = PSI_GET_VER(pdata); switch(pFltCtl->param.psiMode) { case ePSIMODE_SECTION: /* * In private mode, we simply pass the data along. We check CRC if * the section_syntax_indicator is set. * Section mode is like private mode except that we assume section * syntax and force a CRC check regardless of the section_syntax_indicator * bit. */ pFltCtl->receiveCount++; // ¸Þ¸ð¸®¸¦ »õ·Î ÇÒ´çÇÏ°í º¹»çÇØ¼­ »ç¿ë buffer = dhl_psi_alloc_memory(*procLen, 0); if (!buffer) { /* cafrii 090720 bugfix, desc will be freed before exit this function */ if(desc) dhl_psi_free_data_array(desc); event = ePSIEVENT_MEMORYERROR; goto label_exit; } memcpy(buffer, pdata, *procLen); useCRC = (buffer[SECTION_LEN_HI]&0x80); if (pFltCtl->param.updateMode == ePSIUPDATE_CRCCHANGE && useCRC) { // CRC üũ¸¦ ÇØ¾ß ÇÏ´Â ¸ðµå.. pFltCtl->runningCRC = p_get_data_crc(buffer, *procLen); // section ¸ðµå¿¡¼­ runningCRC´Â ±×Àú temp º¯¼ö Á¤µµ¿¡ Áö³ªÁö ¾Ê´Â´Ù. if (pFltCtl->lastCRCValid && pFltCtl->runningCRC == pFltCtl->lastCRC) { //printf( "section: crc same. ignored.\n"); dhl_psi_free_memory(buffer); pFltCtl->runningCRC = 0; goto label_exit; } if (pFltCtl->lastCRCValid) { //printf( "section: crc changed, 0x%08x -> 0x%08x\n", // pFltCtl->lastCRCValid ? pFltCtl->lastCRC : 0, pFltCtl->runningCRC); } pFltCtl->lastCRC = pFltCtl->runningCRC; pFltCtl->lastCRCValid = TRUE; pFltCtl->runningCRC = 0; } else if (pFltCtl->param.updateMode == ePSIUPDATE_VERCHANGE) { // ÀÌ ÇÊÅÍ¿¡¼­ ¸Ç óÀ½ ¼ö½ÅµÈ sectionÀÌ¸é ¹«Á¶°Ç ±â¾ïÇØ¾ß ÇÑ´Ù. // if (pFltCtl->curVersion >= 0 && pFltCtl->curVersion == version) { //printf( "section: ver same %d. ignored\n", version); dhl_psi_free_memory(buffer); // ´õ ÀÌ»ó ÀÌ ¹öÀüÀº ¼ö½ÅÇÏÁö ¸»¶ó°í ¼³Á¤.. dhl_psi_set_filter_value(pFltCtl->pFltData, eFILTERATTR_VERSION, version); update_psi_filter(pFltCtl); goto label_exit; } if (pFltCtl->curVersion >= 0) { //printf( "section: ver changed, %d -> %d\n", // pFltCtl->curVersion >= 0 ? pFltCtl->curVersion : -1, version); } dhl_psi_set_filter_value(pFltCtl->pFltData, eFILTERATTR_VERSION, version); update_psi_filter(pFltCtl); pFltCtl->curVersion = version; } /* cafrii 090720, array size¸¦ 1·Î ¼³Á¤. section À̹ǷΠ1°³¸é µÊ. */ desc = dhl_psi_alloc_memory(DHL_PSIDescriptorSize((unsigned int)1), DHL_PSI_MEMORY_CLEAR); if (!desc) { dhl_psi_free_memory(buffer); event = ePSIEVENT_MEMORYERROR; goto label_exit; } desc->pid = pFltCtl->pid; desc->handle = pFltCtl->handle; //pFltCtl; desc->numSections = 1; desc->maxSections = 1; desc->sectPtr[0] = buffer; if (pFltCtl->curDataArray) { // ÀÌ °æ¿ì´Â caller°¡ event proc ±¸ÇöÀ» ÇÏÁö ¾Ê¾Ò°Å³ª (½É°¢ÇÏÁö ¾ÊÀ½) // ¼º´É µîÀÇ ¹®Á¦·Î 󸮰¡ ´Ê¾îÁ®¼­ »ý±â´Â ¹®Á¦ÀÌ´Ù. (½É°¢ÇÔ) //printf( "!! prev section data still exist, %s\n", // psi_tid_str(PSI_GET_TID(buffer))); dhl_psi_free_data_array(pFltCtl->curDataArray); } // section ¸ðµå¿¡¼­´Â 'nextDataArray'´Â ¹Ì»ç¿ë. // ³ªÁß¿¡ ¹öÀü üũ¸¦ Çϱâ À§Çؼ­ ¹öÀü Á¤º¸ ±â¾ï.. pFltCtl->curDataArray = desc; // ¸Ç ¸¶Áö¸·¿¡ À§Ä¡ÇØ¾ß ÇÔ. ¿¡·¯°¡ ³­ °æ¿ì´Â ´Ù½Ã ¹Þ¾Æ¾ß ÇϹǷÎ.. if (pFltCtl->param.updateMode == ePSIUPDATE_ONESHOT) { //printf( "section: flt[%d] stop action for one shot mode\n", pFltCtl->index); pause_psi_filter(pFltCtl); } event = ePSIEVENT_DATARECEIVED; pFltCtl->goodCount++; break; case ePSIMODE_TABLE: pFltCtl->receiveCount++; sectionNumber = PSI_GET_NUM(pdata); // ¹æ±Ý ¼ö½ÅµÈ sectionÀÇ section number maxSections = PSI_GET_LAST_NUM(pdata)+1; desc = pFltCtl->nextDataArray; // Áö±Ý ¸ð¾ÆÁö°í ÀÖ´Â data array // basic sanity test. // section ÀÌ table ÀÇ version °ú ´Ù¸£°Å³ª, section number°¡ ¹Ù²î¾î¹ö¸° °æ¿ì // ´õ ÀÌ»ó ÁøÇàÀÌ ºÒ°¡´ÉÇÏ´Ù. if (desc && (pFltCtl->nextVersion != version || desc->maxSections != maxSections)) { // comment: nextDataArray °¡ Á¸ÀçÇϸé versionÀº Ç×»ó valid ÇÏ´Ù. // The version number changed or else something weird happened because // last_section_number changed. In any case, throw away what we had printf( "!! inconsistency! ver (in %d, stored %d) max_sec (in %d, stored %d)\n", version, pFltCtl->nextVersion, maxSections, desc->maxSections); // comment: nextDataArray °¡ Á¸ÀçÇϸé versionÀº Ç×»ó valid ÇÏ´Ù. dhl_psi_free_data_array(pFltCtl->nextDataArray); pFltCtl->nextDataArray = desc = NULL; pFltCtl->runningCRC = 0; } if (desc) { // This is a second or subsequent section in the table. Take it if // we haven't seen it yet. Else, discard it. if (sectionNumber >= desc->maxSections) { // This section is beyond maxSections, but we have already informed // the client that this has happened. event = ePSIEVENT_MAXSECTIONOVERFLOW; printf( "!! table: sect[%d] beyond max %d. drop!\n", sectionNumber, desc->maxSections); goto label_exit; } else if (desc->sectPtr[sectionNumber] != NULL) { // we have already received this section, so discard this one quietly. //printf( "table: sect[%d] already exist\n", sectionNumber); goto label_exit; } } else { // We are getting the first section of a new table if (maxSections > pFltCtl->param.maxSections) { printf( "!! table: sect[%d]'s max %d beyond max %d. adjusted to %d\n", sectionNumber, maxSections, desc->maxSections, pFltCtl->param.maxSections); event = ePSIEVENT_MAXSECTIONOVERFLOW; maxSections = pFltCtl->param.maxSections; // use caller's param. } if (sectionNumber >= maxSections) { event = ePSIEVENT_LASTSECTIONOVERFLOW; goto label_exit; } desc = dhl_psi_alloc_memory(DHL_PSIDescriptorSize(maxSections), DHL_PSI_MEMORY_CLEAR); if (!desc) { event = ePSIEVENT_MEMORYERROR; goto label_exit; } desc->pid = pFltCtl->pid; desc->handle = pFltCtl->handle;//pFltCtl; desc->numSections = 0; desc->maxSections = maxSections; // desc->sectPtr is reset to zero in dhl_psi_alloc_memory pFltCtl->runningCRC = 0; pFltCtl->nextVersion = version; pFltCtl->nextDataArray = desc; } // ¸Þ¸ð¸®¸¦ »õ·Î ÇÒ´çÇÏ°í º¹»çÇØ¼­ »ç¿ë buffer = dhl_psi_alloc_memory(*procLen, 0); if (!buffer) { event = ePSIEVENT_MEMORYERROR; dhl_psi_free_data_array(desc); goto label_exit; } memcpy(buffer, pdata, *procLen); desc->sectPtr[sectionNumber] = buffer; // ÀÌÁ¦ºÎÅÍ´Â buffer¸¦ µû·Î free ½Ãų ÇÊ¿ä ¾øÀ½. ÇÊ¿äÇϸé desc¸¸ free ÇÏ¸é µÈ´Ù. if (pFltCtl->param.updateMode == ePSIUPDATE_CRCCHANGE) { pFltCtl->runningCRC ^= p_get_data_crc(buffer, *procLen); } pFltCtl->curSection = sectionNumber; desc->numSections++; if (desc->numSections < desc->maxSections) // ¾ÆÁ÷ ¸ðµç section ÀÌ ¸ð¾ÆÁöÁö ¾Ê¾ÒÀ½. break; /////////////////////////////////////////////////////////////////////////////// // We have the whole table, so we can now feed it to the client /////////////////////////////////////////////////////////////////////////////// if (pFltCtl->param.updateMode == ePSIUPDATE_ONESHOT) { pause_psi_filter(pFltCtl); } else if (pFltCtl->param.updateMode == ePSIUPDATE_CRCCHANGE) { if (pFltCtl->lastCRCValid && pFltCtl->runningCRC == pFltCtl->lastCRC) { // µ¿ÀÏÇÑ CRC.. ¹«½Ã.. //printf( "table: crc same. ignored\n"); pFltCtl->runningCRC = 0; dhl_psi_free_data_array(desc); pFltCtl->nextDataArray = NULL; goto label_exit; } // CRC Change ¸ðµåÀÎ °æ¿ì´Â ÇöÀç ¼³Á¤À» À¯ÁöÇÑ Ã¤ CRC¸¸ ±â¾ïÇØ ³õ´Â´Ù. //printf( "table: crc changed, 0x%08x -> 0x%08x\n", // pFltCtl->lastCRCValid ? pFltCtl->lastCRC : 0, pFltCtl->runningCRC); pFltCtl->lastCRC = pFltCtl->runningCRC; pFltCtl->lastCRCValid = TRUE; pFltCtl->runningCRC = 0; } else if (pFltCtl->param.updateMode == ePSIUPDATE_VERCHANGE) { /* * Here, we modify the psiFilter to only fire on a version different * from the one we just received. */ // ½ÇÁ¦·Î ¹öÀüÀÌ º¯°æ µÈ °ÍÀÎÁö ºñ±³ÇÏ´Â ÄÚµå´Â ¾ø´Ù. // hw filter°¡ Á¦´ë·Î µ¿ÀÛÇß´Ù°í º¸´Â °ÍÀÓ. if (pFltCtl->curVersion >= 0 && pFltCtl->curVersion == version) { //printf( "table: ver same %d. ignored\n", version); // ´õ ÀÌ»ó ÀÌ ¹öÀüÀº ¼ö½ÅÇÏÁö ¸»¶ó°í ¼³Á¤.. dhl_psi_set_filter_value(pFltCtl->pFltData, eFILTERATTR_VERSION, version); update_psi_filter(pFltCtl); dhl_psi_free_data_array(desc); pFltCtl->nextDataArray = NULL; goto label_exit; } //printf( "table: ver changed, %d -> %d\n", // pFltCtl->curVersion >= 0 ? pFltCtl->curVersion : -1, version); dhl_psi_set_filter_value(pFltCtl->pFltData, eFILTERATTR_VERSION, version); update_psi_filter(pFltCtl); pFltCtl->curVersion = version; } if (pFltCtl->curDataArray) { // ÀÌ °æ¿ì´Â caller°¡ event proc ±¸ÇöÀ» ÇÏÁö ¾Ê¾Ò°Å³ª (½É°¢ÇÏÁö ¾ÊÀ½) // ¼º´É µîÀÇ ¹®Á¦·Î 󸮰¡ ´Ê¾îÁ®¼­ »ý±â´Â ¹®Á¦ÀÌ´Ù. (½É°¢ÇÔ) printf( "!! prev table data still exist, %s\n", psi_tid_str(PSI_GET_TID(desc->sectPtr[0]))); dhl_psi_free_data_array(pFltCtl->curDataArray); } pFltCtl->curDataArray = desc; pFltCtl->nextDataArray = NULL; event = ePSIEVENT_DATARECEIVED; pFltCtl->goodCount++; break; default : printf("FATAL: dhl_psi_post_data_received: Bad PSI mode\n"); } return event; label_exit : return event; } #if COMMENT ____Symbol____(){} #endif #if DHL_REGISTER_DEUBG_SYMBOLS #if 0 static DHL_SymbolTable _XxxxSymbols[] = { /* however, if you want typing short-cut, it is good usage. */ DHL_FNC_SYM_ENTRY2("epg_start", App_EpgUpdateStart), DHL_FNC_SYM_ENTRY2("epg_stop", App_EpgUpdateCancel), DHL_FNC_SYM_ENTRY2("epg_list", Dmc_EpgPrintAllTables), DHL_FNC_SYM_ENTRY2("epg_delete", App_EpgDeleteAll), DHL_VAR_SYM_ENTRY(g_XX_TestMode), }; #endif #endif /* DHL_REGISTER_DEUBG_SYMBOLS */ /* end of file */