482 lines
16 KiB
C
482 lines
16 KiB
C
//******************************************************************************
|
|
//! \file npi_tl.c
|
|
//! \brief NPI Transport Layer API
|
|
//
|
|
// Revised $Date: 2015-07-20 15:51:01 -0700 (Mon, 20 Jul 2015) $
|
|
// Revision: $Revision: 44375 $
|
|
//
|
|
// 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 <string.h>
|
|
#include <xdc/std.h>
|
|
#include <ti/sysbios/family/arm/cc26xx/Power.h>
|
|
#include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
|
|
#include <ti/sysbios/family/arm/m3/Hwi.h>
|
|
#include <ti/drivers/pin/PINCC26XX.h>
|
|
#include <ti/sysbios/knl/Task.h>
|
|
#include <ti/sysbios/knl/Swi.h>
|
|
|
|
#include "inc/hw_memmap.h"
|
|
#include "inc/hw_ints.h"
|
|
#include "Board.h"
|
|
#include "ICall.h"
|
|
#include "hal_types.h"
|
|
#include "inc/npi_tl.h"
|
|
#include "inc/npi_config.h"
|
|
|
|
// ****************************************************************************
|
|
// defines
|
|
// ****************************************************************************
|
|
|
|
#if defined(NPI_USE_SPI)
|
|
#include "inc/npi_tl_spi.h"
|
|
#elif defined(NPI_USE_UART)
|
|
#include "inc/npi_tl_uart.h"
|
|
#else
|
|
#error Must define an underlying serial bus for NPI
|
|
#endif
|
|
|
|
|
|
// ****************************************************************************
|
|
// typedefs
|
|
// ****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
// globals
|
|
//*****************************************************************************
|
|
|
|
//! \brief Flag for low power mode
|
|
static volatile bool npiPMSetConstraint = FALSE;
|
|
|
|
//! \brief Flag for ongoing NPI TX
|
|
static volatile bool npiTxActive = FALSE;
|
|
|
|
//! \brief The packet that was being sent when HWI of MRDY going low was received
|
|
static volatile uint32 mrdyPktStamp = 0;
|
|
|
|
//! \brief Packets transmitted counter
|
|
static uint32 txPktCount = 0;
|
|
|
|
//! \brief NPI Transport Layer receive buffer
|
|
static Char npiRxBuf[NPI_TL_BUF_SIZE];
|
|
|
|
//! \brief Index to last byte written into NPI Transport Layer receive buffer
|
|
static uint16_t npiRxBufTail = 0;
|
|
|
|
//! \brief Index to first byte to be read from NPI Transport Layer receive buffer
|
|
static uint16_t npiRxBufHead = 0;
|
|
|
|
//! \brief NPI Transport Layer transmit buffer
|
|
static Char npiTxBuf[NPI_TL_BUF_SIZE];
|
|
|
|
//! \brief Number of bytes in NPI Transport Layer transmit buffer
|
|
static uint16_t npiTxBufLen = 0;
|
|
|
|
//! \brief Call back function in NPI Task for transmit complete
|
|
static npiRtosCB_t taskTxCB = NULL;
|
|
|
|
//! \brief Call back function in NPI Task for receive complete
|
|
static npiRtosCB_t taskRxCB = NULL;
|
|
|
|
//! \brief The remainder of any message that is fragmented
|
|
static uint8 *msgFrag = NULL;
|
|
|
|
//! \brief The length of the remaining message fragment
|
|
static uint16 msgFragLen = 0;
|
|
|
|
#ifdef POWER_SAVING
|
|
//! \brief Call back function in NPI Task for MRDY hardware interrupt
|
|
static npiMrdyRtosCB_t taskMrdyCB = NULL;
|
|
|
|
//! \brief PIN Config for Mrdy and Srdy signals
|
|
static PIN_Config npiHandshakePinsCfg[] =
|
|
{
|
|
MRDY_PIN | PIN_GPIO_OUTPUT_DIS | PIN_INPUT_EN | PIN_PULLUP,
|
|
SRDY_PIN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
|
|
PIN_TERMINATE
|
|
};
|
|
|
|
//! \brief PIN State for Mrdy and Srdy signals
|
|
static PIN_State npiHandshakePins;
|
|
|
|
//! \brief PIN Handles for Mrdy and Srdy signals
|
|
static PIN_Handle hNpiHandshakePins;
|
|
|
|
//! \brief No way to detect whether positive or negative edge with PIN Driver
|
|
//! Use a flag to keep track of state
|
|
static uint8 mrdy_state;
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
// function prototypes
|
|
//*****************************************************************************
|
|
|
|
//! \brief Call back function provided to underlying serial interface to be
|
|
// invoked upon the completion of a transmission
|
|
static void NPITL_transmissionCallBack(uint16 Rxlen, uint16 Txlen);
|
|
|
|
#ifdef POWER_SAVING
|
|
//! \brief HWI interrupt function for MRDY
|
|
static void NPITL_MRDYPinHwiFxn(PIN_Handle hPin, PIN_Id pinId);
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine initializes the transport layer and opens the port
|
|
//! of the device. Note that based on project defines, either the
|
|
//! UART, or SPI driver can be used.
|
|
//!
|
|
//! \param[in] npiCBTx - Call back function for TX complete event
|
|
//! \param[in] npiCBRx - Call back function for RX event
|
|
//! \param[in] npiCBMrdy - Call back function for MRDY event
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
void NPITL_initTL(npiRtosCB_t npiCBTx, npiRtosCB_t npiCBRx, npiRtosCB_t npiCBMrdy)
|
|
{
|
|
ICall_CSState key;
|
|
key = ICall_enterCriticalSection();
|
|
|
|
taskTxCB = npiCBTx;
|
|
taskRxCB = npiCBRx;
|
|
#ifdef POWER_SAVING
|
|
taskMrdyCB = npiCBMrdy;
|
|
#endif
|
|
|
|
transportInit(npiRxBuf,npiTxBuf, NPITL_transmissionCallBack);
|
|
|
|
#ifdef POWER_SAVING
|
|
SRDY_DISABLE();
|
|
|
|
// Initialize SRDY/MRDY. Enable int after callback registered
|
|
hNpiHandshakePins = PIN_open(&npiHandshakePins, npiHandshakePinsCfg);
|
|
PIN_registerIntCb(hNpiHandshakePins, NPITL_MRDYPinHwiFxn);
|
|
PIN_setConfig(hNpiHandshakePins, PIN_BM_IRQ, MRDY_PIN | PIN_IRQ_BOTHEDGES);
|
|
|
|
// Enable wakeup
|
|
PIN_setConfig(hNpiHandshakePins, PINCC26XX_BM_WAKEUP, MRDY_PIN | PINCC26XX_WAKEUP_NEGEDGE);
|
|
|
|
mrdy_state = PIN_getInputValue(MRDY_PIN);
|
|
#endif // ! POWER_SAVING
|
|
|
|
ICall_leaveCriticalSection(key);
|
|
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine returns the state of transmission on NPI
|
|
//!
|
|
//! \return bool - state of NPI transmission - 1 - active, 0 - not active
|
|
// -----------------------------------------------------------------------------
|
|
bool NPITL_checkNpiBusy(void)
|
|
{
|
|
#ifdef POWER_SAVING
|
|
|
|
return !PIN_getOutputValue(SRDY_PIN);
|
|
#else
|
|
return npiTxActive;
|
|
#endif
|
|
}
|
|
|
|
#ifdef POWER_SAVING
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine is used to set constraints on power manager
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
static void NPITL_setPM(void)
|
|
{
|
|
if( npiPMSetConstraint )
|
|
{
|
|
return;
|
|
}
|
|
// set constraints for Standby and idle mode
|
|
Power_setConstraint(Power_SB_DISALLOW);
|
|
Power_setConstraint(Power_IDLE_PD_DISALLOW);
|
|
npiPMSetConstraint = TRUE;
|
|
}
|
|
#endif
|
|
|
|
#ifdef POWER_SAVING
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine is used to release constraints on power manager
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
static void NPITL_relPM(void)
|
|
{
|
|
if ( ! npiPMSetConstraint )
|
|
{
|
|
return;
|
|
}
|
|
// release constraints for Standby and idle mode
|
|
Power_releaseConstraint(Power_SB_DISALLOW);
|
|
Power_releaseConstraint(Power_IDLE_PD_DISALLOW);
|
|
npiPMSetConstraint = FALSE;
|
|
}
|
|
#endif
|
|
|
|
#ifdef POWER_SAVING
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine is used to handle an MRDY transition from a task
|
|
//! context. Certain operations such as UART_read() cannot be
|
|
//! performed from a HWI context
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
void NPITL_handleMrdyEvent(void)
|
|
{
|
|
ICall_CSState key;
|
|
key = ICall_enterCriticalSection();
|
|
|
|
// Check to make sure this event is not occurring during the next packet
|
|
// transmission
|
|
if ( PIN_getInputValue(MRDY_PIN) == 0 ||
|
|
(npiTxActive && mrdyPktStamp == txPktCount ) )
|
|
{
|
|
transportMrdyEvent();
|
|
SRDY_ENABLE();
|
|
}
|
|
|
|
ICall_leaveCriticalSection(key);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This is a HWI function handler for the MRDY pin. Some MRDY
|
|
//! functionality can execute from this HWI context. Others
|
|
//! must be executed from task context hence the taskMrdyCB()
|
|
//!
|
|
//! \param[in] hPin - PIN Handle
|
|
//! \param[in] pinId - ID of pin that triggered HWI
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
static void NPITL_MRDYPinHwiFxn(PIN_Handle hPin, PIN_Id pinId)
|
|
{
|
|
// The pin driver does not currently support returning whether the int
|
|
// was neg or pos edge so we must use a variable to keep track of state.
|
|
// If the physical state of the pin was used then a very quick toggle of
|
|
// of MRDY could be missed.
|
|
mrdy_state ^= 1;
|
|
|
|
if (mrdy_state == 0)
|
|
{
|
|
mrdyPktStamp = txPktCount;
|
|
NPITL_setPM();
|
|
if ( taskMrdyCB )
|
|
{
|
|
taskMrdyCB();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
transportStopTransfer();
|
|
}
|
|
|
|
// Check the physical state of the pin to see if it matches the variable
|
|
// state. If not then edge has been missed
|
|
if (mrdy_state != PIN_getInputValue(MRDY_PIN))
|
|
{
|
|
mrdy_state = PIN_getInputValue(MRDY_PIN);
|
|
|
|
if (mrdy_state == 0)
|
|
{
|
|
mrdyPktStamp = txPktCount;
|
|
NPITL_setPM();
|
|
|
|
if (taskMrdyCB)
|
|
{
|
|
taskMrdyCB();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
transportStopTransfer();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This callback is invoked on the completion of one transmission
|
|
//! to/from the host MCU. Any bytes receives will be [0,Rxlen) in
|
|
//! npiRxBuf.
|
|
//! If bytes were receives or transmitted, this function notifies
|
|
//! the NPI task via registered call backs
|
|
//!
|
|
//! \param[in] Rxlen - lenth of the data received
|
|
//! \param[in] Txlen - length of the data transferred
|
|
//!
|
|
//! \return void
|
|
// -----------------------------------------------------------------------------
|
|
static void NPITL_transmissionCallBack(uint16 Rxlen, uint16 Txlen)
|
|
{
|
|
npiRxBufHead = 0;
|
|
npiRxBufTail = Rxlen;
|
|
|
|
if(Rxlen)
|
|
{
|
|
if ( taskRxCB )
|
|
{
|
|
taskRxCB(Rxlen);
|
|
}
|
|
}
|
|
if(Txlen)
|
|
{
|
|
npiTxActive = FALSE;
|
|
// Only perform call back if NPI Task has been registered
|
|
// and if there is not another fragment to send of this message
|
|
if ( taskTxCB && !msgFragLen )
|
|
{
|
|
taskTxCB(Txlen);
|
|
}
|
|
}
|
|
|
|
#ifdef POWER_SAVING
|
|
// Reset mrdy state in case of missed HWI
|
|
mrdy_state = PIN_getInputValue(MRDY_PIN);
|
|
|
|
NPITL_relPM();
|
|
SRDY_DISABLE();
|
|
#endif
|
|
|
|
// If there is another fragment to send, begin write without notifying
|
|
// higher level tasks
|
|
if ( msgFragLen )
|
|
{
|
|
NPITL_writeTL(msgFrag,msgFragLen);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine reads data from the transport layer based on len,
|
|
//! and places it into the buffer.
|
|
//!
|
|
//! \param[in] buf - Pointer to buffer to place read data.
|
|
//! \param[in] len - Number of bytes to read.
|
|
//!
|
|
//! \return uint16 - the number of bytes read from transport
|
|
// -----------------------------------------------------------------------------
|
|
uint16 NPITL_readTL(uint8 *buf, uint16 len)
|
|
{
|
|
// Only copy the lowest number between len and bytes remaining in buffer
|
|
len = (len > NPITL_getRxBufLen()) ? NPITL_getRxBufLen() : len;
|
|
|
|
memcpy(buf, &npiRxBuf[npiRxBufHead], len);
|
|
npiRxBufHead += len;
|
|
return len;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine writes data from the buffer to the transport layer.
|
|
//!
|
|
//! \param[in] buf - Pointer to buffer to write data from.
|
|
//! \param[in] len - Number of bytes to write.
|
|
//!
|
|
//! \return uint16 - the number of bytes written to transport
|
|
// -----------------------------------------------------------------------------
|
|
uint16 NPITL_writeTL(uint8 *buf, uint16 len)
|
|
{
|
|
ICall_CSState key;
|
|
key = ICall_enterCriticalSection();
|
|
|
|
// Writes are atomic at transport layer
|
|
if ( NPITL_checkNpiBusy() )
|
|
{
|
|
ICall_leaveCriticalSection(key);
|
|
return 0;
|
|
}
|
|
|
|
// If len of message is greater than fragment size
|
|
// then message must be sent over the span of multiple
|
|
// fragments
|
|
if ( len > NPI_MAX_FRAG_SIZE )
|
|
{
|
|
msgFrag = buf + NPI_MAX_FRAG_SIZE;
|
|
msgFragLen = len - NPI_MAX_FRAG_SIZE;
|
|
len = NPI_MAX_FRAG_SIZE;
|
|
}
|
|
else
|
|
{
|
|
msgFrag = NULL;
|
|
msgFragLen = 0;
|
|
}
|
|
|
|
memcpy(npiTxBuf, buf, len);
|
|
npiTxBufLen = len;
|
|
npiTxActive = TRUE;
|
|
txPktCount++;
|
|
|
|
len = transportWrite(npiTxBufLen);
|
|
|
|
#ifdef POWER_SAVING
|
|
SRDY_ENABLE();
|
|
#endif
|
|
|
|
ICall_leaveCriticalSection(key);
|
|
|
|
return len;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine returns the max size receive buffer.
|
|
//!
|
|
//! \return uint16 - max size of the receive buffer
|
|
// -----------------------------------------------------------------------------
|
|
uint16 NPITL_getMaxRxBufSize(void)
|
|
{
|
|
return(NPI_TL_BUF_SIZE);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief This routine returns the max size transmit buffer.
|
|
//!
|
|
//! \return uint16 - max size of the transmit buffer
|
|
// -----------------------------------------------------------------------------
|
|
uint16 NPITL_getMaxTxBufSize(void)
|
|
{
|
|
return(NPI_TL_BUF_SIZE);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
//! \brief Returns number of bytes that are unread in RxBuf
|
|
//!
|
|
//! \return uint16 - number of unread bytes
|
|
// -----------------------------------------------------------------------------
|
|
uint16 NPITL_getRxBufLen(void)
|
|
{
|
|
return ((npiRxBufTail - npiRxBufHead) + NPI_TL_BUF_SIZE) % NPI_TL_BUF_SIZE;
|
|
}
|