mirror of
https://github.com/espressif/openthread.git
synced 2026-08-11 21:27:46 +00:00
[spinel] move the MultiFrameBuffer implementation to multi_frame_buffer.hpp (#9150)
The `MultiFrameBuffer` is not only used by `hdlc.hpp`, it is also used by `spi_interface.hpp` and `radio_spinel.hpp`. This commit moves the `MultiFrameBuffer` implementation from `hdlc.hpp` to `multi_frame_buffer.hpp` as a dependent module.
This commit is contained in:
@@ -34,6 +34,7 @@ target_include_directories(openthread-hdlc
|
||||
PUBLIC
|
||||
${OT_PUBLIC_INCLUDES}
|
||||
PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/src/core
|
||||
)
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ noinst_LIBRARIES = libopenthread-hdlc.a
|
||||
|
||||
libopenthread_hdlc_a_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/core \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ static bool HdlcByteNeedsEscape(uint8_t aByte)
|
||||
return rval;
|
||||
}
|
||||
|
||||
Encoder::Encoder(FrameWritePointer &aWritePointer)
|
||||
Encoder::Encoder(Spinel::FrameWritePointer &aWritePointer)
|
||||
: mWritePointer(aWritePointer)
|
||||
, mFcs(0)
|
||||
{
|
||||
@@ -154,9 +154,9 @@ exit:
|
||||
|
||||
otError Encoder::Encode(const uint8_t *aData, uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t oldFcs = mFcs;
|
||||
FrameWritePointer oldPointer = mWritePointer;
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t oldFcs = mFcs;
|
||||
Spinel::FrameWritePointer oldPointer = mWritePointer;
|
||||
|
||||
while (aLength--)
|
||||
{
|
||||
@@ -176,10 +176,10 @@ exit:
|
||||
|
||||
otError Encoder::EndFrame(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
FrameWritePointer oldPointer = mWritePointer;
|
||||
uint16_t oldFcs = mFcs;
|
||||
uint16_t fcs = mFcs;
|
||||
otError error = OT_ERROR_NONE;
|
||||
Spinel::FrameWritePointer oldPointer = mWritePointer;
|
||||
uint16_t oldFcs = mFcs;
|
||||
uint16_t fcs = mFcs;
|
||||
|
||||
fcs ^= 0xffff;
|
||||
|
||||
@@ -199,7 +199,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Decoder::Decoder(FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext)
|
||||
Decoder::Decoder(Spinel::FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext)
|
||||
: mState(kStateNoSync)
|
||||
, mWritePointer(aFrameWritePointer)
|
||||
, mFrameHandler(aFrameHandler)
|
||||
|
||||
+11
-414
@@ -39,10 +39,7 @@
|
||||
|
||||
#include <openthread/error.h>
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -55,406 +52,6 @@ namespace ot {
|
||||
*/
|
||||
namespace Hdlc {
|
||||
|
||||
/**
|
||||
* Defines a frame write pointer used by `Hdlc::Encoder` or `Hdlc::Decoder`.
|
||||
*
|
||||
* Defines the minimum set of APIs used by `Encoder/Decoder` for writing an encoded/decoded frame. It is
|
||||
* simply a wrapper over a pointer into a buffer indicating where next byte should be written. Along with a write
|
||||
* pointer, this class stores a remaining length variable indicating number of remaining bytes that can be written into
|
||||
* the buffer.
|
||||
*
|
||||
* @note This class does NOT define the underlying buffer space or how it is being managed.
|
||||
*
|
||||
* `Encoder` or `Decoder` users are expected to use sub-classes of this class adding the buffer space and implementing
|
||||
* the frame buffer management scheme.
|
||||
*
|
||||
* Two template sub-class `FrameBuffer` and `MultiFrameBuffer` are defined which respectively allow storing a single
|
||||
* frame or multiple frames (FIFO queue of frame) in a buffer of a given size.
|
||||
*
|
||||
*/
|
||||
class FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Indicates whether there is buffer space available to write @p aWriteLength bytes.
|
||||
*
|
||||
* param[in] aWriteLength Number of bytes to write.
|
||||
*
|
||||
* @retval TRUE Enough buffer space is available to write the requested number of bytes.
|
||||
* @retval FALSE Insufficient buffer space to write the requested number of bytes.
|
||||
*
|
||||
*/
|
||||
bool CanWrite(uint16_t aWriteLength) const { return (mRemainingLength >= aWriteLength); }
|
||||
|
||||
/**
|
||||
* Writes a byte into the buffer and updates the write pointer (if space is available).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully wrote the byte and updated the pointer.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte.
|
||||
*
|
||||
*/
|
||||
otError WriteByte(uint8_t aByte)
|
||||
{
|
||||
return CanWrite(sizeof(uint8_t)) ? (*mWritePointer++ = aByte, mRemainingLength--, OT_ERROR_NONE)
|
||||
: OT_ERROR_NO_BUFS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undoes the last @p aUndoLength writes, removing them from frame.
|
||||
*
|
||||
* @note Caller should ensure that @p aUndoLength is less than or equal to the number of previously written bytes
|
||||
* into the frame. This method does not perform any checks and its behavior is undefined if @p aUndoLength is
|
||||
* larger than the number of bytes previously written into the frame.
|
||||
*
|
||||
* @param[in] aUndoLength Number of bytes to remove (number of last `WriteByte()` calls to undo).
|
||||
*
|
||||
*/
|
||||
void UndoLastWrites(uint16_t aUndoLength)
|
||||
{
|
||||
mWritePointer -= aUndoLength;
|
||||
mRemainingLength += aUndoLength;
|
||||
}
|
||||
|
||||
protected:
|
||||
FrameWritePointer(void)
|
||||
: mWritePointer(nullptr)
|
||||
, mRemainingLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t *mWritePointer; ///< A pointer to current write position in the buffer.
|
||||
uint16_t mRemainingLength; ///< Number of remaining bytes available to write.
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a template frame buffer of a given size for storing a single frame.
|
||||
*
|
||||
* The template parameter `kSize` specifies the size of the buffer.
|
||||
*
|
||||
*/
|
||||
template <uint16_t kSize> class FrameBuffer : public FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the `FrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
FrameBuffer(void)
|
||||
: FrameWritePointer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the buffer, moving the write pointer to the beginning of the buffer.
|
||||
*
|
||||
*/
|
||||
void Clear(void)
|
||||
{
|
||||
mWritePointer = mBuffer;
|
||||
mRemainingLength = sizeof(mBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the buffer is empty or contains a frame.
|
||||
*
|
||||
* @retval TRUE Buffer is empty
|
||||
* @retval FALSE Buffer contains a frame
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return (mWritePointer == mBuffer); }
|
||||
|
||||
/**
|
||||
* Gets the length (number of bytes) in the frame.
|
||||
*
|
||||
* @returns The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); }
|
||||
|
||||
/**
|
||||
* Gets a pointer to start of the frame.
|
||||
*
|
||||
* @returns A pointer to start of the frame.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetFrame(void) { return mBuffer; }
|
||||
|
||||
private:
|
||||
uint8_t mBuffer[kSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a template frame buffer of a given size for storing multiple frames.
|
||||
*
|
||||
* The template parameter `kSize` specifies the total size of the buffer.
|
||||
*
|
||||
* Unlike `FrameBuffer` class where a single frame can be stored, this class is capable of saving multiple frames
|
||||
* in a FIFO queue format.
|
||||
*
|
||||
*/
|
||||
template <uint16_t kSize> class MultiFrameBuffer : public FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the `MultiFrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
MultiFrameBuffer(void)
|
||||
: FrameWritePointer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the buffer, removing current frame and all previously saved frames.
|
||||
*
|
||||
* It moves the write pointer to the beginning of the buffer.
|
||||
*
|
||||
*/
|
||||
void Clear(void)
|
||||
{
|
||||
mWriteFrameStart = mBuffer;
|
||||
mWritePointer = mBuffer + kHeaderSize;
|
||||
mRemainingLength = kSize - kHeaderSize;
|
||||
|
||||
IgnoreError(SetSkipLength(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the current frame (being written) is empty or not.
|
||||
*
|
||||
* @retval TRUE Current frame is empty.
|
||||
* @retval FALSE Current frame is not empty.
|
||||
*
|
||||
*/
|
||||
bool HasFrame(void) const { return (mWritePointer != GetFrame()); }
|
||||
|
||||
/**
|
||||
* 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 <= GetArrayEnd(mBuffer))
|
||||
{
|
||||
mWritePointer = GetFrame() + aLength;
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length (number of bytes) in the current frame being written into the buffer.
|
||||
*
|
||||
* @returns The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); }
|
||||
|
||||
/**
|
||||
* 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 <= GetArrayEnd(mBuffer))
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset);
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the start of the current frame.
|
||||
*
|
||||
* @returns A pointer to the start of the frame.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); }
|
||||
|
||||
/**
|
||||
* 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()); }
|
||||
|
||||
/**
|
||||
* Saves the current frame and prepares the write pointer for a next frame to be written into the
|
||||
* buffer.
|
||||
*
|
||||
* Saved frame can be retrieved later using `GetNextSavedFrame()`.
|
||||
*
|
||||
*/
|
||||
void SaveFrame(void)
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset);
|
||||
mWriteFrameStart = mWritePointer;
|
||||
IgnoreError(SetSkipLength(0));
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the current frame and prepares the write pointer for a next frame to be written into the
|
||||
* buffer.
|
||||
*
|
||||
*/
|
||||
void DiscardFrame(void)
|
||||
{
|
||||
IgnoreError(SetSkipLength(0));
|
||||
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there are any saved frames in the buffer.
|
||||
*
|
||||
* @retval TRUE There is at least one saved frame in the buffer.
|
||||
* @retval FALSE There is no saved frame in the buffer.
|
||||
*
|
||||
*/
|
||||
bool HasSavedFrame(void) const { return (mWriteFrameStart != mBuffer); }
|
||||
|
||||
/**
|
||||
* Iterates through previously saved frames in the buffer, getting a next frame in the queue.
|
||||
*
|
||||
* @param[in,out] aFrame On entry, should point to a previous saved frame or nullptr to get the first frame.
|
||||
* On exit, the pointer variable is updated to next frame or set to nullptr if there are
|
||||
* none.
|
||||
* @param[in,out] 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.
|
||||
*
|
||||
*/
|
||||
otError GetNextSavedFrame(uint8_t *&aFrame, uint16_t &aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
OT_ASSERT(aFrame == nullptr || (mBuffer <= aFrame && aFrame < GetArrayEnd(mBuffer)));
|
||||
|
||||
aFrame = (aFrame == nullptr) ? mBuffer : aFrame + aLength;
|
||||
|
||||
if (aFrame != mWriteFrameStart)
|
||||
{
|
||||
uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset);
|
||||
uint16_t skipLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset);
|
||||
|
||||
aLength = totalLength - skipLength;
|
||||
aFrame += kHeaderSize + skipLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
aLength = 0;
|
||||
aFrame = nullptr;
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all saved frames from the buffer and adjusts all the pointers.
|
||||
*
|
||||
* @note This method moves the pointers into the buffer and also copies the content. Any previously retrieved
|
||||
* pointer to buffer (from `GetFrame()` or `GetNextSavedFrame()`) should be considered invalid after calling this
|
||||
* method.
|
||||
*
|
||||
*/
|
||||
void ClearSavedFrames(void)
|
||||
{
|
||||
uint16_t len = static_cast<uint16_t>(mWriteFrameStart - mBuffer);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
memmove(mBuffer, mWriteFrameStart, static_cast<uint16_t>(mWritePointer - mWriteFrameStart));
|
||||
mWritePointer -= len;
|
||||
mWriteFrameStart -= len;
|
||||
mRemainingLength += len;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* The diagram below illustrates the format of a saved frame.
|
||||
*
|
||||
* +---------+-------------+------------+----------------+----------------------------+
|
||||
* | 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.
|
||||
*
|
||||
* Saved frame #1 Saved frame #2 Current frame being written
|
||||
* / \ / \ / \
|
||||
* +-----------+-------------+-----------+------------+---------+--------------------------------------------+
|
||||
* | header #1 | ... | header #2 | ... | header | ... | ... |
|
||||
* +-----------+-------------+-----------+------------+---------+--------------------------------------------+
|
||||
* ^ ^ ^\ /^
|
||||
* | | | mRemainingLength |
|
||||
* mBuffer[0] mWriteFrameStart | |
|
||||
* | mBuffer[kSize]
|
||||
* mWritePointer
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
kHeaderTotalLengthOffset = 0,
|
||||
kHeaderSkipLengthOffset = sizeof(uint16_t),
|
||||
kHeaderSize = sizeof(uint16_t) + sizeof(uint16_t),
|
||||
};
|
||||
|
||||
uint8_t mBuffer[kSize];
|
||||
uint8_t *mWriteFrameStart; // Pointer to start of current frame being written.
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the HDLC-lite encoder.
|
||||
*
|
||||
@@ -468,7 +65,7 @@ public:
|
||||
* @param[in] aWritePointer The `FrameWritePointer` used by `Encoder` to write the encoded frames.
|
||||
*
|
||||
*/
|
||||
explicit Encoder(FrameWritePointer &aWritePointer);
|
||||
explicit Encoder(Spinel::FrameWritePointer &aWritePointer);
|
||||
|
||||
/**
|
||||
* Begins an HDLC frame.
|
||||
@@ -517,8 +114,8 @@ public:
|
||||
otError EndFrame(void);
|
||||
|
||||
private:
|
||||
FrameWritePointer &mWritePointer;
|
||||
uint16_t mFcs;
|
||||
Spinel::FrameWritePointer &mWritePointer;
|
||||
uint16_t mFcs;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -551,7 +148,7 @@ public:
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
*/
|
||||
Decoder(FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext);
|
||||
Decoder(Spinel::FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* Feeds a block of data into the decoder.
|
||||
@@ -581,12 +178,12 @@ private:
|
||||
kStateEscaped,
|
||||
};
|
||||
|
||||
State mState;
|
||||
FrameWritePointer &mWritePointer;
|
||||
FrameHandler mFrameHandler;
|
||||
void *mContext;
|
||||
uint16_t mFcs;
|
||||
uint16_t mDecodedLength;
|
||||
State mState;
|
||||
Spinel::FrameWritePointer &mWritePointer;
|
||||
FrameHandler mFrameHandler;
|
||||
void *mContext;
|
||||
uint16_t mFcs;
|
||||
uint16_t mDecodedLength;
|
||||
};
|
||||
|
||||
} // namespace Hdlc
|
||||
|
||||
@@ -70,6 +70,7 @@ include_HEADERS = \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
multi_frame_buffer.hpp \
|
||||
radio_spinel.hpp \
|
||||
radio_spinel_impl.hpp \
|
||||
spinel_buffer.hpp \
|
||||
|
||||
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* 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 includes definitions for the multiple frame buffer.
|
||||
*/
|
||||
|
||||
#ifndef SPINEL_MULTI_FRAME_BUFFER_HPP_
|
||||
#define SPINEL_MULTI_FRAME_BUFFER_HPP_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Spinel {
|
||||
|
||||
/**
|
||||
* Defines a frame write pointer.
|
||||
*
|
||||
* Defines the minimum set of APIs used by `Encoder/Decoder` for writing an encoded/decoded frame. It is
|
||||
* simply a wrapper over a pointer into a buffer indicating where next byte should be written. Along with a write
|
||||
* pointer, this class stores a remaining length variable indicating number of remaining bytes that can be written into
|
||||
* the buffer.
|
||||
*
|
||||
* @note This class does NOT define the underlying buffer space or how it is being managed.
|
||||
*
|
||||
* Two template sub-class `FrameBuffer` and `MultiFrameBuffer` are defined which respectively allow storing a single
|
||||
* frame or multiple frames (FIFO queue of frame) in a buffer of a given size.
|
||||
*
|
||||
*/
|
||||
class FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Indicates whether there is buffer space available to write @p aWriteLength bytes.
|
||||
*
|
||||
* param[in] aWriteLength Number of bytes to write.
|
||||
*
|
||||
* @retval TRUE Enough buffer space is available to write the requested number of bytes.
|
||||
* @retval FALSE Insufficient buffer space to write the requested number of bytes.
|
||||
*
|
||||
*/
|
||||
bool CanWrite(uint16_t aWriteLength) const { return (mRemainingLength >= aWriteLength); }
|
||||
|
||||
/**
|
||||
* Writes a byte into the buffer and updates the write pointer (if space is available).
|
||||
*
|
||||
* @param[in] aByte A byte to be written to the buffer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully wrote the byte and updated the pointer.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte.
|
||||
*
|
||||
*/
|
||||
otError WriteByte(uint8_t aByte)
|
||||
{
|
||||
return CanWrite(sizeof(uint8_t)) ? (*mWritePointer++ = aByte, mRemainingLength--, OT_ERROR_NONE)
|
||||
: OT_ERROR_NO_BUFS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undoes the last @p aUndoLength writes, removing them from frame.
|
||||
*
|
||||
* @note Caller should ensure that @p aUndoLength is less than or equal to the number of previously written bytes
|
||||
* into the frame. This method does not perform any checks and its behavior is undefined if @p aUndoLength is
|
||||
* larger than the number of bytes previously written into the frame.
|
||||
*
|
||||
* @param[in] aUndoLength Number of bytes to remove (number of last `WriteByte()` calls to undo).
|
||||
*
|
||||
*/
|
||||
void UndoLastWrites(uint16_t aUndoLength)
|
||||
{
|
||||
mWritePointer -= aUndoLength;
|
||||
mRemainingLength += aUndoLength;
|
||||
}
|
||||
|
||||
protected:
|
||||
FrameWritePointer(void)
|
||||
: mWritePointer(nullptr)
|
||||
, mRemainingLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t *mWritePointer; ///< A pointer to current write position in the buffer.
|
||||
uint16_t mRemainingLength; ///< Number of remaining bytes available to write.
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a template frame buffer of a given size for storing a single frame.
|
||||
*
|
||||
* @tparam kSize The size of the frame buffer.
|
||||
*
|
||||
*/
|
||||
template <uint16_t kSize> class FrameBuffer : public FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the `FrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
FrameBuffer(void)
|
||||
: FrameWritePointer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the buffer, moving the write pointer to the beginning of the buffer.
|
||||
*
|
||||
*/
|
||||
void Clear(void)
|
||||
{
|
||||
mWritePointer = mBuffer;
|
||||
mRemainingLength = sizeof(mBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the buffer is empty or contains a frame.
|
||||
*
|
||||
* @retval TRUE Buffer is empty.
|
||||
* @retval FALSE Buffer contains a frame.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return (mWritePointer == mBuffer); }
|
||||
|
||||
/**
|
||||
* Gets the length (number of bytes) in the frame.
|
||||
*
|
||||
* @returns The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); }
|
||||
|
||||
/**
|
||||
* Gets a pointer to start of the frame.
|
||||
*
|
||||
* @returns A pointer to start of the frame.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetFrame(void) { return mBuffer; }
|
||||
|
||||
private:
|
||||
uint8_t mBuffer[kSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a template frame buffer of a given size for storing multiple frames.
|
||||
*
|
||||
* Unlike `FrameBuffer` class where a single frame can be stored, this class is capable of saving multiple frames
|
||||
* in a FIFO queue format.
|
||||
*
|
||||
* @tparam kSize The total size of the buffer.
|
||||
*
|
||||
*/
|
||||
template <uint16_t kSize> class MultiFrameBuffer : public FrameWritePointer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the `MultiFrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
MultiFrameBuffer(void)
|
||||
: FrameWritePointer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the buffer, removing current frame and all previously saved frames.
|
||||
*
|
||||
* It moves the write pointer to the beginning of the buffer.
|
||||
*
|
||||
*/
|
||||
void Clear(void)
|
||||
{
|
||||
mWriteFrameStart = mBuffer;
|
||||
mWritePointer = mBuffer + kHeaderSize;
|
||||
mRemainingLength = kSize - kHeaderSize;
|
||||
|
||||
IgnoreError(SetSkipLength(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the current frame (being written) is empty or not.
|
||||
*
|
||||
* @retval TRUE Current frame is empty.
|
||||
* @retval FALSE Current frame is not empty.
|
||||
*
|
||||
*/
|
||||
bool HasFrame(void) const { return (mWritePointer != GetFrame()); }
|
||||
|
||||
/**
|
||||
* 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 <= GetArrayEnd(mBuffer))
|
||||
{
|
||||
mWritePointer = GetFrame() + aLength;
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length (number of bytes) in the current frame being written into the buffer.
|
||||
*
|
||||
* @returns The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); }
|
||||
|
||||
/**
|
||||
* 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 <= GetArrayEnd(mBuffer))
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset);
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the start of the current frame.
|
||||
*
|
||||
* @returns A pointer to the start of the frame.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); }
|
||||
|
||||
/**
|
||||
* 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()); }
|
||||
|
||||
/**
|
||||
* Saves the current frame and prepares the write pointer for a next frame to be written into the
|
||||
* buffer.
|
||||
*
|
||||
* Saved frame can be retrieved later using `GetNextSavedFrame()`.
|
||||
*
|
||||
*/
|
||||
void SaveFrame(void)
|
||||
{
|
||||
Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset);
|
||||
mWriteFrameStart = mWritePointer;
|
||||
IgnoreError(SetSkipLength(0));
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the current frame and prepares the write pointer for a next frame to be written into the
|
||||
* buffer.
|
||||
*
|
||||
*/
|
||||
void DiscardFrame(void)
|
||||
{
|
||||
IgnoreError(SetSkipLength(0));
|
||||
|
||||
mWritePointer = GetFrame();
|
||||
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there are any saved frames in the buffer.
|
||||
*
|
||||
* @retval TRUE There is at least one saved frame in the buffer.
|
||||
* @retval FALSE There is no saved frame in the buffer.
|
||||
*
|
||||
*/
|
||||
bool HasSavedFrame(void) const { return (mWriteFrameStart != mBuffer); }
|
||||
|
||||
/**
|
||||
* Iterates through previously saved frames in the buffer, getting a next frame in the queue.
|
||||
*
|
||||
* @param[in,out] aFrame On entry, should point to a previous saved frame or nullptr to get the first frame.
|
||||
* On exit, the pointer variable is updated to next frame or set to nullptr if there are
|
||||
* none.
|
||||
* @param[in,out] 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.
|
||||
*
|
||||
*/
|
||||
otError GetNextSavedFrame(uint8_t *&aFrame, uint16_t &aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
OT_ASSERT(aFrame == nullptr || (mBuffer <= aFrame && aFrame < GetArrayEnd(mBuffer)));
|
||||
|
||||
aFrame = (aFrame == nullptr) ? mBuffer : aFrame + aLength;
|
||||
|
||||
if (aFrame != mWriteFrameStart)
|
||||
{
|
||||
uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset);
|
||||
uint16_t skipLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset);
|
||||
|
||||
aLength = totalLength - skipLength;
|
||||
aFrame += kHeaderSize + skipLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
aLength = 0;
|
||||
aFrame = nullptr;
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all saved frames from the buffer and adjusts all the pointers.
|
||||
*
|
||||
* @note This method moves the pointers into the buffer and also copies the content. Any previously retrieved
|
||||
* pointer to buffer (from `GetFrame()` or `GetNextSavedFrame()`) should be considered invalid after calling this
|
||||
* method.
|
||||
*
|
||||
*/
|
||||
void ClearSavedFrames(void)
|
||||
{
|
||||
uint16_t len = static_cast<uint16_t>(mWriteFrameStart - mBuffer);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
memmove(mBuffer, mWriteFrameStart, static_cast<uint16_t>(mWritePointer - mWriteFrameStart));
|
||||
mWritePointer -= len;
|
||||
mWriteFrameStart -= len;
|
||||
mRemainingLength += len;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* The diagram below illustrates the format of a saved frame.
|
||||
*
|
||||
* +---------+-------------+------------+----------------+----------------------------+
|
||||
* | 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.
|
||||
*
|
||||
* Saved frame #1 Saved frame #2 Current frame being written
|
||||
* / \ / \ / \
|
||||
* +-----------+-------------+-----------+------------+---------+--------------------------------------------+
|
||||
* | header #1 | ... | header #2 | ... | header | ... | ... |
|
||||
* +-----------+-------------+-----------+------------+---------+--------------------------------------------+
|
||||
* ^ ^ ^\ /^
|
||||
* | | | mRemainingLength |
|
||||
* mBuffer[0] mWriteFrameStart | |
|
||||
* | mBuffer[kSize]
|
||||
* mWritePointer
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
kHeaderTotalLengthOffset = 0,
|
||||
kHeaderSkipLengthOffset = sizeof(uint16_t),
|
||||
kHeaderSize = sizeof(uint16_t) + sizeof(uint16_t),
|
||||
};
|
||||
|
||||
uint8_t mBuffer[kSize];
|
||||
uint8_t *mWriteFrameStart; // Pointer to start of current frame being written.
|
||||
};
|
||||
|
||||
} // namespace Spinel
|
||||
} // namespace ot
|
||||
#endif // SPINEL_MULTI_FRAME_BUFFER_HPP_
|
||||
@@ -32,10 +32,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POSIX_APP_SPINEL_INTERFACE_HPP_
|
||||
#define POSIX_APP_SPINEL_INTERFACE_HPP_
|
||||
#ifndef SPINEL_SPINEL_INTERFACE_HPP_
|
||||
#define SPINEL_SPINEL_INTERFACE_HPP_
|
||||
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
#include "lib/spinel/spinel.h"
|
||||
#include "lib/url/url.hpp"
|
||||
|
||||
@@ -53,31 +53,14 @@ public:
|
||||
/**
|
||||
* Defines a receive frame buffer to store received spinel frame(s).
|
||||
*
|
||||
* @note The receive frame buffer is an `Hdlc::MultiFrameBuffer` and therefore it is capable of storing multiple
|
||||
* @note The receive frame buffer is an `Spinel::MultiFrameBuffer` and therefore it is capable of storing multiple
|
||||
* frames in a FIFO queue manner.
|
||||
*
|
||||
*/
|
||||
typedef Hdlc::MultiFrameBuffer<kMaxFrameSize> RxFrameBuffer;
|
||||
typedef MultiFrameBuffer<kMaxFrameSize> RxFrameBuffer;
|
||||
|
||||
typedef void (*ReceiveFrameCallback)(void *aContext);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the frame is the Spinel SPINEL_CMD_RESET frame.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the spinel frame.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval true If the frame is a Spinel SPINEL_CMD_RESET frame.
|
||||
* @retval false If the frame is not a Spinel SPINEL_CMD_RESET frame.
|
||||
*
|
||||
*/
|
||||
static bool IsSpinelResetCommand(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
static constexpr uint8_t kSpinelResetCommand[] = {SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_RESET};
|
||||
return (aLength >= sizeof(kSpinelResetCommand)) &&
|
||||
(memcmp(aFrame, kSpinelResetCommand, sizeof(kSpinelResetCommand)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the interface to the Radio Co-processor (RCP)
|
||||
*
|
||||
@@ -161,8 +144,26 @@ public:
|
||||
*
|
||||
*/
|
||||
virtual ~SpinelInterface() = default;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Indicates whether or not the frame is the Spinel SPINEL_CMD_RESET frame.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the spinel frame.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval true If the frame is a Spinel SPINEL_CMD_RESET frame.
|
||||
* @retval false If the frame is not a Spinel SPINEL_CMD_RESET frame.
|
||||
*
|
||||
*/
|
||||
bool IsSpinelResetCommand(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
static constexpr uint8_t kSpinelResetCommand[] = {SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_RESET};
|
||||
return (aLength >= sizeof(kSpinelResetCommand)) &&
|
||||
(memcmp(aFrame, kSpinelResetCommand, sizeof(kSpinelResetCommand)) == 0);
|
||||
}
|
||||
};
|
||||
} // namespace Spinel
|
||||
} // namespace ot
|
||||
|
||||
#endif // POSIX_APP_SPINEL_INTERFACE_HPP_
|
||||
#endif // SPINEL_SPINEL_INTERFACE_HPP_
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
#include "ncp/ncp_base.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
@@ -128,14 +129,14 @@ private:
|
||||
Spinel::Buffer *aBuffer);
|
||||
otNcpHdlcSendCallback mSendCallback;
|
||||
|
||||
Hdlc::FrameBuffer<kHdlcTxBufferSize> mHdlcBuffer;
|
||||
Hdlc::Encoder mFrameEncoder;
|
||||
Hdlc::Decoder mFrameDecoder;
|
||||
HdlcTxState mState;
|
||||
uint8_t mByte;
|
||||
Hdlc::FrameBuffer<kRxBufferSize> mRxBuffer;
|
||||
bool mHdlcSendImmediate;
|
||||
Tasklet mHdlcSendTask;
|
||||
Spinel::FrameBuffer<kHdlcTxBufferSize> mHdlcBuffer;
|
||||
Hdlc::Encoder mFrameEncoder;
|
||||
Hdlc::Decoder mFrameDecoder;
|
||||
HdlcTxState mState;
|
||||
uint8_t mByte;
|
||||
Spinel::FrameBuffer<kRxBufferSize> mRxBuffer;
|
||||
bool mHdlcSendImmediate;
|
||||
Tasklet mHdlcSendTask;
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
BufferEncrypterReader mTxFrameBufferEncrypterReader;
|
||||
|
||||
@@ -125,14 +125,10 @@
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_UART
|
||||
|
||||
using ot::Spinel::SpinelInterface;
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
void *aCallbackContext,
|
||||
SpinelInterface::RxFrameBuffer &aFrameBuffer)
|
||||
HdlcInterface::HdlcInterface(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer)
|
||||
: mReceiveFrameCallback(aCallback)
|
||||
, mReceiveFrameContext(aCallbackContext)
|
||||
, mReceiveFrameBuffer(aFrameBuffer)
|
||||
@@ -203,9 +199,9 @@ void HdlcInterface::Decode(const uint8_t *aBuffer, uint16_t aLength) { mHdlcDeco
|
||||
|
||||
otError HdlcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Hdlc::FrameBuffer<kMaxFrameSize> encoderBuffer;
|
||||
Hdlc::Encoder hdlcEncoder(encoderBuffer);
|
||||
otError error = OT_ERROR_NONE;
|
||||
Spinel::FrameBuffer<kMaxFrameSize> encoderBuffer;
|
||||
Hdlc::Encoder hdlcEncoder(encoderBuffer);
|
||||
|
||||
SuccessOrExit(error = hdlcEncoder.BeginFrame());
|
||||
SuccessOrExit(error = hdlcEncoder.Encode(aFrame, aLength));
|
||||
@@ -214,7 +210,7 @@ otError HdlcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||
error = Write(encoderBuffer.GetFrame(), encoderBuffer.GetLength());
|
||||
|
||||
exit:
|
||||
if ((error == OT_ERROR_NONE) && ot::Spinel::SpinelInterface::IsSpinelResetCommand(aFrame, aLength))
|
||||
if ((error == OT_ERROR_NONE) && IsSpinelResetCommand(aFrame, aLength))
|
||||
{
|
||||
mHdlcDecoder.Reset();
|
||||
error = ResetConnection();
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "openthread-posix-config.h"
|
||||
#include "platform-posix.h"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
#include "lib/spinel/openthread-spinel-config.h"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
|
||||
@@ -58,9 +59,7 @@ public:
|
||||
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
HdlcInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
void *aCallbackContext,
|
||||
Spinel::SpinelInterface::RxFrameBuffer &aFrameBuffer);
|
||||
HdlcInterface(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
/**
|
||||
* This destructor deinitializes the object.
|
||||
@@ -234,7 +233,6 @@ private:
|
||||
|
||||
enum
|
||||
{
|
||||
kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize,
|
||||
kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||
kResetTimeout = 5000, ///< Maximum wait time in Milliseconds for file to become ready (see `ResetConnection`).
|
||||
kOpenFileDelay = 500, ///< Delay between open file calls, in Milliseconds (see `ResetConnection`).
|
||||
@@ -242,9 +240,9 @@ private:
|
||||
2000, ///< Delay for removing RCP device from host OS after hard reset (see `ResetConnection`).
|
||||
};
|
||||
|
||||
Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback;
|
||||
void *mReceiveFrameContext;
|
||||
Spinel::SpinelInterface::RxFrameBuffer &mReceiveFrameBuffer;
|
||||
ReceiveFrameCallback mReceiveFrameCallback;
|
||||
void *mReceiveFrameContext;
|
||||
RxFrameBuffer &mReceiveFrameBuffer;
|
||||
|
||||
int mSockFd;
|
||||
uint32_t mBaudRate;
|
||||
|
||||
@@ -59,14 +59,10 @@
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
using ot::Spinel::SpinelInterface;
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
void *aCallbackContext,
|
||||
SpinelInterface::RxFrameBuffer &aFrameBuffer)
|
||||
SpiInterface::SpiInterface(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer)
|
||||
: mReceiveFrameCallback(aCallback)
|
||||
, mReceiveFrameContext(aCallbackContext)
|
||||
, mRxFrameBuffer(aFrameBuffer)
|
||||
@@ -805,7 +801,7 @@ otError SpiInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||
|
||||
VerifyOrExit(aLength < (kMaxFrameSize - kSpiFrameHeaderSize), error = OT_ERROR_NO_BUFS);
|
||||
|
||||
if (ot::Spinel::SpinelInterface::IsSpinelResetCommand(aFrame, aLength))
|
||||
if (IsSpinelResetCommand(aFrame, aLength))
|
||||
{
|
||||
ResetStates();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#include "platform-posix.h"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
|
||||
#include <openthread/openthread-system.h>
|
||||
@@ -62,9 +62,7 @@ public:
|
||||
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
|
||||
*
|
||||
*/
|
||||
SpiInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
void *aCallbackContext,
|
||||
Spinel::SpinelInterface::RxFrameBuffer &aFrameBuffer);
|
||||
SpiInterface(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
/**
|
||||
* This destructor deinitializes the object.
|
||||
@@ -206,14 +204,9 @@ private:
|
||||
kSlowRetryTimeoutUs = 33 * kUsecPerMsec,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize,
|
||||
};
|
||||
|
||||
Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback;
|
||||
void *mReceiveFrameContext;
|
||||
Spinel::SpinelInterface::RxFrameBuffer &mRxFrameBuffer;
|
||||
ReceiveFrameCallback mReceiveFrameCallback;
|
||||
void *mReceiveFrameContext;
|
||||
RxFrameBuffer &mRxFrameBuffer;
|
||||
|
||||
int mSpiDevFd;
|
||||
int mResetGpioValueFd;
|
||||
|
||||
+29
-28
@@ -31,6 +31,7 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "lib/spinel/multi_frame_buffer.hpp"
|
||||
|
||||
#include "test_util.h"
|
||||
|
||||
@@ -60,7 +61,7 @@ static const uint8_t sSkipText[] = "Skip text";
|
||||
static const uint8_t sHdlcSpecials[] = {kFlagSequence, kFlagXOn, kFlagXOff,
|
||||
kFlagSequence, kEscapeSequence, kFlagSpecial};
|
||||
|
||||
otError WriteToBuffer(const uint8_t *aText, Hdlc::FrameWritePointer &aWritePointer)
|
||||
otError WriteToBuffer(const uint8_t *aText, Spinel::FrameWritePointer &aWritePointer)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
@@ -75,9 +76,9 @@ exit:
|
||||
|
||||
void TestHdlcFrameBuffer(void)
|
||||
{
|
||||
Hdlc::FrameBuffer<kBufferSize> frameBuffer;
|
||||
Spinel::FrameBuffer<kBufferSize> frameBuffer;
|
||||
|
||||
printf("Testing Hdlc::FrameBuffer");
|
||||
printf("Testing Spinel::FrameBuffer");
|
||||
|
||||
VerifyOrQuit(frameBuffer.IsEmpty(), "after constructor");
|
||||
VerifyOrQuit(frameBuffer.GetLength() == 0, "after constructor");
|
||||
@@ -123,15 +124,15 @@ void TestHdlcFrameBuffer(void)
|
||||
printf(" -- PASS\n");
|
||||
}
|
||||
|
||||
void TestHdlcMultiFrameBuffer(void)
|
||||
void TestSpinelMultiFrameBuffer(void)
|
||||
{
|
||||
Hdlc::MultiFrameBuffer<kBufferSize> frameBuffer;
|
||||
uint8_t *frame = nullptr;
|
||||
uint8_t *newFrame = nullptr;
|
||||
uint16_t length;
|
||||
uint16_t newLength;
|
||||
Spinel::MultiFrameBuffer<kBufferSize> frameBuffer;
|
||||
uint8_t *frame = nullptr;
|
||||
uint8_t *newFrame = nullptr;
|
||||
uint16_t length;
|
||||
uint16_t newLength;
|
||||
|
||||
printf("Testing Hdlc::MultiFrameBuffer");
|
||||
printf("Testing Spinel::MultiFrameBuffer");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Check state after constructor
|
||||
@@ -447,16 +448,16 @@ void ProcessDecodedFrame(void *aContext, otError aError)
|
||||
|
||||
void TestEncoderDecoder(void)
|
||||
{
|
||||
otError error;
|
||||
uint8_t byte;
|
||||
Hdlc::MultiFrameBuffer<kBufferSize> encoderBuffer;
|
||||
Hdlc::MultiFrameBuffer<kBufferSize> decoderBuffer;
|
||||
DecoderContext decoderContext;
|
||||
Hdlc::Encoder encoder(encoderBuffer);
|
||||
Hdlc::Decoder decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
|
||||
uint8_t *frame;
|
||||
uint16_t length;
|
||||
uint8_t badShortFrame[3] = {kFlagSequence, 0xaa, kFlagSequence};
|
||||
otError error;
|
||||
uint8_t byte;
|
||||
Spinel::MultiFrameBuffer<kBufferSize> encoderBuffer;
|
||||
Spinel::MultiFrameBuffer<kBufferSize> decoderBuffer;
|
||||
DecoderContext decoderContext;
|
||||
Hdlc::Encoder encoder(encoderBuffer);
|
||||
Hdlc::Decoder decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
|
||||
uint8_t *frame;
|
||||
uint16_t length;
|
||||
uint8_t badShortFrame[3] = {kFlagSequence, 0xaa, kFlagSequence};
|
||||
|
||||
printf("Testing Hdlc::Encoder and Hdlc::Decoder");
|
||||
|
||||
@@ -595,13 +596,13 @@ uint32_t GetRandom(uint32_t max) { return static_cast<uint32_t>(rand()) % max; }
|
||||
|
||||
void TestFuzzEncoderDecoder(void)
|
||||
{
|
||||
uint16_t length;
|
||||
uint8_t frame[kMaxFrameLength];
|
||||
Hdlc::FrameBuffer<kBufferSize> encoderBuffer;
|
||||
Hdlc::FrameBuffer<kBufferSize> decoderBuffer;
|
||||
DecoderContext decoderContext;
|
||||
Hdlc::Encoder encoder(encoderBuffer);
|
||||
Hdlc::Decoder decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
|
||||
uint16_t length;
|
||||
uint8_t frame[kMaxFrameLength];
|
||||
Spinel::FrameBuffer<kBufferSize> encoderBuffer;
|
||||
Spinel::FrameBuffer<kBufferSize> decoderBuffer;
|
||||
DecoderContext decoderContext;
|
||||
Hdlc::Encoder encoder(encoderBuffer);
|
||||
Hdlc::Decoder decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
|
||||
|
||||
printf("Testing Hdlc::Encoder and Hdlc::Decoder with randomly generated frames");
|
||||
|
||||
@@ -647,7 +648,7 @@ void TestFuzzEncoderDecoder(void)
|
||||
int main(void)
|
||||
{
|
||||
ot::Ncp::TestHdlcFrameBuffer();
|
||||
ot::Ncp::TestHdlcMultiFrameBuffer();
|
||||
ot::Ncp::TestSpinelMultiFrameBuffer();
|
||||
ot::Ncp::TestEncoderDecoder();
|
||||
ot::Ncp::TestFuzzEncoderDecoder();
|
||||
printf("\nAll tests passed.\n");
|
||||
|
||||
Reference in New Issue
Block a user