/******************************************************************************
*
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2010 Freescale Semiconductor
* ALL RIGHTS RESERVED.
*
****************************************************************************//*!
*
* @file freemaster_serial.c
*
* @brief FreeMASTER SCI communication routines
*
* @version 1.1.22.0
*
* @date Apr-23-2010
*
*******************************************************************************/
#include "freemaster.h"
#include "freemaster_private.h"
#include "freemaster_protocol.h"
#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 */
typedef 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;
} FMSTR_SERIAL_FLAGS;
static FMSTR_SERIAL_FLAGS 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;
#if FMSTR_USE_SCI && FMSTR_SCI_TWOWIRE_ONLY
/* to enable TX and RX together in FreeMASTER initialization */
FMSTR_SCI_TE_RE();
#endif
#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_TWOWIRE_ONLY
FMSTR_SCI_TD();
FMSTR_SCI_RE();
#endif
/* disable transmit, enable receive interrupts */
#if FMSTR_SHORT_INTR || FMSTR_LONG_INTR
#if FMSTR_USE_SCI
FMSTR_SCI_DTXI(); /* disable SCI transmit interrupt */
FMSTR_SCI_ERXI(); /* enable SCI recieve interrupt */
#elif FMSTR_USE_JTAG
FMSTR_JTAG_DTXI(); /* disable JTAG transmit interrupt */
FMSTR_JTAG_ERXI(); /* enable JTAG recieve interrupt */
/* RIE bit is forced low by HW until EONCE is first accesed, we will try again in FMSTR_Poll */
if(!FMSTR_JTAG_ERXI_CHECK())
pcm_wFlags.flg.bJtagRIEPending = 1;
#endif
#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<nLength; i++)
{
c = 0U;
pResponse = FMSTR_ValueFromBuffer8(&c, pResponse);
/* add character to checksum */
chSum += c;
/* prevent saturation to happen on DSP platforms */
chSum &= 0xffU;
}
/* store checksum after the message */
pResponse = FMSTR_ValueToBuffer8(pResponse, (FMSTR_U8) (((FMSTR_U16)~(chSum)) + 1U));
/* send the message and the checksum and the SOB */
pcm_nTxTodo = (FMSTR_SIZE8) (nLength + 1U);
/* now transmitting the response */
pcm_wFlags.flg.bTxActive = 1U;
pcm_wFlags.flg.bTxWaitTC = 0U;
/* do not replicate the initial SOB */
pcm_wFlags.flg.bTxLastCharSOB = 0U;
#if FMSTR_USE_SCI
{
/*lint -esym(550, dummySR) */
volatile FMSTR_SCISR dummySR;
/* disable receiver, enable transmitter (single-wire communication) */
#if !FMSTR_SCI_TWOWIRE_ONLY
FMSTR_SCI_RD();
FMSTR_SCI_TE();
#endif
/* kick on the SCI transmission (also clears TX Empty flag on some platforms) */
dummySR = FMSTR_SCI_GETSR();
FMSTR_SCI_PUTCHAR(FMSTR_SOB);
}
#elif FMSTR_USE_JTAG
/* kick on the JTAG transmission */
pcm_wJtagTxData = FMSTR_SOB;
pcm_wJtagTxCtr = 1U;
/* send the next two bytes immediatelly (we can be sure there are two bytes) */
FMSTR_Tx();
FMSTR_Tx();
/* send the third byte (if any) or flush the 32bit JTAG word */
FMSTR_Tx();
#endif
/* TX interrupt enable, RX interrupt disable */
#if FMSTR_LONG_INTR || FMSTR_SHORT_INTR
#if FMSTR_USE_SCI
FMSTR_SCI_DRXI();
FMSTR_SCI_ETXI();
#elif FMSTR_USE_JTAG
#if FMSTR_USE_JTAG_TXFIX
/* in TX-bugfix mode