mirror of
https://github.com/espressif/openthread.git
synced 2026-10-18 21:48:12 +00:00
[ncp-spi] improve callback implementation, change code style format (#2734)
This commit makes the following changes in `NcpSpi` class: - It adds a new class `SpiFrame` which provides helper methods to parse and update the header fields in the header of an SPI frame. - It simplifies/enhances the `SpiTransactionComplete()` callback implementation by combining the parsing of input/output frame headers with the rx/tx frame processing. - It adds a check for correct pattern bits in a received frame flag byte (frames with incorrect pattern bits are ignored). - Code format is changed to follow the "pretty" style. - Fixes a rare issue with a possible incorrect accept length on the first SPI transaction after NCP reset.
This commit is contained in:
committed by
Jonathan Hui
parent
2f9bd174d0
commit
90b160ccfa
+119
-135
@@ -33,8 +33,8 @@
|
|||||||
#include "ncp_spi.hpp"
|
#include "ncp_spi.hpp"
|
||||||
|
|
||||||
#include <openthread/ncp.h>
|
#include <openthread/ncp.h>
|
||||||
#include <openthread/platform/spi-slave.h>
|
|
||||||
#include <openthread/platform/misc.h>
|
#include <openthread/platform/misc.h>
|
||||||
|
#include <openthread/platform/spi-slave.h>
|
||||||
|
|
||||||
#include "openthread-core-config.h"
|
#include "openthread-core-config.h"
|
||||||
#include "common/code_utils.hpp"
|
#include "common/code_utils.hpp"
|
||||||
@@ -43,11 +43,6 @@
|
|||||||
#include "common/new.hpp"
|
#include "common/new.hpp"
|
||||||
#include "net/ip6.hpp"
|
#include "net/ip6.hpp"
|
||||||
|
|
||||||
#define SPI_RESET_FLAG 0x80
|
|
||||||
#define SPI_CRC_FLAG 0x40
|
|
||||||
#define SPI_PATTERN_VALUE 0x02
|
|
||||||
#define SPI_PATTERN_MASK 0x03
|
|
||||||
|
|
||||||
#if OPENTHREAD_ENABLE_NCP_SPI
|
#if OPENTHREAD_ENABLE_NCP_SPI
|
||||||
|
|
||||||
namespace ot {
|
namespace ot {
|
||||||
@@ -59,10 +54,10 @@ static otDEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpSpi), uint64_t);
|
|||||||
|
|
||||||
extern "C" void otNcpInit(otInstance *aInstance)
|
extern "C" void otNcpInit(otInstance *aInstance)
|
||||||
{
|
{
|
||||||
NcpSpi *ncpSpi = NULL;
|
NcpSpi * ncpSpi = NULL;
|
||||||
Instance *instance = static_cast<Instance *>(aInstance);
|
Instance *instance = static_cast<Instance *>(aInstance);
|
||||||
|
|
||||||
ncpSpi = new(&sNcpRaw) NcpSpi(instance);
|
ncpSpi = new (&sNcpRaw) NcpSpi(instance);
|
||||||
|
|
||||||
if (ncpSpi == NULL || ncpSpi != NcpBase::GetNcpInstance())
|
if (ncpSpi == NULL || ncpSpi != NcpBase::GetNcpInstance())
|
||||||
{
|
{
|
||||||
@@ -72,169 +67,154 @@ extern "C" void otNcpInit(otInstance *aInstance)
|
|||||||
|
|
||||||
#endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT == 0
|
#endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT == 0
|
||||||
|
|
||||||
static void spi_header_set_flag_byte(uint8_t *header, uint8_t value)
|
NcpSpi::NcpSpi(Instance *aInstance)
|
||||||
|
: NcpBase(aInstance)
|
||||||
|
, mTxState(kTxStateIdle)
|
||||||
|
, mHandlingRxFrame(false)
|
||||||
|
, mResetFlag(true)
|
||||||
|
, mPrepareTxFrameTask(*aInstance, &NcpSpi::PrepareTxFrame, this)
|
||||||
|
, mSendFrameLength(0)
|
||||||
{
|
{
|
||||||
header[0] = value;
|
SpiFrame sendFrame(mSendFrame);
|
||||||
}
|
SpiFrame emptyFullAccept(mEmptySendFrameFullAccept);
|
||||||
|
SpiFrame emptyZeroAccept(mEmptySendFrameZeroAccept);
|
||||||
|
|
||||||
static void spi_header_set_accept_len(uint8_t *header, uint16_t len)
|
sendFrame.SetHeaderFlagByte(/* aResetFlag */ true);
|
||||||
{
|
sendFrame.SetHeaderAcceptLen(0);
|
||||||
header[1] = ((len >> 0) & 0xff);
|
sendFrame.SetHeaderDataLen(0);
|
||||||
header[2] = ((len >> 8) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spi_header_set_data_len(uint8_t *header, uint16_t len)
|
emptyFullAccept.SetHeaderFlagByte(/* aResetFlag */ true);
|
||||||
{
|
emptyFullAccept.SetHeaderAcceptLen(kSpiBufferSize - kSpiHeaderSize);
|
||||||
header[3] = ((len >> 0) & 0xff);
|
emptyFullAccept.SetHeaderDataLen(0);
|
||||||
header[4] = ((len >> 8) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t spi_header_get_flag_byte(const uint8_t *header)
|
emptyZeroAccept.SetHeaderFlagByte(/* aResetFlag */ true);
|
||||||
{
|
emptyZeroAccept.SetHeaderAcceptLen(0);
|
||||||
return header[0];
|
emptyZeroAccept.SetHeaderDataLen(0);
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t spi_header_get_accept_len(const uint8_t *header)
|
|
||||||
{
|
|
||||||
return ( header[1] + static_cast<uint16_t>(header[2] << 8) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t spi_header_get_data_len(const uint8_t *header)
|
|
||||||
{
|
|
||||||
return ( header[3] + static_cast<uint16_t>(header[4] << 8) );
|
|
||||||
}
|
|
||||||
|
|
||||||
NcpSpi::NcpSpi(Instance *aInstance) :
|
|
||||||
NcpBase(aInstance),
|
|
||||||
mTxState(kTxStateIdle),
|
|
||||||
mHandlingRxFrame(false),
|
|
||||||
mResetFlag(true),
|
|
||||||
mPrepareTxFrameTask(*aInstance, &NcpSpi::PrepareTxFrame, this),
|
|
||||||
mSendFrameLen(0)
|
|
||||||
{
|
|
||||||
memset(mSendFrame, 0, kSpiHeaderLength);
|
|
||||||
memset(mEmptySendFrameZeroAccept, 0, kSpiHeaderLength);
|
|
||||||
memset(mEmptySendFrameFullAccept, 0, kSpiHeaderLength);
|
|
||||||
|
|
||||||
mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToTxBuffer, this);
|
mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToTxBuffer, this);
|
||||||
|
|
||||||
spi_header_set_flag_byte(mSendFrame, SPI_RESET_FLAG | SPI_PATTERN_VALUE);
|
|
||||||
spi_header_set_flag_byte(mEmptySendFrameZeroAccept, SPI_RESET_FLAG | SPI_PATTERN_VALUE);
|
|
||||||
spi_header_set_flag_byte(mEmptySendFrameFullAccept, SPI_RESET_FLAG | SPI_PATTERN_VALUE);
|
|
||||||
|
|
||||||
spi_header_set_accept_len(mSendFrame, sizeof(mReceiveFrame) - kSpiHeaderLength);
|
|
||||||
spi_header_set_accept_len(mEmptySendFrameFullAccept, sizeof(mReceiveFrame) - kSpiHeaderLength);
|
|
||||||
spi_header_set_accept_len(mEmptySendFrameZeroAccept, 0);
|
|
||||||
|
|
||||||
otPlatSpiSlaveEnable(&NcpSpi::SpiTransactionComplete, &NcpSpi::SpiTransactionProcess, this);
|
otPlatSpiSlaveEnable(&NcpSpi::SpiTransactionComplete, &NcpSpi::SpiTransactionProcess, this);
|
||||||
|
|
||||||
// We signal an interrupt on this first transaction to
|
// We signal an interrupt on this first transaction to
|
||||||
// make sure that the host processor knows that our
|
// make sure that the host processor knows that our
|
||||||
// reset flag was set.
|
// reset flag was set.
|
||||||
|
|
||||||
otPlatSpiSlavePrepareTransaction(mEmptySendFrameZeroAccept, kSpiHeaderLength, mEmptyReceiveFrame, kSpiHeaderLength,
|
otPlatSpiSlavePrepareTransaction(mEmptySendFrameZeroAccept, kSpiHeaderSize, mEmptyReceiveFrame, kSpiHeaderSize,
|
||||||
true);
|
/* aRequestTras */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NcpSpi::SpiTransactionComplete(void *aContext, uint8_t *aOutputBuf, uint16_t aOutputBufLen, uint8_t *aInputBuf,
|
bool NcpSpi::SpiTransactionComplete(void * aContext,
|
||||||
uint16_t aInputBufLen, uint16_t aTransactionLength)
|
uint8_t *aOutputBuf,
|
||||||
|
uint16_t aOutputLen,
|
||||||
|
uint8_t *aInputBuf,
|
||||||
|
uint16_t aInputLen,
|
||||||
|
uint16_t aTransLen)
|
||||||
{
|
{
|
||||||
return static_cast<NcpSpi *>(aContext)->SpiTransactionComplete(aOutputBuf, aOutputBufLen, aInputBuf, aInputBufLen,
|
NcpSpi *ncp = reinterpret_cast<NcpSpi *>(aContext);
|
||||||
aTransactionLength);
|
|
||||||
|
return ncp->SpiTransactionComplete(aOutputBuf, aOutputLen, aInputBuf, aInputLen, aTransLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NcpSpi::SpiTransactionComplete(uint8_t *aOutputBuf, uint16_t aOutputBufLen, uint8_t *aInputBuf,
|
bool NcpSpi::SpiTransactionComplete(uint8_t *aOutputBuf,
|
||||||
uint16_t aInputBufLen, uint16_t aTransactionLength)
|
uint16_t aOutputLen,
|
||||||
|
uint8_t *aInputBuf,
|
||||||
|
uint16_t aInputLen,
|
||||||
|
uint16_t aTransLen)
|
||||||
{
|
{
|
||||||
// This may be executed from an interrupt context.
|
// This can be executed from an interrupt context, therefore we cannot
|
||||||
// Must return as quickly as possible.
|
// use any of OpenThread APIs here. If further processing is needed,
|
||||||
|
// returned value `shouldProcess` is set to `true` to indicate to
|
||||||
|
// platform SPI slave driver to invoke `SpiTransactionProcess()` callback
|
||||||
|
// which unlike this callback must be called from the same OS context
|
||||||
|
// that OpenThread APIs/callbacks are executed.
|
||||||
|
|
||||||
uint16_t rx_data_len = 0;
|
uint16_t transDataLen;
|
||||||
uint16_t rx_accept_len = 0;
|
bool shouldProcess = false;
|
||||||
uint16_t tx_data_len = 0;
|
SpiFrame outputFrame(aOutputBuf);
|
||||||
uint16_t tx_accept_len = 0;
|
SpiFrame inputFrame(aInputBuf);
|
||||||
bool shouldProcess = false;
|
SpiFrame sendFrame(mSendFrame);
|
||||||
|
|
||||||
// TODO: Check `PATTERN` bits of `HDR` and ignore frame if not set.
|
VerifyOrExit((aTransLen >= kSpiHeaderSize) && (aInputLen >= kSpiHeaderSize) && (aOutputLen >= kSpiHeaderSize));
|
||||||
// Holding off on implementing this so as to not cause immediate
|
VerifyOrExit(inputFrame.IsValid() && outputFrame.IsValid());
|
||||||
// compatibility problems, even though it is required by the spec.
|
|
||||||
|
|
||||||
if (aTransactionLength >= kSpiHeaderLength)
|
transDataLen = aTransLen - kSpiHeaderSize;
|
||||||
|
|
||||||
|
if (!mHandlingRxFrame)
|
||||||
{
|
{
|
||||||
if (aOutputBufLen >= kSpiHeaderLength)
|
uint16_t rxDataLen = inputFrame.GetHeaderDataLen();
|
||||||
{
|
|
||||||
rx_accept_len = spi_header_get_accept_len(aOutputBuf);
|
|
||||||
tx_data_len = spi_header_get_data_len(aOutputBuf);
|
|
||||||
(void)spi_header_get_flag_byte(aOutputBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aInputBufLen >= kSpiHeaderLength)
|
// A new frame is successfully received if input frame
|
||||||
{
|
// indicates that there is data and the "data len" is not
|
||||||
rx_data_len = spi_header_get_data_len(aInputBuf);
|
// larger than than the "accept len" we provided in the
|
||||||
tx_accept_len = spi_header_get_accept_len(aInputBuf);
|
// exchanged output frame.
|
||||||
}
|
|
||||||
|
|
||||||
if (!mHandlingRxFrame &&
|
if ((rxDataLen > 0) && (rxDataLen <= transDataLen) && (rxDataLen <= outputFrame.GetHeaderAcceptLen()))
|
||||||
(rx_data_len > 0) &&
|
|
||||||
(rx_data_len <= aTransactionLength - kSpiHeaderLength) &&
|
|
||||||
(rx_data_len <= rx_accept_len))
|
|
||||||
{
|
{
|
||||||
mHandlingRxFrame = true;
|
mHandlingRxFrame = true;
|
||||||
shouldProcess = true;
|
shouldProcess = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((mTxState == kTxStateSending) &&
|
if (mTxState == kTxStateSending)
|
||||||
(tx_data_len > 0) &&
|
{
|
||||||
(tx_data_len <= aTransactionLength - kSpiHeaderLength) &&
|
uint16_t txDataLen = outputFrame.GetHeaderDataLen();
|
||||||
(tx_data_len <= tx_accept_len))
|
|
||||||
|
// Frame transmission is successful if master indicates
|
||||||
|
// in the input frame that it could accept the frame
|
||||||
|
// length that was exchanged, i.e., the "data len" in
|
||||||
|
// the output frame is smaller than or equal to "accept
|
||||||
|
// len" in the received input frame from master.
|
||||||
|
|
||||||
|
if ((txDataLen > 0) && (txDataLen <= transDataLen) && (txDataLen <= inputFrame.GetHeaderAcceptLen()))
|
||||||
{
|
{
|
||||||
mTxState = kTxStateHandlingSendDone;
|
mTxState = kTxStateHandlingSendDone;
|
||||||
shouldProcess = true;
|
shouldProcess = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mResetFlag && (aTransactionLength > 0) && (aOutputBufLen > 0))
|
exit:
|
||||||
|
// Determine the input and output frames to prepare a new transaction.
|
||||||
|
|
||||||
|
if (mResetFlag && (aTransLen > 0) && (aOutputLen > 0))
|
||||||
{
|
{
|
||||||
// Clear the reset flag.
|
|
||||||
mResetFlag = false;
|
mResetFlag = false;
|
||||||
spi_header_set_flag_byte(mSendFrame, SPI_PATTERN_VALUE);
|
sendFrame.SetHeaderFlagByte(/*aResetFlag */ false);
|
||||||
spi_header_set_flag_byte(mEmptySendFrameZeroAccept, SPI_PATTERN_VALUE);
|
SpiFrame(mEmptySendFrameFullAccept).SetHeaderFlagByte(/*aResetFlag */ false);
|
||||||
spi_header_set_flag_byte(mEmptySendFrameFullAccept, SPI_PATTERN_VALUE);
|
SpiFrame(mEmptySendFrameZeroAccept).SetHeaderFlagByte(/*aResetFlag */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTxState == kTxStateSending)
|
if (mTxState == kTxStateSending)
|
||||||
{
|
{
|
||||||
aOutputBuf = mSendFrame;
|
aOutputBuf = mSendFrame;
|
||||||
aOutputBufLen = mSendFrameLen;
|
aOutputLen = mSendFrameLength;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aOutputBuf = (mHandlingRxFrame) ? mEmptySendFrameZeroAccept : mEmptySendFrameFullAccept;
|
aOutputBuf = mHandlingRxFrame ? mEmptySendFrameZeroAccept : mEmptySendFrameFullAccept;
|
||||||
aOutputBufLen = kSpiHeaderLength;
|
aOutputLen = kSpiHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mHandlingRxFrame)
|
if (mHandlingRxFrame)
|
||||||
{
|
{
|
||||||
aInputBuf = mEmptyReceiveFrame;
|
aInputBuf = mEmptyReceiveFrame;
|
||||||
aInputBufLen = kSpiHeaderLength;
|
aInputLen = kSpiHeaderSize;
|
||||||
spi_header_set_accept_len(mSendFrame, 0);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aInputBuf = mReceiveFrame;
|
aInputBuf = mReceiveFrame;
|
||||||
aInputBufLen = sizeof(mReceiveFrame);
|
aInputLen = kSpiBufferSize;
|
||||||
spi_header_set_accept_len(mSendFrame, sizeof(mReceiveFrame) - kSpiHeaderLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
otPlatSpiSlavePrepareTransaction(aOutputBuf, aOutputBufLen, aInputBuf, aInputBufLen,
|
sendFrame.SetHeaderAcceptLen(aInputLen - kSpiHeaderSize);
|
||||||
(mTxState == kTxStateSending));
|
|
||||||
|
otPlatSpiSlavePrepareTransaction(aOutputBuf, aOutputLen, aInputBuf, aInputLen, (mTxState == kTxStateSending));
|
||||||
|
|
||||||
return shouldProcess;
|
return shouldProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcpSpi::SpiTransactionProcess(void *aContext)
|
void NcpSpi::SpiTransactionProcess(void *aContext)
|
||||||
{
|
{
|
||||||
static_cast<NcpSpi *>(aContext)->SpiTransactionProcess();
|
reinterpret_cast<NcpSpi *>(aContext)->SpiTransactionProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcpSpi::SpiTransactionProcess(void)
|
void NcpSpi::SpiTransactionProcess(void)
|
||||||
@@ -250,8 +230,10 @@ void NcpSpi::SpiTransactionProcess(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcpSpi::HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag aTag,
|
void NcpSpi::HandleFrameAddedToTxBuffer(void * aContext,
|
||||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer)
|
NcpFrameBuffer::FrameTag aTag,
|
||||||
|
NcpFrameBuffer::Priority aPriority,
|
||||||
|
NcpFrameBuffer * aNcpFrameBuffer)
|
||||||
{
|
{
|
||||||
OT_UNUSED_VARIABLE(aNcpFrameBuffer);
|
OT_UNUSED_VARIABLE(aNcpFrameBuffer);
|
||||||
OT_UNUSED_VARIABLE(aTag);
|
OT_UNUSED_VARIABLE(aTag);
|
||||||
@@ -260,11 +242,12 @@ void NcpSpi::HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag
|
|||||||
static_cast<NcpSpi *>(aContext)->mPrepareTxFrameTask.Post();
|
static_cast<NcpSpi *>(aContext)->mPrepareTxFrameTask.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
otError NcpSpi::PrepareNextSpiSendFrame(void)
|
void NcpSpi::PrepareNextSpiSendFrame(void)
|
||||||
{
|
{
|
||||||
otError errorCode = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
uint16_t frameLength;
|
uint16_t frameLength;
|
||||||
uint16_t readLength;
|
uint16_t readLength;
|
||||||
|
SpiFrame sendFrame(mSendFrame);
|
||||||
|
|
||||||
VerifyOrExit(!mTxFrameBuffer.IsEmpty());
|
VerifyOrExit(!mTxFrameBuffer.IsEmpty());
|
||||||
|
|
||||||
@@ -273,38 +256,36 @@ otError NcpSpi::PrepareNextSpiSendFrame(void)
|
|||||||
otPlatWakeHost();
|
otPlatWakeHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOrExit(errorCode = mTxFrameBuffer.OutFrameBegin());
|
SuccessOrExit(error = mTxFrameBuffer.OutFrameBegin());
|
||||||
|
|
||||||
frameLength = mTxFrameBuffer.OutFrameGetLength();
|
frameLength = mTxFrameBuffer.OutFrameGetLength();
|
||||||
assert(frameLength <= sizeof(mSendFrame) - kSpiHeaderLength);
|
assert(frameLength <= kSpiBufferSize - kSpiHeaderSize);
|
||||||
|
|
||||||
spi_header_set_data_len(mSendFrame, frameLength);
|
|
||||||
|
|
||||||
// The "accept length" in `mSendFrame` is already updated based
|
// The "accept length" in `mSendFrame` is already updated based
|
||||||
// on current state of receive. It is changed either from the
|
// on current state of receive. It is changed either from the
|
||||||
// `SpiTransactionComplete()` callback or from `HandleRxFrame()`.
|
// `SpiTransactionComplete()` callback or from `HandleRxFrame()`.
|
||||||
|
|
||||||
readLength = mTxFrameBuffer.OutFrameRead(frameLength, mSendFrame + kSpiHeaderLength);
|
readLength = mTxFrameBuffer.OutFrameRead(frameLength, sendFrame.GetData());
|
||||||
assert(readLength == frameLength);
|
assert(readLength == frameLength);
|
||||||
|
|
||||||
mSendFrameLen = frameLength + kSpiHeaderLength;
|
sendFrame.SetHeaderDataLen(frameLength);
|
||||||
|
mSendFrameLength = frameLength + kSpiHeaderSize;
|
||||||
|
|
||||||
mTxState = kTxStateSending;
|
mTxState = kTxStateSending;
|
||||||
|
|
||||||
// Prepare new transaction by using `mSendFrame` as the output
|
// Prepare new transaction by using `mSendFrame` as the output
|
||||||
// buffer while keeping the input buffer unchanged.
|
// frame while keeping the input frame unchanged.
|
||||||
|
|
||||||
errorCode = otPlatSpiSlavePrepareTransaction(mSendFrame, mSendFrameLen, NULL, 0, true);
|
error = otPlatSpiSlavePrepareTransaction(mSendFrame, mSendFrameLength, NULL, 0, /* aRequestTrans */ true);
|
||||||
|
|
||||||
if (errorCode == OT_ERROR_BUSY)
|
if (error == OT_ERROR_BUSY)
|
||||||
{
|
{
|
||||||
// Being busy is OK. We will get the transaction
|
// Being busy is OK. We will get the transaction set up
|
||||||
// set up properly when the current transaction
|
// properly when the current transaction is completed.
|
||||||
// is completed.
|
error = OT_ERROR_NONE;
|
||||||
errorCode = OT_ERROR_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode != OT_ERROR_NONE)
|
if (error != OT_ERROR_NONE)
|
||||||
{
|
{
|
||||||
mTxState = kTxStateIdle;
|
mTxState = kTxStateIdle;
|
||||||
mPrepareTxFrameTask.Post();
|
mPrepareTxFrameTask.Post();
|
||||||
@@ -314,7 +295,7 @@ otError NcpSpi::PrepareNextSpiSendFrame(void)
|
|||||||
mTxFrameBuffer.OutFrameRemove();
|
mTxFrameBuffer.OutFrameRemove();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return errorCode;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcpSpi::PrepareTxFrame(Tasklet &aTasklet)
|
void NcpSpi::PrepareTxFrame(Tasklet &aTasklet)
|
||||||
@@ -347,8 +328,11 @@ void NcpSpi::PrepareTxFrame(void)
|
|||||||
|
|
||||||
void NcpSpi::HandleRxFrame(void)
|
void NcpSpi::HandleRxFrame(void)
|
||||||
{
|
{
|
||||||
|
SpiFrame recvFrame(mReceiveFrame);
|
||||||
|
SpiFrame sendFrame(mSendFrame);
|
||||||
|
|
||||||
// Pass the received frame to base class to process.
|
// Pass the received frame to base class to process.
|
||||||
HandleReceive(mReceiveFrame + kSpiHeaderLength, spi_header_get_data_len(mReceiveFrame));
|
HandleReceive(recvFrame.GetData(), recvFrame.GetHeaderDataLen());
|
||||||
|
|
||||||
// The order of operations below is important. We should clear
|
// The order of operations below is important. We should clear
|
||||||
// the `mHandlingRxFrame` before checking `mTxState` and possibly
|
// the `mHandlingRxFrame` before checking `mTxState` and possibly
|
||||||
@@ -371,10 +355,10 @@ void NcpSpi::HandleRxFrame(void)
|
|||||||
|
|
||||||
if (mTxState != kTxStateSending)
|
if (mTxState != kTxStateSending)
|
||||||
{
|
{
|
||||||
spi_header_set_accept_len(mSendFrame, sizeof(mReceiveFrame) - kSpiHeaderLength);
|
sendFrame.SetHeaderAcceptLen(kSpiBufferSize - kSpiHeaderSize);
|
||||||
|
|
||||||
otPlatSpiSlavePrepareTransaction(mEmptySendFrameFullAccept, kSpiHeaderLength, mReceiveFrame,
|
otPlatSpiSlavePrepareTransaction(mEmptySendFrameFullAccept, kSpiHeaderSize, mReceiveFrame, kSpiBufferSize,
|
||||||
sizeof(mReceiveFrame), false);
|
/* aRequestTrans */ false);
|
||||||
|
|
||||||
// No need to check the error status. Getting `OT_ERROR_BUSY`
|
// No need to check the error status. Getting `OT_ERROR_BUSY`
|
||||||
// is OK as everything will be set up properly from callback when
|
// is OK as everything will be set up properly from callback when
|
||||||
@@ -382,7 +366,7 @@ void NcpSpi::HandleRxFrame(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ncp
|
} // namespace Ncp
|
||||||
} // namespace ot
|
} // namespace ot
|
||||||
|
|
||||||
#endif // OPENTHREAD_ENABLE_NCP_SPI
|
#endif // OPENTHREAD_ENABLE_NCP_SPI
|
||||||
|
|||||||
+154
-28
@@ -40,6 +40,121 @@
|
|||||||
namespace ot {
|
namespace ot {
|
||||||
namespace Ncp {
|
namespace Ncp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class defines a SPI frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SpiFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kHeaderSize = 5, ///< SPI header size (in bytes).
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor initializes an `SpiFrame` instance.
|
||||||
|
*
|
||||||
|
* @param[in] aBuffer Pointer to buffer containing the frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SpiFrame(uint8_t *aBuffer) : mBuffer(aBuffer) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method gets a pointer to data portion in the SPI frame skipping the header.
|
||||||
|
*
|
||||||
|
* @returns A pointer to data in the SPI frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint8_t *GetData(void) { return mBuffer + kHeaderSize; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method indicates whether or not the frame is valid.
|
||||||
|
*
|
||||||
|
* In a valid frame the flag byte should contain the pattern bits.
|
||||||
|
*
|
||||||
|
* @returns TRUE if the frame is valid, FALSE otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool IsValid(void) const
|
||||||
|
{
|
||||||
|
return ((mBuffer[kIndexFlagByte] & kFlagPatternMask) == kFlagPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the "flag byte" field in the SPI frame header.
|
||||||
|
*
|
||||||
|
* @param[in] aResetFalg The status of reset flag (TRUE to set the flag, FALSE to clear flag).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SetHeaderFlagByte(bool aResetFlag)
|
||||||
|
{
|
||||||
|
mBuffer[kIndexFlagByte] = kFlagPattern | (aResetFlag ? kFlagReset : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the "accept len" field in the SPI frame header.
|
||||||
|
*
|
||||||
|
* "accept len" specifies number of bytes the sender of the SPI frame can receive.
|
||||||
|
*
|
||||||
|
* @param[in] aAcceptLen The accept length in bytes.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SetHeaderAcceptLen(uint16_t aAcceptLen)
|
||||||
|
{
|
||||||
|
Encoding::LittleEndian::WriteUint16(aAcceptLen, mBuffer + kIndexAcceptLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method gets the "accept len" field in the SPI frame header.
|
||||||
|
*
|
||||||
|
* @returns The accept length in bytes.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint16_t GetHeaderAcceptLen(void) const
|
||||||
|
{
|
||||||
|
return Encoding::LittleEndian::ReadUint16(mBuffer + kIndexAcceptLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the "data len" field in the SPI frame header.
|
||||||
|
*
|
||||||
|
* "Data len" specifies number of data bytes in the transmitted SPI frame.
|
||||||
|
*
|
||||||
|
* @param[in] aDataLen The data length in bytes.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SetHeaderDataLen(uint16_t aDataLen)
|
||||||
|
{
|
||||||
|
Encoding::LittleEndian::WriteUint16(aDataLen, mBuffer + kIndexDataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method gets the "data len" field in the SPI frame header.
|
||||||
|
*
|
||||||
|
* @returns The data length in bytes.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint16_t GetHeaderDataLen(void) const
|
||||||
|
{
|
||||||
|
return Encoding::LittleEndian::ReadUint16(mBuffer + kIndexDataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kIndexFlagByte = 0, // flag byte (uint8_t).
|
||||||
|
kIndexAcceptLen = 1, // accept len (uint16_t little-endian encoding).
|
||||||
|
kIndexDataLen = 3, // data len (uint16_t little-endian encoding).
|
||||||
|
|
||||||
|
kFlagReset = (1 << 7), // Flag byte RESET bit.
|
||||||
|
kFlagPattern = 0x02, // Flag byte PATTERN bits.
|
||||||
|
kFlagPatternMask = 0x03, // Flag byte PATTERN mask.
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t *mBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
class NcpSpi : public NcpBase
|
class NcpSpi : public NcpBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -58,55 +173,66 @@ private:
|
|||||||
* SPI tx and rx buffer size (should fit a max length frame + SPI header).
|
* SPI tx and rx buffer size (should fit a max length frame + SPI header).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
kSpiBufferSize = OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE,
|
kSpiBufferSize = OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of SPI header in bytes.
|
* Size of the SPI header (in bytes).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
kSpiHeaderLength = 5,
|
kSpiHeaderSize = SpiFrame::kHeaderSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TxState
|
enum TxState
|
||||||
{
|
{
|
||||||
kTxStateIdle, // No frame to send.
|
kTxStateIdle, // No frame to send.
|
||||||
kTxStateSending, // A frame is ready to be sent.
|
kTxStateSending, // A frame is ready to be sent.
|
||||||
kTxStateHandlingSendDone // The frame was sent successfully, waiting to prepare the next one (if any).
|
kTxStateHandlingSendDone // The frame was sent successfully, waiting to prepare the next one (if any).
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool SpiTransactionComplete(void *aContext, uint8_t *aOutputBuf, uint16_t aOutputBufLen, uint8_t *aInputBuf,
|
typedef uint8_t LargeFrameBuffer[kSpiBufferSize];
|
||||||
uint16_t aInputBufLen, uint16_t aTransactionLength);
|
typedef uint8_t EmptyFrameBuffer[kSpiHeaderSize];
|
||||||
bool SpiTransactionComplete(uint8_t *aOutputBuf, uint16_t aOutputBufLen, uint8_t *aInputBuf, uint16_t aInputBufLen,
|
|
||||||
uint16_t aTransactionLength);
|
static bool SpiTransactionComplete(void * aContext,
|
||||||
|
uint8_t *aOutputBuf,
|
||||||
|
uint16_t aOutputLen,
|
||||||
|
uint8_t *aInputBuf,
|
||||||
|
uint16_t aInputLen,
|
||||||
|
uint16_t aTransLen);
|
||||||
|
bool SpiTransactionComplete(uint8_t *aOutputBuf,
|
||||||
|
uint16_t aOutputLen,
|
||||||
|
uint8_t *aInputBuf,
|
||||||
|
uint16_t aInputLen,
|
||||||
|
uint16_t aTransLen);
|
||||||
|
|
||||||
static void SpiTransactionProcess(void *aContext);
|
static void SpiTransactionProcess(void *aContext);
|
||||||
void SpiTransactionProcess(void);
|
void SpiTransactionProcess(void);
|
||||||
|
|
||||||
static void HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
|
static void HandleFrameAddedToTxBuffer(void * aContext,
|
||||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer);
|
NcpFrameBuffer::FrameTag aFrameTag,
|
||||||
|
NcpFrameBuffer::Priority aPriority,
|
||||||
|
NcpFrameBuffer * aNcpFrameBuffer);
|
||||||
|
|
||||||
static void PrepareTxFrame(Tasklet &aTasklet);
|
static void PrepareTxFrame(Tasklet &aTasklet);
|
||||||
void PrepareTxFrame(void);
|
void PrepareTxFrame(void);
|
||||||
void HandleRxFrame(void);
|
void HandleRxFrame(void);
|
||||||
|
void PrepareNextSpiSendFrame(void);
|
||||||
otError PrepareNextSpiSendFrame(void);
|
|
||||||
|
|
||||||
volatile TxState mTxState;
|
volatile TxState mTxState;
|
||||||
volatile bool mHandlingRxFrame;
|
volatile bool mHandlingRxFrame;
|
||||||
volatile bool mResetFlag;
|
volatile bool mResetFlag;
|
||||||
|
|
||||||
Tasklet mPrepareTxFrameTask;
|
Tasklet mPrepareTxFrameTask;
|
||||||
|
|
||||||
uint16_t mSendFrameLen;
|
uint16_t mSendFrameLength;
|
||||||
uint8_t mSendFrame[kSpiBufferSize];
|
LargeFrameBuffer mSendFrame;
|
||||||
uint8_t mReceiveFrame[kSpiBufferSize];
|
EmptyFrameBuffer mEmptySendFrameFullAccept;
|
||||||
|
EmptyFrameBuffer mEmptySendFrameZeroAccept;
|
||||||
|
|
||||||
uint8_t mEmptySendFrameZeroAccept[kSpiHeaderLength];
|
LargeFrameBuffer mReceiveFrame;
|
||||||
uint8_t mEmptySendFrameFullAccept[kSpiHeaderLength];
|
EmptyFrameBuffer mEmptyReceiveFrame;
|
||||||
uint8_t mEmptyReceiveFrame[kSpiHeaderLength];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ncp
|
} // namespace Ncp
|
||||||
} // namespace ot
|
} // namespace ot
|
||||||
|
|
||||||
#endif // NCP_SPI_HPP_
|
#endif // NCP_SPI_HPP_
|
||||||
|
|||||||
Reference in New Issue
Block a user