mirror of
https://github.com/espressif/openthread.git
synced 2026-09-12 20:20:04 +00:00
[posix-app] adopt new HDLC buffer models (#3371)
This commit updates the `HdlcInterface` and `RadioSpinel` to use the new HDLC buffer model. In particular, for received spinel frames the decoder uses an `Hdlc::MultiFrameBuffer` which is capable of storing multiple frames in a FIFO queue manner. With this model, the received and decoded spinel frames are directly placed in the FIFO buffer. This allows `RadioSpinel` code during `WaitResponse()` (when waiting for specific Spinel response frame) to simply save/keep a notification frame in the queue buffer (without requiring to copy the frame) so that it can read and process the saved frame later. If a received frame can be processed at the time, the frame is then simply discarded from the queue buffer.
This commit is contained in:
committed by
Jonathan Hui
parent
e96cc1b367
commit
34004c2c57
@@ -205,7 +205,6 @@ LOCAL_SRC_FILES := \
|
||||
src/ncp/spinel_decoder.cpp \
|
||||
src/ncp/spinel_encoder.cpp \
|
||||
src/posix/platform/alarm.c \
|
||||
src/posix/platform/frame_queue.cpp \
|
||||
src/posix/platform/hdlc_interface.cpp \
|
||||
src/posix/platform/logging.c \
|
||||
src/posix/platform/misc.c \
|
||||
|
||||
@@ -41,7 +41,6 @@ libopenthread_posix_a_CPPFLAGS = \
|
||||
|
||||
libopenthread_posix_a_SOURCES = \
|
||||
alarm.c \
|
||||
frame_queue.cpp \
|
||||
hdlc_interface.cpp \
|
||||
logging.c \
|
||||
misc.c \
|
||||
@@ -73,7 +72,6 @@ libopenthread_posix_a_SOURCES += \
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
frame_queue.hpp \
|
||||
openthread-system.h \
|
||||
platform-posix.h \
|
||||
hdlc_interface.hpp \
|
||||
@@ -89,17 +87,7 @@ if OPENTHREAD_BUILD_COVERAGE
|
||||
CLEANFILES = $(wildcard *.gcda *.gcno)
|
||||
endif # OPENTHREAD_BUILD_COVERAGE
|
||||
|
||||
check_PROGRAMS = test-frame-queue test-settings
|
||||
|
||||
test_frame_queue_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src/core \
|
||||
-DSELF_TEST \
|
||||
$(NULL)
|
||||
|
||||
test_frame_queue_SOURCES = \
|
||||
frame_queue.cpp \
|
||||
$(NULL)
|
||||
check_PROGRAMS = test-settings
|
||||
|
||||
test_settings_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
@@ -112,7 +100,6 @@ test_settings_SOURCES = \
|
||||
$(NULL)
|
||||
|
||||
TESTS = \
|
||||
test-frame-queue \
|
||||
test-settings \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 implementation of frame queue.
|
||||
*/
|
||||
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include "frame_queue.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/code_utils.hpp>
|
||||
|
||||
namespace ot {
|
||||
|
||||
otError FrameQueue::Push(const uint8_t *aFrame, uint8_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t newTail = mTail + aLength + 1;
|
||||
|
||||
assert(aFrame != NULL);
|
||||
VerifyOrExit(aFrame != NULL, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
if (mHead > mTail)
|
||||
{
|
||||
VerifyOrExit(newTail < mHead, error = OT_ERROR_NO_BUFS);
|
||||
}
|
||||
else if (newTail >= sizeof(mBuffer))
|
||||
{
|
||||
newTail -= sizeof(mBuffer);
|
||||
VerifyOrExit(newTail < mHead, error = OT_ERROR_NO_BUFS);
|
||||
}
|
||||
|
||||
mBuffer[mTail] = aLength;
|
||||
|
||||
if (newTail > mTail)
|
||||
{
|
||||
memcpy(mBuffer + mTail + 1, aFrame, aLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t half = (sizeof(mBuffer) - mTail - 1);
|
||||
memcpy(mBuffer + mTail + 1, aFrame, half);
|
||||
memcpy(mBuffer, aFrame + half, (aLength - half));
|
||||
}
|
||||
|
||||
mTail = newTail;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
const uint8_t *FrameQueue::Shift(uint8_t *aFrame, uint8_t &aLength)
|
||||
{
|
||||
const uint8_t *frame = NULL;
|
||||
uint16_t next;
|
||||
|
||||
VerifyOrExit(mHead != mTail);
|
||||
|
||||
aLength = mBuffer[mHead];
|
||||
next = mHead + 1 + aLength;
|
||||
if (next >= sizeof(mBuffer))
|
||||
{
|
||||
uint16_t half = sizeof(mBuffer) - mHead - 1;
|
||||
memcpy(aFrame, mBuffer + mHead + 1, half);
|
||||
memcpy(aFrame + half, mBuffer, aLength - half);
|
||||
frame = aFrame;
|
||||
next -= sizeof(mBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame = mBuffer + mHead + 1;
|
||||
}
|
||||
mHead = next;
|
||||
|
||||
exit:
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#if SELF_TEST
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void TestSingle()
|
||||
{
|
||||
otError error;
|
||||
ot::FrameQueue frameQueue;
|
||||
uint8_t length;
|
||||
uint8_t frame[255];
|
||||
|
||||
for (size_t i = 0; i < sizeof(frame); ++i)
|
||||
{
|
||||
frame[i] = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(frame); ++i)
|
||||
{
|
||||
uint8_t outFrame[255];
|
||||
const uint8_t *retFrame = NULL;
|
||||
error = frameQueue.Push(frame, i);
|
||||
assert(OT_ERROR_NONE == error);
|
||||
assert(!frameQueue.IsEmpty());
|
||||
retFrame = frameQueue.Shift(outFrame, length);
|
||||
assert(retFrame != NULL);
|
||||
assert(length == i);
|
||||
|
||||
for (size_t j = 0; j < i; ++j)
|
||||
{
|
||||
assert(retFrame[j] == frame[j]);
|
||||
}
|
||||
|
||||
assert(frameQueue.IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void TestMultiple()
|
||||
{
|
||||
otError error;
|
||||
ot::FrameQueue frameQueue;
|
||||
uint8_t length;
|
||||
uint8_t frame[255];
|
||||
int count = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(frame); ++i)
|
||||
{
|
||||
frame[i] = i;
|
||||
}
|
||||
|
||||
srand(0);
|
||||
|
||||
for (size_t i = 0; i < sizeof(frame); ++i)
|
||||
{
|
||||
uint8_t outFrame[255];
|
||||
int action = rand();
|
||||
|
||||
if (action & 0x01) // push when odd
|
||||
{
|
||||
error = frameQueue.Push(frame, i);
|
||||
if (error == OT_ERROR_NO_BUFS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(OT_ERROR_NONE == error);
|
||||
assert(!frameQueue.IsEmpty());
|
||||
++count;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t *retFrame = NULL;
|
||||
|
||||
retFrame = frameQueue.Shift(outFrame, length);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
assert(retFrame == NULL);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(retFrame != NULL);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < length; ++j)
|
||||
{
|
||||
assert(retFrame[j] == frame[j]);
|
||||
}
|
||||
|
||||
--count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestRing()
|
||||
{
|
||||
ot::FrameQueue frameQueue;
|
||||
uint8_t length;
|
||||
uint8_t frame[255];
|
||||
|
||||
for (size_t i = 0; i < sizeof(frame); ++i)
|
||||
{
|
||||
frame[i] = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < OPENTHREAD_CONFIG_FRAME_QUEUE_SIZE + 255; i += sizeof(frame))
|
||||
{
|
||||
uint8_t outFrame[255];
|
||||
const uint8_t *retFrame = NULL;
|
||||
|
||||
frameQueue.Push(frame, sizeof(frame));
|
||||
|
||||
retFrame = frameQueue.Shift(outFrame, length);
|
||||
|
||||
for (size_t j = 0; j < sizeof(frame); ++j)
|
||||
{
|
||||
assert(retFrame[j] == frame[j]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void RunAllTests()
|
||||
{
|
||||
TestSingle();
|
||||
TestMultiple();
|
||||
TestRing();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
RunAllTests();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif // SELF_TEST
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 frame queue.
|
||||
*/
|
||||
|
||||
#ifndef OT_FRAME_QUEUE_HPP_
|
||||
#define OT_FRAME_QUEUE_HPP_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_FRAME_QUEUE_SIZE
|
||||
*
|
||||
* The size of a frame queue in bytes.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_FRAME_QUEUE_SIZE
|
||||
#define OPENTHREAD_CONFIG_FRAME_QUEUE_SIZE 4096
|
||||
#endif
|
||||
|
||||
namespace ot {
|
||||
|
||||
class FrameQueue
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes a frame queue based on ring buffer.
|
||||
*
|
||||
*/
|
||||
FrameQueue(void)
|
||||
: mHead(0)
|
||||
, mTail(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the cache is empty.
|
||||
*
|
||||
* @retval true No frames are queued.
|
||||
* @retval false At least one frame is queued.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return mHead == mTail; }
|
||||
|
||||
/**
|
||||
* This method pushes one frame into the queue.
|
||||
*
|
||||
* @param[in] aFrame A pointer to a spinel frame to be queued.
|
||||
* @param[in] aLength Frame length in bytes.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully queued this frame.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient memory for this frame.
|
||||
*
|
||||
*/
|
||||
otError Push(const uint8_t *aFrame, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* This method shifts one frame at head.
|
||||
*
|
||||
* @note aFrame is only used when necessary, always use the returned pointer to access frame data.
|
||||
*
|
||||
* @param[out] aFrame A pointer to the frame to receive the data.
|
||||
* @param[out] aLength A reference to receive the frame length.
|
||||
*
|
||||
* @return A pointer to the frame.
|
||||
*
|
||||
*/
|
||||
const uint8_t *Shift(uint8_t *aFrame, uint8_t &aLength);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kQueueSize = OPENTHREAD_CONFIG_FRAME_QUEUE_SIZE,
|
||||
};
|
||||
|
||||
uint8_t mBuffer[kQueueSize];
|
||||
uint16_t mHead;
|
||||
uint16_t mTail;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OT_FRAME_CACHE_HPP_
|
||||
@@ -66,27 +66,12 @@
|
||||
namespace ot {
|
||||
namespace PosixApp {
|
||||
|
||||
class EncoderBuffer : public Hdlc::Encoder::BufferWriteIterator
|
||||
{
|
||||
public:
|
||||
EncoderBuffer(void)
|
||||
{
|
||||
mWritePointer = mBuffer;
|
||||
mRemainingLength = sizeof(mBuffer);
|
||||
}
|
||||
|
||||
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); }
|
||||
const uint8_t *GetBuffer(void) const { return mBuffer; }
|
||||
|
||||
private:
|
||||
uint8_t mBuffer[HdlcInterface::kMaxFrameSize];
|
||||
};
|
||||
|
||||
HdlcInterface::HdlcInterface(Callbacks &aCallbacks)
|
||||
: mCallbacks(aCallbacks)
|
||||
, mSockFd(-1)
|
||||
, mIsDecoding(false)
|
||||
, mHdlcDecoder(mDecoderBuffer, sizeof(mDecoderBuffer), HandleHdlcFrame, HandleHdlcError, this)
|
||||
, mRxFrameBuffer()
|
||||
, mHdlcDecoder(mRxFrameBuffer, HandleHdlcFrame, this)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -166,15 +151,15 @@ void HdlcInterface::Decode(const uint8_t *aBuffer, uint16_t aLength)
|
||||
|
||||
otError HdlcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Hdlc::Encoder hdlcEncoder;
|
||||
EncoderBuffer encoderBuffer;
|
||||
otError error = OT_ERROR_NONE;
|
||||
Hdlc::FrameBuffer<kMaxFrameSize> encoderBuffer;
|
||||
Hdlc::Encoder hdlcEncoder(encoderBuffer);
|
||||
|
||||
SuccessOrExit(error = hdlcEncoder.Init(encoderBuffer));
|
||||
SuccessOrExit(error = hdlcEncoder.Encode(aFrame, aLength, encoderBuffer));
|
||||
SuccessOrExit(error = hdlcEncoder.Finalize(encoderBuffer));
|
||||
SuccessOrExit(error = hdlcEncoder.BeginFrame());
|
||||
SuccessOrExit(error = hdlcEncoder.Encode(aFrame, aLength));
|
||||
SuccessOrExit(error = hdlcEncoder.EndFrame());
|
||||
|
||||
error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength());
|
||||
error = Write(encoderBuffer.GetFrame(), encoderBuffer.GetLength());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -501,19 +486,21 @@ exit:
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||
|
||||
void HdlcInterface::HandleHdlcFrame(void *aContext, uint8_t *aFrame, uint16_t aFrameLength)
|
||||
void HdlcInterface::HandleHdlcFrame(void *aContext, otError aError)
|
||||
{
|
||||
static_cast<HdlcInterface *>(aContext)->mCallbacks.HandleReceivedFrame(aFrame, aFrameLength);
|
||||
static_cast<HdlcInterface *>(aContext)->HandleHdlcFrame(aError);
|
||||
}
|
||||
|
||||
void HdlcInterface::HandleHdlcError(void *aContext, otError aError, uint8_t *aFrame, uint16_t aFrameLength)
|
||||
void HdlcInterface::HandleHdlcFrame(otError aError)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aContext);
|
||||
OT_UNUSED_VARIABLE(aError);
|
||||
OT_UNUSED_VARIABLE(aFrame);
|
||||
OT_UNUSED_VARIABLE(aFrameLength);
|
||||
|
||||
otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError));
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
mCallbacks.HandleReceivedFrame(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PosixApp
|
||||
|
||||
@@ -54,6 +54,15 @@ public:
|
||||
kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||
};
|
||||
|
||||
/**
|
||||
* This type defines a receive frame buffer to store received (and decoded) frame(s).
|
||||
*
|
||||
* @note The receive frame buffer is an `Hdlc::MultiFrameBuffer` and therefore it is capable of storing multiple
|
||||
* frames in a FIFO queue manner.
|
||||
*
|
||||
*/
|
||||
typedef Hdlc::MultiFrameBuffer<kMaxFrameSize> RxFrameBuffer;
|
||||
|
||||
/**
|
||||
* This class defines the callbacks provided by `HdlcInterfac` to its owner/user.
|
||||
*
|
||||
@@ -64,11 +73,15 @@ public:
|
||||
/**
|
||||
* This callback is invoked to notify owner/user of `HdlcInterface` of a received (and decoded) frame.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the received frame.
|
||||
* @param[in] aLength The length (number of bytes) of the received frame.
|
||||
* The newly received frame is available in `RxFrameBuffer` from `HdclInterface::GetRxFrameBuffer()`. The
|
||||
* user can read and process the frame. The callback is expected to either discard the new frame using
|
||||
* `RxFrameBuffer::DiscardFrame()` or save the frame using `RxFrameBuffer::SaveFrame()` to be read and
|
||||
* processed later.
|
||||
*
|
||||
* @param[in] aHdlcInterface A reference to the `HdlcInterface` object.
|
||||
*
|
||||
*/
|
||||
void HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
void HandleReceivedFrame(HdlcInterface &aHdlcInterface);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -133,6 +146,22 @@ public:
|
||||
*/
|
||||
void Read(void);
|
||||
|
||||
/**
|
||||
* This method gets the `RxFrameBuffer`.
|
||||
*
|
||||
* The receive frame buffer is an `Hdlc::MultiFrameBuffer` and therefore it is capable of storing multiple
|
||||
* frames in a FIFO queue manner. The `RxFrameBuffer` contains the decoded received frames.
|
||||
*
|
||||
* Wen during `Read()` the `Callbacks::HandleReceivedFrame()` is invoked, the newly received decoded frame is
|
||||
* available in the receive frame buffer. The callback is expected to either process and then discard the frame
|
||||
* (using `RxFrameBuffer::DiscardFrame()` method) or save the frame (using `RxFrameBuffer::SaveFrame()` so that
|
||||
* it can be read later.
|
||||
*
|
||||
* @returns A reference to receive frame buffer containing newly received frame or previously saved frames.
|
||||
*
|
||||
*/
|
||||
RxFrameBuffer &GetRxFrameBuffer(void) { return mRxFrameBuffer; }
|
||||
|
||||
/**
|
||||
* This method encodes and sends a frame to Radio Co-processor (RCP) over the socket.
|
||||
*
|
||||
@@ -201,8 +230,8 @@ private:
|
||||
*/
|
||||
void Decode(const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
static void HandleHdlcFrame(void *aContext, uint8_t *aFrame, uint16_t aFrameLength);
|
||||
static void HandleHdlcError(void *aContext, otError aError, uint8_t *aFrame, uint16_t aFrameLength);
|
||||
static void HandleHdlcFrame(void *aContext, otError aError);
|
||||
void HandleHdlcFrame(otError aError);
|
||||
|
||||
static int OpenFile(const char *aFile, const char *aConfig);
|
||||
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||
@@ -212,8 +241,8 @@ private:
|
||||
Callbacks & mCallbacks;
|
||||
int mSockFd;
|
||||
bool mIsDecoding;
|
||||
RxFrameBuffer mRxFrameBuffer;
|
||||
Hdlc::Decoder mHdlcDecoder;
|
||||
uint8_t mDecoderBuffer[kMaxFrameSize];
|
||||
};
|
||||
|
||||
} // namespace PosixApp
|
||||
|
||||
@@ -144,9 +144,9 @@ static void LogIfFail(const char *aText, otError aError)
|
||||
}
|
||||
}
|
||||
|
||||
void HdlcInterface::Callbacks::HandleReceivedFrame(const uint8_t *aBuffer, uint16_t aLength)
|
||||
void HdlcInterface::Callbacks::HandleReceivedFrame(HdlcInterface &aInterface)
|
||||
{
|
||||
static_cast<RadioSpinel *>(this)->HandleSpinelFrame(aBuffer, aLength);
|
||||
static_cast<RadioSpinel *>(this)->HandleSpinelFrame(aInterface.GetRxFrameBuffer());
|
||||
}
|
||||
|
||||
RadioSpinel::RadioSpinel(void)
|
||||
@@ -300,31 +300,37 @@ void RadioSpinel::Deinit(void)
|
||||
mHdlcInterface.Deinit();
|
||||
}
|
||||
|
||||
void RadioSpinel::HandleSpinelFrame(const uint8_t *aBuffer, uint16_t aLength)
|
||||
void RadioSpinel::HandleSpinelFrame(HdlcInterface::RxFrameBuffer &aFrameBuffer)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t header;
|
||||
spinel_ssize_t rval;
|
||||
spinel_ssize_t unpacked;
|
||||
|
||||
rval = spinel_datatype_unpack(aBuffer, aLength, "C", &header);
|
||||
unpacked = spinel_datatype_unpack(aFrameBuffer.GetFrame(), aFrameBuffer.GetLength(), "C", &header);
|
||||
|
||||
VerifyOrExit(rval > 0 && (header & SPINEL_HEADER_FLAG) == SPINEL_HEADER_FLAG && SPINEL_HEADER_GET_IID(header) == 0,
|
||||
VerifyOrExit(unpacked > 0 && (header & SPINEL_HEADER_FLAG) == SPINEL_HEADER_FLAG &&
|
||||
SPINEL_HEADER_GET_IID(header) == 0,
|
||||
error = OT_ERROR_PARSE);
|
||||
|
||||
if (SPINEL_HEADER_GET_TID(header) == 0)
|
||||
{
|
||||
HandleNotification(aBuffer, aLength);
|
||||
HandleNotification(aFrameBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleResponse(aBuffer, aLength);
|
||||
HandleResponse(aFrameBuffer.GetFrame(), aFrameBuffer.GetLength());
|
||||
aFrameBuffer.DiscardFrame();
|
||||
}
|
||||
|
||||
exit:
|
||||
LogIfFail("Error handling hdlc frame", error);
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
aFrameBuffer.DiscardFrame();
|
||||
otLogWarnPlat("Error handling hdlc frame: %s", otThreadErrorToString(error));
|
||||
}
|
||||
}
|
||||
|
||||
void RadioSpinel::HandleNotification(const uint8_t *aBuffer, uint16_t aLength)
|
||||
void RadioSpinel::HandleNotification(HdlcInterface::RxFrameBuffer &aFrameBuffer)
|
||||
{
|
||||
spinel_prop_key_t key;
|
||||
spinel_size_t len = 0;
|
||||
@@ -332,9 +338,11 @@ void RadioSpinel::HandleNotification(const uint8_t *aBuffer, uint16_t aLength)
|
||||
uint8_t * data = NULL;
|
||||
uint32_t cmd;
|
||||
uint8_t header;
|
||||
otError error = OT_ERROR_NONE;
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool shouldSaveFrame = false;
|
||||
|
||||
unpacked = spinel_datatype_unpack(aBuffer, aLength, "CiiD", &header, &cmd, &key, &data, &len);
|
||||
unpacked = spinel_datatype_unpack(aFrameBuffer.GetFrame(), aFrameBuffer.GetLength(), "CiiD", &header, &cmd, &key,
|
||||
&data, &len);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OT_ERROR_PARSE);
|
||||
|
||||
@@ -347,9 +355,7 @@ void RadioSpinel::HandleNotification(const uint8_t *aBuffer, uint16_t aLength)
|
||||
|
||||
if (!IsSafeToHandleNow(key))
|
||||
{
|
||||
assert(aLength <= 255);
|
||||
error = mFrameQueue.Push(aBuffer, static_cast<uint8_t>(aLength));
|
||||
ExitNow();
|
||||
ExitNow(shouldSaveFrame = true);
|
||||
}
|
||||
|
||||
HandleValueIs(key, data, static_cast<uint16_t>(len));
|
||||
@@ -365,9 +371,38 @@ void RadioSpinel::HandleNotification(const uint8_t *aBuffer, uint16_t aLength)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (shouldSaveFrame)
|
||||
{
|
||||
aFrameBuffer.SaveFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
aFrameBuffer.DiscardFrame();
|
||||
}
|
||||
|
||||
LogIfFail("Error processing notification", error);
|
||||
}
|
||||
|
||||
void RadioSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
spinel_prop_key_t key;
|
||||
spinel_size_t len = 0;
|
||||
spinel_ssize_t unpacked;
|
||||
uint8_t * data = NULL;
|
||||
uint32_t cmd;
|
||||
uint8_t header;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS);
|
||||
HandleValueIs(key, data, static_cast<uint16_t>(len));
|
||||
|
||||
exit:
|
||||
LogIfFail("Error processing saved notification", error);
|
||||
}
|
||||
|
||||
void RadioSpinel::HandleResponse(const uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
spinel_prop_key_t key;
|
||||
@@ -593,11 +628,10 @@ exit:
|
||||
|
||||
void RadioSpinel::ProcessFrameQueue(void)
|
||||
{
|
||||
uint8_t length;
|
||||
uint8_t buffer[kMaxSpinelFrame];
|
||||
const uint8_t *frame;
|
||||
uint8_t *frame;
|
||||
uint16_t length;
|
||||
|
||||
while ((frame = mFrameQueue.Shift(buffer, length)) != NULL)
|
||||
while (mHdlcInterface.GetRxFrameBuffer().ReadSavedFrame(frame, length) == OT_ERROR_NONE)
|
||||
{
|
||||
HandleNotification(frame, length);
|
||||
}
|
||||
@@ -652,7 +686,7 @@ void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMax
|
||||
FD_SET(sockFd, &aWriteFdSet);
|
||||
}
|
||||
|
||||
if (!mFrameQueue.IsEmpty() || (mState == kStateTransmitDone))
|
||||
if (mHdlcInterface.GetRxFrameBuffer().HasSavedFrame() || (mState == kStateTransmitDone))
|
||||
{
|
||||
aTimeout.tv_sec = 0;
|
||||
aTimeout.tv_usec = 0;
|
||||
@@ -661,18 +695,20 @@ void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMax
|
||||
|
||||
void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet)
|
||||
{
|
||||
if (FD_ISSET(mHdlcInterface.GetSocket(), &aReadFdSet) || !mFrameQueue.IsEmpty())
|
||||
if (mHdlcInterface.GetRxFrameBuffer().HasSavedFrame())
|
||||
{
|
||||
// Handle frames received during WaitResponse()
|
||||
// Handle frames received and saved during `WaitResponse()`
|
||||
ProcessFrameQueue();
|
||||
|
||||
if (FD_ISSET(mHdlcInterface.GetSocket(), &aReadFdSet))
|
||||
{
|
||||
mHdlcInterface.Read();
|
||||
ProcessFrameQueue();
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(mHdlcInterface.GetSocket(), &aReadFdSet))
|
||||
{
|
||||
mHdlcInterface.Read();
|
||||
ProcessFrameQueue();
|
||||
}
|
||||
|
||||
mHdlcInterface.GetRxFrameBuffer().ClearReadFrames();
|
||||
|
||||
if (mState == kStateTransmitDone)
|
||||
{
|
||||
mState = kStateReceive;
|
||||
@@ -1509,7 +1545,7 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
|
||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||
void ot::PosixApp::RadioSpinel::Process(const Event &aEvent)
|
||||
{
|
||||
if (!mFrameQueue.IsEmpty())
|
||||
if (mHdlcInterface.GetRxFrameBuffer().HasSavedFrame())
|
||||
{
|
||||
ProcessFrameQueue();
|
||||
}
|
||||
@@ -1521,6 +1557,8 @@ void ot::PosixApp::RadioSpinel::Process(const Event &aEvent)
|
||||
ProcessFrameQueue();
|
||||
}
|
||||
|
||||
mHdlcInterface.GetRxFrameBuffer().ClearReadFrames();
|
||||
|
||||
if (mState == kStateTransmitDone)
|
||||
{
|
||||
mState = kStateReceive;
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#include "frame_queue.hpp"
|
||||
#include "hdlc_interface.hpp"
|
||||
#include "spinel.h"
|
||||
|
||||
@@ -443,11 +442,9 @@ public:
|
||||
/**
|
||||
* This method processes a received Spinel frame.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to buffer containing the frame.
|
||||
* @param[in] aLength Length (number of bytes) in the received frame.
|
||||
*
|
||||
* @param[in] aFrameBuffer The frame buffer constaining the newly received frame.
|
||||
*/
|
||||
void HandleSpinelFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
void HandleSpinelFrame(HdlcInterface::RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
private:
|
||||
enum
|
||||
@@ -543,11 +540,6 @@ private:
|
||||
va_list args);
|
||||
otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
static void HandleSpinelFrame(void *aContext, uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
static_cast<RadioSpinel *>(aContext)->HandleSpinelFrame(aBuffer, aLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns if the property changed event is safe to be handled now.
|
||||
*
|
||||
@@ -565,6 +557,7 @@ private:
|
||||
(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT));
|
||||
}
|
||||
|
||||
void HandleNotification(HdlcInterface::RxFrameBuffer &aFrameBuffer);
|
||||
void HandleNotification(const uint8_t *aBuffer, uint16_t aLength);
|
||||
void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
@@ -589,8 +582,6 @@ private:
|
||||
uint32_t mExpectedCommand; ///< Expected response command of current transaction.
|
||||
otError mError; ///< The result of current transaction.
|
||||
|
||||
FrameQueue mFrameQueue;
|
||||
|
||||
uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||
uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||
uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||
|
||||
Reference in New Issue
Block a user