//****************************************************************************** //! \file npi_task.c //! \brief NPI is a TI RTOS Application Thread that provides a //! \brief common Network Processor Interface framework. // // Revised $Date: 2015-07-28 14:31:44 -0700 (Tue, 28 Jul 2015) $ // Revision: $Revision: 44419 $ // // Copyright 2015 Texas Instruments Incorporated. All rights reserved. // // IMPORTANT: Your use of this Software is limited to those specific rights // granted under the terms of a software license agreement between the user // who downloaded the software, his/her employer (which must be your employer) // and Texas Instruments Incorporated (the "License"). You may not use this // Software unless you agree to abide by the terms of the License. The License // limits your use, and you acknowledge, that the Software may not be modified, // copied or distributed unless used solely and exclusively in conjunction with // a Texas Instruments radio frequency device, which is integrated into // your product. Other than for the foregoing purpose, you may not use, // reproduce, copy, prepare derivative works of, modify, distribute, perform, // display or sell this Software and/or its documentation for any purpose. // // YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE // PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,l // INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, // NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL // TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, // NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER // LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES // INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE // OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT // OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES // (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. // // Should you have any questions regarding your right to use this Software, // contact Texas Instruments Incorporated at www.TI.com. //****************************************************************************** // **************************************************************************** // includes // **************************************************************************** #include #include #include #include #include #include #include #include "ICall.h" #include "inc/npi_task.h" #include "inc/npi_data.h" #include "inc/npi_frame.h" #include "inc/npi_rxbuf.h" #include "inc/npi_tl.h" // **************************************************************************** // defines // **************************************************************************** //! \brief Transport layer RX Event (ie. bytes received, RX ISR etc.) #define NPITASK_TRANSPORT_RX_EVENT 0x0002 //! \brief Transmit Complete Event (likely associated with TX ISR etc.) #define NPITASK_TRANSPORT_TX_DONE_EVENT 0x0004 //! \brief ASYNC Message Received Event (no framing bytes) #define NPITASK_FRAME_RX_EVENT 0x0008 //! \brief A framed message buffer is ready to be sent to the transport layer. #define NPITASK_TX_READY_EVENT 0x0010 #if defined(NPI_SREQRSP) //! \brief ASYNC Message Received Event (no framing bytes) #define NPITASK_SYNC_FRAME_RX_EVENT 0x0020 //! \brief A SYNC framed message buffer is ready to be sent to the transport layer. #define NPITASK_SYNC_TX_READY_EVENT 0x0040 //! \brief SYNC REQ/RSP Watchdog Timer Duration (in ms) #define NPITASK_WD_TIMEOUT 500 #endif // NPI_SREQRSP //! \brief MRDY Received Event #define NPITASK_MRDY_EVENT 0x0080 //! \brief Size of stack created for NPI RTOS task #define NPITASK_STACK_SIZE 512 //! \brief Task priority for NPI RTOS task #define NPITASK_PRIORITY 2 // **************************************************************************** // typedefs // **************************************************************************** //! \brief Queue record structure //! typedef struct NPI_QueueRec_t { Queue_Elem _elem; NPIMSG_msg_t *npiMsg; } NPI_QueueRec; //***************************************************************************** // globals //***************************************************************************** //! \brief ICall ID for stack which will be sending NPI messages //! static uint32_t stackServiceID = 0x0000; //! \brief RTOS task structure for NPI task //! static Task_Struct npiTaskStruct; //! \brief Allocated memory block for NPI task's stack //! Char npiTaskStack[NPITASK_STACK_SIZE]; //! \brief Handle for the ASYNC TX Queue //! static Queue_Handle npiTxQueue; //! \brief Handle for the ASYNC RX Queue //! static Queue_Handle npiRxQueue; #if defined(NPI_SREQRSP) //! \brief Handle for the SYNC TX Queue //! static Queue_Handle npiSyncTxQueue; //! \brief Handle for the SYNC RX Queue //! static Queue_Handle npiSyncRxQueue; //! \brief Flag/Counter indicating a Synchronous REQ/RSP is currently being //! processed. static int8_t syncTransactionInProgress = 0; //! \brief Clock Struct for Sync REQ/RSP watchdog timer //! static Clock_Struct syncReqRspWatchDogClkStruct; static Clock_Handle syncReqRspWatchDogClkHandle; #endif // NPI_SREQRSP //! \brief Pointer to last tx message. This is free'd once confirmation is //! is received that the buffer has been transmitted //! (ie. NPITASK_TRANSPORT_TX_DONE_EVENT) //! static uint8_t *lastQueuedTxMsg; //! \brief NPI thread ICall Semaphore. //! static ICall_Semaphore appSem = NULL; //! \brief NPI ICall Application Entity ID. //! ICall_EntityID npiAppEntityID = 0; //! \brief Task pending events //! static uint16_t NPITask_events = 0; //! \brief Event flags for capturing Task-related events from ISR context //! static uint16_t TX_DONE_ISR_EVENT_FLAG = 0; static uint16_t MRDY_ISR_EVENT_FLAG = 0; static uint16_t TRANSPORT_RX_ISR_EVENT_FLAG = 0; //! \brief Pointer to Application RX event callback function for optional //! rerouting of messages to application. //! static npiIncomingEventCBack_t incomingRXEventAppCBFunc = NULL; //! \brief Type of rerouting for RX messages requested by Application //! static NPI_IncomingNPIEventRerouteType incomingRXReroute = NONE; //! \brief Pointer to Application TX event callback function for optional //! rerouting of messages to application. //! static npiIncomingEventCBack_t incomingTXEventAppCBFunc = NULL; //! \brief Type of rerouting for TX messages requested by Application //! static NPI_IncomingNPIEventRerouteType incomingTXReroute = NONE; //***************************************************************************** // function prototypes //***************************************************************************** //! \brief NPI main event processing loop. //! static void NPITask_process(void); //! \brief Callback function registered with Transport Layer //! static void NPITask_transportRXCallBack(int size); //! \brief Callback function registered with Transport Layer //! static void NPITask_transportTxDoneCallBack(int size); //! \brief Callback function registered with Transport Layer //! static void NPITask_MRDYEventCB(int size); //! \brief ASYNC TX Q Processing function. //! static void NPITask_ProcessTXQ(void); #if defined(NPI_SREQRSP) //! \brief SYNC TX Q Processing function. //! static void NPITask_ProcessSyncTXQ(void); //! \brief SYNC RX Q Processing function. //! static void NPITask_processSyncRXQ(void); //! \brief Sync REQ/RSP Watchdog Timer CB //! static void syncReqRspWatchDogTimeoutCB( UArg a0 ); #endif // NPI_SREQRSP //! \brief ASYNC RX Q Processing function. //! static void NPITask_processRXQ(void); //! \brief Callback function registered with Frame module to handle successful //! reception of message from host. //! static void NPITask_incomingFrameCB(uint8_t frameSize, uint8_t *pFrame, NPIMSG_Type msgType); //! \brief Function to send message buffer to stack task. Note, message buffer //! referenced by NPIMSG_msg_t is "unframed". //! static ICall_Errno NPITask_sendBufToStack(ICall_EntityID appEntity, NPIMSG_msg_t *msg); //! \brief Function to handle incoming ICall Message Event //! static uint_least16_t NPITask_processICallMsgEvent(uint8_t *pMsg, ICall_ServiceEnum src, ICall_EntityID dest); //! \brief Function to process incoming Msg from stack task. //! static void NPITask_processStackMsg(uint8_t *pMsg); // ----------------------------------------------------------------------------- //! \brief Initialization for the NPI Thread //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_inititializeTask(void) { NPITask_events = 0; lastQueuedTxMsg = NULL; // create a Tx Queue instance npiTxQueue = Queue_create(NULL, NULL); // create an Rx Queue instance npiRxQueue = Queue_create(NULL, NULL); #if defined(NPI_SREQRSP) // create an Sync RX Queue instance npiSyncRxQueue = Queue_create(NULL, NULL); // create an Sync TX Queue instance npiSyncTxQueue = Queue_create(NULL, NULL); // Create clock for SYNC REQ/RSP message watchdog Clock_Params clockParams; // Convert clockDuration in milliseconds to ticks. uint32_t clockTicks = NPITASK_WD_TIMEOUT * (1000 / Clock_tickPeriod); // Setup parameters. Clock_Params_init(&clockParams); // If period is 0, this is a one-shot timer. clockParams.period = 0; // Starts immediately after construction if true, otherwise wait for a call // to start. clockParams.startFlag = 0; // Initialize clock instance. Clock_construct(&syncReqRspWatchDogClkStruct, syncReqRspWatchDogTimeoutCB, clockTicks, &clockParams); syncReqRspWatchDogClkHandle = Clock_handle(&syncReqRspWatchDogClkStruct); #endif // NPI_SREQRSP /* Enroll the service that this stack represents */ ICall_enrollService( ICALL_SERVICE_CLASS_NPI, NULL, &npiAppEntityID, &appSem ); // Initialize Frame Module NPIFrame_initialize(&NPITask_incomingFrameCB); // Initialize Network Processor Interface (NPI) and Transport Layer NPITL_initTL( &NPITask_transportTxDoneCallBack, &NPITask_transportRXCallBack, &NPITask_MRDYEventCB ); } // ----------------------------------------------------------------------------- //! \brief NPI main event processing loop. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_process(void) { ICall_ServiceEnum stackid; ICall_EntityID dest; uint8_t *pMsg; ICall_CSState key; /* Forever loop */ for (;;) { /* Wait for response message */ Semaphore_pend(appSem, BIOS_WAIT_FOREVER); { // Capture the ISR events flags now within a critical section. // We do this to avoid possible race conditions where the ISR is // modifying the event mask while the task is read/writing it. key = ICall_enterCriticalSection(); NPITask_events = NPITask_events | TX_DONE_ISR_EVENT_FLAG | MRDY_ISR_EVENT_FLAG | TRANSPORT_RX_ISR_EVENT_FLAG; TX_DONE_ISR_EVENT_FLAG = 0; MRDY_ISR_EVENT_FLAG = 0; TRANSPORT_RX_ISR_EVENT_FLAG = 0; ICall_leaveCriticalSection(key); // MRDY event if (NPITask_events & NPITASK_MRDY_EVENT) { NPITask_events &= ~NPITASK_MRDY_EVENT; #ifdef POWER_SAVING NPITL_handleMrdyEvent(); #endif //POWER_SAVING } #if defined(NPI_SREQRSP) // Something is ready to send to the Host if (NPITask_events & NPITASK_SYNC_TX_READY_EVENT) { if (syncTransactionInProgress) { // Prioritize Synchronous traffic if ((!Queue_empty(npiSyncTxQueue)) && !NPITL_checkNpiBusy()) { // Push the pending Sync RSP to the host. NPITask_ProcessSyncTXQ(); } } else { // Not expected } if (Queue_empty(npiSyncTxQueue)) { // If the Sync Q is empty now (and it should be) clear the // event. NPITask_events &= ~NPITASK_SYNC_TX_READY_EVENT; } else { // If the Sync Q is not empty now : // - It means we're handling "stacked" SYNC REQ/RSP's // (which shouldn't be happening). // - Preserve the event flag and repost on the semaphore. Semaphore_post(appSem); } } #endif // NPI_SREQRSP // ICall Message Event if (ICall_fetchServiceMsg(&stackid, &dest, (void **) &pMsg) == ICALL_ERRNO_SUCCESS) { NPITask_processICallMsgEvent(pMsg, stackid, dest); } #if defined(NPI_SREQRSP) // Synchronous Frame received from Host if (NPITask_events & NPITASK_SYNC_FRAME_RX_EVENT) { // Process it NPITask_processSyncRXQ(); if (Queue_empty(npiSyncRxQueue)) { // Q is empty, it's safe to clear the event flag. NPITask_events &= ~NPITASK_SYNC_FRAME_RX_EVENT; } else { // Q is not empty, there's more to handle so preserve the // flag and repost to the task semaphore. Semaphore_post(appSem); } } #endif // NPI_SREQRSP // An ASYNC message is ready to send to the Host if (NPITask_events & NPITASK_TX_READY_EVENT) { #if defined(NPI_SREQRSP) // Check for outstanding SYNC REQ/RSP transactions. If so, // this ASYNC message must remain Q'd while we wait for the // SYNC RSP. if (syncTransactionInProgress == 0) { // No outstanding SYNC REQ/RSP transactions, process // ASYNC messages. #endif // NPI_SREQRSP if ((!Queue_empty(npiTxQueue)) && !NPITL_checkNpiBusy()) { NPITask_ProcessTXQ(); } #if defined(NPI_SREQRSP) } #endif // NPI_SREQRSP if (Queue_empty(npiTxQueue)) { // Q is empty, it's safe to clear the event flag. NPITask_events &= ~NPITASK_TX_READY_EVENT; } else { // Q is not empty, there's more to handle so preserve the // flag and repost to the task semaphore. Semaphore_post(appSem); } } // The Transport Layer has received some bytes if (NPITask_events & NPITASK_TRANSPORT_RX_EVENT) { // Call the packet/frame collector parser. This function is // specific to the supported technology: // - HCI for BLE // - MT for ZigBee, TIMAC, RF4CE // - ? for your favorite technology NPIFrame_collectFrameData(); if (NPIRxBuf_GetRxBufCount() == 0) { // No additional bytes to collect, clear the flag. NPITask_events &= ~NPITASK_TRANSPORT_RX_EVENT; } else { // Additional bytes to collect, preserve the flag and repost // to the semaphore Semaphore_post(appSem); } } // A complete frame (msg) has been received and is ready for handling if (NPITask_events & NPITASK_FRAME_RX_EVENT) { #if defined(NPI_SREQRSP) // Check for outstanding SYNC REQ/RSP transactions. If so, // this ASYNC message must remain Q'd while we wait for the // SYNC RSP. if (syncTransactionInProgress == 0) { #endif // NPI_SREQRSP // Process the ASYNC message NPITask_processRXQ(); if (Queue_empty(npiRxQueue)) { // Q is empty, it's safe to clear the event flag. NPITask_events &= ~NPITASK_FRAME_RX_EVENT; } else { // Q is not empty, there's more to handle so preserve the // flag and repost to the task semaphore. Semaphore_post(appSem); } #if defined(NPI_SREQRSP) } else { // Preserve the flag and repost to the task semaphore. Semaphore_post(appSem); } #endif // NPI_SREQRSP } // The last transmission to the host has completed. if (NPITask_events & NPITASK_TRANSPORT_TX_DONE_EVENT) { // Current TX is done. NPITask_events &= ~NPITASK_TRANSPORT_TX_DONE_EVENT; #if defined(NPI_SREQRSP) if (!Queue_empty(npiSyncTxQueue)) { // There are pending SYNC RSP messages waiting to be sent // to the host. Set the appropriate flag and post to // the semaphore. NPITask_events |= NPITASK_SYNC_TX_READY_EVENT; Semaphore_post(appSem); } else { #endif // NPI_SREQRSP if (!Queue_empty(npiTxQueue)) { // There are pending ASYNC messages waiting to be sent // to the host. Set the appropriate flag and post to // the semaphore. NPITask_events |= NPITASK_TX_READY_EVENT; Semaphore_post(appSem); } #if defined(NPI_SREQRSP) } #endif // NPI_SREQRSP } } } } // ----------------------------------------------------------------------------- //! \brief NPI Task function called from within NPITask_Fxn //! //! \return void // ----------------------------------------------------------------------------- void NPITask_task(void) { // Initialize application NPITask_inititializeTask(); // No return from TestProfile2 process NPITask_process(); } // ----------------------------------------------------------------------------- // Exported Functions // ----------------------------------------------------------------------------- //! \brief NPI task entry point. //! //! \return void // ----------------------------------------------------------------------------- void NPITask_Fxn(UArg a0, UArg a1) { NPITask_task(); } // ----------------------------------------------------------------------------- //! \brief Task creation function for NPI //! //! \param[in] stackID ICall ID of stack entity //! //! \return void // ----------------------------------------------------------------------------- void NPITask_createTask(uint32_t stackID) { // Set stackID for future ICall Messaging stackServiceID = stackID; memset(&npiTaskStack, 0xDD, sizeof(npiTaskStack)); // Configure and create the NPI task. Task_Params npiTaskParams; Task_Params_init(&npiTaskParams); npiTaskParams.stack = npiTaskStack; npiTaskParams.stackSize = NPITASK_STACK_SIZE; npiTaskParams.priority = NPITASK_PRIORITY; Task_construct(&npiTaskStruct, NPITask_Fxn, &npiTaskParams, NULL); } // ----------------------------------------------------------------------------- //! \brief Register callback function to reroute incoming (from host) //! NPI messages. //! //! \param[in] appRxCB Callback function. //! \param[in] reRouteType Type of re-routing requested //! //! \return void // ----------------------------------------------------------------------------- void NPITask_registerIncomingRXEventAppCB(npiIncomingEventCBack_t appRxCB, NPI_IncomingNPIEventRerouteType reRouteType) { incomingRXEventAppCBFunc = appRxCB; incomingRXReroute = reRouteType; } // ----------------------------------------------------------------------------- //! \brief Register callback function to reroute outgoing (from stack) //! NPI messages. //! //! \param[in] appTxCB Callback function. //! \param[in] reRouteType Type of re-routing requested //! //! \return void // ----------------------------------------------------------------------------- void NPITask_registerIncomingTXEventAppCB(npiIncomingEventCBack_t appTxCB, NPI_IncomingNPIEventRerouteType reRouteType) { incomingTXEventAppCBFunc = appTxCB; incomingTXReroute = reRouteType; } // ----------------------------------------------------------------------------- //! \brief API for application task to send a message to the Host. //! NOTE: It's assumed all message traffic to the stack will use //! other (ICALL) APIs/Interfaces. //! //! \param[in] pMsg Pointer to "unframed" message buffer. //! //! \return void // ----------------------------------------------------------------------------- void NPITask_sendToHost(uint8_t *pMsg) { NPI_QueueRec *recPtr; NPIMSG_msg_t *pNPIMsg = NPIFrame_frameMsg(pMsg); recPtr = ICall_malloc(sizeof(NPI_QueueRec)); if (pNPIMsg != NULL && recPtr != NULL) { recPtr->npiMsg = pNPIMsg; switch (pNPIMsg->msgType) { // Enqueue to appropriate NPI Task Q and post corresponding event. #if defined(NPI_SREQRSP) case NPIMSG_Type_SYNCRSP: { Queue_enqueue(npiSyncTxQueue, &recPtr->_elem); NPITask_events |= NPITASK_SYNC_TX_READY_EVENT; Semaphore_post(appSem); break; } #endif // NPI_SREQRSP case NPIMSG_Type_ASYNC: { Queue_enqueue(npiTxQueue, &recPtr->_elem); NPITask_events |= NPITASK_TX_READY_EVENT; Semaphore_post(appSem); break; } default: { //error break; } } } } // ----------------------------------------------------------------------------- // Event Handlers // ----------------------------------------------------------------------------- //! \brief Process an ICall message from the Stack //! //! \param[in] pMsg pointer to an unframed message buffer //! \param[in] src Service ID for message source //! \param[in] dest Entity ID for message destination //! //! \return uint_least16_t // ----------------------------------------------------------------------------- static uint_least16_t NPITask_processICallMsgEvent(uint8_t *pMsg, ICall_ServiceEnum src, ICall_EntityID dest) { if (dest == npiAppEntityID) { // Message received from the Stack. NPITask_processStackMsg(pMsg); } return 0; } // ----------------------------------------------------------------------------- // Utility functions // ----------------------------------------------------------------------------- //! \brief Forward the message buffer on to the Stack thread. //! //! \param[in] appEntity ICall Entity ID of the caller. //! \param[in] pMsg Pointer to a NPIMSG_msg_t container. //! //! \return void // ----------------------------------------------------------------------------- static ICall_Errno NPITask_sendBufToStack(ICall_EntityID appEntity, NPIMSG_msg_t *pMsg) { ICall_Errno errno = ICALL_ERRNO_SUCCESS; // Send the message errno = ICall_sendServiceMsg(appEntity, stackServiceID, ICALL_MSG_FORMAT_KEEP, pMsg->pBuf); ICall_free(pMsg); return errno; } // ----------------------------------------------------------------------------- // "Processor" functions // ----------------------------------------------------------------------------- //! \brief Process Response from Stack //! //! \param[in] pMsg Pointer to unframed message buffer //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_processStackMsg(uint8_t *pMsg) { NPI_QueueRec *recPtr; NPIMSG_msg_t *pNPIMsg; if (incomingTXEventAppCBFunc != NULL) { switch (incomingTXReroute) { case INTERCEPT: { // Pass the message along to the application and the leave // this function with an immediate return. // The message needs to be free by the callback. incomingTXEventAppCBFunc(pMsg); return; } case ECHO: { // Pass the message along to the application incomingTXEventAppCBFunc(pMsg); break; } } } pNPIMsg = NPIFrame_frameMsg(pMsg); recPtr = ICall_malloc(sizeof(NPI_QueueRec)); if (pNPIMsg != NULL && recPtr != NULL) { recPtr->npiMsg = pNPIMsg; #if defined(NPI_SREQRSP) switch (pNPIMsg->msgType) { // Enqueue to appropriate NPI Task Q and post corresponding event. case NPIMSG_Type_SYNCRSP: { Queue_enqueue(npiSyncTxQueue, &recPtr->_elem); NPITask_events |= NPITASK_SYNC_TX_READY_EVENT; Semaphore_post(appSem); break; } case NPIMSG_Type_ASYNC: { Queue_enqueue(npiTxQueue, &recPtr->_elem); NPITask_events |= NPITASK_TX_READY_EVENT; Semaphore_post(appSem); break; } default: { //error break; } } #else Queue_enqueue(npiTxQueue, &recPtr->_elem); NPITask_events |= NPITASK_TX_READY_EVENT; Semaphore_post(appSem); #endif // NPI_SREQRSP } } // ----------------------------------------------------------------------------- //! \brief Dequeue next message in the ASYNC TX Queue and send to serial //! interface. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_ProcessTXQ(void) { NPI_QueueRec *recPtr = NULL; recPtr = Queue_dequeue(npiTxQueue); if (recPtr != NULL) { lastQueuedTxMsg = recPtr->npiMsg->pBuf; NPITL_writeTL(recPtr->npiMsg->pBuf, recPtr->npiMsg->pBufSize); //free the Queue record ICall_free(recPtr->npiMsg); ICall_free(recPtr); } } #if defined(NPI_SREQRSP) // ----------------------------------------------------------------------------- //! \brief Dequeue next message in the SYNC TX Queue and send to serial //! interface. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_ProcessSyncTXQ(void) { NPI_QueueRec *recPtr = NULL; recPtr = Queue_dequeue(npiSyncTxQueue); if (recPtr != NULL) { lastQueuedTxMsg = recPtr->npiMsg->pBuf; NPITL_writeTL(recPtr->npiMsg->pBuf, recPtr->npiMsg->pBufSize); // Decrement the outstanding Sync REQ/RSP flag. syncTransactionInProgress--; // Stop watchdog clock. Clock_stop(syncReqRspWatchDogClkHandle); if (syncTransactionInProgress < 0) { // not expected! syncTransactionInProgress = 0; } ICall_free(recPtr->npiMsg); ICall_free(recPtr); } } #endif // NPI_SREQRSP // ----------------------------------------------------------------------------- //! \brief Dequeue next message in the RX Queue and process it. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_processRXQ(void) { NPI_QueueRec *recPtr = NULL; recPtr = Queue_dequeue(npiRxQueue); if (recPtr != NULL) { if (incomingRXEventAppCBFunc != NULL) { switch (incomingRXReroute) { case ECHO: { // send to stack and a copy to the application NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); incomingRXEventAppCBFunc((uint8_t *)recPtr->npiMsg); break; } case INTERCEPT: { // send a copy only to the application // npiMsg need to be free in the callback incomingRXEventAppCBFunc((uint8_t *)recPtr->npiMsg); break; } case NONE: { NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); break; } } } else { // send to stack and a copy to the application NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); } //free the Queue record ICall_free(recPtr); // DON'T free the referenced npiMsg container. This will be free'd in the // stack task. } } #if defined(NPI_SREQRSP) // ----------------------------------------------------------------------------- //! \brief Dequeue next message in the RX Queue and process it. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_processSyncRXQ(void) { NPI_QueueRec *recPtr = NULL; if (syncTransactionInProgress == 0) { recPtr = Queue_dequeue(npiSyncRxQueue); if (recPtr != NULL) { // Increment the outstanding Sync REQ/RSP flag. syncTransactionInProgress++; // Start the Sync REQ/RSP watchdog timer Clock_start(syncReqRspWatchDogClkHandle); if (incomingRXEventAppCBFunc != NULL) { switch (incomingRXReroute) { case ECHO: { // send to stack and a copy to the application NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); incomingRXEventAppCBFunc(recPtr->npiMsg->pBuf); break; } case INTERCEPT: { // send a copy only to the application incomingRXEventAppCBFunc(recPtr->npiMsg->pBuf); break; } case NONE: { NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); break; } } } else { // send to stack and a copy to the application NPITask_sendBufToStack(npiAppEntityID, recPtr->npiMsg); } //free the Queue record ICall_free(recPtr); // DON'T free the referenced npiMsg container. This will be free'd in the // stack task. } } } #endif // NPI_SREQRSP // ----------------------------------------------------------------------------- // Call Back Functions // ----------------------------------------------------------------------------- //! \brief Call back function for TX Done event from transport layer. //! //! \param[in] size Number of bytes transmitted. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_transportTxDoneCallBack(int size) { if (lastQueuedTxMsg) { //Deallocate most recent message being transmitted. ICall_freeMsg(lastQueuedTxMsg); lastQueuedTxMsg = NULL; } // Post the event to the NPI task thread. TX_DONE_ISR_EVENT_FLAG = NPITASK_TRANSPORT_TX_DONE_EVENT; Semaphore_post(appSem); } // ----------------------------------------------------------------------------- //! \brief Call back function to handle complete RX frame from Frame module. //! //! \param[in] frameSize Size of message frame. //! \param[in] pFrame Pointer to message frame. //! \param[in] msgType Message type, SYNC or ASYNC //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_incomingFrameCB(uint8_t frameSize, uint8_t *pFrame, NPIMSG_Type msgType) { NPI_QueueRec *recPtr = ICall_malloc(sizeof(NPI_QueueRec)); // Allocate NPIMSG_msg_t container NPIMSG_msg_t *npiMsgPtr = ICall_malloc(sizeof(NPIMSG_msg_t)); if ((recPtr != NULL) && (npiMsgPtr != NULL)) { npiMsgPtr->pBuf = pFrame; npiMsgPtr->pBufSize = frameSize; recPtr->npiMsg = npiMsgPtr; switch (msgType) { // Enqueue to appropriate NPI Task Q and post corresponding event. case NPIMSG_Type_ASYNC: { recPtr->npiMsg->msgType = NPIMSG_Type_ASYNC; Queue_enqueue(npiRxQueue, &recPtr->_elem); NPITask_events |= NPITASK_FRAME_RX_EVENT; Semaphore_post(appSem); break; } #if defined(NPI_SREQRSP) case NPIMSG_Type_SYNCREQ: { recPtr->npiMsg->msgType = NPIMSG_Type_SYNCREQ; Queue_enqueue(npiSyncRxQueue, &recPtr->_elem); NPITask_events |= NPITASK_SYNC_FRAME_RX_EVENT; Semaphore_post(appSem); break; } #endif // NPI_SREQRSP default: { // undefined msgType ICall_free(npiMsgPtr); ICall_free(recPtr); ICall_freeMsg(pFrame); break; } } } } // ----------------------------------------------------------------------------- //! \brief RX Callback provided to Transport Layer for RX Event (ie.Bytes //! received). //! //! \param[in] size Number of bytes received. //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_transportRXCallBack(int size) { // Check for overflow of RxBuf: // If the buffer has overflowed there is no way to safely recover. All // received bytes can be packet fragments so if a packet fragment is lost // the frame parser behavior becomes undefined. The only way to prevent // RxBuf overflow is to enable POWER_SAVING. // // If POWER_SAVING is not defined then there is no way to for slave to // control the master transfer rate. With POWER_SAVING the slave has SRDY // to use as a software flow control mechanism. // When using POWER_SAVING make sure to increase NPI_TL_BUF_SIZE // to suit the NPI frame length that is expected to be received. if (size < NPIRxBuf_GetRxBufAvail()) { NPIRxBuf_Read(size); TRANSPORT_RX_ISR_EVENT_FLAG = NPITASK_TRANSPORT_RX_EVENT; Semaphore_post(appSem); } else { // Trap here for pending buffer overflow. If you have POWER_SAVING // enabled, increase size of RxBuf to handle larger frames from host. for(;;); } } // ----------------------------------------------------------------------------- //! \brief RX Callback provided to Transport Layer for MRDY Event //! //! \param[in] size not used //! //! \return void // ----------------------------------------------------------------------------- static void NPITask_MRDYEventCB(int size) { MRDY_ISR_EVENT_FLAG = NPITASK_MRDY_EVENT; Semaphore_post(appSem); } #if defined(NPI_SREQRSP) // ----------------------------------------------------------------------------- //! \brief Sync REQ/RSP Watchdog Timer CB //! //! \param[in] a0 pointer passed to watchdog registering function //! //! \return void // ----------------------------------------------------------------------------- static void syncReqRspWatchDogTimeoutCB(UArg a0) { // Something has happened to the SYNC REQ we're waiting on. if (syncTransactionInProgress > 0) { // reduce the number of transactions outstanding syncTransactionInProgress--; // check if there are more pending SYNC REQ's if (!Queue_empty(npiSyncRxQueue)) { NPITask_events |= NPITASK_SYNC_FRAME_RX_EVENT; } // re-enter to Task event loop Semaphore_post(appSem); } else { // not expected } } #endif // NPI_SREQRSP