mirror of
https://github.com/espressif/openthread.git
synced 2026-10-03 14:27:38 +00:00
[posix-app] add HdlcInterface class (#3293)
This commit adds a new class `HdlcInterface` under POSIX App which performs HDLC encoding/decoding and read/write operations on the interface to Radio Co-Processor (RCP). `RadioSpinel` is updated to use the new class.
This commit is contained in:
committed by
Jonathan Hui
parent
5da7469269
commit
0863b652b2
+6
-5
@@ -180,15 +180,16 @@ LOCAL_SRC_FILES := \
|
|||||||
src/ncp/spinel_decoder.cpp \
|
src/ncp/spinel_decoder.cpp \
|
||||||
src/ncp/spinel_encoder.cpp \
|
src/ncp/spinel_encoder.cpp \
|
||||||
src/posix/platform/alarm.c \
|
src/posix/platform/alarm.c \
|
||||||
src/posix/platform/misc.c \
|
src/posix/platform/frame_queue.cpp \
|
||||||
|
src/posix/platform/hdlc_interface.cpp \
|
||||||
src/posix/platform/logging.c \
|
src/posix/platform/logging.c \
|
||||||
|
src/posix/platform/misc.c \
|
||||||
|
src/posix/platform/radio_spinel.cpp \
|
||||||
src/posix/platform/random.c \
|
src/posix/platform/random.c \
|
||||||
|
src/posix/platform/settings.cpp \
|
||||||
|
src/posix/platform/spi-stubs.c \
|
||||||
src/posix/platform/system.c \
|
src/posix/platform/system.c \
|
||||||
src/posix/platform/uart.c \
|
src/posix/platform/uart.c \
|
||||||
src/posix/platform/spi-stubs.c \
|
|
||||||
src/posix/platform/frame_queue.cpp \
|
|
||||||
src/posix/platform/radio_spinel.cpp \
|
|
||||||
src/posix/platform/settings.cpp \
|
|
||||||
third_party/mbedtls/repo/library/md.c \
|
third_party/mbedtls/repo/library/md.c \
|
||||||
third_party/mbedtls/repo/library/md_wrap.c \
|
third_party/mbedtls/repo/library/md_wrap.c \
|
||||||
third_party/mbedtls/repo/library/memory_buffer_alloc.c \
|
third_party/mbedtls/repo/library/memory_buffer_alloc.c \
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ libopenthread_posix_a_CPPFLAGS = \
|
|||||||
libopenthread_posix_a_SOURCES = \
|
libopenthread_posix_a_SOURCES = \
|
||||||
alarm.c \
|
alarm.c \
|
||||||
frame_queue.cpp \
|
frame_queue.cpp \
|
||||||
|
hdlc_interface.cpp \
|
||||||
logging.c \
|
logging.c \
|
||||||
misc.c \
|
misc.c \
|
||||||
radio_spinel.cpp \
|
radio_spinel.cpp \
|
||||||
@@ -75,6 +76,7 @@ noinst_HEADERS = \
|
|||||||
frame_queue.hpp \
|
frame_queue.hpp \
|
||||||
openthread-system.h \
|
openthread-system.h \
|
||||||
platform-posix.h \
|
platform-posix.h \
|
||||||
|
hdlc_interface.hpp \
|
||||||
radio_spinel.hpp \
|
radio_spinel.hpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,457 @@
|
|||||||
|
/*
|
||||||
|
* 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 the implementation for the HDLC interface to radio (RCP).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hdlc_interface.hpp"
|
||||||
|
|
||||||
|
#include "platform-posix.h"
|
||||||
|
#include "radio_spinel.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
#ifdef OPENTHREAD_TARGET_DARWIN
|
||||||
|
#include <util.h>
|
||||||
|
#else
|
||||||
|
#include <pty.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <common/code_utils.hpp>
|
||||||
|
#include <common/logging.hpp>
|
||||||
|
|
||||||
|
#ifndef SOCKET_UTILS_DEFAULT_SHELL
|
||||||
|
#define SOCKET_UTILS_DEFAULT_SHELL "/bin/sh"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
otError HdlcInterface::Init(const char *aRadioFile, const char *aRadioConfig)
|
||||||
|
{
|
||||||
|
otError error = OT_ERROR_NONE;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY);
|
||||||
|
|
||||||
|
VerifyOrExit(stat(aRadioFile, &st) == 0, perror("stat ncp file failed"); error = OT_ERROR_INVALID_ARGS);
|
||||||
|
|
||||||
|
if (S_ISCHR(st.st_mode))
|
||||||
|
{
|
||||||
|
mSockFd = OpenFile(aRadioFile, aRadioConfig);
|
||||||
|
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
||||||
|
}
|
||||||
|
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
else if (S_ISREG(st.st_mode))
|
||||||
|
{
|
||||||
|
mSockFd = ForkPty(aRadioFile, aRadioConfig);
|
||||||
|
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
||||||
|
}
|
||||||
|
#endif // OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
else
|
||||||
|
{
|
||||||
|
otLogCritPlat("Radio file '%s' not supported", aRadioFile);
|
||||||
|
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcInterface::Deinit(void)
|
||||||
|
{
|
||||||
|
assert(mSockFd != -1);
|
||||||
|
|
||||||
|
VerifyOrExit(0 == close(mSockFd), perror("close NCP"));
|
||||||
|
VerifyOrExit(-1 != wait(NULL), perror("wait NCP"));
|
||||||
|
|
||||||
|
mSockFd = -1;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcInterface::Read(void)
|
||||||
|
{
|
||||||
|
uint8_t buffer[kMaxFrameSize];
|
||||||
|
ssize_t rval;
|
||||||
|
|
||||||
|
rval = read(mSockFd, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if (rval < 0)
|
||||||
|
{
|
||||||
|
perror("HdlcInterface::Read()");
|
||||||
|
|
||||||
|
if (errno != EAGAIN)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rval > 0)
|
||||||
|
{
|
||||||
|
Decode(buffer, static_cast<uint16_t>(rval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcInterface::Decode(const uint8_t *aBuffer, uint16_t aLength)
|
||||||
|
{
|
||||||
|
mIsDecoding = true;
|
||||||
|
mHdlcDecoder.Decode(aBuffer, aLength);
|
||||||
|
mIsDecoding = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
otError HdlcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||||
|
{
|
||||||
|
otError error = OT_ERROR_NONE;
|
||||||
|
Hdlc::Encoder hdlcEncoder;
|
||||||
|
EncoderBuffer encoderBuffer;
|
||||||
|
|
||||||
|
SuccessOrExit(error = hdlcEncoder.Init(encoderBuffer));
|
||||||
|
SuccessOrExit(error = hdlcEncoder.Encode(aFrame, aLength, encoderBuffer));
|
||||||
|
SuccessOrExit(error = hdlcEncoder.Finalize(encoderBuffer));
|
||||||
|
|
||||||
|
SuccessOrExit(error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength()));
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
||||||
|
{
|
||||||
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
|
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||||
|
otSimSendRadioSpinelWriteEvent(aFrame, aLength);
|
||||||
|
#else
|
||||||
|
while (aLength)
|
||||||
|
{
|
||||||
|
ssize_t rval = write(mSockFd, aFrame, aLength);
|
||||||
|
|
||||||
|
if (rval > 0)
|
||||||
|
{
|
||||||
|
aLength -= static_cast<uint16_t>(rval);
|
||||||
|
aFrame += static_cast<uint16_t>(rval);
|
||||||
|
}
|
||||||
|
else if (rval < 0)
|
||||||
|
{
|
||||||
|
perror("HdlcInterface::Write");
|
||||||
|
ExitNow(error = OT_ERROR_FAILED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExitNow(error = OT_ERROR_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
fd = open(aFile, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
perror("open uart failed");
|
||||||
|
ExitNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isatty(fd))
|
||||||
|
{
|
||||||
|
struct termios tios;
|
||||||
|
|
||||||
|
int speed = 115200;
|
||||||
|
int cstopb = 1;
|
||||||
|
char parity = 'N';
|
||||||
|
|
||||||
|
VerifyOrExit((rval = tcgetattr(fd, &tios)) == 0);
|
||||||
|
|
||||||
|
cfmakeraw(&tios);
|
||||||
|
|
||||||
|
tios.c_cflag = CS8 | HUPCL | CREAD | CLOCAL;
|
||||||
|
|
||||||
|
// example: 115200N1
|
||||||
|
sscanf(aConfig, "%u%c%d", &speed, &parity, &cstopb);
|
||||||
|
|
||||||
|
switch (parity)
|
||||||
|
{
|
||||||
|
case 'N':
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
tios.c_cflag |= PARENB;
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
tios.c_cflag |= (PARENB | PARODD);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// not supported
|
||||||
|
assert(false);
|
||||||
|
exit(OT_EXIT_INVALID_ARGUMENTS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cstopb)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
tios.c_cflag &= static_cast<unsigned long>(~CSTOPB);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
tios.c_cflag |= CSTOPB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
exit(OT_EXIT_INVALID_ARGUMENTS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (speed)
|
||||||
|
{
|
||||||
|
case 9600:
|
||||||
|
speed = B9600;
|
||||||
|
break;
|
||||||
|
case 19200:
|
||||||
|
speed = B19200;
|
||||||
|
break;
|
||||||
|
case 38400:
|
||||||
|
speed = B38400;
|
||||||
|
break;
|
||||||
|
case 57600:
|
||||||
|
speed = B57600;
|
||||||
|
break;
|
||||||
|
case 115200:
|
||||||
|
speed = B115200;
|
||||||
|
break;
|
||||||
|
#ifdef B230400
|
||||||
|
case 230400:
|
||||||
|
speed = B230400;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B460800
|
||||||
|
case 460800:
|
||||||
|
speed = B460800;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B500000
|
||||||
|
case 500000:
|
||||||
|
speed = B500000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B576000
|
||||||
|
case 576000:
|
||||||
|
speed = B576000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B921600
|
||||||
|
case 921600:
|
||||||
|
speed = B921600;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1000000
|
||||||
|
case 1000000:
|
||||||
|
speed = B1000000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1152000
|
||||||
|
case 1152000:
|
||||||
|
speed = B1152000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1500000
|
||||||
|
case 1500000:
|
||||||
|
speed = B1500000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B2000000
|
||||||
|
case 2000000:
|
||||||
|
speed = B2000000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B2500000
|
||||||
|
case 2500000:
|
||||||
|
speed = B2500000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B3000000
|
||||||
|
case 3000000:
|
||||||
|
speed = B3000000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B3500000
|
||||||
|
case 3500000:
|
||||||
|
speed = B3500000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B4000000
|
||||||
|
case 4000000:
|
||||||
|
speed = B4000000;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
exit(OT_EXIT_INVALID_ARGUMENTS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VerifyOrExit((rval = cfsetspeed(&tios, static_cast<speed_t>(speed))) == 0, perror("cfsetspeed"));
|
||||||
|
VerifyOrExit((rval = tcsetattr(fd, TCSANOW, &tios)) == 0, perror("tcsetattr"));
|
||||||
|
VerifyOrExit((rval = tcflush(fd, TCIOFLUSH)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (rval != 0)
|
||||||
|
{
|
||||||
|
exit(OT_EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
int HdlcInterface::ForkPty(const char *aCommand, const char *aArguments)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int pid = -1;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct termios tios;
|
||||||
|
|
||||||
|
memset(&tios, 0, sizeof(tios));
|
||||||
|
cfmakeraw(&tios);
|
||||||
|
tios.c_cflag = CS8 | HUPCL | CREAD | CLOCAL;
|
||||||
|
|
||||||
|
pid = forkpty(&fd, NULL, &tios, NULL);
|
||||||
|
VerifyOrExit(pid >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == pid)
|
||||||
|
{
|
||||||
|
const int kMaxCommand = 255;
|
||||||
|
char cmd[kMaxCommand];
|
||||||
|
int rval;
|
||||||
|
struct rlimit limit;
|
||||||
|
|
||||||
|
rval = getrlimit(RLIMIT_NOFILE, &limit);
|
||||||
|
rval = setenv("SHELL", SOCKET_UTILS_DEFAULT_SHELL, 0);
|
||||||
|
|
||||||
|
VerifyOrExit(rval == 0, perror("setenv failed"));
|
||||||
|
|
||||||
|
// Close all file descriptors larger than STDERR_FILENO.
|
||||||
|
for (rlim_t i = (STDERR_FILENO + 1); i < limit.rlim_cur; i++)
|
||||||
|
{
|
||||||
|
close(static_cast<int>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
rval = snprintf(cmd, sizeof(cmd), "exec %s %s", aCommand, aArguments);
|
||||||
|
VerifyOrExit(rval > 0 && static_cast<size_t>(rval) < sizeof(cmd),
|
||||||
|
otLogCritPlat("NCP file and configuration is too long!"));
|
||||||
|
|
||||||
|
execl(getenv("SHELL"), getenv("SHELL"), "-c", cmd, NULL);
|
||||||
|
perror("open pty failed");
|
||||||
|
exit(OT_EXIT_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int rval = fcntl(fd, F_GETFL);
|
||||||
|
|
||||||
|
if (rval != -1)
|
||||||
|
{
|
||||||
|
rval = fcntl(fd, F_SETFL, rval | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rval == -1)
|
||||||
|
{
|
||||||
|
perror("set nonblock failed");
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
#endif // OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
|
||||||
|
void HdlcInterface::HandleHdlcFrame(void *aContext, uint8_t *aFrame, uint16_t aFrameLength)
|
||||||
|
{
|
||||||
|
static_cast<HdlcInterface *>(aContext)->mCallbacks.HandleReceivedFrame(aFrame, aFrameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcInterface::HandleHdlcError(void *aContext, otError aError, uint8_t *aFrame, uint16_t aFrameLength)
|
||||||
|
{
|
||||||
|
otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError));
|
||||||
|
|
||||||
|
OT_UNUSED_VARIABLE(aContext);
|
||||||
|
OT_UNUSED_VARIABLE(aError);
|
||||||
|
OT_UNUSED_VARIABLE(aFrame);
|
||||||
|
OT_UNUSED_VARIABLE(aFrameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PosixApp
|
||||||
|
} // namespace ot
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* 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 the HDLC interface to radio (RCP).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POSIX_APP_HDLC_INTERFACE_HPP_
|
||||||
|
#define POSIX_APP_HDLC_INTERFACE_HPP_
|
||||||
|
|
||||||
|
#include "openthread-core-config.h"
|
||||||
|
|
||||||
|
#include "hdlc.hpp"
|
||||||
|
|
||||||
|
namespace ot {
|
||||||
|
namespace PosixApp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class defines an HDLC interface to the Radio Co-processor (RCP)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HdlcInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kMaxFrameSize = 2048, ///< Maximum frame size (number of bytes).
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class defines the callbacks provided by `HdlcInterfac` to its owner/user.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Callbacks
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor initializes the object.
|
||||||
|
*
|
||||||
|
* @param[in] aCallback A reference to a `Callback` object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
explicit HdlcInterface(Callbacks &aCallbacks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method initializes the interface to the Radio Co-processor (RCP)
|
||||||
|
*
|
||||||
|
* @note This method should be called before reading and sending frames to the interface.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param[in] aRadioFile The path to either a UART device or an executable.
|
||||||
|
* @param[in] aRadioConfig Parameters to be given to the device or executable.
|
||||||
|
*
|
||||||
|
* @retval OT_ERROR_NONE The interface is initialized successfully
|
||||||
|
* @retval OT_ERROR_ALREADY The interface is already initialized.
|
||||||
|
* @retval OT_ERROR_INVALID_ARGS The UART device or executable cannot be found or failed to open/run.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
otError Init(const char *aRadioFile, const char *aRadioConfig);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method deinitializes the interface to the RCP.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Deinit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This method returns the socket file descriptor associate with the interface
|
||||||
|
*
|
||||||
|
* @returns The associated socket file descriptor, or -1 if interface is not initializes.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int GetSocket(void) const { return mSockFd; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method indicates whether the `HdclInterface` is currently decoding a received frame or not.
|
||||||
|
*
|
||||||
|
* @returns TRUE if currently decoding a received frame, FALSE otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool IsDecoding(void) const { return mIsDecoding; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method instructs `HdlcInterface` to read and decode data from radio over the socket.
|
||||||
|
*
|
||||||
|
* If a full HDLC frame is decoded while reading data, this method invokes the `HandleReceivedFrame()` (on the
|
||||||
|
* `aCallback` object from constructor) to pass the received frame to be processed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Read(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method encodes and sends a frame to Radio Co-processor (RCP) over the socket.
|
||||||
|
*
|
||||||
|
* @param[in] aFrame A pointer to buffer containing the frame to send.
|
||||||
|
* @param[in] aLength The length (number of bytes) in the frame
|
||||||
|
*
|
||||||
|
* @retval OT_ERROR_NONE Successfully encoded and sent the frame.
|
||||||
|
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
|
||||||
|
* @retval OT_ERROR_FAILED Failed to send frame due to socket write failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||||
|
|
||||||
|
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||||
|
/**
|
||||||
|
* This method process read data (decode the data).
|
||||||
|
*
|
||||||
|
* This method is intended only for virtual time simulation. Its behavior is similar to `Read()` but instead of
|
||||||
|
* reading the data from the radio socket, it uses the given data in the buffer `aBuffer`.
|
||||||
|
*
|
||||||
|
* @param[in] aBuffer A pointer to buffer containing data.
|
||||||
|
* @param[in] aLength The length (number of bytes) in the buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ProcessReadData(const uint8_t *aBuffer, uint16_t aLength) { Decode(aBuffer, aLength); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
otError Write(const uint8_t *aFrame, uint16_t aLength);
|
||||||
|
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 int OpenFile(const char *aFile, const char *aConfig);
|
||||||
|
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
||||||
|
static int ForkPty(const char *aCommand, const char *aArguments);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Callbacks & mCallbacks;
|
||||||
|
int mSockFd;
|
||||||
|
bool mIsDecoding;
|
||||||
|
Hdlc::Decoder mHdlcDecoder;
|
||||||
|
uint8_t mDecoderBuffer[kMaxFrameSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PosixApp
|
||||||
|
} // namespace ot
|
||||||
|
|
||||||
|
#endif // POSIX_APP_HDLC_INTERFACE_HPP_
|
||||||
@@ -37,14 +37,6 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
|
||||||
#ifdef OPENTHREAD_TARGET_DARWIN
|
|
||||||
#include <util.h>
|
|
||||||
#else
|
|
||||||
#include <pty.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -62,10 +54,6 @@
|
|||||||
#include <openthread/platform/diag.h>
|
#include <openthread/platform/diag.h>
|
||||||
#include <openthread/platform/radio.h>
|
#include <openthread/platform/radio.h>
|
||||||
|
|
||||||
#ifndef SOCKET_UTILS_DEFAULT_SHELL
|
|
||||||
#define SOCKET_UTILS_DEFAULT_SHELL "/bin/sh"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
IEEE802154_MIN_LENGTH = 5,
|
IEEE802154_MIN_LENGTH = 5,
|
||||||
@@ -115,7 +103,7 @@ enum
|
|||||||
kDone,
|
kDone,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ot::RadioSpinel sRadioSpinel;
|
static ot::PosixApp::RadioSpinel sRadioSpinel;
|
||||||
|
|
||||||
static inline otPanId getDstPan(const uint8_t *frame)
|
static inline otPanId getDstPan(const uint8_t *frame)
|
||||||
{
|
{
|
||||||
@@ -143,6 +131,7 @@ static inline bool isAckRequested(const uint8_t *frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ot {
|
namespace ot {
|
||||||
|
namespace PosixApp {
|
||||||
|
|
||||||
static otError SpinelStatusToOtError(spinel_status_t aError)
|
static otError SpinelStatusToOtError(spinel_status_t aError)
|
||||||
{
|
{
|
||||||
@@ -229,266 +218,23 @@ static void LogIfFail(const char *aText, otError aError)
|
|||||||
OT_UNUSED_VARIABLE(aError);
|
OT_UNUSED_VARIABLE(aError);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
void HdlcInterface::Callbacks::HandleReceivedFrame(const uint8_t *aBuffer, uint16_t aLength)
|
||||||
static int ForkPty(const char *aCommand, const char *aArguments)
|
|
||||||
{
|
{
|
||||||
int fd = -1;
|
static_cast<RadioSpinel *>(this)->HandleSpinelFrame(aBuffer, aLength);
|
||||||
int pid = -1;
|
|
||||||
|
|
||||||
{
|
|
||||||
struct termios tios;
|
|
||||||
|
|
||||||
memset(&tios, 0, sizeof(tios));
|
|
||||||
cfmakeraw(&tios);
|
|
||||||
tios.c_cflag = CS8 | HUPCL | CREAD | CLOCAL;
|
|
||||||
|
|
||||||
pid = forkpty(&fd, NULL, &tios, NULL);
|
|
||||||
VerifyOrExit(pid >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == pid)
|
|
||||||
{
|
|
||||||
const int kMaxCommand = 255;
|
|
||||||
char cmd[kMaxCommand];
|
|
||||||
int rval;
|
|
||||||
struct rlimit limit;
|
|
||||||
|
|
||||||
rval = getrlimit(RLIMIT_NOFILE, &limit);
|
|
||||||
rval = setenv("SHELL", SOCKET_UTILS_DEFAULT_SHELL, 0);
|
|
||||||
|
|
||||||
VerifyOrExit(rval == 0, perror("setenv failed"));
|
|
||||||
|
|
||||||
// Close all file descriptors larger than STDERR_FILENO.
|
|
||||||
for (rlim_t i = (STDERR_FILENO + 1); i < limit.rlim_cur; i++)
|
|
||||||
{
|
|
||||||
close(static_cast<int>(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
rval = snprintf(cmd, sizeof(cmd), "exec %s %s", aCommand, aArguments);
|
|
||||||
VerifyOrExit(rval > 0 && static_cast<size_t>(rval) < sizeof(cmd),
|
|
||||||
otLogCritPlat("NCP file and configuration is too long!"));
|
|
||||||
|
|
||||||
execl(getenv("SHELL"), getenv("SHELL"), "-c", cmd, NULL);
|
|
||||||
perror("open pty failed");
|
|
||||||
exit(OT_EXIT_INVALID_ARGUMENTS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int rval = fcntl(fd, F_GETFL);
|
|
||||||
|
|
||||||
if (rval != -1)
|
|
||||||
{
|
|
||||||
rval = fcntl(fd, F_SETFL, rval | O_NONBLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rval == -1)
|
|
||||||
{
|
|
||||||
perror("set nonblock failed");
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
#endif // OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
|
||||||
|
|
||||||
static int OpenFile(const char *aFile, const char *aConfig)
|
|
||||||
{
|
|
||||||
int fd = -1;
|
|
||||||
int rval = 0;
|
|
||||||
|
|
||||||
fd = open(aFile, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror("open uart failed");
|
|
||||||
ExitNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isatty(fd))
|
|
||||||
{
|
|
||||||
struct termios tios;
|
|
||||||
|
|
||||||
int speed = 115200;
|
|
||||||
int cstopb = 1;
|
|
||||||
char parity = 'N';
|
|
||||||
|
|
||||||
VerifyOrExit((rval = tcgetattr(fd, &tios)) == 0);
|
|
||||||
|
|
||||||
cfmakeraw(&tios);
|
|
||||||
|
|
||||||
tios.c_cflag = CS8 | HUPCL | CREAD | CLOCAL;
|
|
||||||
|
|
||||||
// example: 115200N1
|
|
||||||
sscanf(aConfig, "%u%c%d", &speed, &parity, &cstopb);
|
|
||||||
|
|
||||||
switch (parity)
|
|
||||||
{
|
|
||||||
case 'N':
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
tios.c_cflag |= PARENB;
|
|
||||||
break;
|
|
||||||
case 'O':
|
|
||||||
tios.c_cflag |= (PARENB | PARODD);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// not supported
|
|
||||||
assert(false);
|
|
||||||
exit(OT_EXIT_INVALID_ARGUMENTS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cstopb)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
tios.c_cflag &= static_cast<unsigned long>(~CSTOPB);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
tios.c_cflag |= CSTOPB;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
exit(OT_EXIT_INVALID_ARGUMENTS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (speed)
|
|
||||||
{
|
|
||||||
case 9600:
|
|
||||||
speed = B9600;
|
|
||||||
break;
|
|
||||||
case 19200:
|
|
||||||
speed = B19200;
|
|
||||||
break;
|
|
||||||
case 38400:
|
|
||||||
speed = B38400;
|
|
||||||
break;
|
|
||||||
case 57600:
|
|
||||||
speed = B57600;
|
|
||||||
break;
|
|
||||||
case 115200:
|
|
||||||
speed = B115200;
|
|
||||||
break;
|
|
||||||
#ifdef B230400
|
|
||||||
case 230400:
|
|
||||||
speed = B230400;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B460800
|
|
||||||
case 460800:
|
|
||||||
speed = B460800;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B500000
|
|
||||||
case 500000:
|
|
||||||
speed = B500000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B576000
|
|
||||||
case 576000:
|
|
||||||
speed = B576000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B921600
|
|
||||||
case 921600:
|
|
||||||
speed = B921600;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B1000000
|
|
||||||
case 1000000:
|
|
||||||
speed = B1000000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B1152000
|
|
||||||
case 1152000:
|
|
||||||
speed = B1152000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B1500000
|
|
||||||
case 1500000:
|
|
||||||
speed = B1500000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B2000000
|
|
||||||
case 2000000:
|
|
||||||
speed = B2000000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B2500000
|
|
||||||
case 2500000:
|
|
||||||
speed = B2500000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B3000000
|
|
||||||
case 3000000:
|
|
||||||
speed = B3000000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B3500000
|
|
||||||
case 3500000:
|
|
||||||
speed = B3500000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef B4000000
|
|
||||||
case 4000000:
|
|
||||||
speed = B4000000;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
exit(OT_EXIT_INVALID_ARGUMENTS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
VerifyOrExit((rval = cfsetspeed(&tios, static_cast<speed_t>(speed))) == 0, perror("cfsetspeed"));
|
|
||||||
VerifyOrExit((rval = tcsetattr(fd, TCSANOW, &tios)) == 0, perror("tcsetattr"));
|
|
||||||
VerifyOrExit((rval = tcflush(fd, TCIOFLUSH)) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
if (rval != 0)
|
|
||||||
{
|
|
||||||
exit(OT_EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
class UartTxBuffer : public Hdlc::Encoder::BufferWriteIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
UartTxBuffer(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:
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
kUartTxBufferSize = 512, // Uart tx buffer size.
|
|
||||||
};
|
|
||||||
uint8_t mBuffer[kUartTxBufferSize];
|
|
||||||
};
|
|
||||||
|
|
||||||
RadioSpinel::RadioSpinel(void)
|
RadioSpinel::RadioSpinel(void)
|
||||||
: mCmdTidsInUse(0)
|
: mInstance(NULL)
|
||||||
|
, mHdlcInterface(*this)
|
||||||
|
, mCmdTidsInUse(0)
|
||||||
, mCmdNextTid(1)
|
, mCmdNextTid(1)
|
||||||
, mTxRadioTid(0)
|
, mTxRadioTid(0)
|
||||||
, mWaitingTid(0)
|
, mWaitingTid(0)
|
||||||
, mWaitingKey(SPINEL_PROP_LAST_STATUS)
|
, mWaitingKey(SPINEL_PROP_LAST_STATUS)
|
||||||
, mHdlcDecoder(mHdlcBuffer, sizeof(mHdlcBuffer), HandleSpinelFrame, HandleHdlcError, this)
|
|
||||||
, mRxSensitivity(0)
|
, mRxSensitivity(0)
|
||||||
, mTxState(kIdle)
|
, mTxState(kIdle)
|
||||||
, mSockFd(-1)
|
|
||||||
, mState(OT_RADIO_STATE_DISABLED)
|
, mState(OT_RADIO_STATE_DISABLED)
|
||||||
, mIsAckRequested(false)
|
, mIsAckRequested(false)
|
||||||
, mIsDecoding(false)
|
|
||||||
, mIsPromiscuous(false)
|
, mIsPromiscuous(false)
|
||||||
, mIsReady(false)
|
, mIsReady(false)
|
||||||
, mSupportsLogStream(false)
|
, mSupportsLogStream(false)
|
||||||
@@ -503,31 +249,9 @@ RadioSpinel::RadioSpinel(void)
|
|||||||
|
|
||||||
void RadioSpinel::Init(const char *aRadioFile, const char *aRadioConfig)
|
void RadioSpinel::Init(const char *aRadioFile, const char *aRadioConfig)
|
||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
// not allowed to initialize again.
|
SuccessOrExit(error = mHdlcInterface.Init(aRadioFile, aRadioConfig));
|
||||||
assert(mSockFd == -1);
|
|
||||||
|
|
||||||
VerifyOrExit(stat(aRadioFile, &st) == 0, perror("stat ncp file failed"); error = OT_ERROR_INVALID_ARGS);
|
|
||||||
|
|
||||||
if (S_ISCHR(st.st_mode))
|
|
||||||
{
|
|
||||||
mSockFd = OpenFile(aRadioFile, aRadioConfig);
|
|
||||||
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
|
||||||
}
|
|
||||||
#if OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
|
||||||
else if (S_ISREG(st.st_mode))
|
|
||||||
{
|
|
||||||
mSockFd = ForkPty(aRadioFile, aRadioConfig);
|
|
||||||
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
|
||||||
}
|
|
||||||
#endif // OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
|
|
||||||
else
|
|
||||||
{
|
|
||||||
otLogCritPlat("Radio file '%s' not supported", aRadioFile);
|
|
||||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
SuccessOrExit(error = SendReset());
|
SuccessOrExit(error = SendReset());
|
||||||
SuccessOrExit(error = WaitResponse());
|
SuccessOrExit(error = WaitResponse());
|
||||||
@@ -640,14 +364,7 @@ exit:
|
|||||||
|
|
||||||
void RadioSpinel::Deinit(void)
|
void RadioSpinel::Deinit(void)
|
||||||
{
|
{
|
||||||
// this function is only allowed after successfully initialized.
|
mHdlcInterface.Deinit();
|
||||||
assert(mSockFd != -1);
|
|
||||||
|
|
||||||
VerifyOrExit(0 == close(mSockFd), perror("close NCP"));
|
|
||||||
VerifyOrExit(-1 != wait(NULL), perror("wait NCP"));
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioSpinel::HandleSpinelFrame(const uint8_t *aBuffer, uint16_t aLength)
|
void RadioSpinel::HandleSpinelFrame(const uint8_t *aBuffer, uint16_t aLength)
|
||||||
@@ -946,33 +663,6 @@ exit:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioSpinel::DecodeHdlc(const uint8_t *aData, uint16_t aLength)
|
|
||||||
{
|
|
||||||
mIsDecoding = true;
|
|
||||||
mHdlcDecoder.Decode(aData, aLength);
|
|
||||||
mIsDecoding = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioSpinel::ReadAll(void)
|
|
||||||
{
|
|
||||||
uint8_t buf[kMaxSpinelFrame];
|
|
||||||
ssize_t rval = read(mSockFd, buf, sizeof(buf));
|
|
||||||
|
|
||||||
if (rval < 0)
|
|
||||||
{
|
|
||||||
perror("read spinel");
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rval > 0)
|
|
||||||
{
|
|
||||||
DecodeHdlc(buf, static_cast<uint16_t>(rval));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioSpinel::ProcessFrameQueue(void)
|
void RadioSpinel::ProcessFrameQueue(void)
|
||||||
{
|
{
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
@@ -1038,23 +728,25 @@ exit:
|
|||||||
|
|
||||||
void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout)
|
void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout)
|
||||||
{
|
{
|
||||||
|
int sockFd = mHdlcInterface.GetSocket();
|
||||||
|
|
||||||
if ((mState != OT_RADIO_STATE_TRANSMIT || mTxState == kSent))
|
if ((mState != OT_RADIO_STATE_TRANSMIT || mTxState == kSent))
|
||||||
{
|
{
|
||||||
FD_SET(mSockFd, &aReadFdSet);
|
FD_SET(sockFd, &aReadFdSet);
|
||||||
|
|
||||||
if (aMaxFd < mSockFd)
|
if (aMaxFd < sockFd)
|
||||||
{
|
{
|
||||||
aMaxFd = mSockFd;
|
aMaxFd = sockFd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
||||||
{
|
{
|
||||||
FD_SET(mSockFd, &aWriteFdSet);
|
FD_SET(sockFd, &aWriteFdSet);
|
||||||
|
|
||||||
if (aMaxFd < mSockFd)
|
if (aMaxFd < sockFd)
|
||||||
{
|
{
|
||||||
aMaxFd = mSockFd;
|
aMaxFd = sockFd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,14 +759,14 @@ void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMax
|
|||||||
|
|
||||||
void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet)
|
void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet)
|
||||||
{
|
{
|
||||||
if (FD_ISSET(mSockFd, &aReadFdSet) || !mFrameQueue.IsEmpty())
|
if (FD_ISSET(mHdlcInterface.GetSocket(), &aReadFdSet) || !mFrameQueue.IsEmpty())
|
||||||
{
|
{
|
||||||
// Handle frames received during WaitResponse()
|
// Handle frames received during WaitResponse()
|
||||||
ProcessFrameQueue();
|
ProcessFrameQueue();
|
||||||
|
|
||||||
if (FD_ISSET(mSockFd, &aReadFdSet))
|
if (FD_ISSET(mHdlcInterface.GetSocket(), &aReadFdSet))
|
||||||
{
|
{
|
||||||
ReadAll();
|
mHdlcInterface.Read();
|
||||||
ProcessFrameQueue();
|
ProcessFrameQueue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1097,7 +789,7 @@ void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet)
|
|||||||
mTxState = kIdle;
|
mTxState = kIdle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(mSockFd, &aWriteFdSet))
|
if (FD_ISSET(mHdlcInterface.GetSocket(), &aWriteFdSet))
|
||||||
{
|
{
|
||||||
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
||||||
{
|
{
|
||||||
@@ -1308,7 +1000,7 @@ otError RadioSpinel::WaitResponse(void)
|
|||||||
switch (event.mEvent)
|
switch (event.mEvent)
|
||||||
{
|
{
|
||||||
case OT_SIM_EVENT_RADIO_SPINEL_WRITE:
|
case OT_SIM_EVENT_RADIO_SPINEL_WRITE:
|
||||||
DecodeHdlc(event.mData, event.mDataLength);
|
mHdlcInterface.ProcessReadData(event.mData, event.mDataLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OT_SIM_EVENT_ALARM_FIRED:
|
case OT_SIM_EVENT_ALARM_FIRED:
|
||||||
@@ -1322,24 +1014,25 @@ otError RadioSpinel::WaitResponse(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else // OPENTHREAD_POSIX_VIRTUAL_TIME
|
#else // OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||||
|
int sockFd = mHdlcInterface.GetSocket();
|
||||||
fd_set read_fds;
|
fd_set read_fds;
|
||||||
fd_set error_fds;
|
fd_set error_fds;
|
||||||
int rval;
|
int rval;
|
||||||
|
|
||||||
FD_ZERO(&read_fds);
|
FD_ZERO(&read_fds);
|
||||||
FD_ZERO(&error_fds);
|
FD_ZERO(&error_fds);
|
||||||
FD_SET(mSockFd, &read_fds);
|
FD_SET(sockFd, &read_fds);
|
||||||
FD_SET(mSockFd, &error_fds);
|
FD_SET(sockFd, &error_fds);
|
||||||
|
|
||||||
rval = select(mSockFd + 1, &read_fds, NULL, &error_fds, &timeout);
|
rval = select(sockFd + 1, &read_fds, NULL, &error_fds, &timeout);
|
||||||
|
|
||||||
if (rval > 0)
|
if (rval > 0)
|
||||||
{
|
{
|
||||||
if (FD_ISSET(mSockFd, &read_fds))
|
if (FD_ISSET(sockFd, &read_fds))
|
||||||
{
|
{
|
||||||
ReadAll();
|
mHdlcInterface.Read();
|
||||||
}
|
}
|
||||||
else if (FD_ISSET(mSockFd, &error_fds))
|
else if (FD_ISSET(sockFd, &error_fds))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "NCP error\r\n");
|
fprintf(stderr, "NCP error\r\n");
|
||||||
exit(OT_EXIT_FAILURE);
|
exit(OT_EXIT_FAILURE);
|
||||||
@@ -1397,7 +1090,7 @@ spinel_tid_t RadioSpinel::GetNextTid(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method delievers the radio frame to transceiver.
|
* This method delivers the radio frame to transceiver.
|
||||||
*
|
*
|
||||||
* otPlatRadioTxStarted() is triggered immediately for now, which may be earlier than real started time.
|
* otPlatRadioTxStarted() is triggered immediately for now, which may be earlier than real started time.
|
||||||
*
|
*
|
||||||
@@ -1440,42 +1133,10 @@ void RadioSpinel::RadioTransmit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
otError RadioSpinel::WriteAll(const uint8_t *aBuffer, uint16_t aLength)
|
|
||||||
{
|
|
||||||
otError error = OT_ERROR_NONE;
|
|
||||||
|
|
||||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
|
||||||
otSimSendRadioSpinelWriteEvent(aBuffer, aLength);
|
|
||||||
#else
|
|
||||||
while (aLength)
|
|
||||||
{
|
|
||||||
ssize_t rval = write(mSockFd, aBuffer, aLength);
|
|
||||||
|
|
||||||
if (rval > 0)
|
|
||||||
{
|
|
||||||
aLength -= static_cast<uint16_t>(rval);
|
|
||||||
aBuffer += static_cast<uint16_t>(rval);
|
|
||||||
}
|
|
||||||
else if (rval < 0)
|
|
||||||
{
|
|
||||||
perror("send command failed");
|
|
||||||
ExitNow(error = OT_ERROR_FAILED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExitNow(error = OT_ERROR_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
#endif
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
otError RadioSpinel::SendReset(void)
|
otError RadioSpinel::SendReset(void)
|
||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
uint8_t buffer[kMaxSpinelFrame];
|
uint8_t buffer[kMaxSpinelFrame];
|
||||||
UartTxBuffer txBuffer;
|
|
||||||
spinel_ssize_t packed;
|
spinel_ssize_t packed;
|
||||||
|
|
||||||
// Pack the header, command and key
|
// Pack the header, command and key
|
||||||
@@ -1484,16 +1145,7 @@ otError RadioSpinel::SendReset(void)
|
|||||||
|
|
||||||
VerifyOrExit(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
|
VerifyOrExit(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
|
||||||
|
|
||||||
mHdlcEncoder.Init(txBuffer);
|
SuccessOrExit(error = mHdlcInterface.SendFrame(buffer, static_cast<uint16_t>(packed)));
|
||||||
for (spinel_ssize_t i = 0; i < packed; i++)
|
|
||||||
{
|
|
||||||
error = mHdlcEncoder.Encode(buffer[i], txBuffer);
|
|
||||||
VerifyOrExit(error == OT_ERROR_NONE);
|
|
||||||
}
|
|
||||||
mHdlcEncoder.Finalize(txBuffer);
|
|
||||||
|
|
||||||
error = WriteAll(txBuffer.GetBuffer(), txBuffer.GetLength());
|
|
||||||
VerifyOrExit(error == OT_ERROR_NONE);
|
|
||||||
|
|
||||||
sleep(0);
|
sleep(0);
|
||||||
|
|
||||||
@@ -1509,7 +1161,6 @@ otError RadioSpinel::SendCommand(uint32_t aCommand,
|
|||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
uint8_t buffer[kMaxSpinelFrame];
|
uint8_t buffer[kMaxSpinelFrame];
|
||||||
UartTxBuffer txBuffer;
|
|
||||||
spinel_ssize_t packed;
|
spinel_ssize_t packed;
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
|
|
||||||
@@ -1530,15 +1181,7 @@ otError RadioSpinel::SendCommand(uint32_t aCommand,
|
|||||||
offset += static_cast<uint16_t>(packed);
|
offset += static_cast<uint16_t>(packed);
|
||||||
}
|
}
|
||||||
|
|
||||||
mHdlcEncoder.Init(txBuffer);
|
error = mHdlcInterface.SendFrame(buffer, offset);
|
||||||
for (uint8_t i = 0; i < offset; i++)
|
|
||||||
{
|
|
||||||
error = mHdlcEncoder.Encode(buffer[i], txBuffer);
|
|
||||||
VerifyOrExit(error == OT_ERROR_NONE);
|
|
||||||
}
|
|
||||||
mHdlcEncoder.Finalize(txBuffer);
|
|
||||||
|
|
||||||
error = WriteAll(txBuffer.GetBuffer(), txBuffer.GetLength());
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return error;
|
return error;
|
||||||
@@ -1753,6 +1396,7 @@ otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} // namespace PosixApp
|
||||||
} // namespace ot
|
} // namespace ot
|
||||||
|
|
||||||
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
|
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
|
||||||
@@ -1960,7 +1604,7 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||||
void ot::RadioSpinel::Process(const Event &aEvent)
|
void ot::PosixApp::RadioSpinel::Process(const Event &aEvent)
|
||||||
{
|
{
|
||||||
if (!mFrameQueue.IsEmpty())
|
if (!mFrameQueue.IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -1970,7 +1614,7 @@ void ot::RadioSpinel::Process(const Event &aEvent)
|
|||||||
// The current event can be other event types
|
// The current event can be other event types
|
||||||
if (aEvent.mEvent == OT_SIM_EVENT_RADIO_SPINEL_WRITE)
|
if (aEvent.mEvent == OT_SIM_EVENT_RADIO_SPINEL_WRITE)
|
||||||
{
|
{
|
||||||
mHdlcDecoder.Decode(aEvent.mData, aEvent.mDataLength);
|
mHdlcInterface.ProcessReadData(aEvent.mData, aEvent.mDataLength);
|
||||||
ProcessFrameQueue();
|
ProcessFrameQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1998,7 +1642,7 @@ void ot::RadioSpinel::Process(const Event &aEvent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ot::RadioSpinel::Update(struct timeval &aTimeout)
|
void ot::PosixApp::RadioSpinel::Update(struct timeval &aTimeout)
|
||||||
{
|
{
|
||||||
// Prevent sleep event when transmitting
|
// Prevent sleep event when transmitting
|
||||||
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
if (mState == OT_RADIO_STATE_TRANSMIT && mTxState == kIdle)
|
||||||
|
|||||||
@@ -37,12 +37,13 @@
|
|||||||
#include <openthread/platform/radio.h>
|
#include <openthread/platform/radio.h>
|
||||||
|
|
||||||
#include "frame_queue.hpp"
|
#include "frame_queue.hpp"
|
||||||
#include "hdlc.hpp"
|
#include "hdlc_interface.hpp"
|
||||||
#include "spinel.h"
|
#include "spinel.h"
|
||||||
|
|
||||||
namespace ot {
|
namespace ot {
|
||||||
|
namespace PosixApp {
|
||||||
|
|
||||||
class RadioSpinel
|
class RadioSpinel : public HdlcInterface::Callbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -439,10 +440,19 @@ public:
|
|||||||
otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen);
|
otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void HandleSpinelFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kMaxSpinelFrame = 2048, ///< Max size in bytes for transferring spinel frames.
|
kMaxSpinelFrame = HdlcInterface::kMaxFrameSize,
|
||||||
kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds.
|
kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds.
|
||||||
kVersionStringSize = 128, ///< Max size of version string.
|
kVersionStringSize = 128, ///< Max size of version string.
|
||||||
kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
|
kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
|
||||||
@@ -451,9 +461,6 @@ private:
|
|||||||
otError CheckSpinelVersion(void);
|
otError CheckSpinelVersion(void);
|
||||||
otError CheckCapabilities(void);
|
otError CheckCapabilities(void);
|
||||||
otError CheckRadioCapabilities(void);
|
otError CheckRadioCapabilities(void);
|
||||||
void DecodeHdlc(const uint8_t *aData, uint16_t aLength);
|
|
||||||
void ReadAll(void);
|
|
||||||
otError WriteAll(const uint8_t *aBuffer, uint16_t aLength);
|
|
||||||
void ProcessFrameQueue(void);
|
void ProcessFrameQueue(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -531,7 +538,6 @@ private:
|
|||||||
{
|
{
|
||||||
static_cast<RadioSpinel *>(aContext)->HandleSpinelFrame(aBuffer, aLength);
|
static_cast<RadioSpinel *>(aContext)->HandleSpinelFrame(aBuffer, aLength);
|
||||||
}
|
}
|
||||||
void HandleSpinelFrame(const uint8_t *aBuffer, uint16_t aLength);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns if the property changed event is safe to be handled now.
|
* This method returns if the property changed event is safe to be handled now.
|
||||||
@@ -546,7 +552,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool IsSafeToHandleNow(spinel_prop_key_t aKey) const
|
bool IsSafeToHandleNow(spinel_prop_key_t aKey) const
|
||||||
{
|
{
|
||||||
return !((mIsDecoding || mWaitingKey != SPINEL_PROP_LAST_STATUS) &&
|
return !((mHdlcInterface.IsDecoding() || mWaitingKey != SPINEL_PROP_LAST_STATUS) &&
|
||||||
(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT));
|
(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,6 +568,8 @@ private:
|
|||||||
|
|
||||||
otInstance *mInstance;
|
otInstance *mInstance;
|
||||||
|
|
||||||
|
HdlcInterface mHdlcInterface;
|
||||||
|
|
||||||
uint16_t mCmdTidsInUse; ///< Used transaction ids.
|
uint16_t mCmdTidsInUse; ///< Used transaction ids.
|
||||||
spinel_tid_t mCmdNextTid; ///< Next available transaction id.
|
spinel_tid_t mCmdNextTid; ///< Next available transaction id.
|
||||||
spinel_tid_t mTxRadioTid; ///< The transaction id used to send a radio frame.
|
spinel_tid_t mTxRadioTid; ///< The transaction id used to send a radio frame.
|
||||||
@@ -572,10 +580,7 @@ private:
|
|||||||
uint32_t mExpectedCommand; ///< Expected response command of current transaction.
|
uint32_t mExpectedCommand; ///< Expected response command of current transaction.
|
||||||
otError mError; ///< The result of current transaction.
|
otError mError; ///< The result of current transaction.
|
||||||
|
|
||||||
uint8_t mHdlcBuffer[kMaxSpinelFrame];
|
FrameQueue mFrameQueue;
|
||||||
Hdlc::Decoder mHdlcDecoder;
|
|
||||||
Hdlc::Encoder mHdlcEncoder;
|
|
||||||
FrameQueue mFrameQueue;
|
|
||||||
|
|
||||||
uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||||
uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||||
@@ -593,10 +598,8 @@ private:
|
|||||||
otError mTxError;
|
otError mTxError;
|
||||||
char mVersion[kVersionStringSize];
|
char mVersion[kVersionStringSize];
|
||||||
|
|
||||||
int mSockFd;
|
|
||||||
otRadioState mState;
|
otRadioState mState;
|
||||||
bool mIsAckRequested : 1; ///< Ack requested.
|
bool mIsAckRequested : 1; ///< Ack requested.
|
||||||
bool mIsDecoding : 1; ///< Decoding hdlc frames.
|
|
||||||
bool mIsPromiscuous : 1; ///< Promiscuous mode.
|
bool mIsPromiscuous : 1; ///< Promiscuous mode.
|
||||||
bool mIsReady : 1; ///< NCP ready.
|
bool mIsReady : 1; ///< NCP ready.
|
||||||
bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
|
bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
|
||||||
@@ -608,6 +611,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace PosixApp
|
||||||
} // namespace ot
|
} // namespace ot
|
||||||
|
|
||||||
#endif // RADIO_SPINEL_HPP_
|
#endif // RADIO_SPINEL_HPP_
|
||||||
|
|||||||
Reference in New Issue
Block a user