//***************************************************************************** // (C) Automotive Lighting China // // Automotive Lighting Reutlingen GmbH owns all the rights to this work. // This work shall not be copied, reproduced, used, modified, transferred // or its information shall not be disclosed without the prior written // authorization of Automotive Lighting China. //***************************************************************************** // ---------------------------------------------------------------------------- /// \file CddUartEng.c /// /// \author f24301c [mailto:walker.lv@marelli.com] /// /// \date 05.27.2024 /// /// \brief implementation of CddUartEng /// // ---------------------------------------------------------------------------- //============================================================================= // Includes //============================================================================= #include "CddUartEng.h" #include #include #include #include #include "UniHwAbstract/UniHwAbstract.h" #include "DummyLoad.h" #include #include //============================================================================= // Defines and Typedef //============================================================================= //----------------------------------------------------------------------------- // Start declaration or definitions of functions //----------------------------------------------------------------------------- STATIC_AL void ChannelReset(UartEngChannel_t* channel); STATIC_AL UUE_ErrorType startTransaction(UartEngChannel_t* channel); STATIC_AL UUE_ErrorType startTransaction_LL(UartEngChannel_t* channel); STATIC_AL UUE_ErrorType stopTransaction(UartEngChannel_t* channel, uint8 needAbort); STATIC_AL uint8 prepareTcbForRetry(TransactionControl_t* tcb); STATIC_AL void transactionErrorHandler(UartEngChannel_t* channel, ProtocolBuf_t* pdu, TransactionError_t err); STATIC_AL void transactionSuccessHandler(UartEngChannel_t* channel, ProtocolBuf_t* pdu); STATIC_AL INLINE uint8 getUartEngChannelFromMcal(uint8 HWUnit); STATIC_AL INLINE TransactionError_t hwErrorDecode(Uart_ErrorIdType errId); //----------------------------------------------------------------------------- // End declaration or definitions of functions //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Start definition of functions //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /// \brief Uart write complete notification /// /// \descr in ISR. Notified when TxPdu transferred. if no response expected, /// this is the end of transaction, else nothing to do /// NOETNOTE: if Transaction has no response but echo mode on, e.g., broadcast /// over CAN, it is possible write complete notification after Receive /// complete notification. need to handle such case with cautions. /// /// \param channelId: configured Uart channel array index, see Uart_PBcfg.c for detail /// ErrorId: MCAL error during transmit. /// /// \return None //----------------------------------------------------------------------------- void Uart_WriteNotification(uint8 hwUnit, Uart_ErrorIdType errId) { uint8 channelIdx = getUartEngChannelFromMcal(hwUnit); uint8 skipFlag = 0; if (hwUnit == 4) IoHwAb_ToggleDebugPin(DEBUG_PIN1); if (channelIdx != 0xFF) { UartEngChannel_t* channel = &UartEngine_Config.channels[channelIdx]; // channel object UUE_ASSERT(channel != (UartEngChannel_t*)NULL_PTR); UUE_ASSERT(channel->channelId == hwUnit); // should be the same ProtocolBuf_t* pdu = &Queue_GetEntity(channel->queue)->pdu; // get payload of this transaction TransactionControl_t* tcb = (TransactionControl_t*)NULL_PTR; // NOTENOTE: possible ReadNotification occurred before write notification //UUE_ASSERT(pdu != (ProtocolBuf_t*)NULL_PTR); if (pdu != (ProtocolBuf_t*)NULL_PTR) { tcb = &pdu->tcb; } if (tcb != (TransactionControl_t*)NULL_PTR) { // 1, check HW error TransactionError_t writeErr = hwErrorDecode(errId); if (writeErr != TransactionError_NoError) { stopTransaction(channel, TRUE); // something bad happened during write... transactionErrorHandler(channel, pdu, writeErr); // start a new transaction or retry (void)startTransaction(channel); } else { // no HW error during write phase // BUGBUG: it is possible transfer timeout occurred before TxComplete notification // so tcb->errorState could be TransactionError_LL_Timeout if transaction timeout // is not too long (e.g. 500us), reason unknown could be interrupt disabled for too // long. in this case, also based on understanding of Mcal Uart implementation // Uart_AbortWrite, UartAbs_GetState should return idle. just ignore TxCompNotification // in this case, because GptTimerNotification already start a new transaction. these code // is not tested, so i would suggest set a long transaction timeout, e.g, 1000us. // //UUE_ASSERT(tcb->errorState == TransactionError_NoError); if (tcb->errorState != TransactionError_NoError) { UUE_ASSERT(tcb->errorState == TransactionError_LL_Timeout); if (UartAbs_GetState(channel->channelId) == BusState_Idle) skipFlag = 1; } if (skipFlag) { // skip following process, see BUGBUG above } else { // clear write complete event UTIL_CLEAR_BIT(channel->flowControl, UARTENG_FLOWCONTROL_WRCOMP_OFFSET); // 2, check if transaction is done if (((pdu->resPduBuffer == NULL_PTR) && (channel->echoMode == 0)) // no response expected || (channel->flowControl == 0)) // or Rx notification before Tx { // transaction finished, start a new one UUE_ASSERT(channel->flowControl == 0); // no pending event // no response expected, transaction done stopTransaction(channel, FALSE); transactionSuccessHandler(channel, pdu); // start next transaction (void)startTransaction(channel); } else { // 3, transaction not finished, wait for Rx to be done // nothing to be done here for now... // MUST has read pending event UUE_ASSERT(UTIL_TEST_BIT(channel->flowControl, UARTENG_FLOWCONTROL_RDCOMP_OFFSET)); } } // skipFlag } } else { // pdu/tcb is NULL, read notification already move queue.head, nothing to do here. } } else { UUE_ASSERT(0); // internal error, channel mapping not found } if (hwUnit == 4) IoHwAb_ToggleDebugPin(DEBUG_PIN1); } //----------------------------------------------------------------------------- /// \brief Uart read complete notification /// /// \descr in ISR. Notified when expected response from slave received. /// Normally this indicate end of transaction. Performance bus level /// integrity check here. transferred. if no response expected, /// this is the end of transaction, else nothing to do /// /// \param channelId: configured Uart channel array index, see Uart_PBcfg.c for detail /// ErrorId: MCAL error during transmit. /// /// \return None //----------------------------------------------------------------------------- void Uart_ReadNotification(uint8 hWUnit, Uart_ErrorIdType errId) { uint8 channelIdx = getUartEngChannelFromMcal(hWUnit); if (hWUnit == 4) IoHwAb_ToggleDebugPin(DEBUG_PIN2); if (channelIdx != 0xFF) { UartEngChannel_t* channel = &UartEngine_Config.channels[channelIdx]; // channel object UUE_ASSERT(channel != (UartEngChannel_t*)NULL_PTR); UUE_ASSERT(channel->channelId == hWUnit); // should be the same ProtocolBuf_t* pdu = &Queue_GetEntity(channel->queue)->pdu; // get payload of this transaction UUE_ASSERT(pdu != (ProtocolBuf_t*)NULL_PTR); TransactionControl_t* tcb = &pdu->tcb; // 1, check HW error TransactionError_t readErr = hwErrorDecode(errId); if (readErr != TransactionError_NoError) { // HW error occurred, abort current transaction, start a new one or retry stopTransaction(channel, TRUE); // something bad happened during write... transactionErrorHandler(channel, pdu, readErr); // continue process queue (void)startTransaction(channel); } else { UUE_ASSERT(tcb->errorState == TransactionError_NoError); UTIL_CLEAR_BIT(channel->flowControl, UARTENG_FLOWCONTROL_RDCOMP_OFFSET); if (channel->flowControl != 0) { // read complete event occurred before write complete, need to wait for write complete event to driver // next transaction UUE_ASSERT(UTIL_TEST_BIT(channel->flowControl, UARTENG_FLOWCONTROL_WRCOMP_OFFSET)); } else { // no HW error, start bus layer verify if echo mode is on stopTransaction(channel, FALSE); if (channel->echoMode == TRUE) { // bus level communication verification if (memcmp(pdu->reqPduBuffer, channel->sharedRxBuf, pdu->reqPduLength) != 0) { // not match // // BUGBUG: unknown error. sometimes few bytes not sent (MCAL uart tx left > 0) but read notification // invoke from Uart_IsrError ISR. it looks like using abort can cancel current transfer // NOTENOTE: the error is known. it is mcal Uart driver enable Rx Fifo overflow interrupt, which not // suitable for Uart over CAN scenario. I modify mcal Uart driver to adapt to this case. // something bad happened during write... transactionErrorHandler(channel, pdu, TransactionError_LL_Verify); } } if (tcb->errorState == TransactionError_NoError) { transactionSuccessHandler(channel, pdu); } // start next transaction or retry current one (void)startTransaction(channel); } } } else { UUE_ASSERT(0); // internal error, channel mapping not found, for debug only } if (hWUnit == 4) IoHwAb_ToggleDebugPin(DEBUG_PIN2); } //----------------------------------------------------------------------------- /// \brief transaction timeout notification /// /// \descr in ISR. Notified when expected response from slave received. /// Normally this indicate end of transaction. Performance bus level /// integrity check here. transferred. if no response expected, /// this is the end of transaction, else nothing to do /// /// \param channelId: configured Uart channel array index, see Uart_PBcfg.c for detail /// ErrorId: MCAL error during transmit. /// /// \return None //----------------------------------------------------------------------------- void Uart_GptTimerNotification(UniTimerHandle hwUnit) { // get channel by GPT timer Id uint8 loops = UartEngine_Config.numberOfChannels; uint8 channelIdx = 0; // index to UartEngine_Config.channel[] for (; channelIdx < loops; channelIdx++) { if (UartEngine_Config.channels[channelIdx].timerId == hwUnit) break; } if (channelIdx < loops) { UartEngChannel_t* channel = &UartEngine_Config.channels[channelIdx]; UUE_ASSERT(channel != (UartEngChannel_t*)NULL_PTR); UUE_ASSERT(channel->timerId == hwUnit); // should be the same ProtocolBuf_t* pdu = &Queue_GetEntity(channel->queue)->pdu; // get payload of this transaction if (pdu->tcb.transactionState == TransactionState_TransferDelay) { (void)TimerAbs_Stop(channel->timerId); // transaction start delay finished, start the real transfer (void)startTransaction_LL(channel); } else { UUE_ASSERT(pdu->tcb.transactionState == TransactionState_Transfering); // transaction timeout error handle stopTransaction(channel, TRUE); // need abort operation transactionErrorHandler(channel, pdu, TransactionError_LL_Timeout); // continue process queue (void)startTransaction(channel); } } else { // configuration integrity error, for debug only UUE_ASSERT(0); } } //----------------------------------------------------------------------------- /// \brief reset channel state /// /// \descr Uart channel object logical reset, not bus reset. a helper /// function for initialization or POR reset. Some property can not /// be changed. /// /// \param channel: UartEngChannel_t object to be reset /// /// \return None //----------------------------------------------------------------------------- STATIC_AL void ChannelReset(UartEngChannel_t* channel) { TimerAbs_Stop(channel->timerId); UartAbs_Abort(channel->channelId); channel->busState = BusState_Idle; channel->flowControl = 0; // clear shared Rx buffer memset(channel->sharedRxBuf, 0, sizeof(channel->sharedRxBuf)); (void)Queue_Init(channel->queue); #if (UUE_UARTBUS_PROFILE == STD_ON) memset(channel->statistic, 0, sizeof(ChannelStistic_t)); #endif } //----------------------------------------------------------------------------- /// \brief runnable initialization /// /// \descr /// /// \param None /// /// \return None //----------------------------------------------------------------------------- void CddUartEng_Init(void) { UUE_ASSERT(UartEngine_Config.numberOfChannels >= 1); uint8 loops = UartEngine_Config.numberOfChannels; for (uint8 idx = 0; idx < loops; idx++) { // add channel initialization here // NOTENOTE: currently channel is statically initial in CddUartEng_PBcfg.c ChannelReset(&UartEngine_Config.channels[idx]); } //AddTestPdu(); } //----------------------------------------------------------------------------- /// \brief runnable initialization /// /// \descr /// /// \param None /// /// \return None //----------------------------------------------------------------------------- void CddUartEng_Deinit(void) { // remain empty } //----------------------------------------------------------------------------- /// \brief cyclic runnable /// /// \descr actually nothing to do here, due to Uart Layer verification would be /// done in Uart_WriteNotification. /// /// \param None /// /// \return None //----------------------------------------------------------------------------- void CddUartEng_MainHandle(void) { // add 20ms delay for lamp PCBA power supply steady static uint8 delayCounter = 20 / UUE_UARTENG_MAINHANDLE_PEROID; static uint8 runOnce = 1; if (delayCounter > 0) { delayCounter--; return; } if (runOnce) { runOnce = 0; #if (UEE_STANDALONE_TEST == STD_ON) /////////////////////////////////////////////////////////////////// // test code /////////////////////////////////////////////////////////////////// // add one time test code here AddTestRunOncePdu(); /////////////////////////////////////////////////////////////////// #else #endif return; } // trigger a transaction in case of queue is full due to lot of transaction error (retransmit) // in this case, enqueue will failed, no new transaction would start, kind of deadlock. for (uint8 channelIdx = 0; channelIdx < UartEngine_Config.numberOfChannels; channelIdx++) { startTransaction(&UartEngine_Config.channels[channelIdx]); } #if (UEE_STANDALONE_TEST == STD_ON) /////////////////////////////////////////////////////////////////// // test code /////////////////////////////////////////////////////////////////// AddTestPeroidPdu(); /////////////////////////////////////////////////////////////////// #else #endif #if ((UUE_TRANSACTION_PROFILE == STD_ON) && (UUE_UARTBUS_PROFILE == STD_ON)) static uint32 period100ms = 0; period100ms++; if ((period100ms % (UUE_UARTENG_BANDWIDTH_TIMEUNIT / UUE_UARTENG_MAINHANDLE_PEROID)) == 0) { // computer then reset bus bandwidth every 100ms for (uint8 index = 0; index < UartEngine_Config.numberOfChannels; index++) { ChannelStistic_t* chnStatistic = UartEngine_Config.channels[index].statistic; if (chnStatistic->tansactionTimeAccu) { chnStatistic->bandwidthPermillage = (uint16)((chnStatistic->tansactionTimeAccu * 1000) / (100 * 1000)) + 1; chnStatistic->tansactionTimeAccu = 0; // reset } // update error ratio if (chnStatistic->transactionCount) chnStatistic->errorRatio = (uint16)((chnStatistic->errorCount * 10000) / chnStatistic->transactionCount); } } #endif } //----------------------------------------------------------------------------- /// \brief add a protocol level pdu to a specified CddUartEng channel /// /// \descr queuing Pdu then start transaction /// /// \param channelCfgId: specified uart channel idx, according CddUartEng definition /// pdu: a ProtocolBuf_t object, aka, transaction data and control block /// to be transfer. if channel is idle, start the transaction immediately /// /// \return UUE_ErrorType //----------------------------------------------------------------------------- UUE_ErrorType CddUartEng_AddPud( ProtocolBuf_t* pdu) { UUE_ErrorType retVal = E_UUE_NO_ERROR; if (pdu == NULL_PTR) { retVal = E_UUE_BAD_PARAMETER; } TransactionControl_t* tcb = &pdu->tcb; if (tcb->channel >= UartEngine_Config.numberOfChannels) { retVal = E_UUE_BAD_PARAMETER; } // check pdu state if (retVal == E_UUE_NO_ERROR) { if (tcb->transactionState != TransactionState_RequestReady) { retVal = E_UUE_BAD_PARAMETER; } else if (pdu->reqPduLength == 0) { retVal = E_UUE_PDU_NO_PAYLOAD; } else { // check complete, no error } } if (retVal == E_UUE_NO_ERROR) { // everything ok, start processing // check if channel is configured. //if (UartEngine_Config.channelMap[tcb->channel] == 0xFF) //{ // // channel not used or not configured // retVal = E_UUE_CHANNEL_NOT_CONFIG; //} //else { UartEngChannel_t* channel = &UartEngine_Config.channels[tcb->channel]; if (channel->busState == BusState_Uninitial) { retVal = E_UUE_CHANNEL_NOT_INIT; } else { retVal = Queue_Enqueue(channel->queue, (void*)pdu); if (retVal == E_UUE_NO_ERROR) { // try start the transaction // NOTENOTE: following code is useless. tcb is copy to queue in Queue_Enqueue(), // change tcb is meaningless //tcb->errorState = TransactionError_NoError; //tcb->transactionState = TransactionState_RequestReady; //TIMESTAMP_TRANSACTION_ENQUEUE(tcb); retVal = startTransaction(channel); } } } } return retVal; } //----------------------------------------------------------------------------- /// \brief start a transaction if channel is idle /// /// \descr internal API. start low-level transaction /// /// \param channel: pointer to a UartEngChannel_t object, which transaction executes /// /// \return UUE_ErrorType //----------------------------------------------------------------------------- STATIC_AL UUE_ErrorType startTransaction_LL(UartEngChannel_t* channel) { UUE_ErrorType retVal = E_UUE_NO_ERROR; // when this internal api called, bus state can not be idle UUE_ASSERT(channel->busState != BusState_Idle); if (channel->busState != BusState_Idle) { // get first pending pdu from queue QueueEntity_t* entity = Queue_GetEntity(channel->queue); if (!Queue_IsEmpty(channel->queue)) { // everything set, we gotta go to the HW layer ProtocolBuf_t* proPdu = &entity->pdu; TransactionControl_t* tcb = &proPdu->tcb; uint16 expectedRxLen = 0; // local variable for response len calculation if (proPdu->reqPduLength == 0) { // invalid transaction pdu defined retVal = E_UUE_PDU_NO_PAYLOAD; } else { if (channel->echoMode) { expectedRxLen += proPdu->reqPduLength; } if ((proPdu->resPduBuffer != NULL_PTR) && (proPdu->resPduLength > 0)) { // if response required, increase expecting receive length... expectedRxLen += proPdu->resPduLength; } else { // possible no Rx for broadcasting pdu } if (expectedRxLen > 0) // need read operation during transaction { UUE_ASSERT(expectedRxLen <= sizeof(channel->sharedRxBuf)); memset(channel->sharedRxBuf, 0, sizeof(channel->sharedRxBuf)); retVal = UartAbs_Read(channel->channelId, channel->sharedRxBuf, expectedRxLen); //UUE_ASSERT(retVal == UART_E_OK); // for debug only if (retVal == UART_E_OK) // Uart_ReturnType, // assumption: UART_E_OK == E_UUE_NO_ERROR { // set expecting read complete event UTIL_SET_BIT(channel->flowControl, UARTENG_FLOWCONTROL_RDCOMP_OFFSET); } else { // LL uart bus busy // retVal is set to error, skip and wait for next call of startTransaction() UUE_ASSERT(0); // should never reach } } // prepare for HW write if (retVal == E_UUE_NO_ERROR) { retVal = UartAbs_Write(channel->channelId, proPdu->reqPduBuffer, proPdu->reqPduLength); if (retVal == UART_E_OK) { // set expecting read complete event UTIL_SET_BIT(channel->flowControl, UARTENG_FLOWCONTROL_WRCOMP_OFFSET); } else { // LL uart bus busy // retVal is set to error, skip and wait for next call of startTransaction() // NOTENOTE: shall we abort Uart_Read()? UartAbs_Abort(channel->channelId); UUE_ASSERT(0); // should never reach } } if (retVal == E_UUE_NO_ERROR) { // no error so far, start timeout monitor if (tcb->transactionTimeout > 0) { (void)TimerAbs_Start(channel->timerId, tcb->transactionTimeout); // never fail } tcb->errorState = TransactionError_NoError; // clear error, even if it is an retry tcb->transactionState = TransactionState_Transfering; TIMESTAMP_TRANSACTION_START(tcb); #if (UUE_UARTBUS_PROFILE == STD_ON) if (channel->statistic->transactionCount < UTIL_MAX_OF_TYPE(uint32)) channel->statistic->transactionCount++; #endif } else // HW abstract layer return error { // any error, try to undo what was done?? // NOTENOTE: is this the right way? is it possible that abort other transaction on bus? (void)UartAbs_Abort(channel->channelId); transactionErrorHandler(channel, proPdu, TransactionError_LL_Internal); } } // end of start of transaction } else { // queue is already empty... } } else { retVal = E_UUE_UARGENG_INTERNAL; } if (retVal == E_UUE_NO_ERROR) { channel->busState = BusState_Busy; } else { channel->busState = BusState_Idle; } return retVal; } //----------------------------------------------------------------------------- /// \brief start a transaction if channel is idle /// /// \descr internal API. check if a transaction delay required, if yes, start a /// delay timer, if not, call low level transaction API /// notification to start transaction in line, i.e., in a ISR context. /// Be very careful for implementation /// /// \param channel: pointer to a UartEngChannel_t object, which transaction executes /// /// \return UUE_ErrorType //----------------------------------------------------------------------------- STATIC_AL UUE_ErrorType startTransaction(UartEngChannel_t* channel) { UUE_ErrorType retVal = E_UUE_NO_ERROR; if (channel->busState == BusState_Idle) { // get first pending pdu from queue QueueEntity_t* entity = Queue_GetEntity(channel->queue); if (!Queue_IsEmpty(channel->queue)) { channel->busState = BusState_Busy; // everything set, we gotta go to the HW layer ProtocolBuf_t* proPdu = &entity->pdu; TransactionControl_t* tcb = &proPdu->tcb; if (tcb->transactionDelay) { tcb->transactionState = TransactionState_TransferDelay; // set a flag for timer notification (void)TimerAbs_Start(channel->timerId, tcb->transactionDelay); // never fail } else { retVal = startTransaction_LL(channel); } } } return retVal; } //----------------------------------------------------------------------------- /// \brief clear up a transaction state /// /// \descr internal API. do the general BUS state clear up when a /// transaction done /// /// \param channel: pointer to a UartEngChannel_t object, which transaction executes /// needAbort: flag to invoke Uart Abort operation /// /// \return UUE_ErrorType //----------------------------------------------------------------------------- #pragma warning 589 // W589: pointer assumed to be nonzero - test removed STATIC_AL UUE_ErrorType stopTransaction(UartEngChannel_t* channel, uint8 needAbort) { UUE_ASSERT(channel != NULL_PTR); TimerAbs_Stop(channel->timerId); if (needAbort) { UartAbs_Abort(channel->channelId); } channel->busState = BusState_Idle; channel->flowControl = 0; // clear all expected flow control (event) return E_UUE_NO_ERROR; } //----------------------------------------------------------------------------- /// \brief preparing TCB for retry /// /// \descr internal API. /// /// \param tcb: pointer to a TCB, if retry limit not reach, clear transaction /// state for retry /// /// \return uint8: consider as bool, true means need retry, false means no retry or out of limit //----------------------------------------------------------------------------- STATIC_AL uint8 prepareTcbForRetry(TransactionControl_t* tcb) { UUE_ASSERT(tcb != NULL_PTR); uint8 retVal = 0; // default no retry tcb->retransmitAttempt++; if (tcb->retransmitAttempt >= tcb->retransmitLimit) { // consider as transaction done, with error in errorState tcb->errorState = TransactionError_LL_Timeout; tcb->transactionState = TransactionState_ResponseReady; retVal = 0; } else { // reset transactionState state for retry tcb->transactionState = TransactionState_RequestReady; retVal = 1; } // on way or the other, current transaction end here TIMESTAMP_TRANSACTION_END(tcb); return retVal; } #pragma warning restore //----------------------------------------------------------------------------- /// \brief get CddUart channel index from MCAL HWUnit /// /// \descr internal API. /// /// \param HWUnit: MCAL define channel id, normally provide in ISR parameter /// /// \return uint8: UartEng channel index. 0xFF means not found //----------------------------------------------------------------------------- STATIC_AL INLINE uint8 getUartEngChannelFromMcal(uint8 HWUnit) { uint8 index = 0xFF; if (HWUnit < UUE_MAX_UART_CHANNEL) { index = UartEngine_Config.channelMap[HWUnit]; } return index; } //----------------------------------------------------------------------------- /// \brief convert HW error to transaction error /// /// \descr internal API. /// /// \param channel: error related channel object /// errId: MCAL Uart error /// /// \return None //----------------------------------------------------------------------------- STATIC_AL INLINE TransactionError_t hwErrorDecode(Uart_ErrorIdType errId) { TransactionError_t retVal = TransactionError_NoError; switch (errId) { case UART_E_PARITY_ERR: retVal = TransactionError_LL_Parity; break; case UART_E_FRAME_ERR: retVal = TransactionError_LL_Frame; break; case UART_E_RXFIFO_OVERFLOW: retVal = TransactionError_LL_Overrun; break; case UART_E_INSUFFICIENT_BUFSIZE: retVal = TransactionError_LL_Overrun; break; // MCAL did not define bit error default: break; } return retVal; } //----------------------------------------------------------------------------- /// \brief general transaction error handler /// /// \descr internal API. all when error occurred during transaction. a simple helper /// API, no architecture meaning /// /// \param channel: channel object /// tcb: transaction control block /// err: error to be update to tcb /// /// \return None //----------------------------------------------------------------------------- #pragma warning 589 // W589: pointer assumed to be nonzero - test removed STATIC_AL void transactionErrorHandler(UartEngChannel_t* channel, ProtocolBuf_t* pdu, TransactionError_t err) { UUE_ASSERT(channel != NULL_PTR); UUE_ASSERT(pdu != NULL_PTR); TransactionControl_t* tcb = &pdu->tcb; // do not override previous error if (tcb->errorState == TransactionError_NoError) { tcb->errorState = err; } if (prepareTcbForRetry(tcb) == 0) { TIMESTAMP_TRANSACTION_DEQUEUE(tcb); // no need to retry, dequeue, then start next transaction in queue // transaction complete notification if (pdu->transactionNotifyCallback) pdu->transactionNotifyCallback(pdu); Queue_Dequeue(channel->queue); } else { // queue pointer not moved, if need retry } #if (UUE_UARTBUS_PROFILE == STD_ON) // no wrap if (channel->statistic->errorCount < UTIL_MAX_OF_TYPE(uint32)) { if (channel->channelId == 4) IoHwAb_ToggleDebugPin(DEBUG_PIN3); channel->statistic->errorCount++; //while (1); } #endif } //----------------------------------------------------------------------------- /// \brief general transaction success handler /// /// \descr internal API. all when no error occurred during transaction. a simple helper /// API, no architecture meaning /// /// \param channel: channel object /// tcb: transaction control block /// /// \return None //----------------------------------------------------------------------------- STATIC_AL void transactionSuccessHandler(UartEngChannel_t* channel, ProtocolBuf_t* pdu) { UUE_ASSERT(channel != NULL_PTR); UUE_ASSERT(pdu != NULL_PTR); TransactionControl_t* tcb = &pdu->tcb; ProtocolBuf_t* pdu = &Queue_GetEntity(channel->queue)->pdu; // get payload of this transaction UUE_ASSERT(pdu != (ProtocolBuf_t*)NULL_PTR); // Low level part of transaction is done, clear up, dequeue, start next pending transaction tcb->transactionState = TransactionState_ResponseReady; // copy response from channel.sharedRxBuff to pdu.resPduBuffer // NOTENOTE: shall we disable interrupt here? if (pdu->resPduBuffer != NULL_PTR) { UUE_ASSERT(pdu->resPduLength != 0); memcpy(pdu->resPduBuffer, channel->sharedRxBuf + pdu->reqPduLength, pdu->resPduLength); } TIMESTAMP_TRANSACTION_END(tcb); #if ((UUE_TRANSACTION_PROFILE == STD_ON) && (UUE_UARTBUS_PROFILE == STD_ON)) channel->statistic->tansactionTimeAccu += (tcb->tsTransactionEnd - tcb->tsTransactionStart); #endif TIMESTAMP_TRANSACTION_DEQUEUE(tcb); // transaction complete notification if (pdu->transactionNotifyCallback) pdu->transactionNotifyCallback(pdu); #if (UUE_UARTBUS_PROFILE == STD_ON) channel->statistic->byteSent += pdu->reqPduLength; channel->statistic->byteRecv += pdu->resPduLength; if (channel->echoMode) channel->statistic->byteRecv += pdu->reqPduLength; #endif Queue_Dequeue(channel->queue); } #pragma warning restore