mirror of
https://github.com/espressif/openthread.git
synced 2026-07-18 18:14:07 +00:00
spi-hdlc-adapter: Add support for raw mode. (#1341)
This commit adds support for two new arguments:
* `--raw`: Do not encode/decode packets using HDLC. Instead, write
whole, raw frames to the specified input and output FDs. This is
useful for emulating a serial port, or when datagram-based sockets
are supplied for `stdin` and `stdout` (when used with `--stdio`).
* `--mtu=[MTU]`: Specify the MTU. Currently only used in raw mode.
Default and maximum value is 2043. Must be greater than zero.
The `--raw` argument will allow `wpantund` to use `spi-hdlc-adapter`
without HDLC escaping by supplying datagram sockets for stdin and
stdout. This should improve performance and reduce latency.
The `--mtu` argument is supplied to benefit the use case where we
are emulating an asynchronous serial port over SPI. In such a case,
you would likely want to lower the MTU significantly to match the
internal buffer size of the MCU.
Version is bumped to 0.04.
This commit is contained in:
committed by
Jonathan Hui
parent
75486af85d
commit
ccc0020dc0
@@ -19,6 +19,12 @@ protocol document.
|
||||
* `--pty`: Create a pseudo terminal for HDLC input/output. The path
|
||||
of the newly-created PTY will be written to `stdout`, followed by
|
||||
a newline.
|
||||
* `--raw`: Do not encode/decode packets using HDLC. Instead, write
|
||||
whole, raw frames to the specified input and output FDs. This is
|
||||
useful for emulating a serial port, or when datagram-based sockets
|
||||
are supplied for `stdin` and `stdout` (when used with `--stdio`).
|
||||
* `--mtu=[MTU]`: Specify the MTU. Currently only used in raw mode.
|
||||
Default and maximum value is 2043. Must be greater than zero.
|
||||
* `--gpio-int[=gpio-path]`: Specify a path to the Linux
|
||||
sysfs-exported GPIO directory for the `I̅N̅T̅` pin. If not
|
||||
specified, `spi-hdlc-adapter` will fall back to polling, which is
|
||||
@@ -27,8 +33,14 @@ protocol document.
|
||||
sysfs-exported GPIO directory for the `R̅E̅S̅` pin.
|
||||
* `--spi-mode[=mode]`: Specify the SPI mode to use (0-3).
|
||||
* `--spi-speed[=hertz]`: Specify the SPI speed in hertz.
|
||||
* `--spi-cs-delay[=usec]`: Specify the delay after C̅S̅ assertion, in
|
||||
microseconds.
|
||||
* `--spi-cs-delay[=usec]`: Specify the delay after C̅S̅ assertion,
|
||||
in microseconds.
|
||||
* `--spi-align-allowance[=n]`: Specify the the maximum number of 0xFF
|
||||
bytes to clip from start of MISO frame. This makes this tool usable
|
||||
with SPI slaves which have buggy SPI blocks that prepend up to
|
||||
three 0xFF bytes to the start of MISO frame. Default value is `0`.
|
||||
Maximum value is `3`. *This must be set to `2` for chips in the
|
||||
SiLabs EM35x family.*
|
||||
* `--verbose`: Increase debug verbosity.
|
||||
* `--help`: Print out usage information to `stdout` and exit.
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -66,7 +67,7 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* MARK: Macros and Constants */
|
||||
|
||||
#define SPI_HDLC_VERSION "0.03"
|
||||
#define SPI_HDLC_VERSION "0.04"
|
||||
|
||||
#define MAX_FRAME_SIZE 2048
|
||||
#define HEADER_LEN 5
|
||||
@@ -158,6 +159,13 @@ static uint32_t sSpiValidFrameCount = 0;
|
||||
|
||||
static bool sSlaveDidReset = false;
|
||||
|
||||
// If sUseRawFrames is set to true, HDLC encoding/encoding
|
||||
// is skipped and the raw frames are read-from/written-to
|
||||
// the sHdlcInputFd/sHdlcOutputFd whole. See `--raw`.
|
||||
static bool sUseRawFrames = false;
|
||||
|
||||
static int sMTU = MAX_FRAME_SIZE - HEADER_LEN;
|
||||
|
||||
static int sRet = 0;
|
||||
|
||||
static sig_t sPreviousHandlerForSIGINT;
|
||||
@@ -989,6 +997,111 @@ static int pull_hdlc(void)
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* MARK: Raw Transfer Functions */
|
||||
|
||||
static int push_raw(void)
|
||||
{
|
||||
int ret = 0;
|
||||
const uint8_t* spiRxFrameBuffer = get_real_rx_frame_start();
|
||||
static uint8_t raw_frame_buffer[MAX_FRAME_SIZE];
|
||||
static uint16_t raw_frame_len;
|
||||
static uint16_t raw_frame_sent;
|
||||
|
||||
if (raw_frame_len == 0)
|
||||
{
|
||||
if (sSlaveDidReset)
|
||||
{
|
||||
// Indicates an MCU reset.
|
||||
// We don't have anything to do here because
|
||||
// raw mode doesn't have any way to signal
|
||||
// resets out-of-band.
|
||||
sSlaveDidReset = false;
|
||||
}
|
||||
else if (sSpiRxPayloadSize > 0)
|
||||
{
|
||||
// Read the frame into raw_frame_buffer
|
||||
assert(sSpiRxPayloadSize <= sizeof(raw_frame_buffer));
|
||||
memcpy(raw_frame_buffer, &spiRxFrameBuffer[HEADER_LEN], sSpiRxPayloadSize);
|
||||
raw_frame_len = sSpiRxPayloadSize;
|
||||
raw_frame_sent = 0;
|
||||
sSpiRxPayloadSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do.
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = (int)write(
|
||||
sHdlcOutputFd,
|
||||
raw_frame_buffer + raw_frame_sent,
|
||||
raw_frame_len - raw_frame_sent
|
||||
);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("push_raw:write");
|
||||
syslog(LOG_ERR, "push_raw:write: errno=%d (%s)", errno, strerror(errno));
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
|
||||
raw_frame_sent += ret;
|
||||
|
||||
// Reset state once we have sent the entire frame.
|
||||
if (raw_frame_len == raw_frame_sent)
|
||||
{
|
||||
raw_frame_len = raw_frame_sent = 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pull_raw(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!sSpiTxIsReady)
|
||||
{
|
||||
ret = (int)read(sHdlcInputFd, &sSpiTxFrameBuffer[HEADER_LEN], (size_t)sMTU);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("pull_raw:read");
|
||||
syslog(LOG_ERR, "pull_raw:read: errno=%d (%s)", errno, strerror(errno));
|
||||
}
|
||||
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
sSpiTxPayloadSize = (uint16_t)ret;
|
||||
sSpiTxIsReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret < 0
|
||||
? ret
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* MARK: Setup Functions */
|
||||
|
||||
@@ -1288,6 +1401,14 @@ static void print_help(void)
|
||||
" will be written to `stdout`, followed by a\n"
|
||||
" newline.\n"
|
||||
#endif // HAVE_OPENPTY
|
||||
" --raw ........................ Do not encode/decode packets using HDLC.\n"
|
||||
" Instead, write whole, raw frames to the\n"
|
||||
" specified input and output FDs. This is useful\n"
|
||||
" for emulating a serial port, or when datagram-\n"
|
||||
" based sockets are supplied for stdin and\n"
|
||||
" stdout` (when used with --stdio).\n"
|
||||
" --mtu=[MTU] .................. Specify the MTU. Currently only used in raw mode.\n"
|
||||
" Default and maximum value is 2043.\n"
|
||||
" -i/--gpio-int[=gpio-path] .... Specify a path to the Linux sysfs-exported\n"
|
||||
" GPIO directory for the `I̅N̅T̅` pin. If not\n"
|
||||
" specified, `spi-hdlc` will fall back to\n"
|
||||
@@ -1298,7 +1419,7 @@ static void print_help(void)
|
||||
" --spi-speed[=hertz] .......... Specify the SPI speed in hertz.\n"
|
||||
" --spi-cs-delay[=usec] ........ Specify the delay after C̅S̅ assertion, in usec\n"
|
||||
" --spi-align-allowance[=n] .... Specify the the maximum number of FF bytes to\n"
|
||||
" clip from start of RX frame.\n"
|
||||
" clip from start of MISO frame.\n"
|
||||
" -v/--verbose ................. Increase debug verbosity. (Repeatable)\n"
|
||||
" -h/-?/--help ................. Print out usage information and exit.\n"
|
||||
"\n";
|
||||
@@ -1331,6 +1452,8 @@ int main(int argc, char *argv[])
|
||||
ARG_VERBOSE = 1003,
|
||||
ARG_SPI_CS_DELAY = 1004,
|
||||
ARG_SPI_ALIGN_ALLOWANCE = 1005,
|
||||
ARG_RAW = 1006,
|
||||
ARG_MTU = 1007,
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
@@ -1340,6 +1463,8 @@ int main(int argc, char *argv[])
|
||||
{ "gpio-res", required_argument, NULL, 'r' },
|
||||
{ "verbose", optional_argument, NULL, ARG_VERBOSE },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "raw", no_argument, NULL, ARG_RAW },
|
||||
{ "mtu", required_argument, NULL, ARG_MTU },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "spi-mode", required_argument, NULL, ARG_SPI_MODE },
|
||||
{ "spi-speed", required_argument, NULL, ARG_SPI_SPEED },
|
||||
@@ -1432,6 +1557,24 @@ int main(int argc, char *argv[])
|
||||
syslog(LOG_NOTICE, "SPI CS Delay set to %d usec", sSpiCsDelay);
|
||||
break;
|
||||
|
||||
case ARG_RAW:
|
||||
sUseRawFrames = true;
|
||||
syslog(LOG_NOTICE, "HDLC encoding/decoding disabled. Will use raw frames for input/output.");
|
||||
break;
|
||||
|
||||
case ARG_MTU:
|
||||
sMTU = atoi(optarg);
|
||||
if (sMTU > MAX_FRAME_SIZE - HEADER_LEN) {
|
||||
syslog(LOG_ERR, "Specified MTU of %d is too large, maximum is %d bytes.", sMTU, MAX_FRAME_SIZE - HEADER_LEN);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (sMTU < 1) {
|
||||
syslog(LOG_ERR, "Specified MTU of %d is too small, minimum is 1 byte.", sMTU);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
syslog(LOG_NOTICE, "MTU set to %d bytes", sMTU);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
if (!setup_res_gpio(optarg))
|
||||
{
|
||||
@@ -1665,7 +1808,7 @@ int main(int argc, char *argv[])
|
||||
if (FD_ISSET(sHdlcInputFd, &read_set))
|
||||
{
|
||||
// Read in the data.
|
||||
if (pull_hdlc() < 0)
|
||||
if ((sUseRawFrames ? pull_raw() : pull_hdlc()) < 0)
|
||||
{
|
||||
sRet = EXIT_FAILURE;
|
||||
break;
|
||||
@@ -1676,7 +1819,7 @@ int main(int argc, char *argv[])
|
||||
if (FD_ISSET(sHdlcOutputFd, &write_set))
|
||||
{
|
||||
// Write out the data.
|
||||
if (push_hdlc() < 0)
|
||||
if ((sUseRawFrames ? push_raw() : push_hdlc()) < 0)
|
||||
{
|
||||
sRet = EXIT_FAILURE;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user