/****************************************************************************** * * Freescale Semiconductor Inc. * (c) Copyright 2004-2007 Freescale Semiconductor, Inc. * (c) Copyright 2001-2004 Motorola, Inc. * ALL RIGHTS RESERVED. * ****************************************************************************//*! * * @file PE_freemaster_serial.c * * @brief FreeMASTER SCI communication routines * * @version 1.1.18.0 * * @date Oct-22-2007 * *******************************************************************************/ #include "PE_freemaster.h" #include "PE_freemaster_private.h" #include "PE_freemaster_protocol.h" //#include "include.h" extern void FMSTR_SCI_PUTCHAR(char _data); extern char FMSTR_SCI_GETCHAR(void); extern void FMSTR_SCI_RE(void); extern void FMSTR_SCI_RD(void); extern void FMSTR_SCI_TE(void); extern void FMSTR_SCI_TD(void); extern FMSTR_SCISR FMSTR_SCI_RDCLRSR(void); #if FMSTR_USE_SCI || FMSTR_USE_JTAG /*********************************** * local variables ***********************************/ /* FreeMASTER communication buffer (in/out) plus the STS and LEN bytes */ static FMSTR_BCHR pcm_pCommBuffer[FMSTR_COMM_BUFFER_SIZE+3]; /* FreeMASTER runtime flags */ /*lint -e{960} using union */ static volatile union { FMSTR_FLAGS all; struct { unsigned bTxActive : 1; /* response is being transmitted */ unsigned bTxWaitTC : 1; /* response sent, wait for transmission complete */ unsigned bTxLastCharSOB : 1; /* last transmitted char was equal to SOB */ unsigned bRxLastCharSOB : 1; /* last received character was SOB */ unsigned bRxMsgLengthNext : 1; /* expect the length byte next time */ unsigned bJtagRIEPending : 1; /* JTAG RIE bit failed to be set, try again later */ } flg; } pcm_wFlags; /* receive and transmit buffers and counters */ static FMSTR_SIZE8 pcm_nTxTodo; /* transmission to-do counter (0 when tx is idle) */ static FMSTR_SIZE8 pcm_nRxTodo; /* reception to-do counter (0 when rx is idle) */ static FMSTR_BPTR pcm_pTxBuff; /* pointer to next byte to transmit */ static FMSTR_BPTR pcm_pRxBuff; /* pointer to next free place in RX buffer */ static FMSTR_BCHR pcm_nRxCheckSum; /* checksum of data being received */ /* SHORT_INTR receive queue (circular buffer) */ #if FMSTR_SHORT_INTR static FMSTR_BCHR pcm_pRQueueBuffer[FMSTR_COMM_RQUEUE_SIZE]; static FMSTR_BPTR pcm_pRQueueRP; /* SHORT_INTR queue read-pointer */ static FMSTR_BPTR pcm_pRQueueWP; /* SHORT_INTR queue write-pointer */ #endif #if FMSTR_USE_JTAG static FMSTR_U32 pcm_wJtagTxData; /* four bytes buffer to be sent over JTAG (LSB first) */ static FMSTR_SIZE8 pcm_wJtagTxCtr; /* counter of bytes in pcm_wJtagTxData */ #endif /*********************************** * local function prototypes ***********************************/ static void FMSTR_Listen(void); static void FMSTR_SendError(FMSTR_BCHR nErrCode); static void FMSTR_Tx(void); static void FMSTR_Rx(FMSTR_BCHR nRxChar); //static void FMSTR_RxQueue(FMSTR_BCHR nRxChar); //static void FMSTR_RxDequeue(void); /*lint -esym(752,FMSTR_RxQueue) this may be unreferenced in some cases */ /*lint -esym(752,FMSTR_RxDequeue) this may be unreferenced in some cases */ /**************************************************************************//*! * * @brief Serial communication initialization * ******************************************************************************/ void FMSTR_InitSerial(void) { /* initialize all state variables */ pcm_wFlags.all = 0U; pcm_nTxTodo = 0U; pcm_nRxTodo = 0U; #if FMSTR_SHORT_INTR pcm_pRQueueRP = pcm_pRQueueBuffer; pcm_pRQueueWP = pcm_pRQueueBuffer; #endif /* start listening for commands */ FMSTR_Listen(); } /**************************************************************************//*! * * @brief Start listening on a serial line * * Reset the receiver machine and start listening on a serial line * ******************************************************************************/ static void FMSTR_Listen(void) { pcm_nRxTodo = 0U; /* disable transmitter state machine */ pcm_wFlags.flg.bTxActive = 0U; pcm_wFlags.flg.bTxWaitTC = 0U; /* disable transmitter, enable receiver (enables single-wire connection) */ #if FMSTR_USE_SCI FMSTR_SCI_TD(); FMSTR_SCI_RE(); #endif } /**************************************************************************//*! * * @brief Send response of given error code (no data) * * @param nErrCode - error code to be sent * ******************************************************************************/ static void FMSTR_SendError(FMSTR_BCHR nErrCode) { /* fill & send single-byte response */ *pcm_pCommBuffer = nErrCode; FMSTR_SendResponse(pcm_pCommBuffer, 1U); } /**************************************************************************//*! * * @brief Finalize transmit buffer before transmitting * * @param nLength - response length (1 for status + data length) * * * This Function takes the data already prepared in the transmit buffer * (inlcuding the status byte). It computes the check sum and kicks on tx. * ******************************************************************************/ void FMSTR_SendResponse(FMSTR_BPTR pResponse, FMSTR_SIZE8 nLength) { FMSTR_U16 chSum = 0U; FMSTR_U8 i, c; /* remeber the buffer to be sent */ pcm_pTxBuff = pResponse; /* status byte and data are already there, compute checksum only */ for (i=0U; i 0U) { /* add padding bytes */ while(!(pcm_wJtagTxCtr & 4U)) { pcm_wJtagTxData = (pcm_wJtagTxData << 8U) | 0xffU; pcm_wJtagTxCtr++; } /* send the word just completed */ FMSTR_JTAG_PUTDWORD(pcm_wJtagTxData); /* done, bTxActive will be deactivated next time */ pcm_wJtagTxCtr = 0U; } #endif /* transmission finished, start listening again */ else { /* when SCI TX buffering is enabled, we must first wait until all characters are physically transmitted (before disabling transmitter) */ #if FMSTR_USE_SCI && FMSTR_SCI_HAS_TXQUEUE pcm_wFlags.flg.bTxWaitTC = 1; /* wait for SCI TC interrupt */ #if FMSTR_SHORT_INTR || FMSTR_LONG_INTR FMSTR_SCI_ETCI(); #endif #else /* start listening immediatelly */ FMSTR_Listen(); #endif } } /**************************************************************************//*! * * @brief Handle received character * * @param nRxChar The character to be processed * * Handle the character received and -if the message is complete- call the * protocol decode routine. * ******************************************************************************/ static void FMSTR_Rx(FMSTR_BCHR nRxChar) { /* first, handle the replicated SOB characters */ if(nRxChar == FMSTR_SOB) { /* this is the 2nd byte of replicated SOB char */ if(pcm_wFlags.flg.bRxLastCharSOB) { /* join the two SOBs into one 0x2b character and continue processing */ pcm_wFlags.flg.bRxLastCharSOB = 0U; } /* this is either the first byte of replicated SOB or a */ /* real Start-of-Block mark - we will decide next time in FMSTR_Rx */ else { pcm_wFlags.flg.bRxLastCharSOB = 1U; return; } } /* we have got a common character preceeded by the SOB - */ /* this is the command code! */ if(pcm_wFlags.flg.bRxLastCharSOB) { /* reset reciving process */ pcm_pRxBuff = pcm_pCommBuffer; *pcm_pRxBuff++ = nRxChar; /* start computing the checksum */ pcm_nRxCheckSum = nRxChar; pcm_nRxTodo = 0U; /* fast command? */ if((nRxChar & FMSTR_FASTCMD) == FMSTR_FASTCMD) { /* there will be no length information */ pcm_wFlags.flg.bRxMsgLengthNext = 0U; /* as it is encoded in the command byte directly */ pcm_nRxTodo = (FMSTR_SIZE8) (((((FMSTR_SIZE8)nRxChar) & FMSTR_FASTCMD_DATALEN_MASK) >> FMSTR_FASTCMD_DATALEN_SHIFT) + 1U); } /* standard command */ else { /* the message length will come in next byte */ pcm_wFlags.flg.bRxMsgLengthNext = 1U; } /* command code stored & processed */ pcm_wFlags.flg.bRxLastCharSOB = 0U; return; } /* we are waiting for the length byte */ if(pcm_wFlags.flg.bRxMsgLengthNext) { /* this byte, total data length and the checksum */ pcm_nRxTodo = (FMSTR_SIZE8) (1U + ((FMSTR_SIZE8)nRxChar) + 1U); /* now read the data bytes */ pcm_wFlags.flg.bRxMsgLengthNext = 0U; } /* waiting for a data byte? */ if(pcm_nRxTodo) { /* add this byte to checksum */ pcm_nRxCheckSum += nRxChar; /* was it the last byte of the message (checksum)? */ if(!--pcm_nRxTodo) { /* receive buffer overflow? */ if(pcm_pRxBuff == NULL) { FMSTR_SendError(FMSTR_STC_CMDTOOLONG); } /* checksum error? */ else if((pcm_nRxCheckSum & 0xffU) != 0U) { FMSTR_SendError(FMSTR_STC_CMDCSERR); } /* message is okay */ else { /* do decode now! */ FMSTR_ProtocolDecoder(pcm_pCommBuffer); } } /* not the last character yet */ else { /* is there still a space in the buffer? */ if(pcm_pRxBuff) { /*lint -e{946} pointer arithmetic is okay here (same array) */ if(pcm_pRxBuff < (pcm_pCommBuffer + FMSTR_COMM_BUFFER_SIZE)) { /* store byte */ *pcm_pRxBuff++ = nRxChar; } /* buffer is full! */ else { /* NULL rx pointer means buffer overflow - but we still need */ /* to receive all message characters (for the single-wire mode) */ /* so keep "receiving" - but throw away all characters from now */ pcm_pRxBuff = NULL; } } } } } /******************************************************************************* * * @brief Routine to quick-receive a character (put to a queue only) * * This function puts received character into a queue and exits as soon as possible. * *******************************************************************************/ #if FMSTR_SHORT_INTR static void FMSTR_RxQueue(FMSTR_BCHR nRxChar) { /* future value of write pointer */ FMSTR_BPTR wpnext = pcm_pRQueueWP + 1; /*lint -e{946} pointer arithmetic is okay here (same array) */ if(wpnext >= (pcm_pRQueueBuffer + FMSTR_COMM_RQUEUE_SIZE)) { wpnext = pcm_pRQueueBuffer; } /* any space in queue? */ if(wpnext != pcm_pRQueueRP) { *pcm_pRQueueWP = (FMSTR_U8) nRxChar; pcm_pRQueueWP = wpnext; } } #endif /* FMSTR_SHORT_INTR */ /******************************************************************************* * * @brief Late processing of queued characters * * This function takes the queued characters and calls FMSTR_Rx() for each of them, * just like as the characters would be received from SCI one by one. * *******************************************************************************/ #if FMSTR_SHORT_INTR static void FMSTR_RxDequeue(void) { FMSTR_BCHR nChar = 0U; /* get all queued characters */ while(pcm_pRQueueRP != pcm_pRQueueWP) { nChar = *pcm_pRQueueRP++; /*lint -e{946} pointer arithmetic is okay here (same array) */ if(pcm_pRQueueRP >= (pcm_pRQueueBuffer + FMSTR_COMM_RQUEUE_SIZE)) { pcm_pRQueueRP = pcm_pRQueueBuffer; } /* emulate the SCI receive event */ if(!pcm_wFlags.flg.bTxActive) { FMSTR_Rx(nChar); } } } #endif /* FMSTR_SHORT_INTR */ /**************************************************************************//*! * * @brief Handle SCI communication (both TX and RX) * * This function checks the SCI flags and calls the Rx and/or Tx functions * * @note This function can be called either from SCI ISR or from the polling routine * ******************************************************************************/ #if FMSTR_USE_SCI void FMSTR_ProcessSCI(void) { /* read & clear status */ FMSTR_SCISR wSciSR = FMSTR_SCI_RDCLRSR(); /* transmitter active and empty? */ if (pcm_wFlags.flg.bTxActive) { /* able to accept another character? */ if(wSciSR & FMSTR_SCISR_TDRE) { FMSTR_Tx(); } /* read-out and ignore any received character (loopback) */ if(wSciSR & FMSTR_SCISR_RDRF) { /*lint -esym(550, nRxChar) */ volatile FMSTR_U16 nRxChar; nRxChar = FMSTR_SCI_GETCHAR(); } } /* transmitter not active, able to receive */ else { /* data byte received? */ if (wSciSR & FMSTR_SCISR_RDRF) { FMSTR_BCHR nRxChar = 0U; nRxChar = (FMSTR_BCHR) FMSTR_SCI_GETCHAR(); FMSTR_Rx(nRxChar); // FMSTR_Tx(); } } } #endif /**************************************************************************//*! * * @brief Handle JTAG communication (both TX and RX) * * This function checks the JTAG flags and calls the Rx and/or Tx functions * * @note This function can be called either from JTAG ISR or from the polling routine * ******************************************************************************/ #if FMSTR_USE_JTAG void FMSTR_ProcessJTAG(void) { /* read & clear status */ register FMSTR_U16 wJtagSR = FMSTR_JTAG_GETSR(); /* transmitter active? */ if (pcm_wFlags.flg.bTxActive) { /* able to transmit a new character? (TX must be empty = read-out by PC) */ if(!(wJtagSR & FMSTR_JTAG_OTXRXSR_TDF)) { #if FMSTR_USE_JTAG_TXFIX /* if TDF bit is useless due to silicon bug, use the RX flag */ /* instead (PC sends us a dummy word to kick the RX flag on) */ if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF) #endif { /* send one byte always */ FMSTR_Tx(); /* try to fill-up the full 32bit JTAG word */ while(pcm_wFlags.flg.bTxActive && pcm_wJtagTxCtr) { FMSTR_Tx(); } } } /* ignore (read-out) the JTAG-received word */ if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF) { /*lint -esym(550, nRxWord) */ volatile FMSTR_U16 nRxWord; nRxWord = FMSTR_JTAG_GETWORD(); } } /* transmitter not active */ else { /* JTAG 32bit word (four bytes) received? */ if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF) { register FMSTR_U32 nRxDWord; FMSTR_INDEX i; nRxDWord = FMSTR_JTAG_GETDWORD(); /* process all bytes, MSB first */ for(i=0; i<4; i++) { #if FMSTR_SHORT_INTR FMSTR_RxQueue((FMSTR_BCHR)((nRxDWord >> 24U) & 0xffU)); #else FMSTR_Rx((FMSTR_BCHR)((nRxDWord >> 24U) & 0xffU)); /* ignore the rest if previous bytes triggered a transmission */ /* (i.e. the packet was complete and only filled-up to 32bit word) */ if(pcm_wFlags.flg.bTxActive) { break; } #endif /* next byte of 32bit word */ nRxDWord = nRxDWord << 8; } } } } #endif /******************************************************************************* * * @brief API: Main "Polling" call from the application main loop * * This function either handles all the SCI communictaion (polling-only mode = * FMSTR_POLL_DRIVEN) or decodes messages received on the background by SCI interrupt * (short-interrupt mode = FMSTR_SHORT_INTR). * * In the JTAG interrupt-driven mode (both short and long), this function also checks * if setting the JTAG RIE bit failed recently. This may happen because of the * RIE is held low by the EONCE hardware until the EONCE is first accessed from host. * FMSTR_Init (->FMSTR_Listen) is often called while the PC-side FreeMASTER is still * turned off. So really, the JTAG is not enabled by this time and RIE bit is not set. * This problem is detected (see how bJtagRIEPending is set above in FSMTR_Listen) * and it is tried to be fixed periodically here in FMSTR_Poll. * *******************************************************************************/ void FMSTR_Poll(void) { FMSTR_ProcessSCI(); } #else /* FMSTR_USE_SCI || FMSTR_USE_JTAG */ /* Empty implementation of communication functions Without a SCI and JTAG the FreeMASTER driver still passes the compilation, but no communication is supported. The user may imlement his own communication protocol and use FreeMASTER by calling FMSTR_ProtocolDecoder and overriding the FMSTR_SendResponse calls */ void FMSTR_SendResponse(FMSTR_BPTR pResponse, FMSTR_SIZE8 nLength) { FMSTR_UNUSED(pResponse); FMSTR_UNUSED(nLength); } void FMSTR_Poll(void) { } /*lint -efile(766, PE_freemaster_protocol.h) include file is not used in this case */ #endif /* FMSTR_USE_SCI || FMSTR_USE_JTAG */