mirror of
https://github.com/espressif/openthread.git
synced 2026-08-26 04:09:52 +00:00
[posix-host] use MultiFrameBuffer as SPI receive buffer (#4577)
This commit improves MultiFrameBuffer so that MultiFrameBuffer can reserve a space in front of the frame. SPI interface uses MultiFrameBuffer to store received frame directly, which avoids copying data from receive buffer to MultiFrameBuffer.
This commit is contained in:
+103
-15
@@ -216,6 +216,8 @@ public:
|
||||
mWriteFrameStart = mBuffer;
|
||||
mWritePointer = mBuffer + kHeaderSize;
|
||||
mRemainingLength = kSize - kHeaderSize;
|
||||
|
||||
SetSkipLength(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,7 +227,30 @@ public:
|
||||
* @retval FALSE Current frame is not empty.
|
||||
*
|
||||
*/
|
||||
bool HasFrame(void) const { return (mWritePointer != mWriteFrameStart + kHeaderSize); }
|
||||
bool HasFrame(void) const { return (mWritePointer != GetFrame()); }
|
||||
|
||||
/**
|
||||
* This method sets the length (number of bytes) of the current frame being written.
|
||||
*
|
||||
* param[in] aLength The length of current frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the length of the current frame.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to hold a frame of length @p aLength.
|
||||
*
|
||||
*/
|
||||
otError SetLength(uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NO_BUFS;
|
||||
|
||||
if (GetFrame() + aLength <= OT_ARRAY_END(mBuffer))
|
||||
{
|
||||
mWritePointer = GetFrame() + aLength;
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the length (number of bytes) in the current frame being written into the buffer.
|
||||
@@ -233,7 +258,42 @@ public:
|
||||
* @returns The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mWriteFrameStart - kHeaderSize); }
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); }
|
||||
|
||||
/**
|
||||
* This method sets the length (number of bytes) of reserved buffer in front of the current frame being written.
|
||||
*
|
||||
* param[in] aSkipLength The length of reserved buffer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the length of reserved buffer.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to hold a reserved buffer of length @p aLength.
|
||||
*
|
||||
*/
|
||||
otError SetSkipLength(uint16_t aSkipLength)
|
||||
{
|
||||
otError error = OT_ERROR_NO_BUFS;
|
||||
|
||||
if (mWriteFrameStart + kHeaderSize + aSkipLength <= OT_ARRAY_END(mBuffer))
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset);
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the length (number of bytes) of reserved buffer in front of the current frame being written.
|
||||
*
|
||||
* @returns The length (number of bytes) of the reserved buffer.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSkipLength(void) const
|
||||
{
|
||||
return Encoding::LittleEndian::ReadUint16(mWriteFrameStart + kHeaderSkipLengthOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets a pointer to the start of the current frame.
|
||||
@@ -241,7 +301,15 @@ public:
|
||||
* @returns A pointer to the start of the frame.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetFrame(void) { return mWriteFrameStart + kHeaderSize; }
|
||||
uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); }
|
||||
|
||||
/**
|
||||
* This method gets the maximum length of the current frame.
|
||||
*
|
||||
* @returns The maximum length of the current frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetFrameMaxLength(void) const { return static_cast<uint16_t>(mBuffer + kSize - GetFrame()); }
|
||||
|
||||
/**
|
||||
* This method saves the current frame and prepares the write pointer for a next frame to be written into the
|
||||
@@ -252,9 +320,10 @@ public:
|
||||
*/
|
||||
void SaveFrame(void)
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(GetLength(), mWriteFrameStart);
|
||||
Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset);
|
||||
mWriteFrameStart = mWritePointer;
|
||||
mWritePointer += kHeaderSize;
|
||||
SetSkipLength(0);
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
@@ -265,7 +334,9 @@ public:
|
||||
*/
|
||||
void DiscardFrame(void)
|
||||
{
|
||||
mWritePointer = mWriteFrameStart + kHeaderSize;
|
||||
SetSkipLength(0);
|
||||
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
@@ -283,7 +354,8 @@ public:
|
||||
*
|
||||
* @param[inout] aFrame On entry, should point to a previous saved frame or NULL to get the first frame.
|
||||
* On exit, the pointer variable is updated to next frame or set to NULL if there are none.
|
||||
* @param[out] aLength A reference to a variable to return the frame length (number of bytes).
|
||||
* @param[inout] aLength On entry, should be a reference to the frame length of the previous saved frame.
|
||||
* On exit, the reference is updated to the frame length (number of bytes) of next frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Updated @aFrame and @aLength successfully with the next saved frame.
|
||||
* @retval OT_ERROR_NOT_FOUND No more saved frame in the buffer.
|
||||
@@ -295,12 +367,15 @@ public:
|
||||
|
||||
assert(aFrame == NULL || (mBuffer <= aFrame && aFrame < OT_ARRAY_END(mBuffer)));
|
||||
|
||||
aFrame = (aFrame == NULL) ? mBuffer : aFrame + Encoding::LittleEndian::ReadUint16(aFrame - kHeaderSize);
|
||||
aFrame = (aFrame == NULL) ? mBuffer : aFrame + aLength;
|
||||
|
||||
if (aFrame != mWriteFrameStart)
|
||||
{
|
||||
aLength = Encoding::LittleEndian::ReadUint16(aFrame);
|
||||
aFrame += kHeaderSize;
|
||||
uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset);
|
||||
uint16_t skipLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset);
|
||||
|
||||
aLength = totalLength - skipLength;
|
||||
aFrame += kHeaderSize + skipLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -335,11 +410,22 @@ public:
|
||||
|
||||
private:
|
||||
/*
|
||||
* The diagram below illustrates how the frames are saved in the buffer.
|
||||
* The diagram below illustrates the format of a saved frame.
|
||||
*
|
||||
* Each saved frame contains a header which is 2 bytes long and specifies the frame length (the length does not
|
||||
* include the header itself). The frame length is stored in header bytes as a `uint16_t` value using little-endian
|
||||
* encoding.
|
||||
* +---------+-------------+------------+----------------+----------------------------+
|
||||
* | Octets: | 2 | 2 | SkipLength | TotalLength - SkipLength |
|
||||
* +---------+-------------+------------+----------------+----------------------------+
|
||||
* | Fields: | TotalLength | SkipLength | ReservedBuffer | FrameBuffer |
|
||||
* +---------+-------------+------------+----------------+----------------------------+
|
||||
*
|
||||
* - "TotalLength" : The total length of the `ReservedBuffer` and `FrameBuffer`. It is stored in header bytes
|
||||
* as a `uint16_t` value using little-endian encoding.
|
||||
* - "SkipLength" : The length of the `ReservedBuffer`. It is stored in header bytes as a `uint16_t` value
|
||||
* using little-endian encoding.
|
||||
* - "ReservedBuffer": A reserved buffer in front of `FrameBuffer`. User can use it to store extra header, etc.
|
||||
* - "FrameBuffer" : Frame buffer.
|
||||
*
|
||||
* The diagram below illustrates how the frames are saved in the buffer.
|
||||
*
|
||||
* The diagram shows `mBuffer` and different pointers into the buffer. It represents buffer state when there are
|
||||
* two saved frames in the buffer.
|
||||
@@ -358,7 +444,9 @@ private:
|
||||
|
||||
enum
|
||||
{
|
||||
kHeaderSize = sizeof(uint16_t),
|
||||
kHeaderTotalLengthOffset = 0,
|
||||
kHeaderSkipLengthOffset = sizeof(uint16_t),
|
||||
kHeaderSize = sizeof(uint16_t) + sizeof(uint16_t),
|
||||
};
|
||||
|
||||
uint8_t mBuffer[kSize];
|
||||
|
||||
@@ -266,18 +266,20 @@ void SpiInterface::TrigerReset(void)
|
||||
otLogNotePlat("Triggered hardware reset");
|
||||
}
|
||||
|
||||
uint8_t *SpiInterface::GetRealRxFrameStart(void)
|
||||
uint8_t *SpiInterface::GetRealRxFrameStart(uint8_t *aSpiRxFrameBuffer, uint8_t aAlignAllowance, uint16_t &aSkipLength)
|
||||
{
|
||||
uint8_t * ret = mSpiRxFrameBuffer;
|
||||
const uint8_t *end = mSpiRxFrameBuffer + mSpiAlignAllowance;
|
||||
uint8_t * start = aSpiRxFrameBuffer;
|
||||
const uint8_t *end = aSpiRxFrameBuffer + aAlignAllowance;
|
||||
|
||||
for (; ret != end && ret[0] == 0xff; ret++)
|
||||
for (; start != end && start[0] == 0xff; start++)
|
||||
;
|
||||
|
||||
return ret;
|
||||
aSkipLength = static_cast<uint16_t>(start - aSpiRxFrameBuffer);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
otError SpiInterface::DoSpiTransfer(uint32_t aLength)
|
||||
otError SpiInterface::DoSpiTransfer(uint8_t *aSpiRxFrameBuffer, uint32_t aTransferLength)
|
||||
{
|
||||
int ret;
|
||||
struct spi_ioc_transfer transfer[2];
|
||||
@@ -296,8 +298,8 @@ otError SpiInterface::DoSpiTransfer(uint32_t aLength)
|
||||
|
||||
// This part is the actual SPI transfer.
|
||||
transfer[1].tx_buf = reinterpret_cast<uintptr_t>(mSpiTxFrameBuffer);
|
||||
transfer[1].rx_buf = reinterpret_cast<uintptr_t>(mSpiRxFrameBuffer);
|
||||
transfer[1].len = aLength + kSpiFrameHeaderSize + mSpiAlignAllowance;
|
||||
transfer[1].rx_buf = reinterpret_cast<uintptr_t>(aSpiRxFrameBuffer);
|
||||
transfer[1].len = aTransferLength;
|
||||
transfer[1].speed_hz = mSpiSpeedHz;
|
||||
transfer[1].delay_usecs = 0;
|
||||
transfer[1].bits_per_word = kSpiBitsPerWord;
|
||||
@@ -317,7 +319,7 @@ otError SpiInterface::DoSpiTransfer(uint32_t aLength)
|
||||
if (ret != -1)
|
||||
{
|
||||
otDumpDebg(OT_LOG_REGION_PLATFORM, "SPI-TX", mSpiTxFrameBuffer, transfer[1].len);
|
||||
otDumpDebg(OT_LOG_REGION_PLATFORM, "SPI-RX", mSpiRxFrameBuffer, transfer[1].len);
|
||||
otDumpDebg(OT_LOG_REGION_PLATFORM, "SPI-RX", aSpiRxFrameBuffer, transfer[1].len);
|
||||
|
||||
mSpiFrameCount++;
|
||||
}
|
||||
@@ -327,13 +329,16 @@ otError SpiInterface::DoSpiTransfer(uint32_t aLength)
|
||||
|
||||
otError SpiInterface::PushPullSpi(void)
|
||||
{
|
||||
otError error;
|
||||
uint8_t * spiRxFrameBuffer = NULL;
|
||||
otError error = OT_ERROR_FAILED;
|
||||
uint16_t spiTransferBytes = 0;
|
||||
uint8_t successfulExchanges = 0;
|
||||
bool discardRxFrame = true;
|
||||
uint8_t * spiRxFrameBuffer;
|
||||
uint8_t * spiRxFrame;
|
||||
uint8_t slaveHeader;
|
||||
uint16_t slaveAcceptLen;
|
||||
Ncp::SpiFrame txFrame(mSpiTxFrameBuffer);
|
||||
uint16_t skipAlignAllowanceLength;
|
||||
|
||||
if (mSpiValidFrameCount == 0)
|
||||
{
|
||||
@@ -387,8 +392,20 @@ otError SpiInterface::PushPullSpi(void)
|
||||
|
||||
txFrame.SetHeaderAcceptLen(spiTransferBytes);
|
||||
|
||||
// Set skip length to make MultiFrameBuffer to reserve a space in front of the frame buffer.
|
||||
SuccessOrExit(error = mRxFrameBuffer.SetSkipLength(kSpiFrameHeaderSize));
|
||||
|
||||
// Check whether the remaining frame buffer has enough space to store the data to be received.
|
||||
VerifyOrExit(mRxFrameBuffer.GetFrameMaxLength() >= spiTransferBytes + mSpiAlignAllowance);
|
||||
|
||||
// Point to the start of the reserved buffer.
|
||||
spiRxFrameBuffer = mRxFrameBuffer.GetFrame() - kSpiFrameHeaderSize;
|
||||
|
||||
// Set the total number of bytes to be transmitted.
|
||||
spiTransferBytes += kSpiFrameHeaderSize + mSpiAlignAllowance;
|
||||
|
||||
// Perform the SPI transaction.
|
||||
error = DoSpiTransfer(spiTransferBytes);
|
||||
error = DoSpiTransfer(spiRxFrameBuffer, spiTransferBytes);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
@@ -405,10 +422,10 @@ otError SpiInterface::PushPullSpi(void)
|
||||
}
|
||||
|
||||
// Account for misalignment (0xFF bytes at the start)
|
||||
spiRxFrameBuffer = GetRealRxFrameStart();
|
||||
spiRxFrame = GetRealRxFrameStart(spiRxFrameBuffer, mSpiAlignAllowance, skipAlignAllowanceLength);
|
||||
|
||||
{
|
||||
Ncp::SpiFrame rxFrame(spiRxFrameBuffer);
|
||||
Ncp::SpiFrame rxFrame(spiRxFrame);
|
||||
|
||||
otLogDebgPlat("spi_transfer TX: H:%02X ACCEPT:%" PRIu16 " DATA:%" PRIu16, txFrame.GetHeaderFlagByte(),
|
||||
txFrame.GetHeaderAcceptLen(), txFrame.GetHeaderDataLen());
|
||||
@@ -418,8 +435,8 @@ otError SpiInterface::PushPullSpi(void)
|
||||
slaveHeader = rxFrame.GetHeaderFlagByte();
|
||||
if ((slaveHeader == 0xFF) || (slaveHeader == 0x00))
|
||||
{
|
||||
if ((slaveHeader == spiRxFrameBuffer[1]) && (slaveHeader == spiRxFrameBuffer[2]) &&
|
||||
(slaveHeader == spiRxFrameBuffer[3]) && (slaveHeader == spiRxFrameBuffer[4]))
|
||||
if ((slaveHeader == spiRxFrame[1]) && (slaveHeader == spiRxFrame[2]) && (slaveHeader == spiRxFrame[3]) &&
|
||||
(slaveHeader == spiRxFrame[4]))
|
||||
{
|
||||
// Device is off or in a bad state. In some cases may be induced by flow control.
|
||||
if (mSpiSlaveDataLen == 0)
|
||||
@@ -438,12 +455,10 @@ otError SpiInterface::PushPullSpi(void)
|
||||
// Header is full of garbage
|
||||
mSpiGarbageFrameCount++;
|
||||
|
||||
otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrameBuffer[0], spiRxFrameBuffer[1],
|
||||
spiRxFrameBuffer[2], spiRxFrameBuffer[3], spiRxFrameBuffer[4]);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-TX", mSpiTxFrameBuffer,
|
||||
spiTransferBytes + kSpiFrameHeaderSize + mSpiAlignAllowance);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-RX", mSpiRxFrameBuffer,
|
||||
spiTransferBytes + kSpiFrameHeaderSize + mSpiAlignAllowance);
|
||||
otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrame[0], spiRxFrame[1],
|
||||
spiRxFrame[2], spiRxFrame[3], spiRxFrame[4]);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-TX", mSpiTxFrameBuffer, spiTransferBytes);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-RX", spiRxFrameBuffer, spiTransferBytes);
|
||||
}
|
||||
|
||||
mSpiTxRefusedCount++;
|
||||
@@ -459,12 +474,10 @@ otError SpiInterface::PushPullSpi(void)
|
||||
mSpiTxRefusedCount++;
|
||||
mSpiSlaveDataLen = 0;
|
||||
|
||||
otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrameBuffer[0], spiRxFrameBuffer[1],
|
||||
spiRxFrameBuffer[2], spiRxFrameBuffer[3], spiRxFrameBuffer[4]);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-TX", mSpiTxFrameBuffer,
|
||||
spiTransferBytes + kSpiFrameHeaderSize + mSpiAlignAllowance);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-RX", mSpiRxFrameBuffer,
|
||||
spiTransferBytes + kSpiFrameHeaderSize + mSpiAlignAllowance);
|
||||
otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrame[0], spiRxFrame[1], spiRxFrame[2],
|
||||
spiRxFrame[3], spiRxFrame[4]);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-TX", mSpiTxFrameBuffer, spiTransferBytes);
|
||||
otDumpWarn(OT_LOG_REGION_PLATFORM, "SPI-RX", spiRxFrameBuffer, spiTransferBytes);
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
@@ -487,7 +500,15 @@ otError SpiInterface::PushPullSpi(void)
|
||||
mSpiRxFrameCount++;
|
||||
successfulExchanges++;
|
||||
|
||||
HandleReceivedFrame(rxFrame);
|
||||
// Set the skip length to skip align bytes and SPI frame header.
|
||||
SuccessOrExit(error = mRxFrameBuffer.SetSkipLength(skipAlignAllowanceLength + kSpiFrameHeaderSize));
|
||||
// Set the received frame length.
|
||||
SuccessOrExit(error = mRxFrameBuffer.SetLength(rxFrame.GetHeaderDataLen()));
|
||||
|
||||
// Upper layer will free the frame buffer.
|
||||
discardRxFrame = false;
|
||||
|
||||
mCallbacks.HandleReceivedFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +547,11 @@ otError SpiInterface::PushPullSpi(void)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (discardRxFrame)
|
||||
{
|
||||
mRxFrameBuffer.DiscardFrame();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -737,26 +763,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void SpiInterface::HandleReceivedFrame(Ncp::SpiFrame &aSpiFrame)
|
||||
{
|
||||
const uint8_t *spinelFrame = aSpiFrame.GetData();
|
||||
|
||||
for (uint16_t i = 0; i < aSpiFrame.GetHeaderDataLen(); i++)
|
||||
{
|
||||
if (mRxFrameBuffer.WriteByte(spinelFrame[i]) != OT_ERROR_NONE)
|
||||
{
|
||||
mRxFrameBuffer.DiscardFrame();
|
||||
otLogNotePlat("No enough memory buffers, drop packet");
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
mCallbacks.HandleReceivedFrame();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SpiInterface::LogError(const char *aString)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aString);
|
||||
|
||||
@@ -146,12 +146,11 @@ private:
|
||||
void InitSpiDev(const char *aPath, uint8_t aMode, uint32_t aSpeed);
|
||||
void TrigerReset(void);
|
||||
|
||||
uint8_t *GetRealRxFrameStart(void);
|
||||
otError DoSpiTransfer(uint32_t aLength);
|
||||
uint8_t *GetRealRxFrameStart(uint8_t *aSpiRxFrameBuffer, uint8_t aAlignAllowance, uint16_t &aSkipLength);
|
||||
otError DoSpiTransfer(uint8_t *aSpiRxFrameBuffer, uint32_t aTransferLength);
|
||||
otError PushPullSpi(void);
|
||||
|
||||
bool CheckInterrupt(void);
|
||||
void HandleReceivedFrame(Ncp::SpiFrame &aSpiFrame);
|
||||
void LogStats(void);
|
||||
void LogError(const char *aString);
|
||||
void LogBuffer(const char *aDesc, const uint8_t *aBuffer, uint16_t aLength, bool aForce);
|
||||
@@ -212,8 +211,6 @@ private:
|
||||
uint64_t mSpiTxFrameCount;
|
||||
uint64_t mSpiTxFrameByteCount;
|
||||
|
||||
uint8_t mSpiRxFrameBuffer[kMaxFrameSize + kSpiAlignAllowanceMax];
|
||||
|
||||
bool mSpiTxIsReady;
|
||||
uint16_t mSpiTxRefusedCount;
|
||||
uint16_t mSpiTxPayloadSize;
|
||||
|
||||
+109
-6
@@ -42,6 +42,7 @@ enum
|
||||
kBufferSize = 1500, // Frame buffer size
|
||||
kMaxFrameLength = 500, // Maximum allowed frame length (used when randomly generating frames)
|
||||
kFuzzTestIteration = 50000, // Number of iteration during fuzz test (randomly generating frames)
|
||||
kFrameHeaderSize = 4, // Frame header size
|
||||
|
||||
kFlagXOn = 0x11,
|
||||
kFlagXOff = 0x13,
|
||||
@@ -55,6 +56,7 @@ static const uint8_t sOpenThreadText[] = "OpenThread Rocks";
|
||||
static const uint8_t sHelloText[] = "Hello there!";
|
||||
static const uint8_t sMottoText[] = "Think good thoughts, say good words, do good deeds!";
|
||||
static const uint8_t sHexText[] = "0123456789abcdef";
|
||||
static const uint8_t sSkipText[] = "Skip text";
|
||||
static const uint8_t sHdlcSpecials[] = {kFlagSequence, kFlagXOn, kFlagXOff,
|
||||
kFlagSequence, kEscapeSequence, kFlagSpecial};
|
||||
|
||||
@@ -130,6 +132,7 @@ void TestHdlcMultiFrameBuffer(void)
|
||||
uint8_t * frame = NULL;
|
||||
uint8_t * newFrame = NULL;
|
||||
uint16_t length;
|
||||
uint16_t newLength;
|
||||
|
||||
printf("Testing Hdlc::MultiFrameBuffer");
|
||||
|
||||
@@ -221,8 +224,9 @@ void TestHdlcMultiFrameBuffer(void)
|
||||
VerifyOrQuit(length == sizeof(sHexText) - 1, "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sHexText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
|
||||
newFrame = frame;
|
||||
VerifyOrQuit(frameBuffer.GetNextSavedFrame(newFrame, length) == OT_ERROR_NOT_FOUND,
|
||||
newFrame = frame;
|
||||
newLength = length;
|
||||
VerifyOrQuit(frameBuffer.GetNextSavedFrame(newFrame, newLength) == OT_ERROR_NOT_FOUND,
|
||||
"GetNextSavedFrame() incorrect behavior after all frames were read");
|
||||
VerifyOrQuit(newFrame == NULL, "GetNextSavedFrame() incorrect behavior after all frames were read");
|
||||
|
||||
@@ -286,8 +290,10 @@ void TestHdlcMultiFrameBuffer(void)
|
||||
|
||||
VerifyOrQuit(!frameBuffer.HasFrame(), "HasFrame() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(!frameBuffer.HasSavedFrame(), "HasFrame() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - 1) == false, "CanWrite() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - 2) == true, "CanWrite() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - (kFrameHeaderSize - 1)) == false,
|
||||
"CanWrite() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - kFrameHeaderSize) == true,
|
||||
"CanWrite() incorrect behavior after Clear()");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Verify behavior of `ClearSavedFrames()`
|
||||
@@ -333,9 +339,9 @@ void TestHdlcMultiFrameBuffer(void)
|
||||
|
||||
VerifyOrQuit(!frameBuffer.HasFrame(), "HasFrame() incorrect behavior after all frames are read and discarded");
|
||||
VerifyOrQuit(!frameBuffer.HasSavedFrame(), "HasFrame() incorrect behavior after all read or discarded");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - 1) == false,
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - (kFrameHeaderSize - 1)) == false,
|
||||
"CanWrite() incorrect behavior after all read or discarded");
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - 2) == true,
|
||||
VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - kFrameHeaderSize) == true,
|
||||
"CanWrite() incorrect behavior after all read of discarded");
|
||||
|
||||
SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer), "WriteByte() failed");
|
||||
@@ -352,6 +358,103 @@ void TestHdlcMultiFrameBuffer(void)
|
||||
VerifyOrQuit(length == sizeof(sHelloText) - 1, "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Verify behavior of `SetSkipLength()` and `GetSkipLength()`
|
||||
|
||||
frameBuffer.Clear();
|
||||
|
||||
VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "GetSkipLength() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.SetSkipLength(sizeof(sSkipText)) == OT_ERROR_NONE, "SetSkipLength() failed");
|
||||
SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer), "WriteByte() failed");
|
||||
VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0,
|
||||
"GetFrame() content is incorrect");
|
||||
memcpy(frameBuffer.GetFrame() - sizeof(sSkipText), sSkipText, sizeof(sSkipText));
|
||||
VerifyOrQuit(frameBuffer.GetSkipLength() == sizeof(sSkipText), "GetSkipLength() failed");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText) - 1, "GetLength() failed");
|
||||
VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0,
|
||||
"GetFrame() content is incorrect");
|
||||
|
||||
frameBuffer.SaveFrame();
|
||||
VerifyOrQuit(!frameBuffer.HasFrame(), "HasFrame() incorrect behavior after SaveFrame()");
|
||||
VerifyOrQuit(frameBuffer.HasSavedFrame(), "HasFrame() incorrect behavior after SaveFrame()");
|
||||
VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "GetSkipLength() incorrect behavior after SaveFrame()");
|
||||
|
||||
VerifyOrQuit(frameBuffer.SetSkipLength(sizeof(sSkipText)) == OT_ERROR_NONE, "SetSkipLength() failed");
|
||||
SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer), "WriteByte() failed");
|
||||
VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0,
|
||||
"GetFrame() content is incorrect");
|
||||
memcpy(frameBuffer.GetFrame() - sizeof(sSkipText), sSkipText, sizeof(sSkipText));
|
||||
VerifyOrQuit(frameBuffer.GetSkipLength() == sizeof(sSkipText), "GetSkipLength() failed");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1, "GetLength() failed");
|
||||
VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0,
|
||||
"GetFrame() content is incorrect");
|
||||
|
||||
frameBuffer.SaveFrame();
|
||||
VerifyOrQuit(!frameBuffer.HasFrame(), "HasFrame() incorrect behavior after SaveFrame()");
|
||||
VerifyOrQuit(frameBuffer.HasSavedFrame(), "HasFrame() incorrect behavior after SaveFrame()");
|
||||
VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "GetSkipLength() incorrect behavior after SaveFrame()");
|
||||
|
||||
frame = NULL;
|
||||
SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length), "GetNextSavedFrame() failed unexpectedly");
|
||||
VerifyOrQuit(length == sizeof(sMottoText) - 1, "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
VerifyOrQuit(memcmp(frame - sizeof(sSkipText), sSkipText, sizeof(sSkipText)) == 0,
|
||||
"GetNextSavedFrame() reserved frame buffer content is incorrect");
|
||||
|
||||
SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length), "GetNextSavedFrame() failed unexpectedly");
|
||||
VerifyOrQuit(length == sizeof(sOpenThreadText) - 1, "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sOpenThreadText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
VerifyOrQuit(memcmp(frame - sizeof(sSkipText), sSkipText, sizeof(sSkipText)) == 0,
|
||||
"GetNextSavedFrame() reserved frame buffer content is incorrect");
|
||||
|
||||
frameBuffer.Clear();
|
||||
VerifyOrQuit(frameBuffer.SetSkipLength(kBufferSize - (kFrameHeaderSize - 1)) == OT_ERROR_NO_BUFS,
|
||||
"SetSkipLength() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.SetSkipLength(kBufferSize - kFrameHeaderSize) == OT_ERROR_NONE,
|
||||
"SetSkipLength() incorrect behavior after Clear()");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Verify behavior of `SetLength()` and `GetLength()`
|
||||
|
||||
frameBuffer.Clear();
|
||||
VerifyOrQuit((frame = frameBuffer.GetFrame()) != NULL, "GetFrame() failed");
|
||||
memcpy(frame, sHelloText, sizeof(sHelloText));
|
||||
VerifyOrQuit(frameBuffer.SetLength(sizeof(sHelloText)) == OT_ERROR_NONE, "SetLength() failed");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHelloText), "GetLength() failed");
|
||||
VerifyOrQuit(frameBuffer.HasFrame(), "HasFrame() is incorrect");
|
||||
frameBuffer.SaveFrame();
|
||||
|
||||
VerifyOrQuit((frame = frameBuffer.GetFrame()) != NULL, "GetFrame() failed");
|
||||
memcpy(frame, sMottoText, sizeof(sMottoText));
|
||||
VerifyOrQuit(frameBuffer.SetLength(sizeof(sMottoText)) == OT_ERROR_NONE, "SetLength() failed");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText), "GetLength() failed");
|
||||
VerifyOrQuit(frameBuffer.HasFrame(), "HasFrame() is incorrect");
|
||||
frameBuffer.SaveFrame();
|
||||
|
||||
VerifyOrQuit((frame = frameBuffer.GetFrame()) != NULL, "GetFrame() failed");
|
||||
memcpy(frame, sHexText, sizeof(sHexText));
|
||||
VerifyOrQuit(frameBuffer.SetLength(sizeof(sHexText)) == OT_ERROR_NONE, "SetLength() failed");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHexText), "GetLength() failed");
|
||||
frameBuffer.DiscardFrame();
|
||||
VerifyOrQuit(!frameBuffer.HasFrame(), "HasFrame() is incorrect");
|
||||
|
||||
frame = NULL;
|
||||
SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length), "GetNextSavedFrame() failed unexpectedly");
|
||||
VerifyOrQuit(length == sizeof(sHelloText), "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
|
||||
SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length), "GetNextSavedFrame() failed unexpectedly");
|
||||
VerifyOrQuit(length == sizeof(sMottoText), "GetNextSavedFrame() length is incorrect");
|
||||
VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
|
||||
|
||||
SuccessOrQuit(!frameBuffer.GetNextSavedFrame(frame, length), "GetNextSavedFrame() failed unexpectedly");
|
||||
|
||||
frameBuffer.Clear();
|
||||
VerifyOrQuit(frameBuffer.SetLength(kBufferSize - (kFrameHeaderSize - 1)) == OT_ERROR_NO_BUFS,
|
||||
"SetLength() incorrect behavior after Clear()");
|
||||
VerifyOrQuit(frameBuffer.SetLength(kBufferSize - kFrameHeaderSize) == OT_ERROR_NONE,
|
||||
"SetLength() incorrect behavior after Clear()");
|
||||
|
||||
printf(" -- PASS\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user