1150 lines
38 KiB
C
1150 lines
38 KiB
C
//******************************************************************************
|
|
//! \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 <xdc/std.h>
|
|
#include <ti/sysbios/knl/Semaphore.h>
|
|
#include <ti/sysbios/knl/Queue.h>
|
|
#include <ti/sysbios/knl/Task.h>
|
|
#include <ti/sysbios/knl/Clock.h>
|
|
#include <ti/sysbios/BIOS.h>
|
|
|
|
#include <string.h>
|
|
#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
|
|
|