[spinel] move SpiFrame implementation to spi_frame.hpp (#9151)

The `SpiFrame` is used by `ncp_spi.hpp` and `spi_interface.hpp`. This
commit moves the `SpiFrame` implementation from `ncp_spi.hpp` to
`spi_frame.hpp` as a dependent module.
This commit is contained in:
Zhanglong Xia
2023-06-13 14:39:28 -07:00
committed by GitHub
parent cbc62cda08
commit 4e2ed6476c
7 changed files with 266 additions and 216 deletions
+1
View File
@@ -36,6 +36,7 @@ spinel_sources = [
"openthread-spinel-config.h",
"radio_spinel.hpp",
"radio_spinel_impl.hpp",
"spi_frame.hpp",
"spinel.c",
"spinel_buffer.cpp",
"spinel_buffer.hpp",
+1
View File
@@ -73,6 +73,7 @@ noinst_HEADERS = \
multi_frame_buffer.hpp \
radio_spinel.hpp \
radio_spinel_impl.hpp \
spi_frame.hpp \
spinel_buffer.hpp \
spinel_decoder.hpp \
spinel_encoder.hpp \
+246
View File
@@ -0,0 +1,246 @@
/*
* Copyright (c) 2023, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file contains definitions of the SPI frame.
*/
#ifndef SPINEL_SPI_FRAME_HPP_
#define SPINEL_SPI_FRAME_HPP_
#include <stdint.h>
#include "common/encoding.hpp"
namespace ot {
namespace Spinel {
/*
* SPI Framing Protocol
*
* Each SPI frame starts with a 5-byte frame header:
*
* +---------+-----+----------+----------+
* | Octets: | 1 | 2 | 2 |
* +---------+-----+----------+----------+
* | Fields: | HDR | RECV_LEN | DATA_LEN |
* +---------+-----+----------+----------+
*
* - "HDR": The first byte is the header byte (defined below)
* - "RECV_LEN": The second and third bytes indicate the largest frame
* size that that device is ready to receive. If zero, then the
* other device must not send any data. (Little endian)
* - "DATA_LEN": The fourth and fifth bytes indicate the size of the
* pending data frame to be sent to the other device. If this value
* is equal-to or less-than the number of bytes that the other device
* is willing to receive, then the data of the frame is immediately
* after the header. (Little Endian)
*
* The "HDR" byte is defined as:
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* |RST|CRC|CCF| RESERVED |PATTERN|
* +---+---+---+---+---+---+---+---+
*
* - "RST": This bit is set when that device has been reset since the
* last time `CS` (chip select) was asserted.
* - "CRC": This bit is set when that device supports writing a 16-bit
* CRC at the end of the data. The CRC length is NOT included in
* DATA_LEN.
* - "CCF": "CRC Check Failure". Set if the CRC check on the last
* received frame failed, cleared to zero otherwise. This bit is
* only used if both sides support CRC.
* - "RESERVED": These bits are all reserved for future used. They
* MUST be cleared to zero and MUST be ignored if set.
* - "PATTERN": These bits are set to a fixed value to help distinguish
* valid SPI frames from garbage (by explicitly making "0xFF" and
* "0x00" invalid values). Bit 6 MUST be set to be one and bit 7
* MUST be cleared (0). A frame received that has any other values
* for these bits MUST be dropped.
*
* Prior to a sending or receiving a frame, the master MAY send a
* 5-octet frame with zeros for both the max receive frame size and the
* the contained frame length. This will induce the slave device to
* indicate the length of the frame it wants to send (if any) and
* indicate the largest frame it is capable of receiving at the moment.
* This allows the master to calculate the size of the next transaction.
* Alternatively, if the master has a frame to send it can just go ahead
* and send a frame of that length and determine if the frame was
* accepted by checking that the "RECV_LEN" from the slave frame is
* larger than the frame the master just tried to send. If the
* "RECV_LEN" is smaller then the frame wasn't accepted and will need to
* be transmitted again.
*
* This protocol can be used either unidirectionally or bidirectionally,
* determined by the behavior of the master and the slave.
*
* If the the master notices "PATTERN" is not set correctly, the master
* should consider the transaction to have failed and try again after 10
* milliseconds, retrying up to 200 times. After unsuccessfully trying
* 200 times in a row, the master MAY take appropriate remedial action
* (like a NCP hardware reset, or indicating a communication failure to
* a user interface).
*
* At the end of the data of a frame is an optional 16-bit CRC, support
* for which is indicated by the "CRC" bit of the "HDR" byte being set.
* If these bits are set for both the master and slave frames, then CRC
* checking is enabled on both sides, effectively requiring that frame
* sizes be two bytes longer than would be otherwise required. The CRC
* is calculated using the same mechanism used for the CRC calculation
* in HDLC-Lite (See Appendix A.1.2). When both of the "CRC" bits are
* set, both sides must verify that the "CRC" is valid before accepting
* the frame. If not enough bytes were clocked out for the CRC to be
* read, then the frame must be ignored. If enough bytes were clocked
* out to perform a CRC check, but the CRC check fails, then the frame
* must be rejected and the "CRC_FAIL" bit on the next frame (and ONLY
* the next frame) MUST be set.
*/
/**
* Defines a SPI frame.
*
*/
class SpiFrame
{
public:
enum
{
kHeaderSize = 5, ///< SPI header size (in bytes).
};
/**
* Initializes an `SpiFrame` instance.
*
* @param[in] aBuffer Pointer to buffer containing the frame.
*
*/
explicit SpiFrame(uint8_t *aBuffer)
: mBuffer(aBuffer)
{
}
/**
* 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; }
/**
* 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); }
/**
* Indicates whether or not the "RST" bit is set.
*
* @returns TRUE if the "RST" bit is set, FALSE otherwise.
*
*/
bool IsResetFlagSet(void) const { return ((mBuffer[kIndexFlagByte] & kFlagReset) == kFlagReset); }
/**
* Sets the "flag byte" field in the SPI frame header.
*
* @param[in] aResetFlag The status of reset flag (TRUE to set the flag, FALSE to clear flag).
*
*/
void SetHeaderFlagByte(bool aResetFlag) { mBuffer[kIndexFlagByte] = kFlagPattern | (aResetFlag ? kFlagReset : 0); }
/**
* Gets the "flag byte" field in the SPI frame header.
*
* @returns The flag byte.
*
*/
uint8_t GetHeaderFlagByte(void) const { return mBuffer[kIndexFlagByte]; }
/**
* 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);
}
/**
* 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); }
/**
* 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); }
/**
* 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;
};
} // namespace Spinel
} // namespace ot
#endif // SPINEL_SPI_FRAME_HPP_
+3 -1
View File
@@ -49,7 +49,7 @@
#if OPENTHREAD_CONFIG_DIAG_ENABLE
static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <=
OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE - ot::Ncp::NcpBase::kSpinelCmdHeaderSize -
ot::Ncp::NcpBase::kSpinelPropIdSize - ot::Ncp::SpiFrame::kHeaderSize,
ot::Ncp::NcpBase::kSpinelPropIdSize - ot::Spinel::SpiFrame::kHeaderSize,
"diag output should be smaller than NCP SPI tx buffer");
static_assert(OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE <= OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE,
"diag command line should be smaller than NCP SPI rx buffer");
@@ -58,6 +58,8 @@ static_assert(OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE <= OPENTHREAD_CONFIG_N
namespace ot {
namespace Ncp {
using Spinel::SpiFrame;
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK == 0
static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpSpi), uint64_t);
+2 -202
View File
@@ -35,212 +35,12 @@
#include "openthread-core-config.h"
#include "lib/spinel/spi_frame.hpp"
#include "ncp/ncp_base.hpp"
/*
* SPI Framing Protocol
*
* Each SPI frame starts with a 5-byte frame header:
*
* +---------+-----+----------+----------+
* | Octets: | 1 | 2 | 2 |
* +---------+-----+----------+----------+
* | Fields: | HDR | RECV_LEN | DATA_LEN |
* +---------+-----+----------+----------+
*
* - "HDR": The first byte is the header byte (defined below)
* - "RECV_LEN": The second and third bytes indicate the largest frame
* size that that device is ready to receive. If zero, then the
* other device must not send any data. (Little endian)
* - "DATA_LEN": The fourth and fifth bytes indicate the size of the
* pending data frame to be sent to the other device. If this value
* is equal-to or less-than the number of bytes that the other device
* is willing to receive, then the data of the frame is immediately
* after the header. (Little Endian)
*
* The "HDR" byte is defined as:
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* |RST|CRC|CCF| RESERVED |PATTERN|
* +---+---+---+---+---+---+---+---+
*
* - "RST": This bit is set when that device has been reset since the
* last time `CS` (chip select) was asserted.
* - "CRC": This bit is set when that device supports writing a 16-bit
* CRC at the end of the data. The CRC length is NOT included in
* DATA_LEN.
* - "CCF": "CRC Check Failure". Set if the CRC check on the last
* received frame failed, cleared to zero otherwise. This bit is
* only used if both sides support CRC.
* - "RESERVED": These bits are all reserved for future used. They
* MUST be cleared to zero and MUST be ignored if set.
* - "PATTERN": These bits are set to a fixed value to help distinguish
* valid SPI frames from garbage (by explicitly making "0xFF" and
* "0x00" invalid values). Bit 6 MUST be set to be one and bit 7
* MUST be cleared (0). A frame received that has any other values
* for these bits MUST be dropped.
*
* Prior to a sending or receiving a frame, the master MAY send a
* 5-octet frame with zeros for both the max receive frame size and the
* the contained frame length. This will induce the slave device to
* indicate the length of the frame it wants to send (if any) and
* indicate the largest frame it is capable of receiving at the moment.
* This allows the master to calculate the size of the next transaction.
* Alternatively, if the master has a frame to send it can just go ahead
* and send a frame of that length and determine if the frame was
* accepted by checking that the "RECV_LEN" from the slave frame is
* larger than the frame the master just tried to send. If the
* "RECV_LEN" is smaller then the frame wasn't accepted and will need to
* be transmitted again.
*
* This protocol can be used either unidirectionally or bidirectionally,
* determined by the behavior of the master and the slave.
*
* If the the master notices "PATTERN" is not set correctly, the master
* should consider the transaction to have failed and try again after 10
* milliseconds, retrying up to 200 times. After unsuccessfully trying
* 200 times in a row, the master MAY take appropriate remedial action
* (like a NCP hardware reset, or indicating a communication failure to
* a user interface).
*
* At the end of the data of a frame is an optional 16-bit CRC, support
* for which is indicated by the "CRC" bit of the "HDR" byte being set.
* If these bits are set for both the master and slave frames, then CRC
* checking is enabled on both sides, effectively requiring that frame
* sizes be two bytes longer than would be otherwise required. The CRC
* is calculated using the same mechanism used for the CRC calculation
* in HDLC-Lite (See Appendix A.1.2). When both of the "CRC" bits are
* set, both sides must verify that the "CRC" is valid before accepting
* the frame. If not enough bytes were clocked out for the CRC to be
* read, then the frame must be ignored. If enough bytes were clocked
* out to perform a CRC check, but the CRC check fails, then the frame
* must be rejected and the "CRC_FAIL" bit on the next frame (and ONLY
* the next frame) MUST be set.
*/
namespace ot {
namespace Ncp {
/**
* Defines a SPI frame.
*
*/
class SpiFrame
{
public:
enum
{
kHeaderSize = 5, ///< SPI header size (in bytes).
};
/**
* Initializes an `SpiFrame` instance.
*
* @param[in] aBuffer Pointer to buffer containing the frame.
*
*/
explicit SpiFrame(uint8_t *aBuffer)
: mBuffer(aBuffer)
{
}
/**
* 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; }
/**
* 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); }
/**
* Indicates whether or not the "RST" bit is set.
*
* @returns TRUE if the "RST" bit is set, FALSE otherwise.
*
*/
bool IsResetFlagSet(void) const { return ((mBuffer[kIndexFlagByte] & kFlagReset) == kFlagReset); }
/**
* Sets the "flag byte" field in the SPI frame header.
*
* @param[in] aResetFlag The status of reset flag (TRUE to set the flag, FALSE to clear flag).
*
*/
void SetHeaderFlagByte(bool aResetFlag) { mBuffer[kIndexFlagByte] = kFlagPattern | (aResetFlag ? kFlagReset : 0); }
/**
* Gets the "flag byte" field in the SPI frame header.
*
* @returns The flag byte.
*
*/
uint8_t GetHeaderFlagByte(void) const { return mBuffer[kIndexFlagByte]; }
/**
* 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);
}
/**
* 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); }
/**
* 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); }
/**
* 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
{
public:
@@ -265,7 +65,7 @@ private:
* Size of the SPI header (in bytes).
*
*/
kSpiHeaderSize = SpiFrame::kHeaderSize,
kSpiHeaderSize = Spinel::SpiFrame::kHeaderSize,
};
enum TxState
+11 -11
View File
@@ -402,16 +402,16 @@ otError SpiInterface::DoSpiTransfer(uint8_t *aSpiRxFrameBuffer, uint32_t aTransf
otError SpiInterface::PushPullSpi(void)
{
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;
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;
Spinel::SpiFrame txFrame(mSpiTxFrameBuffer);
uint16_t skipAlignAllowanceLength;
if (mInterfaceMetrics.mTransferredValidFrameCount == 0)
{
@@ -489,7 +489,7 @@ otError SpiInterface::PushPullSpi(void)
spiRxFrame = GetRealRxFrameStart(spiRxFrameBuffer, mSpiAlignAllowance, skipAlignAllowanceLength);
{
Ncp::SpiFrame rxFrame(spiRxFrame);
Spinel::SpiFrame rxFrame(spiRxFrame);
otLogDebgPlat("spi_transfer TX: H:%02X ACCEPT:%" PRIu16 " DATA:%" PRIu16, txFrame.GetHeaderFlagByte(),
txFrame.GetHeaderAcceptLen(), txFrame.GetHeaderDataLen());
+2 -2
View File
@@ -37,13 +37,13 @@
#include "openthread-posix-config.h"
#include "platform-posix.h"
#include "lib/hdlc/hdlc.hpp"
#include "lib/spinel/multi_frame_buffer.hpp"
#include "lib/spinel/spi_frame.hpp"
#include "lib/spinel/spinel_interface.hpp"
#include <openthread/openthread-system.h>
#include "ncp/ncp_spi.hpp"
namespace ot {
namespace Posix {