/****************************************************************************** * * Freescale Semiconductor Inc. * (c) Copyright 2004-2006 Freescale Semiconductor, Inc. * (c) Copyright 2001-2004 Motorola, Inc. * ALL RIGHTS RESERVED. * ****************************************************************************//*! * * @file PE_freemaster_rec.c * * @brief FreeMASTER Recorder implementation. * * @version 1.0.10.0 * * @date Oct-22-2007 * *******************************************************************************/ #include "PE_freemaster.h" #include "PE_freemaster_private.h" #include "PE_freemaster_protocol.h" #if FMSTR_USE_RECORDER #include "PE_freemaster_rec.h" #if FMSTR_USE_FASTREC #include "PE_freemaster_fastrec.h" #endif /******************************************************** * global variables (shared with FastRecorder if used) ********************************************************/ /* configuration variables */ FMSTR_U16 pcm_wRecTotalSmps; /* number of samples to measure */ FMSTR_U16 pcm_wRecPostTrigger; /* number of post-trigger samples to keep */ FMSTR_U8 pcm_nRecTriggerMode; /* triger mode (0 = disabled, 1 = _/, 2 = \_) */ FMSTR_U16 pcm_wRecTimeDiv; /* divisor of recorder "clock" */ FMSTR_U8 pcm_nRecVarCount; /* number of active recorder variables */ FMSTR_ADDR pcm_pRecVarAddr[FMSTR_MAX_SCOPE_VARS]; /* addresses of recorded variables */ FMSTR_SIZE8 pcm_pRecVarSize[FMSTR_MAX_SCOPE_VARS]; /* sizes of recorded variables */ /* runtime variables */ FMSTR_U16 pcm_wRecBuffStartIx; /* first sample index */ FMSTR_ADDR pcm_dwRecWritePtr; /* write pointer in recorder buffer */ FMSTR_ADDR pcm_dwRecEndBuffPtr; /* pointer to end of active recorder buffer */ FMSTR_U16 pcm_wRecTimeDivCtr; /* recorder "clock" divisor counter */ FMSTR_U16 pcm_wStoprecCountDown; /* post-trigger countdown counter */ /* recorder flags */ FMSTR_REC_FLAGS pcm_wRecFlags; /*********************************** * local variables ***********************************/ /* configuration variables */ static FMSTR_ADDR pcm_nTrgVarAddr; /* trigger variable address */ static FMSTR_U8 pcm_nTrgVarSize; /* trigger variable threshold size */ static FMSTR_U8 pcm_bTrgVarSigned; /* trigger compare mode (0 = unsigned, 1 = signed) */ /*lint -e{960} using union */ static union { #if FMSTR_CFG_BUS_WIDTH == 1 FMSTR_U8 u8; FMSTR_S8 s8; #endif FMSTR_U16 u16; FMSTR_S16 s16; FMSTR_U32 u32; FMSTR_S32 s32; } pcm_uTrgThreshold; /* trigger threshold level (1,2 or 4 bytes) */ static FMSTR_ADDR pcm_nRecBuffAddr; /* recorder buffer address */ static FMSTR_SIZE pcm_wRecBuffSize; /* recorder buffer size */ /* compare functions prototype */ typedef FMSTR_BOOL (*FMSTR_PCOMPAREFUNC)(void); /*/ pointer to active compare function */ static FMSTR_PCOMPAREFUNC pcm_pCompareFunc; #if !FMSTR_REC_OWNBUFF && !FMSTR_USE_FASTREC /* put buffer into far memory ? */ #if FMSTR_REC_FARBUFF #pragma section fardata begin #endif /* FMSTR_REC_FARBUFF */ /* statically allocated recorder buffer (FMSTR_REC_OWNBUFF is FALSE) */ static FMSTR_U8 pcm_pOwnRecBuffer[FMSTR_REC_BUFF_SIZE]; /* end of far memory section */ #if FMSTR_REC_FARBUFF #pragma section fardata end #endif /* FMSTR_REC_FARBUFF */ #endif /* FMSTR_REC_OWNBUFF */ /*********************************** * local functions ***********************************/ static FMSTR_BOOL FMSTR_Compare8S(void); static FMSTR_BOOL FMSTR_Compare8U(void); static FMSTR_BOOL FMSTR_Compare16S(void); static FMSTR_BOOL FMSTR_Compare16U(void); static FMSTR_BOOL FMSTR_Compare32S(void); static FMSTR_BOOL FMSTR_Compare32U(void); static void FMSTR_Recorder2(void); /**************************************************************************//*! * * @brief Recorder Initialization * ******************************************************************************/ void FMSTR_InitRec(void) { /* setup buffer pointer and size so IsInRecBuffer works even before the recorder is first initialized and used */ #if FMSTR_REC_OWNBUFF || FMSTR_USE_FASTREC /* user wants to use his own buffer */ pcm_nRecBuffAddr = 0U; pcm_wRecBuffSize = 0U; #else /* size in native sizeof units (=bytes on most platforms) */ pcm_wRecBuffSize = (FMSTR_SIZE) FMSTR_REC_BUFF_SIZE; FMSTR_ARR2ADDR(pcm_nRecBuffAddr, pcm_pOwnRecBuffer); /*lint -esym(528, pcm_pOwnRecBuffer) this symbol is used outside of lint sight */ #endif #if FMSTR_USE_FASTREC FMSTR_InitFastRec(); #endif } /**************************************************************************//*! * * @brief API: Replacing the recorder buffer with the user's one * * @param pBuffer - user buffer pointer * @param wBuffSize - buffer size * * @note Use the FMSTR_SetUpBuff32 to pass the forced 32bit address in SDM * ******************************************************************************/ void FMSTR_SetUpRecBuff(FMSTR_ADDR pBuffer, FMSTR_SIZE nBuffSize) { pcm_nRecBuffAddr = pBuffer; pcm_wRecBuffSize = nBuffSize; } /**************************************************************************//*! * * @brief Handling SETUPREC and SETUPREC_EX commands * * @param pMessageIO - original command (in) and response buffer (out) * * @return As all command handlers, the return value should be the buffer * pointer where the response output finished (except checksum) * ******************************************************************************/ FMSTR_BPTR FMSTR_SetUpRec(FMSTR_BPTR pMessageIO) { FMSTR_BPTR pResponse = pMessageIO; FMSTR_SIZE8 nRecVarsetSize; FMSTR_SIZE blen; FMSTR_U8 i, sz; /* de-initialize first */ FMSTR_AbortRec(); #if FMSTR_REC_OWNBUFF || FMSTR_USE_FASTREC /* user wants to use his own buffer, check if it is valid */ if(!pcm_nRecBuffAddr || !pcm_wRecBuffSize) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVBUFF); } #else /* size in native sizeof units (=bytes on most platforms) */ pcm_wRecBuffSize = (FMSTR_SIZE)FMSTR_REC_BUFF_SIZE; FMSTR_ARR2ADDR(pcm_nRecBuffAddr, pcm_pOwnRecBuffer); // заполнение буфера #endif /* seek the setup data */ pMessageIO = FMSTR_SkipInBuffer(pMessageIO, 2U); pMessageIO = FMSTR_ValueFromBuffer8(&pcm_nRecTriggerMode, pMessageIO); pMessageIO = FMSTR_ValueFromBuffer16(&pcm_wRecTotalSmps, pMessageIO); pMessageIO = FMSTR_ValueFromBuffer16(&pcm_wRecPostTrigger, pMessageIO); pMessageIO = FMSTR_ValueFromBuffer16(&pcm_wRecTimeDiv, pMessageIO); /* address & size of trigger variable */ pMessageIO = FMSTR_AddressFromBuffer(&pcm_nTrgVarAddr, pMessageIO); pMessageIO = FMSTR_ValueFromBuffer8(&pcm_nTrgVarSize, pMessageIO); /* trigger compare mode */ pMessageIO = FMSTR_ValueFromBuffer8(&pcm_bTrgVarSigned, pMessageIO); /* threshold value */ pMessageIO = FMSTR_ValueFromBuffer32(&pcm_uTrgThreshold.u32, pMessageIO); /* recorder variable count */ pMessageIO = FMSTR_ValueFromBuffer8(&pcm_nRecVarCount, pMessageIO); /* rec variable information must fit into our buffers */ if(!pcm_nRecVarCount || pcm_nRecVarCount > (FMSTR_U8)FMSTR_MAX_REC_VARS) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVBUFF); } /* calculate sum of sizes of all variables */ nRecVarsetSize = 0U; /* get all addresses and sizes */ for(i=0U; i 8U) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVSIZE); } #if FMSTR_CFG_BUS_WIDTH > 1U /* even sizes only */ if(sz & 0x1) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVSIZE); } #endif #if FMSTR_USE_TSA && FMSTR_USE_TSA_SAFETY if(!FMSTR_CheckTsaSpace(pcm_pRecVarAddr[i], (FMSTR_SIZE8)sz, 0U)) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_EACCESS); } #endif } /* fast recorder handles trigger by itself */ #if !FMSTR_USE_FASTREC /* any trigger? */ pcm_pCompareFunc = NULL; if(pcm_nRecTriggerMode) { /* access to trigger variable? */ #if FMSTR_USE_TSA && FMSTR_USE_TSA_SAFETY if(!FMSTR_CheckTsaSpace(pcm_nTrgVarAddr, (FMSTR_SIZE8)pcm_nTrgVarSize, 0U)) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_EACCESS); } #endif /* get compare function */ switch(pcm_nTrgVarSize) { #if FMSTR_CFG_BUS_WIDTH == 1U case 1: pcm_pCompareFunc = pcm_bTrgVarSigned ? FMSTR_Compare8S : FMSTR_Compare8U; break; #endif case 2: pcm_pCompareFunc = pcm_bTrgVarSigned ? FMSTR_Compare16S : FMSTR_Compare16U; break; case 4: pcm_pCompareFunc = pcm_bTrgVarSigned ? FMSTR_Compare32S : FMSTR_Compare32U; break; /* invalid trigger variable size */ default: return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVSIZE); } } #endif /* !FMSTR_USE_FASTREC */ /* total recorder buffer length in native sizeof units (=bytes on most platforms) */ blen = (FMSTR_SIZE) (pcm_wRecTotalSmps * nRecVarsetSize / FMSTR_CFG_BUS_WIDTH); /* recorder memory available? */ if(blen > pcm_wRecBuffSize) { return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_INVSIZE); } /* remember the effective end of circular buffer */ pcm_dwRecEndBuffPtr = pcm_nRecBuffAddr + blen; #if FMSTR_USE_FASTREC if(!FMSTR_SetUpFastRec()) return FMSTR_ConstToBuffer8(pResponse, FMSTR_STC_FASTRECERR); #endif /* everything is okay */ pcm_wRecFlags.flg.bIsConfigured = 1U; return FMSTR_ConstToBuffer8(pResponse, FMSTR_STS_OK); } /**************************************************************************//*! * * @brief Abort and de-initialize recorder * ******************************************************************************/ void FMSTR_AbortRec(void) { /* clear flags */ pcm_wRecFlags.all = 0U; } /**************************************************************************//*! * * @brief Check wether given memory region is inside the recorder buffer * * @param dwAddr - address of the memory to be checked * @param wSize - size of the memory to be checked * * @return This function returns non-zero if user space is in recorder buffer * * This function is called as a pert of TSA-checking process when the PC host * is requesting memory contents * ******************************************************************************/ FMSTR_BOOL FMSTR_IsInRecBuffer(FMSTR_ADDR dwAddr, FMSTR_SIZE8 nSize) { FMSTR_BOOL bRet = 0U; if(dwAddr >= pcm_nRecBuffAddr) { bRet = (FMSTR_BOOL)((dwAddr + nSize) <= (pcm_nRecBuffAddr + FMSTR_GetRecBuffSize()) ? FMSTR_TRUE : FMSTR_FALSE); } return bRet; } /**************************************************************************//*! * * @brief Get recorder memory size * * @return Recorder memory size in native sizeof units (=bytes on most platforms) * ******************************************************************************/ FMSTR_SIZE FMSTR_GetRecBuffSize() { #if FMSTR_REC_OWNBUFF || FMSTR_USE_FASTREC return pcm_wRecBuffSize; #else return (FMSTR_SIZE) FMSTR_REC_BUFF_SIZE; #endif } /**************************************************************************//*! * * @brief API: Pull the trigger of the recorder * * This function starts the post-trigger stop countdown * ******************************************************************************/ void FMSTR_TriggerRec(void) { if(!pcm_wRecFlags.flg.bIsStopping) { pcm_wRecFlags.flg.bIsStopping = 1U; pcm_wStoprecCountDown = pcm_wRecPostTrigger; #if FMSTR_USE_FASTREC FMSTR_TriggerFastRec(); #endif } } /**************************************************************************//*! * * @brief Handling STARTREC command * * @param pMessageIO - original command (in) and response buffer (out) * * @return As all command handlers, the return value should be the length * of the response filled into the buffer (including status byte) * * This function starts recording (initializes internal recording variables * and flags) * ******************************************************************************/ FMSTR_BPTR FMSTR_StartRec(FMSTR_BPTR pMessageIO) { /* must be configured */ if(!pcm_wRecFlags.flg.bIsConfigured) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STC_NOTINIT); } /* already running ? */ if(pcm_wRecFlags.flg.bIsRunning) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STS_RECRUN); } /* initialize write pointer */ pcm_dwRecWritePtr = pcm_nRecBuffAddr; /* current (first) sample index */ pcm_wRecBuffStartIx = 0U; /* initialize time divisor */ pcm_wRecTimeDivCtr = 0U; /* initiate virgin cycle */ pcm_wRecFlags.flg.bIsStopping = 0U; /* no trigger active */ pcm_wRecFlags.flg.bTrgCrossActive = 0U; /* waiting for threshold crossing */ pcm_wRecFlags.flg.bInvirginCycle = 1U; /* initial cycle */ /* start fast recorder */ #if FMSTR_USE_FASTREC FMSTR_StartFastRec(); #endif /* run now */ pcm_wRecFlags.flg.bIsRunning = 1U; /* is running now! */ return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STS_OK); } /**************************************************************************//*! * * @brief Handling STOPREC command * * @param pMessageIO - original command (in) and response buffer (out) * * @return As all command handlers, the return value should be the length * of the response filled into the buffer (including status byte) * * This function stops recording (same as manual trigger) * ******************************************************************************/ FMSTR_BPTR FMSTR_StopRec(FMSTR_BPTR pMessageIO) { /* must be configured */ if(!pcm_wRecFlags.flg.bIsConfigured) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STC_NOTINIT); } /* already stopped ? */ if(!pcm_wRecFlags.flg.bIsRunning) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STS_RECDONE); } /* simulate trigger */ FMSTR_TriggerRec(); return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STS_OK); } /**************************************************************************//*! * * @brief Handling GETRECSTS command * * @param pMessageIO - original command (in) and response buffer (out) * * @return As all command handlers, the return value should be the buffer * pointer where the response output finished (except checksum) * * This function returns current recorder status * ******************************************************************************/ FMSTR_BPTR FMSTR_GetRecStatus(FMSTR_BPTR pMessageIO) { /* must be configured */ if(!pcm_wRecFlags.flg.bIsConfigured) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STC_NOTINIT); } /* get run/stop status */ return FMSTR_ConstToBuffer8(pMessageIO, (FMSTR_U8)(pcm_wRecFlags.flg.bIsRunning ? FMSTR_STS_RECRUN : FMSTR_STS_RECDONE)); } /**************************************************************************//*! * * @brief Handling GETRECBUFF and GETRECBUFF_EX command * * @param pMessageIO - original command (in) and response buffer (out) * * @return As all command handlers, the return value should be the buffer * pointer where the response output finished (except checksum) * * This function returns recorder buffer information * ******************************************************************************/ FMSTR_BPTR FMSTR_GetRecBuff(FMSTR_BPTR pMessageIO) { /* must be configured */ if(!pcm_wRecFlags.flg.bIsConfigured) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STC_NOTINIT); } /* must be stopped */ if(pcm_wRecFlags.flg.bIsRunning) { return FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STC_SERVBUSY); } #if FMSTR_USE_FASTREC FMSTR_GetFastRecBuff(); #endif /* fill the return info */ pMessageIO = FMSTR_ConstToBuffer8(pMessageIO, FMSTR_STS_OK); pMessageIO = FMSTR_AddressToBuffer(pMessageIO, pcm_nRecBuffAddr); return FMSTR_ValueToBuffer16(pMessageIO, pcm_wRecBuffStartIx); } /* now follows the sampling routines, skip that if FastRecorder is used */ #if !FMSTR_USE_FASTREC /**************************************************************************//*! * * @brief Compare macro used in trigger detection * * @param v - original command * @param t - response buffer * * @return zero when value is lower than threshold. * @return non-zero when value is greater than or equal as treshold * ******************************************************************************/ #define CMP(v,t) ((FMSTR_BOOL)(((v) < (t)) ? 0 : 1)) #if FMSTR_CFG_BUS_WIDTH == 1U static FMSTR_BOOL FMSTR_Compare8S() { return CMP(FMSTR_GetS8(pcm_nTrgVarAddr), pcm_uTrgThreshold.s8); } static FMSTR_BOOL FMSTR_Compare8U() { return CMP(FMSTR_GetU8(pcm_nTrgVarAddr), pcm_uTrgThreshold.u8); } #endif static FMSTR_BOOL FMSTR_Compare16S() { return CMP(FMSTR_GetS16(pcm_nTrgVarAddr), pcm_uTrgThreshold.s16); } static FMSTR_BOOL FMSTR_Compare16U() { return CMP(FMSTR_GetU16(pcm_nTrgVarAddr), pcm_uTrgThreshold.u16); } static FMSTR_BOOL FMSTR_Compare32S() { return CMP(FMSTR_GetS32(pcm_nTrgVarAddr), pcm_uTrgThreshold.s32); } static FMSTR_BOOL FMSTR_Compare32U() { return CMP(FMSTR_GetU32(pcm_nTrgVarAddr), pcm_uTrgThreshold.u32); } /**************************************************************************//*! * * @brief API: Recorder worker routine - can be called from application's timer ISR * * * This returns quickly if recorder is not running, otherwise it calls quite lengthy * recorder routine which does all the recorder work (sampling, triggering) * ******************************************************************************/ void FMSTR_Recorder(void) { /* recorder not active */ if(!pcm_wRecFlags.flg.bIsRunning) { return ; } /* do the hard work */ FMSTR_Recorder2(); } /**************************************************************************//*! * * @brief Recorder function called when recorder is active * ******************************************************************************/ static void FMSTR_Recorder2(void) { FMSTR_SIZE8 sz; FMSTR_BOOL cmp; FMSTR_U8 i; /* skip this call ? */ if(pcm_wRecTimeDivCtr) { /* maybe next time... */ pcm_wRecTimeDivCtr--; return; } /* re-initialize divider */ pcm_wRecTimeDivCtr = pcm_wRecTimeDiv; /* take snapshot of variable values */ for (i=0U; i= pcm_dwRecEndBuffPtr) { pcm_dwRecWritePtr = pcm_nRecBuffAddr; pcm_wRecFlags.flg.bInvirginCycle = 0U; pcm_wRecBuffStartIx = 0U; } /* no trigger testing in virgin cycle */ if(pcm_wRecFlags.flg.bInvirginCycle) { return; } /* test trigger condition if still running */ if(!pcm_wRecFlags.flg.bIsStopping && pcm_pCompareFunc != NULL) { /* compare trigger threshold */ cmp = pcm_pCompareFunc(); /* negated logic (falling-edge) ? */ if(pcm_nRecTriggerMode == 2U) { cmp = (FMSTR_BOOL) !cmp; } /* above threshold ? */ if(cmp) { /* were we at least once below threshold ? */ if(pcm_wRecFlags.flg.bTrgCrossActive) { /* EDGE TRIGGER ! */ FMSTR_TriggerRec(); } } else { /* we got bellow threshold, now wait for being above threshold */ pcm_wRecFlags.flg.bTrgCrossActive = 1U; } } /* in stopping mode ? (note that this bit might have been set just above!) */ if(pcm_wRecFlags.flg.bIsStopping) { /* count down post-trigger samples expired ? */ if(!pcm_wStoprecCountDown) { /* STOP RECORDER */ pcm_wRecFlags.flg.bIsRunning = 0U; return; } /* perhaps next time */ pcm_wStoprecCountDown--; } } #endif /* !FMSTR_USE_FASTREC */ #else /* FMSTR_USE_RECORDER */ /* use void recorder API functions */ void FMSTR_Recorder(void) { } void FMSTR_TriggerRec(void) { } void FMSTR_SetUpRecBuff(FMSTR_ADDR pBuffer, FMSTR_SIZE wBuffSize) { FMSTR_UNUSED(pBuffer); FMSTR_UNUSED(wBuffSize); } /*lint -efile(766, PE_freemaster_protocol.h) include file is not used in this case */ #endif /* FMSTR_USE_RECORDER */