ncp(spinel/SPI): Various additions and documentation updates (#342)

This commit includes some revisions to the spinel protocol, including
the addition of several new properties. It also includes some minor
updates to the SPI protocol, which should reduce ambiguity.

The new properties haven't been implemented in `ncp_base.cpp` yet,
but that will be comming soon.
This commit is contained in:
Robert Quattlebaum
2016-08-08 15:19:46 -07:00
committed by Jonathan Hui
parent 08f6ffd4fe
commit c1917179f7
5 changed files with 276 additions and 37 deletions
+79 -27
View File
@@ -1,7 +1,7 @@
Spinel Host Controller Interface
================================
Updated: 2016-07-28
Updated: 2016-08-05
Written by: Robert Quattlebaum <rquattle@nestlabs.com>
@@ -716,21 +716,29 @@ of the metadata is defined by the associated network protocol.
* 0: `STATUS_OK`: Operation has completed successfully.
* 1: `STATUS_FAILURE`: Operation has failed for some undefined
reason.
* 2: `STATUS_UNIMPLEMENTED`
* 3: `STATUS_INVALID_ARGUMENT`
* 4: `STATUS_INVALID_STATE`
* 5: `STATUS_INVALID_COMMAND`
* 6: `STATUS_INVALID_INTERFACE`
* 7: `STATUS_INTERNAL_ERROR`
* 8: `STATUS_SECURITY_ERROR`
* 9: `STATUS_PARSE_ERROR`
* 10: `STATUS_IN_PROGRESS`
* 11: `STATUS_NOMEM`
* 12: `STATUS_BUSY`
* 13: `STATUS_PROPERTY_NOT_FOUND`
* 14: `STATUS_PACKET_DROPPED`
* 15: `STATUS_EMPTY`
* 16-111: *RESERVED*
* 2: `STATUS_UNIMPLEMENTED`: The given operation has not been implemented.
* 3: `STATUS_INVALID_ARGUMENT`: An argument to the given operation is invalid.
* 4: `STATUS_INVALID_STATE` : The given operation is invalid for the current
state of the device.
* 5: `STATUS_INVALID_COMMAND`: The given command is not recognized.
* 6: `STATUS_INVALID_INTERFACE`: The given Spinel interface is not supported.
* 7: `STATUS_INTERNAL_ERROR`: An internal runtime error has occured.
* 8: `STATUS_SECURITY_ERROR`: A security or authentication error has occured.
* 9: `STATUS_PARSE_ERROR`: An error has occured while parsing the command.
* 10: `STATUS_IN_PROGRESS`: The operation is in progress and will be
completed asynchronously.
* 11: `STATUS_NOMEM`: The operation has been prevented due to memory
pressure.
* 12: `STATUS_BUSY`: The device is currently performing a mutually exclusive
operation.
* 13: `STATUS_PROPERTY_NOT_FOUND`: The given property is not recognized.
* 14: `STATUS_PACKET_DROPPED`: The packet was dropped.
* 15: `STATUS_EMPTY`: The result of the operation is empty.
* 16: `STATUS_CMD_TOO_BIG`: The command was too large to fit in the internal
buffer.
* 17: `STATUS_NO_ACK`: The packet was not acknowledged.
* 18: `STATUS_CCA_FAILURE`: The packet was not sent due to a CCA failure.
* 19-111: *RESERVED*
* 112-127: Reset Causes
* 112: `STATUS_RESET_POWER_ON`
* 113: `STATUS_RESET_EXTERNAL`
@@ -739,7 +747,9 @@ of the metadata is defined by the associated network protocol.
* 116: `STATUS_RESET_CRASH`
* 117: `STATUS_RESET_ASSERT`
* 118: `STATUS_RESET_OTHER`
* 119-127: *RESERVED-RESET-CODES*
* 119: `STATUS_RESET_UNKNOWN`
* 120: `STATUS_RESET_WATCHDOG`
* 121-127: *RESERVED-RESET-CODES*
* 128 - 15,359: *UNALLOCATED*
* 15,360 - 16,383: Vendor-specific
* 16,384 - 1,999,999: *UNALLOCATED*
@@ -1011,14 +1021,12 @@ individual needs of the application or product.
#### A.2.1 SPI Framing Protocol ####
Each SPI frame starts with a 6-byte frame header:
Each SPI frame starts with a 5-byte frame header:
Octets: | 1 | 1 | 2 | 2
--------|-----|-----|----------|----------
Fields: | PAD | HDR | RECV_LEN | DATA_LEN
Octets: | 1 | 2 | 2
--------|-----|----------|----------
Fields: | HDR | RECV_LEN | DATA_LEN
* `PAD`: Padding byte. Discarded. May be ommitted on platforms which
don't need it.
* `HDR`: The first byte is the header byte (defined below)
* `RECV_LEN`: The second and third bytes indicate the largest frame
size that that device is ready to receive. If zero, then the other
@@ -1033,12 +1041,20 @@ The `HDR` byte is defined as:
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
|RST| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|RST|CRC| RESERVED |PATTERN|
+---+---+---+---+---+---+---+---+
* `RST`: This bit is set when that device has been reset since the
last time `C̅S̅` was asserted.
* All other bits are reserved and MUST be cleared to zero.
* `CRC`: This bit is set when that device supports writing a 16-bit
CRC at the end of the data. This CRC is NOT included in DATA_LEN.
* `RESERVED`: These bits are all reserved for future used. They
MUST be cleared to zero and MUST be ignored if set.
* `PATTERN`: These bits are set to a fixed value to help distinguish
valid SPI frames from garbage (by explicitly making `0xFF` and `0x00`
invalid values). Bit 6 MUST be set to be one and bit 7 MUST be
cleared (0). A frame received that has any other values for these bits
MUST be dropped.
Prior to a sending or receiving a frame, the master SHOULD send a
5-octet frame with zeros for both the max receive frame size and the
@@ -1050,10 +1066,10 @@ This allows the master to calculate the size of the next transaction.
This protocol can be used either unidirectionally or bidirectionally,
determined by the behavior of the master and the slave.
If the the master reads value of `0xFF` for the `HDR` byte, the master
If the the master notices `PATTERN` is not set correctly, the master
should consider the transaction to have failed and try again after 10
milliseconds, retrying up to 200 times. After unsuccessfully trying
200 times in a row, the master should take appropriate remedial action
200 times in a row, the master MAY take appropriate remedial action
(like a NCP hardware reset, or indicating a communication failure to a
user interface).
@@ -1400,6 +1416,10 @@ Possible Values:
* 1: `MAC_FILTER_MODE_PROMISCUOUS`: All MAC packets matching network are passed up the stack.
* 2: `MAC_FILTER_MODE_MONITOR`: All decoded MAC packets are passed up the stack.
#### D.2.10. PROP 4864: `PROP_MAC_WHITELIST`
* Type: Read-Write
* Packed-Encoding: `A(T(E))`
### D.3. NET Properties
@@ -1544,7 +1564,39 @@ Data per item is:
* Type: Read-Write
* Packed-Encoding: `A(S)`
#### D.4.14. PROP 93: `PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE`
* Type: Read-Write
* Packed-Encoding: `b`
Set to true before changing local net data. Set to false when finished.
This allows changes to be aggregated into single events.
#### D.4.15. PROP 94: `PROP_THREAD_MODE`
* Type: Read-Write
* Packed-Encoding: `C`
This property contains the value of the mode
TLV for this node. The meaning of the bits in this
bitfield are defined by section 4.5.2 of the Thread
specification.
#### D.4.16. PROP 5376: `PROP_THREAD_CHILD_TIMEOUT`
* Type: Read-Write
* Packed-Encoding: `L`
Used when operating in the Child role.
#### D.4.17. PROP 5377: `PROP_THREAD_RLOC16`
* Type: Read-Write
* Packed-Encoding: `S`
#### D.4.18. PROP 5378: `PROP_THREAD_ROUTER_UPGRADE_THRESHOLD`
* Type: Read-Write
* Packed-Encoding: `C`
#### D.4.19. PROP 5379: `PROP_THREAD_CONTEXT_REUSE_DELAY`
* Type: Read-Write
* Packed-Encoding: `L`
### D.5. IPv6 Properties
+12 -5
View File
@@ -38,6 +38,9 @@
#include <core/openthread-core-config.h>
#define SPI_RESET_FLAG 0x80
#define SPI_CRC_FLAG 0x40
#define SPI_PATTERN_VALUE 0x02
#define SPI_PATTERN_MASK 0x03
namespace Thread {
@@ -91,8 +94,8 @@ NcpSpi::NcpSpi():
mSending = false;
spi_header_set_flag_byte(mSendFrame, SPI_RESET_FLAG);
spi_header_set_flag_byte(mEmptySendFrame, SPI_RESET_FLAG);
spi_header_set_flag_byte(mSendFrame, SPI_RESET_FLAG|SPI_PATTERN_VALUE);
spi_header_set_flag_byte(mEmptySendFrame, SPI_RESET_FLAG|SPI_PATTERN_VALUE);
spi_header_set_accept_len(mSendFrame, sizeof(mReceiveFrame) - SPI_HEADER_LENGTH);
otPlatSpiSlaveEnable(&SpiTransactionComplete, (void*)this);
@@ -143,6 +146,10 @@ NcpSpi::SpiTransactionComplete(
uint16_t tx_data_len(0);
uint16_t tx_accept_len(0);
// TODO: Check `PATTERN` bits of `HDR` and ignore frame if not set.
// Holding off on implementing this so as to not cause immediate
// compatability problems, even though it is required by the spec.
if (aTransactionLength >= SPI_HEADER_LENGTH)
{
if (aMISOBufLen >= SPI_HEADER_LENGTH)
@@ -181,9 +188,9 @@ NcpSpi::SpiTransactionComplete(
if ( (aTransactionLength >= 1)
&& (aMISOBufLen >= 1)
) {
// Clear the reset flag
spi_header_set_flag_byte(mSendFrame, 0);
spi_header_set_flag_byte(mEmptySendFrame, 0);
// Clear the reset flag.
spi_header_set_flag_byte(mSendFrame, SPI_PATTERN_VALUE);
spi_header_set_flag_byte(mEmptySendFrame, SPI_PATTERN_VALUE);
}
if (mSending && !mHandlingSendDone)
+125
View File
@@ -1113,6 +1113,131 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
return ret;
}
const char *spinel_status_to_cstr(spinel_status_t status)
{
const char *ret = "UNKNOWN";
switch (status)
{
case SPINEL_STATUS_OK:
ret = "STATUS_OK";
break;
case SPINEL_STATUS_FAILURE:
ret = "STATUS_FAILURE";
break;
case SPINEL_STATUS_UNIMPLEMENTED:
ret = "STATUS_UNIMPLEMENTED";
break;
case SPINEL_STATUS_INVALID_ARGUMENT:
ret = "STATUS_INVALID_ARGUMENT";
break;
case SPINEL_STATUS_INVALID_STATE:
ret = "STATUS_INVALID_STATE";
break;
case SPINEL_STATUS_INVALID_COMMAND:
ret = "STATUS_INVALID_COMMAND";
break;
case SPINEL_STATUS_INVALID_INTERFACE:
ret = "STATUS_INVALID_INTERFACE";
break;
case SPINEL_STATUS_INTERNAL_ERROR:
ret = "STATUS_INTERNAL_ERROR";
break;
case SPINEL_STATUS_SECURITY_ERROR:
ret = "STATUS_SECURITY_ERROR";
break;
case SPINEL_STATUS_PARSE_ERROR:
ret = "STATUS_PARSE_ERROR";
break;
case SPINEL_STATUS_IN_PROGRESS:
ret = "STATUS_IN_PROGRESS";
break;
case SPINEL_STATUS_NOMEM:
ret = "STATUS_NOMEM";
break;
case SPINEL_STATUS_BUSY:
ret = "STATUS_BUSY";
break;
case SPINEL_STATUS_PROP_NOT_FOUND:
ret = "STATUS_PROP_NOT_FOUND";
break;
case SPINEL_STATUS_DROPPED:
ret = "STATUS_DROPPED";
break;
case SPINEL_STATUS_EMPTY:
ret = "STATUS_EMPTY";
break;
case SPINEL_STATUS_CMD_TOO_BIG:
ret = "STATUS_CMD_TOO_BIG";
break;
case SPINEL_STATUS_NO_ACK:
ret = "STATUS_NO_ACK";
break;
case SPINEL_STATUS_CCA_FAILURE:
ret = "STATUS_CCA_FAILURE";
break;
case SPINEL_STATUS_RESET_POWER_ON:
ret = "STATUS_RESET_POWER_ON";
break;
case SPINEL_STATUS_RESET_EXTERNAL:
ret = "STATUS_RESET_EXTERNAL";
break;
case SPINEL_STATUS_RESET_SOFTWARE:
ret = "STATUS_RESET_SOFTWARE";
break;
case SPINEL_STATUS_RESET_FAULT:
ret = "STATUS_RESET_FAULT";
break;
case SPINEL_STATUS_RESET_CRASH:
ret = "STATUS_RESET_CRASH";
break;
case SPINEL_STATUS_RESET_ASSERT:
ret = "STATUS_RESET_ASSERT";
break;
case SPINEL_STATUS_RESET_OTHER:
ret = "STATUS_RESET_OTHER";
break;
case SPINEL_STATUS_RESET_UNKNOWN:
ret = "STATUS_RESET_UNKNOWN";
break;
case SPINEL_STATUS_RESET_WATCHDOG:
ret = "STATUS_RESET_WATCHDOG";
break;
default:
break;
}
return ret;
}
/* -------------------------------------------------------------------------- */
+47 -2
View File
@@ -92,8 +92,8 @@ typedef enum
SPINEL_STATUS_PARSE_ERROR = 9, ///< A error has occured while parsing the command.
SPINEL_STATUS_IN_PROGRESS = 10, ///< This operation is in progress.
SPINEL_STATUS_NOMEM = 11, ///< Operation prevented due to memory pressure.
SPINEL_STATUS_BUSY = 12, ///< The device is currently performing an mutually exclusive operation
SPINEL_STATUS_PROP_NOT_FOUND = 12, ///< The given property is not recognized.
SPINEL_STATUS_BUSY = 12, ///< The device is currently performing a mutually exclusive operation
SPINEL_STATUS_PROP_NOT_FOUND = 13, ///< The given property is not recognized.
SPINEL_STATUS_DROPPED = 14, ///< A/The packet was dropped.
SPINEL_STATUS_EMPTY = 15, ///< The result of the operation is empty.
SPINEL_STATUS_CMD_TOO_BIG = 16, ///< The command was too large to fit in the internal buffer.
@@ -316,6 +316,13 @@ typedef enum
SPINEL_PROP_MAC_FILTER_MODE = SPINEL_PROP_MAC__BEGIN + 8, ///< [C]
SPINEL_PROP_MAC__END = 0x40,
SPINEL_PROP_MAC_EXT__BEGIN = 0x1300,
/// MAC Whitelist
/** Format: `A(T(E))`
*/
SPINEL_PROP_MAC_WHITELIST = SPINEL_PROP_MAC_EXT__BEGIN + 0, ///< [A(T(E))]
SPINEL_PROP_MAC_EXT__END = 0x1400,
SPINEL_PROP_NET__BEGIN = 0x40,
SPINEL_PROP_NET_SAVED = SPINEL_PROP_NET__BEGIN + 0, ///< [b]
SPINEL_PROP_NET_ENABLED = SPINEL_PROP_NET__BEGIN + 1, ///< [b]
@@ -348,8 +355,45 @@ typedef enum
SPINEL_PROP_THREAD_ASSISTING_PORTS = SPINEL_PROP_THREAD__BEGIN + 12, ///< array(portn) [A(S)]
SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE
= SPINEL_PROP_THREAD__BEGIN + 13, ///< [b]
/// Thread Mode
/** Format: `C`
*
* This property contains the value of the mode
* TLV for this node. The meaning of the bits in this
* bitfield are defined by section 4.5.2 of the Thread
* specification.
*/
SPINEL_PROP_THREAD_MODE = SPINEL_PROP_THREAD__BEGIN + 14,
SPINEL_PROP_THREAD__END = 0x60,
SPINEL_PROP_THREAD_EXT__BEGIN = 0x1500,
/// Thread Child Timeout
/** Format: `L`
*
* Used when operating in the Child role.
*/
SPINEL_PROP_THREAD_CHILD_TIMEOUT = SPINEL_PROP_THREAD_EXT__BEGIN + 0,
/// Thread RLOC16
/** Format: `S`
*/
SPINEL_PROP_THREAD_RLOC16 = SPINEL_PROP_THREAD_EXT__BEGIN + 1,
/// Thread Router Upgrade Threshold
/** Format: `C`
*/
SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD
= SPINEL_PROP_THREAD_EXT__BEGIN + 2,
/// Thread Context Reuse Delay
/** Format: `L`
*/
SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY
= SPINEL_PROP_THREAD_EXT__BEGIN + 3,
SPINEL_PROP_THREAD_EXT__END = 0x1600,
SPINEL_PROP_IPV6__BEGIN = 0x60,
SPINEL_PROP_IPV6_LL_ADDR = SPINEL_PROP_IPV6__BEGIN + 0, ///< [6]
SPINEL_PROP_IPV6_ML_ADDR = SPINEL_PROP_IPV6__BEGIN + 1, ///< [6C]
@@ -365,6 +409,7 @@ typedef enum
SPINEL_PROP_STREAM_NET_INSECURE = SPINEL_PROP_STREAM__BEGIN + 3, ///< [D]
SPINEL_PROP_STREAM__END = 0x80,
/// UART Bitrate
/** Format: `L`
*
+13 -3
View File
@@ -63,7 +63,10 @@
#define MAX_FRAME_SIZE 2048
#define HEADER_LEN 5
#define SPI_HEADER_RESET_FLAG (1 << 7)
#define SPI_HEADER_RESET_FLAG 0x80
#define SPI_HEADER_CRC_FLAG 0x40
#define SPI_HEADER_PATTERN_VALUE 0x02
#define SPI_HEADER_PATTERN_MASK 0x03
#define EXIT_QUIT 65535
@@ -437,7 +440,14 @@ static int push_pull_spi(void)
// so that the slave doesn't think
// we are actually trying to transfer
// data.
spi_header_set_flag_byte(sSpiTxFrameBuffer, sSpiValidFrameCount ? 0 : SPI_HEADER_RESET_FLAG);
if (sSpiValidFrameCount == 0)
{
spi_header_set_flag_byte(sSpiTxFrameBuffer, SPI_HEADER_RESET_FLAG|SPI_HEADER_PATTERN_VALUE);
}
else
{
spi_header_set_flag_byte(sSpiTxFrameBuffer, SPI_HEADER_PATTERN_VALUE);
}
spi_header_set_accept_len(sSpiTxFrameBuffer, 0);
spi_header_set_data_len(sSpiTxFrameBuffer, 0);
ret = do_spi_xfer(0);
@@ -514,7 +524,7 @@ static int push_pull_spi(void)
usleep(sSpiTransactionDelay);
spi_header_set_flag_byte(sSpiTxFrameBuffer, 0);
spi_header_set_flag_byte(sSpiTxFrameBuffer, SPI_HEADER_PATTERN_VALUE);
// This is the real transfer.
ret = do_spi_xfer(spi_xfer_bytes);