mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[posix] add radio url (#4935)
Radio url provides a unified interface for users to specify the radio peripheral device and arguments to the OpenThread core stack.
This commit is contained in:
@@ -281,6 +281,7 @@ LOCAL_SRC_FILES := \
|
||||
src/posix/platform/misc.cpp \
|
||||
src/posix/platform/netif.cpp \
|
||||
src/posix/platform/radio.cpp \
|
||||
src/posix/platform/radio_url.cpp \
|
||||
src/posix/platform/settings.cpp \
|
||||
src/posix/platform/spi_interface.cpp \
|
||||
src/posix/platform/system.cpp \
|
||||
|
||||
@@ -93,12 +93,12 @@ EOF
|
||||
|
||||
echo "Step 2. Start retrieving dataset from Radio..."
|
||||
RADIO_NCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-ncp-ftd)"
|
||||
"$(pwd)/$(ls output/posix/*linux*/bin/ot-ncp)" -n --radio-version --ncp-dataset -- "${RADIO_NCP_PATH}" 1
|
||||
"$(pwd)/$(ls output/posix/*linux*/bin/ot-ncp)" -n --radio-version "spinel+hdlc+forkpty://${RADIO_NCP_PATH}?arg=1&ncp-dataset=1"
|
||||
|
||||
echo "Step 3. Start posix app and check whether PAN dataset is the same..."
|
||||
RADIO_RCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-rcp)"
|
||||
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) ${RADIO_RCP_PATH} 1"
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) spinel+hdlc+forkpty://${RADIO_RCP_PATH}?arg=1"
|
||||
|
||||
expect <<EOF
|
||||
spawn ${OT_CLI_CMD}
|
||||
@@ -126,8 +126,9 @@ expect eof
|
||||
EOF
|
||||
|
||||
echo "Step 4. Start posix app and check whether it can get radio firmware version..."
|
||||
RADIO_VERSION="$("$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)" -n --radio-version --ncp-dataset -- "${RADIO_RCP_PATH}" 1)" || true
|
||||
test -n "${RADIO_VERSION}"
|
||||
RADIO_VERSION="$("$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)" -n --radio-version "spinel+hdlc+forkpty://${RADIO_RCP_PATH}?arg=1&ncp-dataset=1")" || true
|
||||
echo "${RADIO_VERSION}"
|
||||
test -n "{RADIO_VERSION}"
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -81,12 +81,10 @@ check()
|
||||
# Cover setting a valid network interface name.
|
||||
readonly VALID_NETIF_NAME="wan$(date +%H%M%S)"
|
||||
|
||||
local options=(
|
||||
'--max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26'
|
||||
)
|
||||
RADIO_URL="spinel+hdlc+uart://${CORE_PTY}?max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26"
|
||||
|
||||
if [[ ${DAEMON} == 1 ]]; then
|
||||
sudo "$(pwd)/$(ls output/posix/*linux*/bin/ot-daemon)" "${options[@]}" -I "${VALID_NETIF_NAME}" "${CORE_PTY}" &
|
||||
sudo "$(pwd)/$(ls output/posix/*linux*/bin/ot-daemon)" -I "${VALID_NETIF_NAME}" "${RADIO_URL}" &
|
||||
sleep 1
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-ctl)"
|
||||
sudo "${OT_CLI_CMD}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl'
|
||||
@@ -96,14 +94,14 @@ check()
|
||||
sudo "${OT_CLI_CMD}" factoryreset
|
||||
else
|
||||
OT_CLI="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)"
|
||||
sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${CORE_PTY}"
|
||||
sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${RADIO_URL}"
|
||||
|
||||
# Cover setting a too long(max is 15 characters) network interface name.
|
||||
# Expect exit code to be 2(OT_EXIT_INVALID_ARGUMENTS).
|
||||
readonly INVALID_NETIF_NAME="wan0123456789123"
|
||||
sudo "${OT_CLI}" -I "${INVALID_NETIF_NAME}" -n "${CORE_PTY}" || test $? = 2
|
||||
sudo "${OT_CLI}" -I "${INVALID_NETIF_NAME}" -n "${RADIO_URL}" || test $? = 2
|
||||
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) ${CORE_PTY}"
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) ${RADIO_URL}"
|
||||
fi
|
||||
|
||||
sudo expect <<EOF | tee "${OT_OUTPUT}" &
|
||||
|
||||
+6
-115
@@ -75,6 +75,7 @@
|
||||
#error "Unknown posix app type!"
|
||||
#endif
|
||||
#include <common/code_utils.hpp>
|
||||
#include <common/logging.hpp>
|
||||
#include <lib/platform/exit_code.h>
|
||||
#include <openthread/openthread-system.h>
|
||||
|
||||
@@ -102,88 +103,31 @@ void __gcov_flush();
|
||||
enum
|
||||
{
|
||||
ARG_PRINT_RADIO_VERSION = 1001,
|
||||
ARG_NO_RADIO_RESET = 1002,
|
||||
ARG_RESTORE_NCP_DATASET = 1003,
|
||||
ARG_SPI_GPIO_INT_DEV = 1011,
|
||||
ARG_SPI_GPIO_INT_LINE = 1012,
|
||||
ARG_SPI_GPIO_RESET_DEV = 1013,
|
||||
ARG_SPI_GPIO_RESET_LINE = 1014,
|
||||
ARG_SPI_MODE = 1015,
|
||||
ARG_SPI_SPEED = 1016,
|
||||
ARG_SPI_CS_DELAY = 1017,
|
||||
ARG_SPI_RESET_DELAY = 1018,
|
||||
ARG_SPI_ALIGN_ALLOWANCE = 1019,
|
||||
ARG_SPI_SMALL_PACKET = 1020,
|
||||
ARG_MAX_POWER_TABLE = 1021,
|
||||
|
||||
};
|
||||
|
||||
static const struct option kOptions[] = {{"debug-level", required_argument, NULL, 'd'},
|
||||
{"dry-run", no_argument, NULL, 'n'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"interface-name", required_argument, NULL, 'I'},
|
||||
{"no-reset", no_argument, NULL, ARG_NO_RADIO_RESET},
|
||||
{"radio-version", no_argument, NULL, ARG_PRINT_RADIO_VERSION},
|
||||
{"ncp-dataset", no_argument, NULL, ARG_RESTORE_NCP_DATASET},
|
||||
{"time-speed", required_argument, NULL, 's'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
|
||||
{"max-power-table", required_argument, NULL, ARG_MAX_POWER_TABLE},
|
||||
#endif
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
|
||||
{"gpio-int-dev", required_argument, NULL, ARG_SPI_GPIO_INT_DEV},
|
||||
{"gpio-int-line", required_argument, NULL, ARG_SPI_GPIO_INT_LINE},
|
||||
{"gpio-reset-dev", required_argument, NULL, ARG_SPI_GPIO_RESET_DEV},
|
||||
{"gpio-reset-line", required_argument, NULL, ARG_SPI_GPIO_RESET_LINE},
|
||||
{"spi-mode", required_argument, NULL, ARG_SPI_MODE},
|
||||
{"spi-speed", required_argument, NULL, ARG_SPI_SPEED},
|
||||
{"spi-cs-delay", required_argument, NULL, ARG_SPI_CS_DELAY},
|
||||
{"spi-reset-delay", required_argument, NULL, ARG_SPI_RESET_DELAY},
|
||||
{"spi-align-allowance", required_argument, NULL, ARG_SPI_ALIGN_ALLOWANCE},
|
||||
{"spi-small-packet", required_argument, NULL, ARG_SPI_SMALL_PACKET},
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
{
|
||||
fprintf(aStream,
|
||||
"Syntax:\n"
|
||||
" %s [Options] NodeId|Device|Command [DeviceConfig|CommandArgs]\n"
|
||||
" %s [Options] RadioURL\n"
|
||||
"Options:\n"
|
||||
" -d --debug-level Debug level of logging.\n"
|
||||
" -h --help Display this usage information.\n"
|
||||
" -I --interface-name name Thread network interface name.\n"
|
||||
" -n --dry-run Just verify if arguments is valid and radio spinel is compatible.\n"
|
||||
" --no-reset Do not send Spinel reset command to RCP on initialization.\n"
|
||||
" --radio-version Print radio firmware version.\n"
|
||||
" --ncp-dataset Retrieve and save NCP dataset to file.\n"
|
||||
" -s --time-speed factor Time speed up factor.\n"
|
||||
" -v --verbose Also log to stderr.\n",
|
||||
aProgramName);
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
|
||||
fprintf(aStream,
|
||||
" --gpio-int-dev[=gpio-device-path]\n"
|
||||
" Specify a path to the Linux sysfs-exported GPIO device for the\n"
|
||||
" `I̅N̅T̅` pin. If not specified, `SPI` interface will fall back to\n"
|
||||
" polling, which is inefficient.\n"
|
||||
" --gpio-int-line[=line-offset]\n"
|
||||
" The offset index of `I̅N̅T̅` pin for the associated GPIO device.\n"
|
||||
" If not specified, `SPI` interface will fall back to polling,\n"
|
||||
" which is inefficient.\n"
|
||||
" --gpio-reset-dev[=gpio-device-path]\n"
|
||||
" Specify a path to the Linux sysfs-exported GPIO device for the\n"
|
||||
" `R̅E̅S̅` pin.\n"
|
||||
" --gpio-reset-line[=line-offset]"
|
||||
" The offset index of `R̅E̅S̅` pin for the associated GPIO device.\n"
|
||||
" --spi-mode[=mode] Specify the SPI mode to use (0-3).\n"
|
||||
" --spi-speed[=hertz] Specify the SPI speed in hertz.\n"
|
||||
" --spi-cs-delay[=usec] Specify the delay after C̅S̅ assertion, in µsec.\n"
|
||||
" --spi-reset-delay[=ms] Specify the delay after R̅E̅S̅E̅T̅ assertion, in milliseconds.\n"
|
||||
" --spi-align-allowance[=n] Specify the maximum number of 0xFF bytes to clip from start of\n"
|
||||
" MISO frame. Max value is 16.\n"
|
||||
" --spi-small-packet=[n] Specify the smallest packet we can receive in a single transaction.\n"
|
||||
" (larger packets will require two transactions). Default value is 32.\n");
|
||||
#endif
|
||||
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
|
||||
fprintf(aStream,
|
||||
" --max-power-table Max power for channels in ascending order separated by commas,\n"
|
||||
@@ -191,6 +135,7 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
" the last value will be applied to all remaining channels.\n"
|
||||
" Special value 0x7f disables a channel.\n");
|
||||
#endif
|
||||
fprintf(aStream, "%s", otSysGetRadioUrlHelpString());
|
||||
exit(aExitCode);
|
||||
}
|
||||
|
||||
@@ -198,15 +143,8 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
{
|
||||
memset(aConfig, 0, sizeof(*aConfig));
|
||||
|
||||
aConfig->mPlatformConfig.mSpeedUpFactor = 1;
|
||||
aConfig->mPlatformConfig.mResetRadio = true;
|
||||
aConfig->mPlatformConfig.mSpiSpeed = OT_PLATFORM_CONFIG_SPI_DEFAULT_SPEED_HZ;
|
||||
aConfig->mPlatformConfig.mSpiCsDelay = OT_PLATFORM_CONFIG_SPI_DEFAULT_CS_DELAY_US;
|
||||
aConfig->mPlatformConfig.mSpiResetDelay = OT_PLATFORM_CONFIG_SPI_DEFAULT_RESET_DELAY_MS;
|
||||
aConfig->mPlatformConfig.mSpiAlignAllowance = OT_PLATFORM_CONFIG_SPI_DEFAULT_ALIGN_ALLOWANCE;
|
||||
aConfig->mPlatformConfig.mSpiSmallPacketSize = OT_PLATFORM_CONFIG_SPI_DEFAULT_SMALL_PACKET_SIZE;
|
||||
aConfig->mPlatformConfig.mSpiMode = OT_PLATFORM_CONFIG_SPI_DEFAULT_MODE;
|
||||
aConfig->mLogLevel = OT_LOG_LEVEL_CRIT;
|
||||
aConfig->mPlatformConfig.mSpeedUpFactor = 1;
|
||||
aConfig->mLogLevel = OT_LOG_LEVEL_CRIT;
|
||||
|
||||
optind = 1;
|
||||
|
||||
@@ -253,47 +191,6 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
case ARG_PRINT_RADIO_VERSION:
|
||||
aConfig->mPrintRadioVersion = true;
|
||||
break;
|
||||
case ARG_NO_RADIO_RESET:
|
||||
aConfig->mPlatformConfig.mResetRadio = false;
|
||||
break;
|
||||
case ARG_RESTORE_NCP_DATASET:
|
||||
aConfig->mPlatformConfig.mRestoreDatasetFromNcp = true;
|
||||
break;
|
||||
case ARG_SPI_GPIO_INT_DEV:
|
||||
aConfig->mPlatformConfig.mSpiGpioIntDevice = optarg;
|
||||
break;
|
||||
case ARG_SPI_GPIO_INT_LINE:
|
||||
aConfig->mPlatformConfig.mSpiGpioIntLine = (uint8_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_GPIO_RESET_DEV:
|
||||
aConfig->mPlatformConfig.mSpiGpioResetDevice = optarg;
|
||||
break;
|
||||
case ARG_SPI_GPIO_RESET_LINE:
|
||||
aConfig->mPlatformConfig.mSpiGpioResetLine = (uint8_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_MODE:
|
||||
aConfig->mPlatformConfig.mSpiMode = (uint8_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_SPEED:
|
||||
aConfig->mPlatformConfig.mSpiSpeed = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_CS_DELAY:
|
||||
aConfig->mPlatformConfig.mSpiCsDelay = (uint16_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_RESET_DELAY:
|
||||
aConfig->mPlatformConfig.mSpiResetDelay = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_ALIGN_ALLOWANCE:
|
||||
aConfig->mPlatformConfig.mSpiAlignAllowance = (uint8_t)atoi(optarg);
|
||||
break;
|
||||
case ARG_SPI_SMALL_PACKET:
|
||||
aConfig->mPlatformConfig.mSpiSmallPacketSize = (uint8_t)atoi(optarg);
|
||||
break;
|
||||
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
|
||||
case ARG_MAX_POWER_TABLE:
|
||||
aConfig->mPlatformConfig.mMaxPowerTable = optarg;
|
||||
break;
|
||||
#endif
|
||||
case '?':
|
||||
PrintUsage(aArgVector[0], stderr, OT_EXIT_INVALID_ARGUMENTS);
|
||||
break;
|
||||
@@ -307,13 +204,7 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
{
|
||||
PrintUsage(aArgVector[0], stderr, OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
aConfig->mPlatformConfig.mRadioFile = aArgVector[optind];
|
||||
|
||||
if (optind + 1 < aArgCount)
|
||||
{
|
||||
aConfig->mPlatformConfig.mRadioConfig = aArgVector[optind + 1];
|
||||
}
|
||||
aConfig->mPlatformConfig.mRadioUrl = aArgVector[optind];
|
||||
}
|
||||
|
||||
static otInstance *InitInstance(int aArgCount, char *aArgVector[])
|
||||
|
||||
@@ -67,6 +67,7 @@ add_library(openthread-posix
|
||||
misc.cpp
|
||||
netif.cpp
|
||||
radio.cpp
|
||||
radio_url.cpp
|
||||
settings.cpp
|
||||
spi_interface.cpp
|
||||
system.cpp
|
||||
|
||||
@@ -50,6 +50,7 @@ libopenthread_posix_a_SOURCES = \
|
||||
misc.cpp \
|
||||
netif.cpp \
|
||||
radio.cpp \
|
||||
radio_url.cpp \
|
||||
settings.cpp \
|
||||
spi_interface.cpp \
|
||||
system.cpp \
|
||||
@@ -62,6 +63,7 @@ noinst_HEADERS = \
|
||||
hdlc_interface.hpp \
|
||||
openthread-posix-config.h \
|
||||
platform-posix.h \
|
||||
radio_url.hpp \
|
||||
$(NULL)
|
||||
|
||||
openthread_HEADERS = \
|
||||
@@ -75,7 +77,7 @@ if OPENTHREAD_BUILD_COVERAGE
|
||||
CLEANFILES = $(wildcard *.gcda *.gcno)
|
||||
endif # OPENTHREAD_BUILD_COVERAGE
|
||||
|
||||
check_PROGRAMS = test-settings
|
||||
check_PROGRAMS = test-settings test-radio-url
|
||||
|
||||
test_settings_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
@@ -90,8 +92,22 @@ test_settings_SOURCES = \
|
||||
settings.cpp \
|
||||
$(NULL)
|
||||
|
||||
test_radio_url_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/core \
|
||||
-I$(top_srcdir)/src/posix/platform/include \
|
||||
-DOPENTHREAD_CONFIG_LOG_PLATFORM=0 \
|
||||
-DSELF_TEST \
|
||||
$(NULL)
|
||||
|
||||
test_radio_url_SOURCES = \
|
||||
radio_url.cpp \
|
||||
$(NULL)
|
||||
|
||||
TESTS = \
|
||||
test-settings \
|
||||
test-radio-url \
|
||||
$(NULL)
|
||||
|
||||
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
|
||||
|
||||
@@ -138,30 +138,30 @@ HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
{
|
||||
}
|
||||
|
||||
otError HdlcInterface::Init(const otPlatformConfig &aPlatformConfig)
|
||||
otError HdlcInterface::Init(Arguments &aArguments)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
struct stat st;
|
||||
|
||||
VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY);
|
||||
|
||||
VerifyOrDie(stat(aPlatformConfig.mRadioFile, &st) == 0, OT_EXIT_INVALID_ARGUMENTS);
|
||||
VerifyOrDie(stat(aArguments.GetPath(), &st) == 0, OT_EXIT_INVALID_ARGUMENTS);
|
||||
|
||||
if (S_ISCHR(st.st_mode))
|
||||
{
|
||||
mSockFd = OpenFile(aPlatformConfig.mRadioFile, aPlatformConfig.mRadioConfig);
|
||||
mSockFd = OpenFile(aArguments.GetPath(), aArguments);
|
||||
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE
|
||||
else if (S_ISREG(st.st_mode))
|
||||
{
|
||||
mSockFd = ForkPty(aPlatformConfig.mRadioFile, aPlatformConfig.mRadioConfig);
|
||||
mSockFd = ForkPty(aArguments.GetPath(), aArguments.GetValue("arg"));
|
||||
VerifyOrExit(mSockFd != -1, error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE
|
||||
else
|
||||
{
|
||||
otLogCritPlat("Radio file '%s' not supported", aPlatformConfig.mRadioFile);
|
||||
otLogCritPlat("Radio file '%s' not supported", aArguments.GetPath());
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
@@ -407,10 +407,12 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||
int HdlcInterface::OpenFile(const char *aFile, Arguments &aArguments)
|
||||
{
|
||||
int fd = -1;
|
||||
int rval = 0;
|
||||
int fd = -1;
|
||||
int rval = 0;
|
||||
const char *parity = aArguments.GetValue("uart-parity");
|
||||
uint32_t baudrate = 115200;
|
||||
|
||||
fd = open(aFile, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
@@ -423,10 +425,8 @@ int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||
{
|
||||
struct termios tios;
|
||||
|
||||
unsigned int speed = 115200;
|
||||
int cstopb = 1;
|
||||
char parity = 'N';
|
||||
char flow = 'N';
|
||||
unsigned int speed = 115200;
|
||||
int stopBit = 1;
|
||||
|
||||
VerifyOrExit((rval = tcgetattr(fd, &tios)) == 0, OT_NOOP);
|
||||
|
||||
@@ -434,29 +434,29 @@ int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||
|
||||
tios.c_cflag = CS8 | HUPCL | CREAD | CLOCAL;
|
||||
|
||||
// example: 115200N1H
|
||||
if (aConfig != NULL)
|
||||
if (parity)
|
||||
{
|
||||
sscanf(aConfig, "%u%c%d%c", &speed, &parity, &cstopb, &flow);
|
||||
if (strncmp(parity, "odd", 3) == 0)
|
||||
{
|
||||
tios.c_cflag |= PARENB;
|
||||
tios.c_cflag |= PARODD;
|
||||
}
|
||||
else if (strncmp(parity, "even", 4) == 0)
|
||||
{
|
||||
tios.c_cflag |= PARENB;
|
||||
}
|
||||
else
|
||||
{
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
}
|
||||
|
||||
switch (parity)
|
||||
if (aArguments.GetValue("uart-stop"))
|
||||
{
|
||||
case 'N':
|
||||
break;
|
||||
case 'E':
|
||||
tios.c_cflag |= PARENB;
|
||||
break;
|
||||
case 'O':
|
||||
tios.c_cflag |= (PARENB | PARODD);
|
||||
break;
|
||||
default:
|
||||
// not supported
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
break;
|
||||
stopBit = atoi(aArguments.GetValue("uart-stop"));
|
||||
}
|
||||
|
||||
switch (cstopb)
|
||||
switch (stopBit)
|
||||
{
|
||||
case 1:
|
||||
tios.c_cflag &= static_cast<unsigned long>(~CSTOPB);
|
||||
@@ -469,7 +469,11 @@ int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (speed)
|
||||
if (aArguments.GetValue("baudrate"))
|
||||
{
|
||||
baudrate = static_cast<uint32_t>(atoi(aArguments.GetValue("baudrate")));
|
||||
}
|
||||
switch (baudrate)
|
||||
{
|
||||
case 9600:
|
||||
speed = B9600;
|
||||
@@ -556,17 +560,9 @@ int HdlcInterface::OpenFile(const char *aFile, const char *aConfig)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (flow)
|
||||
if (aArguments.GetValue("uart-flow-control") != NULL)
|
||||
{
|
||||
case 'N':
|
||||
break;
|
||||
case 'H':
|
||||
tios.c_cflag |= CRTSCTS;
|
||||
break;
|
||||
default:
|
||||
// not supported
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit((rval = cfsetspeed(&tios, static_cast<speed_t>(speed))) == 0, perror("cfsetspeed"));
|
||||
|
||||
@@ -74,14 +74,14 @@ public:
|
||||
*
|
||||
* @note This method should be called before reading and sending spinel frames to the interface.
|
||||
*
|
||||
* @param[in] aPlatformConfig Platform configuration structure.
|
||||
* @param[in] aArguments Arguments parsed from radio url.
|
||||
*
|
||||
* @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 otPlatformConfig &aPlatformConfig);
|
||||
otError Init(Arguments &aArguments);
|
||||
|
||||
/**
|
||||
* This method deinitializes the interface to the RCP.
|
||||
@@ -198,7 +198,7 @@ private:
|
||||
static void HandleHdlcFrame(void *aContext, otError aError);
|
||||
void HandleHdlcFrame(otError aError);
|
||||
|
||||
static int OpenFile(const char *aFile, const char *aConfig);
|
||||
static int OpenFile(const char *aFile, Arguments &aArguments);
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE
|
||||
static int ForkPty(const char *aCommand, const char *aArguments);
|
||||
#endif
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <setjmp.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
@@ -69,25 +70,9 @@ enum
|
||||
*/
|
||||
typedef struct otPlatformConfig
|
||||
{
|
||||
uint64_t mNodeId; ///< Unique node ID.
|
||||
uint32_t mSpeedUpFactor; ///< Speed up factor.
|
||||
const char *mInterfaceName; ///< Thread network interface name.
|
||||
const char *mRadioFile; ///< Radio file path.
|
||||
const char *mRadioConfig; ///< Radio configurations.
|
||||
const char *mMaxPowerTable; ///< Radio max transmit power table.
|
||||
bool mResetRadio; ///< Whether to reset RCP when initializing.
|
||||
bool mRestoreDatasetFromNcp; ///< Whether to retrieve dataset from NCP and save to file.
|
||||
|
||||
char * mSpiGpioIntDevice; ///< Path to the Linux GPIO character device for the `I̅N̅T̅` pin.
|
||||
char * mSpiGpioResetDevice; ///< Path to the Linux GPIO character device for the `R̅E̅S̅E̅T̅` pin.
|
||||
uint8_t mSpiGpioIntLine; ///< Line index of the `I̅N̅T̅` pin for the associated GPIO character device.
|
||||
uint8_t mSpiGpioResetLine; ///< Line index of the `R̅E̅S̅E̅T̅` pin for the associated GPIO character device.
|
||||
uint8_t mSpiMode; ///< SPI mode to use (0-3).
|
||||
uint32_t mSpiSpeed; ///< SPI speed in hertz.
|
||||
uint32_t mSpiResetDelay; ///< The delay after R̅E̅S̅E̅T̅ assertion, in miliseconds.
|
||||
uint16_t mSpiCsDelay; ///< The delay after SPI C̅S̅ assertion, in µsec.
|
||||
uint8_t mSpiAlignAllowance; ///< Maximum number of 0xFF bytes to clip from start of MISO frame.
|
||||
uint8_t mSpiSmallPacketSize; ///< Smallest SPI packet size we can receive in a single transaction.
|
||||
uint32_t mSpeedUpFactor; ///< Speed up factor.
|
||||
const char *mInterfaceName; ///< Thread network interface name.
|
||||
const char *mRadioUrl; ///< Radio url.
|
||||
} otPlatformConfig;
|
||||
|
||||
/**
|
||||
@@ -156,6 +141,14 @@ int otSysMainloopPoll(otSysMainloopContext *aMainloop);
|
||||
*/
|
||||
void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMainloop);
|
||||
|
||||
/**
|
||||
* This method returns the radio url help string.
|
||||
*
|
||||
* @returns the radio url help string.
|
||||
*
|
||||
*/
|
||||
const char *otSysGetRadioUrlHelpString(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end of extern "C"
|
||||
#endif
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
#include "common/logging.hpp"
|
||||
|
||||
#include "radio_url.hpp"
|
||||
#include "lib/platform/exit_code.h"
|
||||
|
||||
/**
|
||||
@@ -162,7 +163,7 @@ void platformAlarmAdvanceNow(uint64_t aDelta);
|
||||
* @param[in] aPlatformConfig Platform configuration structure.
|
||||
*
|
||||
*/
|
||||
void platformRadioInit(const otPlatformConfig *aPlatformConfig);
|
||||
void platformRadioInit(otPosixRadioArguments *aArguments);
|
||||
|
||||
/**
|
||||
* This function shuts down the radio service used by OpenThread.
|
||||
|
||||
@@ -94,18 +94,22 @@ void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
|
||||
SuccessOrDie(sRadioSpinel.SetPromiscuous(aEnable));
|
||||
}
|
||||
|
||||
void platformRadioInit(const otPlatformConfig *aPlatformConfig)
|
||||
void platformRadioInit(otPosixRadioArguments *aArguments)
|
||||
{
|
||||
ot::Posix::Arguments *args = reinterpret_cast<ot::Posix::Arguments *>(aArguments);
|
||||
bool resetRadio = (args->GetValue("no-reset") == NULL);
|
||||
bool restoreDataset = (args->GetValue("ncp-dataset") != NULL);
|
||||
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
|
||||
uint8_t channel = ot::Radio::kChannelMin;
|
||||
int8_t power = ot::Posix::MaxPowerTable::kPowerDefault;
|
||||
uint8_t channel = ot::Radio::kChannelMin;
|
||||
int8_t power = ot::Posix::MaxPowerTable::kPowerDefault;
|
||||
const char *maxPowerTable = args->GetValue("max-power-table");
|
||||
|
||||
if (aPlatformConfig->mMaxPowerTable != NULL)
|
||||
if (maxPowerTable != NULL)
|
||||
{
|
||||
const char *str = NULL;
|
||||
|
||||
for (str = strtok(const_cast<char *>(aPlatformConfig->mMaxPowerTable), ",");
|
||||
str != NULL && channel <= ot::Radio::kChannelMax; str = strtok(NULL, ","))
|
||||
for (str = strtok(const_cast<char *>(maxPowerTable), ","); str != NULL && channel <= ot::Radio::kChannelMax;
|
||||
str = strtok(NULL, ","))
|
||||
{
|
||||
power = static_cast<int8_t>(strtol(str, NULL, 0));
|
||||
sMaxPowerTable.SetTransmitPower(channel++, power);
|
||||
@@ -122,8 +126,8 @@ void platformRadioInit(const otPlatformConfig *aPlatformConfig)
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(*aPlatformConfig));
|
||||
sRadioSpinel.Init(aPlatformConfig->mResetRadio, aPlatformConfig->mRestoreDatasetFromNcp);
|
||||
SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(*args));
|
||||
sRadioSpinel.Init(resetRadio, restoreDataset);
|
||||
}
|
||||
|
||||
void platformRadioDeinit(void)
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#include "posix/platform/radio_url.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/openthread-system.h>
|
||||
|
||||
#include "core/common/code_utils.hpp"
|
||||
#include "posix/platform/platform-posix.h"
|
||||
|
||||
const char *otSysGetRadioUrlHelpString(void)
|
||||
{
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
|
||||
#define RADIO_URL_HELP_BUS \
|
||||
"Radio URL:\n" \
|
||||
"spinel+spi://${PATH_TO_SPI_DEVICE}?${arguments}\n" \
|
||||
"arguments:\n" \
|
||||
" gpio-int-device[=gpio-device-path]\n" \
|
||||
" Specify a path to the Linux sysfs-exported GPIO device for the\n" \
|
||||
" `I̅N̅T̅` pin. If not specified, `SPI` interface will fall back to\n" \
|
||||
" polling, which is inefficient.\n" \
|
||||
" gpio-int-line[=line-offset]\n" \
|
||||
" The offset index of `I̅N̅T̅` pin for the associated GPIO device.\n" \
|
||||
" If not specified, `SPI` interface will fall back to polling,\n" \
|
||||
" which is inefficient.\n" \
|
||||
" gpio-reset-dev[=gpio-device-path]\n" \
|
||||
" Specify a path to the Linux sysfs-exported GPIO device for the\n" \
|
||||
" `R̅E̅S̅` pin.\n" \
|
||||
" gpio-reset-line[=line-offset]" \
|
||||
" The offset index of `R̅E̅S̅` pin for the associated GPIO device.\n" \
|
||||
" spi-mode[=mode] Specify the SPI mode to use (0-3).\n" \
|
||||
" spi-speed[=hertz] Specify the SPI speed in hertz.\n" \
|
||||
" spi-cs-delay[=usec] Specify the delay after C̅S̅ assertion, in µsec.\n" \
|
||||
" spi-reset-delay[=ms] Specify the delay after R̅E̅S̅E̅T̅ assertion, in milliseconds.\n" \
|
||||
" spi-align-allowance[=n] Specify the maximum number of 0xFF bytes to clip from start of\n" \
|
||||
" MISO frame. Max value is 16.\n" \
|
||||
" spi-small-packet=[n] Specify the smallest packet we can receive in a single transaction.\n" \
|
||||
" (larger packets will require two transactions). Default value is 32.\n"
|
||||
#else
|
||||
#define RADIO_URL_HELP_BUS \
|
||||
"Radio URL:\n" \
|
||||
"spinel+hdlc+uart://${PATH_TO_UART_DEVICE}?${arguments} for real uart device\n" \
|
||||
"spinel+hdlc+fortpty://${PATH_TO_UART_DEVICE}?${arguments} for forking a pty subprocess.\n" \
|
||||
"arguments:\n" \
|
||||
" uart-parity[=even|odd] Uart parity config, optional.\n" \
|
||||
" uart-stop[=number-of-bits] Uart stop bit, default is 1.\n" \
|
||||
" baudrate[=baudrate] Uart baud rate, default is 115200.\n" \
|
||||
" arg[=argument string] Command line arguments for subprocess, can be repeated.\n"
|
||||
#endif
|
||||
return RADIO_URL_HELP_BUS " no-reset Skip resetting the radio device.\n"
|
||||
" ncp-dataset Retrieve dataset from ncp.\n"
|
||||
" max-power-table Max power table for each channel, splitted by comma.\n";
|
||||
}
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
Arguments::Arguments(const char *aUrl)
|
||||
{
|
||||
char *url = &mUrl[0];
|
||||
|
||||
mPath = NULL;
|
||||
mStart = NULL;
|
||||
mEnd = NULL;
|
||||
|
||||
VerifyOrExit(aUrl != NULL, OT_NOOP);
|
||||
VerifyOrExit(strnlen(aUrl, sizeof(mUrl)) < sizeof(mUrl), OT_NOOP);
|
||||
strncpy(mUrl, aUrl, sizeof(mUrl) - 1);
|
||||
url = strstr(url, "://");
|
||||
VerifyOrExit(url != NULL, OT_NOOP);
|
||||
url += sizeof("://") - 1;
|
||||
mPath = url;
|
||||
|
||||
mStart = strstr(url, "?");
|
||||
|
||||
if (mStart != NULL)
|
||||
{
|
||||
mStart[0] = '\0';
|
||||
mStart++;
|
||||
|
||||
mEnd = mStart + strlen(mStart);
|
||||
|
||||
for (char *cur = strtok(mStart, "&"); cur != NULL; cur = strtok(NULL, "&"))
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEnd = url + strlen(url);
|
||||
mStart = mEnd;
|
||||
}
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
const char *Arguments::GetValue(const char *aName, const char *aLastValue)
|
||||
{
|
||||
const char * rval = NULL;
|
||||
const size_t len = strlen(aName);
|
||||
char * start = (aLastValue == NULL ? mStart : (const_cast<char *>(aLastValue) + strlen(aLastValue) + 1));
|
||||
|
||||
while (start < mEnd)
|
||||
{
|
||||
char *last = NULL;
|
||||
|
||||
if (!strncmp(aName, start, len))
|
||||
{
|
||||
if (start[len] == '=')
|
||||
{
|
||||
ExitNow(rval = &start[len + 1]);
|
||||
}
|
||||
else if (start[len] == '&' || start[len] == '\0')
|
||||
{
|
||||
ExitNow(rval = "");
|
||||
}
|
||||
}
|
||||
last = start;
|
||||
start = last + strlen(last) + 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#ifndef SELF_TEST
|
||||
#define SELF_TEST 0
|
||||
#endif
|
||||
|
||||
#if SELF_TEST
|
||||
#include <assert.h>
|
||||
|
||||
void TestSimple()
|
||||
{
|
||||
char url[] = "spinel:///dev/ttyUSB0?baudrate=115200";
|
||||
ot::Posix::Arguments args(url);
|
||||
|
||||
assert(!strcmp(args.GetPath(), "/dev/ttyUSB0"));
|
||||
assert(!strcmp(args.GetValue("baudrate"), "115200"));
|
||||
|
||||
printf("PASS %s\r\n", __func__);
|
||||
}
|
||||
|
||||
void TestSimpleNoArguments()
|
||||
{
|
||||
char url[] = "spinel:///dev/ttyUSB0";
|
||||
ot::Posix::Arguments args(url);
|
||||
|
||||
assert(!strcmp(args.GetPath(), "/dev/ttyUSB0"));
|
||||
|
||||
printf("PASS %s\r\n", __func__);
|
||||
}
|
||||
|
||||
void TestMultipleProtocols()
|
||||
{
|
||||
char url[] = "spinel+spi:///dev/ttyUSB0?baudrate=115200";
|
||||
ot::Posix::Arguments args(url);
|
||||
|
||||
assert(!strcmp(args.GetPath(), "/dev/ttyUSB0"));
|
||||
assert(!strcmp(args.GetValue("baudrate"), "115200"));
|
||||
|
||||
printf("PASS %s\r\n", __func__);
|
||||
}
|
||||
|
||||
void TestMultipleProtocolsAndDuplicateParameters()
|
||||
{
|
||||
char url[] = "spinel+exec:///path/to/ot-rcp?arg=1&arg=arg2&arg=3";
|
||||
ot::Posix::Arguments args(url);
|
||||
const char * arg = NULL;
|
||||
|
||||
assert(!strcmp(args.GetPath(), "/path/to/ot-rcp"));
|
||||
|
||||
arg = args.GetValue("arg");
|
||||
assert(!strcmp(arg, "1"));
|
||||
|
||||
arg = args.GetValue("arg", arg);
|
||||
assert(!strcmp(arg, "arg2"));
|
||||
|
||||
arg = args.GetValue("arg", arg);
|
||||
assert(!strcmp(arg, "3"));
|
||||
|
||||
printf("PASS %s\r\n", __func__);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TestSimple();
|
||||
TestSimpleNoArguments();
|
||||
TestMultipleProtocols();
|
||||
TestMultipleProtocolsAndDuplicateParameters();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // SELF_TEST
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_PLATFORM_RADIO_URL_HPP_
|
||||
#define POSIX_PLATFORM_RADIO_URL_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openthread/openthread-system.h>
|
||||
|
||||
extern "C" {
|
||||
typedef struct otPosixRadioArguments
|
||||
{
|
||||
const char *mPath; ///< The path to the executable or device
|
||||
} otPosixRadioArguments;
|
||||
}
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
class Arguments : public otPosixRadioArguments
|
||||
{
|
||||
public:
|
||||
Arguments(const char *aUrl);
|
||||
|
||||
/**
|
||||
* This method gets the path in url
|
||||
*
|
||||
* @returns The path in url.
|
||||
*
|
||||
*/
|
||||
const char *GetPath(void) const { return mPath; }
|
||||
|
||||
/**
|
||||
* This method returns the url agument value.
|
||||
*
|
||||
* @param[in] aName Argument name.
|
||||
* @param[in] aLastValue The last iterated argument value, NULL for first value.
|
||||
*
|
||||
* @returns The argument value.
|
||||
*
|
||||
*/
|
||||
const char *GetValue(const char *aName, const char *aLastValue = NULL);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kRadioUrlMaxSize = 512,
|
||||
};
|
||||
char mUrl[kRadioUrlMaxSize];
|
||||
|
||||
char *mStart;
|
||||
char *mEnd;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // POSIX_PLATFORM_RADIO_URL_HPP_
|
||||
@@ -91,32 +91,91 @@ SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback,
|
||||
{
|
||||
}
|
||||
|
||||
otError SpiInterface::Init(const otPlatformConfig &aPlatformConfig)
|
||||
otError SpiInterface::Init(Arguments &aArguments)
|
||||
{
|
||||
VerifyOrDie(aPlatformConfig.mSpiAlignAllowance <= kSpiAlignAllowanceMax, OT_EXIT_FAILURE);
|
||||
const char *spiGpioIntDevice;
|
||||
const char *spiGpioResetDevice;
|
||||
uint8_t spiGpioIntLine = 0;
|
||||
uint8_t spiGpioResetLine = 0;
|
||||
uint8_t spiMode = OT_PLATFORM_CONFIG_SPI_DEFAULT_MODE;
|
||||
uint32_t spiSpeed = SPI_IOC_WR_MAX_SPEED_HZ;
|
||||
uint32_t spiResetDelay = OT_PLATFORM_CONFIG_SPI_DEFAULT_RESET_DELAY_MS;
|
||||
uint16_t spiCsDelay = OT_PLATFORM_CONFIG_SPI_DEFAULT_CS_DELAY_US;
|
||||
uint8_t spiAlignAllowance = OT_PLATFORM_CONFIG_SPI_DEFAULT_ALIGN_ALLOWANCE;
|
||||
uint8_t spiSmallPacketSize = OT_PLATFORM_CONFIG_SPI_DEFAULT_SMALL_PACKET_SIZE;
|
||||
|
||||
mSpiCsDelayUs = aPlatformConfig.mSpiCsDelay;
|
||||
mSpiSmallPacketSize = aPlatformConfig.mSpiSmallPacketSize;
|
||||
mSpiAlignAllowance = aPlatformConfig.mSpiAlignAllowance;
|
||||
spiGpioIntDevice = aArguments.GetValue("gpio-int-device");
|
||||
spiGpioResetDevice = aArguments.GetValue("gpio-reset-device");
|
||||
if (!spiGpioIntDevice || !spiGpioResetDevice)
|
||||
{
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (aPlatformConfig.mSpiGpioIntDevice != NULL)
|
||||
if (aArguments.GetValue("gpio-int-line"))
|
||||
{
|
||||
spiGpioIntLine = static_cast<uint8_t>(atoi(aArguments.GetValue("gpio-int-line")));
|
||||
}
|
||||
else
|
||||
{
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
if (aArguments.GetValue("gpio-reset-line"))
|
||||
{
|
||||
spiGpioResetLine = static_cast<uint8_t>(atoi(aArguments.GetValue("gpio-reset-line")));
|
||||
}
|
||||
else
|
||||
{
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
if (aArguments.GetValue("spi-mode"))
|
||||
{
|
||||
spiMode = static_cast<uint8_t>(atoi(aArguments.GetValue("spi-mode")));
|
||||
}
|
||||
if (aArguments.GetValue("spi-speed"))
|
||||
{
|
||||
spiSpeed = static_cast<uint32_t>(atoi(aArguments.GetValue("spi-speed")));
|
||||
}
|
||||
if (aArguments.GetValue("spi-reset-delay"))
|
||||
{
|
||||
spiResetDelay = static_cast<uint32_t>(atoi(aArguments.GetValue("spi-reset-delay")));
|
||||
}
|
||||
if (aArguments.GetValue("spi-cs-delay"))
|
||||
{
|
||||
spiCsDelay = static_cast<uint16_t>(atoi(aArguments.GetValue("spi-cs-delay")));
|
||||
}
|
||||
if (aArguments.GetValue("spi-align-allowance"))
|
||||
{
|
||||
spiAlignAllowance = static_cast<uint8_t>(atoi(aArguments.GetValue("spi-align-allowance")));
|
||||
}
|
||||
if (aArguments.GetValue("spi-small-packet"))
|
||||
{
|
||||
spiSmallPacketSize = static_cast<uint8_t>(atoi(aArguments.GetValue("spi-small-packet")));
|
||||
}
|
||||
|
||||
VerifyOrDie(spiAlignAllowance <= kSpiAlignAllowanceMax, OT_EXIT_FAILURE);
|
||||
|
||||
mSpiCsDelayUs = spiCsDelay;
|
||||
mSpiSmallPacketSize = spiSmallPacketSize;
|
||||
mSpiAlignAllowance = spiAlignAllowance;
|
||||
|
||||
if (spiGpioIntDevice != NULL)
|
||||
{
|
||||
// If the interrupt pin is not set, SPI interface will use polling mode.
|
||||
InitIntPin(aPlatformConfig.mSpiGpioIntDevice, aPlatformConfig.mSpiGpioIntLine);
|
||||
InitIntPin(spiGpioIntDevice, spiGpioIntLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogNotePlat("SPI interface enters polling mode.");
|
||||
}
|
||||
|
||||
InitResetPin(aPlatformConfig.mSpiGpioResetDevice, aPlatformConfig.mSpiGpioResetLine);
|
||||
InitSpiDev(aPlatformConfig.mRadioFile, aPlatformConfig.mSpiMode, aPlatformConfig.mSpiSpeed);
|
||||
InitResetPin(spiGpioResetDevice, spiGpioResetLine);
|
||||
InitSpiDev(aArguments.GetPath(), spiMode, spiSpeed);
|
||||
|
||||
// Reset RCP chip.
|
||||
TrigerReset();
|
||||
|
||||
// Waiting for the RCP chip starts up.
|
||||
usleep(static_cast<useconds_t>(aPlatformConfig.mSpiResetDelay) * kUsecPerMsec);
|
||||
usleep(static_cast<useconds_t>(spiResetDelay) * kUsecPerMsec);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -79,14 +79,14 @@ public:
|
||||
*
|
||||
* @note This method should be called before reading and sending spinel frames to the interface.
|
||||
*
|
||||
* @param[in] aPlatformConfig Platform configuration structure.
|
||||
* @param[in] aArguments Arguments parsed from radio url.
|
||||
*
|
||||
* @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 otPlatformConfig &aPlatformConfig);
|
||||
otError Init(Arguments &aArguments);
|
||||
|
||||
/**
|
||||
* This method deinitializes the interface to the RCP.
|
||||
|
||||
@@ -49,13 +49,16 @@ uint64_t gNodeId = 0;
|
||||
|
||||
otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
|
||||
{
|
||||
otInstance *instance = NULL;
|
||||
otInstance * instance = NULL;
|
||||
ot::Posix::Arguments args(aPlatformConfig->mRadioUrl);
|
||||
|
||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||
virtualTimeInit(static_cast<uint16_t>(atoi(aPlatformConfig->mRadioConfig)));
|
||||
virtualTimeInit(static_cast<uint16_t>(atoi(args.GetValue("arg"))));
|
||||
#endif
|
||||
|
||||
VerifyOrDie(args.GetPath() != NULL, OT_EXIT_INVALID_ARGUMENTS);
|
||||
platformAlarmInit(aPlatformConfig->mSpeedUpFactor);
|
||||
platformRadioInit(aPlatformConfig);
|
||||
platformRadioInit(&args);
|
||||
platformRandomInit();
|
||||
|
||||
instance = otInstanceInitSingle();
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
spawn $env(OT_COMMAND) $env(RCP_COMMAND) 1
|
||||
spawn $env(OT_COMMAND) "spinel+hdlc+uart://$env(RCP_COMMAND)?arg=1"
|
||||
set timeout 1
|
||||
expect_after {
|
||||
timeout { exit 1 }
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#
|
||||
|
||||
# allows 11-25 and forbidden 26
|
||||
spawn $env(OT_COMMAND) --max-power-table 11,12,13,14,15,16,17,18,19,20,21,22,23,24,-1,0x7f $env(RCP_COMMAND) 1
|
||||
spawn $env(OT_COMMAND) "spinel+hdlc+uart://$env(RCP_COMMAND)?max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,-1,0x7f&arg=1"
|
||||
set timeout 1
|
||||
expect_after {
|
||||
timeout { exit 1 }
|
||||
@@ -42,7 +42,7 @@ expect "Done"
|
||||
send "\x04"
|
||||
expect eof
|
||||
# allows all channels by default
|
||||
spawn $env(OT_COMMAND) $env(RCP_COMMAND) 1
|
||||
spawn $env(OT_COMMAND) "spinel+hdlc+uart://$env(RCP_COMMAND)?arg=1"
|
||||
set timeout 1
|
||||
expect_after {
|
||||
timeout { exit 1 }
|
||||
|
||||
@@ -108,7 +108,8 @@ class Node:
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
cmd += ' -v %s' % os.environ['RADIO_DEVICE']
|
||||
cmd += ' -v spinel+hdlc+uart://%s?arg=%d' % (
|
||||
os.environ['RADIO_DEVICE'], nodeid)
|
||||
|
||||
# Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability
|
||||
elif self.version == '1.1':
|
||||
@@ -120,7 +121,8 @@ class Node:
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
|
||||
if 'RADIO_DEVICE_1_1' in os.environ:
|
||||
cmd += ' -v %s' % os.environ['RADIO_DEVICE_1_1']
|
||||
cmd += ' -v spinel+hdlc+uart://%s?arg=%d' % (
|
||||
os.environ['RADIO_DEVICE_1_1'], nodeid)
|
||||
|
||||
cmd += ' %d' % nodeid
|
||||
print("%s" % cmd)
|
||||
@@ -146,7 +148,8 @@ class Node:
|
||||
# If Thread version of node matches the testing environment version.
|
||||
if self.version == self.env_version:
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
args = ' %s' % os.environ['RADIO_DEVICE']
|
||||
args = ' spinel+hdlc+uart://%s?arg=%d' % (
|
||||
os.environ['RADIO_DEVICE'], nodeid)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
@@ -184,7 +187,8 @@ class Node:
|
||||
# Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability.
|
||||
elif self.version == '1.1':
|
||||
if 'RADIO_DEVICE_1_1' in os.environ:
|
||||
args = ' %s' % os.environ['RADIO_DEVICE_1_1']
|
||||
args = ' spinel+hdlc+uart://%s?arg=%d' % (
|
||||
os.environ['RADIO_DEVICE_1_1'], nodeid)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ class Node(object):
|
||||
self._use_posix_with_rcp = False
|
||||
|
||||
if self._use_posix_with_rcp:
|
||||
ncp_socket_path = 'system:{} -s {} {} {}'.format(
|
||||
ncp_socket_path = 'system:{} -s {} spinel+hdlc+uart://{}?arg={}'.format(
|
||||
self._OT_NCP_FTD_POSIX, self._SPEED_UP_FACTOR, self._OT_RCP,
|
||||
index)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user