ncp: Network Control Processor (NCP) implementation (#31) (#45)

In addition to the "SoC/CLI" implementation that is already included,
OpenThread needs a Network Control Processor (NCP) implementation to
facilitate applications where the Host Controller is logically
separate from the controller that implements the Thread stack (Which
is the NCP). This task also necessitates the definition of the
protocol that the Host Controller and the NCP use to communicate with
each other.

This commit represents a functional starting point for both of these.
The initial name of the line protocol is "Spinel" (Named after the
[gemstone][1]). The long-term goal is to standardize the Spinel
protocol to be the official line protocol for host-to-NCP comunication
for Thread.

A [draft of the Spinel protocol document][2] is included in this
commit. At this point everything is subject to change, but as-is the
protocol has been demonstrated to work fairly well.

The NCP implementation in the has been tested and is working well
enough for basic connectivity, but it is far from complete. A Host
implementation is not yet provided in the tree, but will eventually be
included. A separate host implementation for Linux has been written
and is anticipated to be released as a separate project over the next
few weeks.

[1]: https://en.wikipedia.org/wiki/Spinel
[2]: https://github.com/openthread/openthread/blob/feature/ncp-spinel/src/ncp/PROTOCOL.md#spinel-host-controller-interface
This commit is contained in:
Robert Quattlebaum
2016-05-19 17:46:16 -07:00
committed by Jonathan Hui
parent d1b0fed201
commit 12a7060a85
18 changed files with 5726 additions and 2 deletions
+2
View File
@@ -429,6 +429,7 @@ include/crypto/Makefile
include/platform/Makefile
src/Makefile
src/cli/Makefile
src/ncp/Makefile
src/core/Makefile
third_party/Makefile
third_party/mbedtls/Makefile
@@ -436,6 +437,7 @@ examples/Makefile
examples/platform/Makefile
examples/platform/posix/Makefile
examples/cli/Makefile
examples/ncp/Makefile
tests/Makefile
tests/scripts/Makefile
tests/unit/Makefile
+2
View File
@@ -33,6 +33,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
DIST_SUBDIRS = \
platform \
cli \
ncp \
$(NULL)
# Always build (e.g. for 'make all') these subdirectories.
@@ -40,6 +41,7 @@ DIST_SUBDIRS = \
SUBDIRS = \
platform \
cli \
ncp \
$(NULL)
# Always pretty (e.g. for 'make pretty') these subdirectories.
+53
View File
@@ -0,0 +1,53 @@
#
# Copyright (c) 2016, Nest Labs, Inc.
# 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 $(abs_top_nlbuild_autotools_dir)/automake/pre.am
bin_PROGRAMS = ncp
ncp_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/examples \
-I$(top_srcdir)/examples/platform/posix \
-I$(top_srcdir)/third_party \
$(OPENTHREAD_TARGET_DEFINES) \
$(NULL)
ncp_LDADD = \
$(top_builddir)/src/ncp/libopenthread-ncp.a \
$(top_builddir)/src/core/libopenthread.a \
$(top_builddir)/examples/platform/posix/libopenthread-posix.a \
$(top_builddir)/third_party/mbedtls/libmbedcrypto.a \
-lpthread \
$(NULL)
ncp_SOURCES = main.cpp
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 <stdlib.h>
#include <platform/posix/cmdline.h>
#include <ncp/ncp.hpp>
#include <platform/atomic.h>
#include <platform.h>
struct gengetopt_args_info args_info;
Thread::Ncp sNcp;
void otSignalTaskletPending(void)
{
}
int main(int argc, char *argv[])
{
uint32_t atomic_state;
memset(&args_info, 0, sizeof(args_info));
if (cmdline_parser(argc, argv, &args_info) != 0)
{
exit(1);
}
hwAlarmInit();
hwRadioInit();
hwRandomInit();
otInit();
sNcp.Start();
while (1)
{
otProcessNextTasklet();
atomic_state = otPlatAtomicBegin();
if (!otAreTaskletsPending())
{
hwSleep();
}
otPlatAtomicEnd(atomic_state);
}
return 0;
}
+2
View File
@@ -33,6 +33,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
DIST_SUBDIRS = \
cli \
core \
ncp \
$(NULL)
# Always build (e.g. for 'make all') these subdirectories.
@@ -40,6 +41,7 @@ DIST_SUBDIRS = \
SUBDIRS = \
cli \
core \
ncp \
$(NULL)
# Always pretty (e.g. for 'make pretty') these subdirectories.
+5 -2
View File
@@ -45,6 +45,11 @@
namespace Thread {
// This needs to not be static until the NCP
// the OpenThread API is capable enough for
// of of the features in the NCP.
ThreadNetif *sThreadNetif;
#ifdef __cplusplus
extern "C" {
#endif
@@ -55,8 +60,6 @@ extern "C" {
static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t);
static ThreadNetif *sThreadNetif;
static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame);
void otInit()
+82
View File
@@ -0,0 +1,82 @@
#
# Copyright (c) 2016, Nest Labs, Inc.
# 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 $(abs_top_nlbuild_autotools_dir)/automake/pre.am
EXTRA_DIST = \
PROTOCOL.md \
$(NULL)
# Pull in the sources that comprise the OpenThread NCP library.
lib_LIBRARIES = libopenthread-ncp.a
libopenthread_ncp_a_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/third_party \
$(OPENTHREAD_TARGET_DEFINES) \
$(NULL)
libopenthread_ncp_a_CXXFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/third_party \
$(OPENTHREAD_TARGET_DEFINES) \
$(NULL)
libopenthread_ncp_a_SOURCES = \
hdlc.cpp \
hdlc.hpp \
flen.cpp \
flen.hpp \
ncp.cpp \
ncp.hpp \
ncp_base.cpp \
ncp_base.hpp \
spinel.c spinel.h \
$(NULL)
include_HEADERS = \
$(NULL)
noinst_PROGRAMS = spinel-test
spinel_test_SOURCES = spinel.c
spinel_test_CFLAGS = -DSPINEL_SELF_TEST=1
TESTS = spinel-test
install-headers: install-includeHEADERS
if OPENTHREAD_BUILD_COVERAGE
CLEANFILES = $(wildcard *.gcda *.gcno)
endif # OPENTHREAD_BUILD_COVERAGE
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
+1235
View File
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 implements an FLEN encoder and decoder.
*/
#include <common/code_utils.hpp>
#include <ncp/flen.hpp>
namespace Thread {
namespace Flen {
enum
{
kFlagSequence = 0x7e, ///< FLen Flag value
};
ThreadError Encoder::Init(uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
mOutBuf = aOutBuf;
VerifyOrExit(aOutLength >= 3, error = kThreadError_NoBufs);
aOutBuf[0] = kFlagSequence;
// Leave the next two bytes empty.
aOutLength = 3;
mOutLength = 0;
exit:
return error;
}
ThreadError Encoder::Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength)
{
ThreadError error = kThreadError_None;
VerifyOrExit(mOutOffset + 1 < aOutLength, error = kThreadError_NoBufs);
aOutBuf[mOutOffset++] = aInByte;
exit:
return error;
}
ThreadError Encoder::Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
mOutOffset = 0;
for (int i = 0; i < aInLength; i++)
{
SuccessOrExit(error = Encode(aInBuf[i], aOutBuf, aOutLength));
}
exit:
aOutLength = mOutOffset;
mOutLength += aOutLength;
return error;
}
ThreadError Encoder::Finalize(uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
VerifyOrExit(mOutOffset < aOutLength, error = kThreadError_NoBufs);
mOutBuf[1] = (mOutLength >> 8);
mOutBuf[2] = (mOutLength & 0xFF);
aOutLength = 0;
exit:
return error;
}
Decoder::Decoder(uint8_t *aOutBuf, uint16_t aOutLength, FrameHandler aFrameHandler, void *aContext)
{
mState = kStateNeedFlag;
mFrameHandler = aFrameHandler;
mContext = aContext;
mOutBuf = aOutBuf;
mOutOffset = 0;
mOutLength = aOutLength;
}
void Decoder::Decode(const uint8_t *aInBuf, uint16_t aInLength)
{
uint8_t byte;
for (int i = 0; i < aInLength; i++)
{
byte = aInBuf[i];
switch (mState)
{
case kStateNeedFlag:
if (byte == kFlagSequence)
{
mState = kStateNeedLenH;
mOutOffset = 0;
}
break;
case kStateNeedLenH:
mReadLength = (byte << 8);
mState = kStateNeedLenL;
break;
case kStateNeedLenL:
mReadLength += byte;
if (mReadLength > mOutLength)
{
// Too big.
mState = kStateNeedFlag;
}
else
{
mState = kStateNeedData;
}
break;
case kStateNeedData:
mOutBuf[mOutOffset++] = byte;
if (mOutOffset >= mReadLength)
{
mState = kStateNeedFlag;
mFrameHandler(mContext, mOutBuf, mReadLength);
}
break;
}
}
}
} // namespace Flen
} // namespace Thread
+162
View File
@@ -0,0 +1,162 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 an FLEN (flag/length) encoder and decoder.
*/
#ifndef FLEN_HPP_
#define FLEN_HPP_
#include <openthread-types.h>
#include <common/message.hpp>
namespace Thread {
/**
* @namespace Thread::Flen
*
* @brief
* This namespace includes definitions for the FLEN encoder and decoder.
*
*/
namespace Flen {
/**
* This class implements the FLEN encoder.
*
*/
class Encoder
{
public:
/**
* This method begins an FLEN frame and puts the initial bytes into @p aOutBuf.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[inout] aOutLength On entry, the output buffer size; On exit, the output length.
*
* @retval kThreadError_None Successfully started the FLEN frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to start the FLEN frame.
*
*/
ThreadError Init(uint8_t *aOutBuf, uint16_t &aOutLength);
/**
* This method encodes the frame.
*
* @param[in] aInBuf A pointer to the input buffer.
* @param[in] aInLength The number of bytes in @p aInBuf to encode.
* @param[out] aOutBuf A pointer to the output buffer.
* @param[out] aOutLength On exit, the number of bytes placed in @p aOutBuf.
*
* @retval kThreadError_None Successfully encoded the FLEN frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to encode the FLEN frame.
*
*/
ThreadError Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength);
/**
* This method ends an FLEN frame and puts the initial bytes into @p aOutBuf.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[inout] aOutLength On entry, the output buffer size; On exit, the output length.
*
* @retval kThreadError_None Successfully ended the FLEN frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to end the FLEN frame.
*
*/
ThreadError Finalize(uint8_t *aOutBuf, uint16_t &aOutLength);
private:
ThreadError Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength);
uint8_t *mOutBuf;
uint16_t mOutOffset;
uint16_t mOutLength;
};
/**
* This class implements the FLEN decoder.
*
*/
class Decoder
{
public:
/**
* This function pointer is called when a complete frame has been formed.
*
* @param[in] aContext A pointer to arbitrary context information.
* @param[in] aFrame A pointer to the frame.
* @param[in] aFrameLength The frame length in bytes.
*
*/
typedef void (*FrameHandler)(void *aContext, uint8_t *aFrame, uint16_t aFrameLength);
/**
* This constructor initializes the decoder.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[in] aOutLength Size of the output buffer in bytes.
* @param[in] aFrameHandler A pointer to a function that is called when a complete frame is received.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
Decoder(uint8_t *aOutBuf, uint16_t aOutLength, FrameHandler aFrameHandler, void *aContext);
/**
* This method streams bytes into the decoder.
*
* @param[in] aInBuf A pointer to the input buffer.
* @param[in] aInLength The number of bytes in @p aInBuf.
*
*/
void Decode(const uint8_t *aInBuf, uint16_t aInLength);
private:
enum State
{
kStateNeedFlag = 0,
kStateNeedLenH,
kStateNeedLenL,
kStateNeedData,
};
State mState;
FrameHandler mFrameHandler;
void *mContext;
uint8_t *mOutBuf;
uint16_t mOutOffset;
uint16_t mOutLength;
uint16_t mReadLength;
};
} // namespace Flen
} // namespace Thread
#endif // FLEN_HPP_
+266
View File
@@ -0,0 +1,266 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 implements an HDLC-lite encoder and decoder.
*/
#include <common/code_utils.hpp>
#include <ncp/hdlc.hpp>
namespace Thread {
namespace Hdlc {
/**
* This method updates an FCS.
*
* @param[in] aFcs The FCS to update.
* @param[in] aByte The intput byte value.
*
* @returns The updated FCS.
*
*/
static uint16_t UpdateFcs(uint16_t aFcs, uint8_t aByte);
enum
{
kFlagSequence = 0x7e, ///< HDLC Flag value
kEscapeSequence = 0x7d, ///< HDLC Escape value
};
/**
* FCS lookup table
*
*/
enum
{
kInitFcs = 0xffff, ///< Initial FCS value.
kGoodFcs = 0xf0b8, ///< Good FCS value.
};
uint16_t UpdateFcs(uint16_t aFcs, uint8_t aByte)
{
static const uint16_t sFcsTable[256] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
return (aFcs >> 8) ^ sFcsTable[(aFcs ^ aByte) & 0xff];
}
ThreadError Encoder::Init(uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
mFcs = kInitFcs;
VerifyOrExit(aOutLength > 0, error = kThreadError_NoBufs);
aOutBuf[0] = kFlagSequence;
aOutLength = 1;
exit:
return error;
}
ThreadError Encoder::Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength)
{
ThreadError error = kThreadError_None;
mFcs = UpdateFcs(mFcs, aInByte);
if (aInByte == kFlagSequence || aInByte == kEscapeSequence)
{
VerifyOrExit(mOutOffset + 2 < aOutLength, error = kThreadError_NoBufs);
aOutBuf[mOutOffset++] = kEscapeSequence;
aOutBuf[mOutOffset++] = aInByte ^ 0x20;
}
else
{
VerifyOrExit(mOutOffset + 1 < aOutLength, error = kThreadError_NoBufs);
aOutBuf[mOutOffset++] = aInByte;
}
exit:
return error;
}
ThreadError Encoder::Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
mOutOffset = 0;
for (int i = 0; i < aInLength; i++)
{
SuccessOrExit(error = Encode(aInBuf[i], aOutBuf, aOutLength));
}
exit:
aOutLength = mOutOffset;
return error;
}
ThreadError Encoder::Finalize(uint8_t *aOutBuf, uint16_t &aOutLength)
{
ThreadError error = kThreadError_None;
uint16_t fcs = mFcs;
mOutOffset = 0;
fcs ^= 0xffff;
SuccessOrExit(error = Encode(fcs, aOutBuf, aOutLength));
SuccessOrExit(error = Encode(fcs >> 8, aOutBuf, aOutLength));
VerifyOrExit(mOutOffset < aOutLength, error = kThreadError_NoBufs);
aOutBuf[mOutOffset++] = kFlagSequence;
aOutLength = mOutOffset;
exit:
return error;
}
Decoder::Decoder(uint8_t *aOutBuf, uint16_t aOutLength, FrameHandler aFrameHandler, void *aContext)
{
mState = kStateNoSync;
mFrameHandler = aFrameHandler;
mContext = aContext;
mOutBuf = aOutBuf;
mOutOffset = 0;
mOutLength = aOutLength;
}
void Decoder::Decode(const uint8_t *aInBuf, uint16_t aInLength)
{
uint8_t byte;
for (int i = 0; i < aInLength; i++)
{
byte = aInBuf[i];
switch (mState)
{
case kStateNoSync:
if (byte == kFlagSequence)
{
mState = kStateSync;
mOutOffset = 0;
mFcs = kInitFcs;
}
break;
case kStateSync:
switch (byte)
{
case kEscapeSequence:
mState = kStateEscaped;
break;
case kFlagSequence:
if (mOutOffset > 0)
{
if (mFcs == kGoodFcs)
{
mFrameHandler(mContext, mOutBuf, mOutOffset - 2);
}
mOutOffset = 0;
mFcs = kInitFcs;
}
break;
default:
if (mOutOffset < mOutLength)
{
mFcs = UpdateFcs(mFcs, byte);
mOutBuf[mOutOffset++] = byte;
}
else
{
mState = kStateNoSync;
}
break;
}
break;
case kStateEscaped:
if (mOutOffset < mOutLength)
{
byte ^= 0x20;
mFcs = UpdateFcs(mFcs, byte);
mOutBuf[mOutOffset++] = byte;
mState = kStateSync;
}
else
{
mState = kStateNoSync;
}
break;
}
}
}
} // namespace Hdlc
} // namespace Thread
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 an HDLC-lite encoder and decoer.
*/
#ifndef HDLC_HPP_
#define HDLC_HPP_
#include <openthread-types.h>
#include <common/message.hpp>
namespace Thread {
/**
* @namespace Thread::Hdlc
*
* @brief
* This namespace includes definitions for the HDLC-lite encoder and decoder.
*
*/
namespace Hdlc {
/**
* This class implements the HDLC-lite encoder.
*
*/
class Encoder
{
public:
/**
* This method begins an HDLC frame and puts the initial bytes into @p aOutBuf.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[inout] aOutLength On entry, the output buffer size; On exit, the output length.
*
* @retval kThreadError_None Successfully started the HDLC frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to start the HDLC frame.
*
*/
ThreadError Init(uint8_t *aOutBuf, uint16_t &aOutLength);
/**
* This method encodes the frame.
*
* @param[in] aInBuf A pointer to the input buffer.
* @param[in] aInLength The number of bytes in @p aInBuf to encode.
* @param[out] aOutBuf A pointer to the output buffer.
* @param[out] aOutLength On exit, the number of bytes placed in @p aOutBuf.
*
* @retval kThreadError_None Successfully encoded the HDLC frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to encode the HDLC frame.
*
*/
ThreadError Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength);
/**
* This method ends an HDLC frame and puts the initial bytes into @p aOutBuf.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[inout] aOutLength On entry, the output buffer size; On exit, the output length.
*
* @retval kThreadError_None Successfully ended the HDLC frame.
* @retval kThreadError_NoBufs Insufficient buffer space available to end the HDLC frame.
*
*/
ThreadError Finalize(uint8_t *aOutBuf, uint16_t &aOutLength);
private:
ThreadError Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength);
uint16_t mOutOffset;
uint16_t mFcs;
};
/**
* This class implements the HDLC-lite decoder.
*
*/
class Decoder
{
public:
/**
* This function pointer is called when a complete frame has been formed.
*
* @param[in] aContext A pointer to arbitrary context information.
* @param[in] aFrame A pointer to the frame.
* @param[in] aFrameLength The frame length in bytes.
*
*/
typedef void (*FrameHandler)(void *aContext, uint8_t *aFrame, uint16_t aFrameLength);
/**
* This constructor initializes the decoder.
*
* @param[in] aOutBuf A pointer to the output buffer.
* @param[in] aOutLength Size of the output buffer in bytes.
* @param[in] aFrameHandler A pointer to a function that is called when a complete frame is received.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
Decoder(uint8_t *aOutBuf, uint16_t aOutLength, FrameHandler aFrameHandler, void *aContext);
/**
* This method streams bytes into the decoder.
*
* @param[in] aInBuf A pointer to the input buffer.
* @param[in] aInLength The number of bytes in @p aInBuf.
*
*/
void Decode(const uint8_t *aInBuf, uint16_t aInLength);
private:
enum State
{
kStateNoSync = 0,
kStateSync,
kStateEscaped,
};
State mState;
FrameHandler mFrameHandler;
void *mContext;
uint8_t *mOutBuf;
uint16_t mOutOffset;
uint16_t mOutLength;
uint16_t mFcs;
};
} // namespace Hdlc
} // namespace Thread
#endif // HDLC_HPP_
+204
View File
@@ -0,0 +1,204 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 implements an HDLC interface to the Thread stack.
*/
#include <common/code_utils.hpp>
#include <ncp/ncp.hpp>
#include <platform/serial.h>
namespace Thread {
static Tasklet sSendDoneTask(&Ncp::SendDoneTask, NULL);
static Tasklet sReceiveTask(&Ncp::ReceiveTask, NULL);
static Ncp *sNcp;
Ncp::Ncp():
NcpBase(),
mFrameDecoder(mReceiveFrame, sizeof(mReceiveFrame), &HandleFrame, this)
{
sNcp = this;
}
ThreadError Ncp::Start()
{
otPlatSerialEnable();
return super_t::Start();
}
ThreadError Ncp::Stop()
{
otPlatSerialDisable();
return super_t::Stop();
}
uint16_t
Ncp::OutboundFrameGetRemaining(void)
{
return static_cast<int16_t>(sizeof(mSendFrame) - (mSendFrameIter - mSendFrame));
}
ThreadError
Ncp::OutboundFrameBegin(void)
{
ThreadError errorCode;
uint16_t outLength;
mSendFrameIter = mSendFrame;
outLength = OutboundFrameGetRemaining();
errorCode = mFrameEncoder.Init(mSendFrameIter, outLength);
if (errorCode == kThreadError_None)
{
mSendFrameIter += outLength;
}
return errorCode;
}
ThreadError
Ncp::OutboundFrameFeedData(const uint8_t *frame, uint16_t frameLength)
{
ThreadError errorCode;
uint16_t outLength(OutboundFrameGetRemaining());
errorCode = mFrameEncoder.Encode(frame, frameLength, mSendFrameIter, outLength);
if (errorCode == kThreadError_None)
{
mSendFrameIter += outLength;
}
return errorCode;
}
ThreadError
Ncp::OutboundFrameFeedMessage(Message &message)
{
ThreadError errorCode;
uint16_t inLength;
uint16_t outLength;
uint8_t inBuf[16];
for (int offset = 0; offset < message.GetLength(); offset += sizeof(inBuf))
{
outLength = OutboundFrameGetRemaining();
inLength = message.Read(offset, sizeof(inBuf), inBuf);
errorCode = OutboundFrameFeedData(inBuf, inLength);
if (errorCode != kThreadError_None)
{
break;
}
}
return errorCode;
}
ThreadError
Ncp::OutboundFrameSend(void)
{
ThreadError errorCode;
uint16_t outLength(OutboundFrameGetRemaining());
errorCode = mFrameEncoder.Finalize(mSendFrameIter, outLength);
if (errorCode == kThreadError_None)
{
mSendFrameIter += outLength;
errorCode = otPlatSerialSend(mSendFrame, mSendFrameIter - mSendFrame);
}
if (errorCode == kThreadError_None)
{
mSending = true;
}
return errorCode;
}
extern "C" void otPlatSerialSignalSendDone()
{
sSendDoneTask.Post();
}
void Ncp::SendDoneTask(void *context)
{
sNcp->SendDoneTask();
}
void Ncp::SendDoneTask()
{
mSending = false;
if (mSendMessage)
{
Message::Free(*mSendMessage);
mSendMessage = NULL;
}
super_t::HandleSendDone();
}
extern "C" void otPlatSerialSignalReceive()
{
sReceiveTask.Post();
}
void Ncp::ReceiveTask(void *context)
{
sNcp->ReceiveTask();
}
void Ncp::ReceiveTask()
{
const uint8_t *buf;
uint16_t bufLength;
buf = otPlatSerialGetReceivedBytes(&bufLength);
mFrameDecoder.Decode(buf, bufLength);
otPlatSerialHandleReceiveDone();
}
void Ncp::HandleFrame(void *context, uint8_t *aBuf, uint16_t aBufLength)
{
sNcp->HandleFrame(aBuf, aBufLength);
}
void Ncp::HandleFrame(uint8_t *aBuf, uint16_t aBufLength)
{
super_t::HandleReceive(aBuf, aBufLength);
}
} // namespace Thread
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 contains definitions for an FLEN/HDLC interface to the OpenThread stack.
*/
#ifndef NCP_HPP_
#define NCP_HPP_
#include <ncp/ncp_base.hpp>
#include <ncp/flen.hpp>
#include <ncp/hdlc.hpp>
namespace Thread {
class Ncp : public NcpBase
{
typedef NcpBase super_t;
public:
Ncp();
ThreadError Start();
ThreadError Stop();
virtual ThreadError OutboundFrameBegin(void);
virtual uint16_t OutboundFrameGetRemaining(void);
virtual ThreadError OutboundFrameFeedData(const uint8_t *frame, uint16_t frameLength);
virtual ThreadError OutboundFrameFeedMessage(Message &message);
virtual ThreadError OutboundFrameSend(void);
static void HandleFrame(void *context, uint8_t *aBuf, uint16_t aBufLength);
static void SendDoneTask(void *context);
static void ReceiveTask(void *context);
private:
void HandleFrame(uint8_t *aBuf, uint16_t aBufLength);
void SendDoneTask();
void ReceiveTask();
Hdlc::Encoder mFrameEncoder;
Hdlc::Decoder mFrameDecoder;
uint8_t mSendFrame[1500];
uint8_t mReceiveFrame[1500];
uint8_t *mSendFrameIter;
Message *mSendMessage;
};
} // namespace Thread
#endif // NCP_HPP_
+1572
View File
File diff suppressed because it is too large Load Diff
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 contains definitions a spinel interface to the OpenThread stack.
*/
#ifndef NCP_BASE_HPP_
#define NCP_BASE_HPP_
#include <openthread-types.h>
#include <common/message.hpp>
#include <thread/thread_netif.hpp>
#include "spinel.h"
namespace Thread {
class NcpBase
{
public:
NcpBase();
virtual ThreadError Start();
virtual ThreadError Stop();
virtual ThreadError OutboundFrameBegin(void) = 0;
virtual uint16_t OutboundFrameGetRemaining(void) = 0;
virtual ThreadError OutboundFrameFeedData(const uint8_t *frame, uint16_t frameLength) = 0;
virtual ThreadError OutboundFrameFeedMessage(Message &message) = 0;
virtual ThreadError OutboundFrameFeedPacked(const char *pack_format, ...);
virtual ThreadError OutboundFrameFeedVPacked(const char *pack_format, va_list args);
virtual ThreadError OutboundFrameSend(void) = 0;
static void HandleReceivedDatagram(void *context, Message &message);
void HandleReceivedDatagram(Message &message);
protected:
static void HandleReceive(void *context, const uint8_t *buf, uint16_t bufLength);
void HandleReceive(const uint8_t *buf, uint16_t bufLength);
static void HandleSendDone(void *context);
void HandleSendDone();
bool mSending;
private:
void HandleCommand(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
void HandleCommandReset(uint8_t header);
void HandleCommandNoop(uint8_t header);
void HandleCommandPropertyGet(uint8_t header, spinel_prop_key_t key);
void HandleCommandPropertySet(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len);
void HandleCommandPropertyInsert(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len);
void HandleCommandPropertyRemove(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len);
void HandleCommandPropertyGetAddressList(uint8_t header);
void HandleCommandPropertyGetRoutingTable(uint8_t header);
void SendLastStatus(uint8_t header, spinel_status_t lastStatus);
void SendPropteryUpdate(uint8_t header, uint8_t command, spinel_prop_key_t key, const uint8_t *value_ptr,
uint16_t value_len);
void SendPropteryUpdate(uint8_t header, uint8_t command, spinel_prop_key_t key, Message &message);
void SendPropteryUpdate(uint8_t header, uint8_t command, spinel_prop_key_t key, const char *format, ...);
static void HandleActiveScanResult_Jump(otActiveScanResult *result);
void HandleActiveScanResult(otActiveScanResult *result);
static void HandleUnicastAddressesChanged(void *context);
static void RunUpdateAddressesTask(void *context);
Ip6::NetifHandler mNetifHandler;
spinel_status_t mLastStatus;
uint32_t mChannelMask;
uint8_t mQueuedGetHeader;
spinel_prop_key_t mQueuedGetKey;
void RunUpdateAddressesTask();
Tasklet mUpdateAddressesTask;
void RunSendScanResultsTask();
protected:
MessageQueue mSendQueue;
};
} // namespace Thread
#endif // NCP_BASE_HPP_
+1123
View File
File diff suppressed because it is too large Load Diff
+415
View File
@@ -0,0 +1,415 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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 SPINEL_HEADER_INCLUDED
#define SPINEL_HEADER_INCLUDED 1
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <arpa/inet.h>
__BEGIN_DECLS
// ----------------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
# if defined(__GNUC__) && !SPINEL_EMBEDDED
# define SPINEL_API_EXTERN extern __attribute__ ((visibility ("default")))
# define SPINEL_API_NONNULL_ALL __attribute__((nonnull))
# define SPINEL_API_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
# endif // ifdef __GNUC__
#endif // ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifndef SPINEL_API_EXTERN
# define SPINEL_API_EXTERN extern
#endif
#ifndef SPINEL_API_NONNULL_ALL
# define SPINEL_API_NONNULL_ALL
#endif
#ifndef SPINEL_API_WARN_UNUSED_RESULT
# define SPINEL_API_WARN_UNUSED_RESULT
#endif
// ----------------------------------------------------------------------------
#define SPINEL_PROTOCOL_VERSION_THREAD_MAJOR 0
#define SPINEL_PROTOCOL_VERSION_THREAD_MINOR 0
#define SPINEL_FRAME_MAX_SIZE 1300
// ----------------------------------------------------------------------------
typedef enum
{
SPINEL_STATUS_OK = 0, //!< Operation has completed successfully.
SPINEL_STATUS_FAILURE = 1, //!< Operation has failed for some undefined reason.
SPINEL_STATUS_UNIMPLEMENTED = 2,
SPINEL_STATUS_INVALID_ARGUMENT = 3,
SPINEL_STATUS_INVALID_STATE = 4,
SPINEL_STATUS_INVALID_COMMAND = 5,
SPINEL_STATUS_INVALID_INTERFACE = 6,
SPINEL_STATUS_INTERNAL_ERROR = 7,
SPINEL_STATUS_SECURITY_ERROR = 8,
SPINEL_STATUS_PARSE_ERROR = 9,
SPINEL_STATUS_IN_PROGRESS = 10,
SPINEL_STATUS_NOMEM = 11,
SPINEL_STATUS_BUSY = 12,
SPINEL_STATUS_PROPERTY_NOT_FOUND = 12,
SPINEL_STATUS_DROPPED = 14,
SPINEL_STATUS_EMPTY = 15,
SPINEL_STATUS_RESET__BEGIN = 112,
SPINEL_STATUS_RESET_POWER_ON = SPINEL_STATUS_RESET__BEGIN + 0,
SPINEL_STATUS_RESET_EXTERNAL = SPINEL_STATUS_RESET__BEGIN + 1,
SPINEL_STATUS_RESET_SOFTWARE = SPINEL_STATUS_RESET__BEGIN + 2,
SPINEL_STATUS_RESET_FAULT = SPINEL_STATUS_RESET__BEGIN + 3,
SPINEL_STATUS_RESET_CRASH = SPINEL_STATUS_RESET__BEGIN + 4,
SPINEL_STATUS_RESET_ASSERT = SPINEL_STATUS_RESET__BEGIN + 5,
SPINEL_STATUS_RESET_OTHER = SPINEL_STATUS_RESET__BEGIN + 6,
SPINEL_STATUS_RESET__END = 128,
SPINEL_STATUS_VENDOR__BEGIN = 15360,
SPINEL_STATUS_VENDOR__END = 16384,
SPINEL_STATUS_EXPERIMENTAL__BEGIN = 2000000,
SPINEL_STATUS_EXPERIMENTAL__END = 2097152,
} spinel_status_t;
typedef enum
{
SPINEL_NET_STATE_OFFLINE = 0,
SPINEL_NET_STATE_DETACHED = 1,
SPINEL_NET_STATE_ATTACHING = 2,
SPINEL_NET_STATE_ATTACHED = 3,
} spinel_net_state_t;
typedef enum
{
SPINEL_NET_ROLE_NONE = 0,
SPINEL_NET_ROLE_CHILD = 1,
SPINEL_NET_ROLE_ROUTER = 2,
SPINEL_NET_ROLE_LEADER = 3,
} spinel_net_role_t;
typedef enum
{
SPINEL_SCAN_STATE_IDLE = 0,
SPINEL_SCAN_STATE_BEACON = 1,
SPINEL_SCAN_STATE_ENERGY = 2,
} spinel_scan_state_t;
typedef enum
{
SPINEL_POWER_STATE_OFFLINE = 0,
SPINEL_POWER_STATE_DEEP_SLEEP = 1,
SPINEL_POWER_STATE_STANDBY = 2,
SPINEL_POWER_STATE_LOW_POWER = 3,
SPINEL_POWER_STATE_ONLINE = 4,
} spinel_power_state_t;
enum
{
SPINEL_PROTOCOL_TYPE_ZIGBEE = 1,
SPINEL_PROTOCOL_TYPE_ZIGBEE_IP = 2,
SPINEL_PROTOCOL_TYPE_THREAD = 3,
};
typedef struct
{
uint8_t bytes[8];
} spinel_eui64_t;
typedef struct
{
uint8_t bytes[8];
} spinel_net_xpanid_t;
typedef struct
{
uint8_t bytes[6];
} spinel_eui48_t;
typedef struct in6_addr spinel_ipv6addr_t;
typedef int spinel_ssize_t;
typedef unsigned int spinel_size_t;
typedef uint8_t spinel_tid_t;
enum
{
SPINEL_CMD_NOOP = 0,
SPINEL_CMD_RESET = 1,
SPINEL_CMD_PROP_VALUE_GET = 2,
SPINEL_CMD_PROP_VALUE_SET = 3,
SPINEL_CMD_PROP_VALUE_INSERT = 4,
SPINEL_CMD_PROP_VALUE_REMOVE = 5,
SPINEL_CMD_PROP_VALUE_IS = 6,
SPINEL_CMD_PROP_VALUE_INSERTED = 7,
SPINEL_CMD_PROP_VALUE_REMOVED = 8,
SPINEL_CMD_NET_SAVE = 9,
SPINEL_CMD_NET_CLEAR = 10,
SPINEL_CMD_NET_RECALL = 11,
SPINEL_CMD_HBO_OFFLOAD = 12,
SPINEL_CMD_HBO_RECLAIM = 13,
SPINEL_CMD_HBO_DROP = 14,
SPINEL_CMD_HBO_OFFLOADED = 15,
SPINEL_CMD_HBO_RECLAIMED = 16,
SPINEL_CMD_HBO_DROPED = 17,
SPINEL_CMD_NEST__BEGIN = 15296,
SPINEL_CMD_NEST__END = 15360,
SPINEL_CMD_VENDOR__BEGIN = 15360,
SPINEL_CMD_VENDOR__END = 16384,
SPINEL_CMD_EXPERIMENTAL__BEGIN = 2000000,
SPINEL_CMD_EXPERIMENTAL__END = 2097152,
};
enum
{
SPINEL_CAP_LOCK = 1,
SPINEL_CAP_NET_SAVE = 2,
SPINEL_CAP_HBO = 3,
SPINEL_CAP_POWER_SAVE = 4,
SPINEL_CAP_802_15_4__BEGIN = 16,
SPINEL_CAP_802_15_4_2003 = (SPINEL_CAP_802_15_4__BEGIN + 0),
SPINEL_CAP_802_15_4_2006 = (SPINEL_CAP_802_15_4__BEGIN + 1),
SPINEL_CAP_802_15_4_2011 = (SPINEL_CAP_802_15_4__BEGIN + 2),
SPINEL_CAP_802_15_4_PIB = (SPINEL_CAP_802_15_4__BEGIN + 5),
SPINEL_CAP_802_15_4_2450MHZ_OQPSK = (SPINEL_CAP_802_15_4__BEGIN + 8),
SPINEL_CAP_802_15_4_915MHZ_OQPSK = (SPINEL_CAP_802_15_4__BEGIN + 9),
SPINEL_CAP_802_15_4_868MHZ_OQPSK = (SPINEL_CAP_802_15_4__BEGIN + 10),
SPINEL_CAP_802_15_4_915MHZ_BPSK = (SPINEL_CAP_802_15_4__BEGIN + 11),
SPINEL_CAP_802_15_4_868MHZ_BPSK = (SPINEL_CAP_802_15_4__BEGIN + 12),
SPINEL_CAP_802_15_4_915MHZ_ASK = (SPINEL_CAP_802_15_4__BEGIN + 13),
SPINEL_CAP_802_15_4_868MHZ_ASK = (SPINEL_CAP_802_15_4__BEGIN + 14),
SPINEL_CAP_802_15_4__END = 32,
SPINEL_CAP_ROLE__BEGIN = 48,
SPINEL_CAP_ROLE_ROUTER = (SPINEL_CAP_ROLE__BEGIN + 0),
SPINEL_CAP_ROLE_SLEEPY = (SPINEL_CAP_ROLE__BEGIN + 1),
SPINEL_CAP_ROLE__END = 52,
SPINEL_CAP_NET__BEGIN = 52,
SPINEL_CAP_NET_THREAD_1_0 = (SPINEL_CAP_NET__BEGIN + 0),
SPINEL_CAP_NET__END = 64,
SPINEL_CAP_NEST__BEGIN = 15296,
SPINEL_CAP_NEST_LEGACY_INTERFACE = (SPINEL_CAP_NEST__BEGIN + 0),
SPINEL_CAP_NEST_LEGACY_NET_WAKE = (SPINEL_CAP_NEST__BEGIN + 1),
SPINEL_CAP_NEST_TRANSMIT_HOOK = (SPINEL_CAP_NEST__BEGIN + 2),
SPINEL_CAP_NEST__END = 15360,
SPINEL_CAP_VENDOR__BEGIN = 15360,
SPINEL_CAP_VENDOR__END = 16384,
SPINEL_CAP_EXPERIMENTAL__BEGIN = 2000000,
SPINEL_CAP_EXPERIMENTAL__END = 2097152,
};
typedef enum
{
SPINEL_PROP_LAST_STATUS = 0, // status [i]
SPINEL_PROP_PROTOCOL_VERSION = 1, // interface type, major, minor, vendor [i,i,i,i]
SPINEL_PROP_CAPABILITIES = 2, // capability list [A(i)]
SPINEL_PROP_NCP_VERSION = 3, // version string [U]
SPINEL_PROP_INTERFACE_COUNT = 4, // Interface count [C]
SPINEL_PROP_POWER_STATE = 5, // PowerState [C]
SPINEL_PROP_HWADDR = 6, // PermEUI64 [E]
SPINEL_PROP_LOCK = 7, // PropLock [b]
SPINEL_PROP_HBO_MEM_MAX = 8, // Max offload mem [S]
SPINEL_PROP_HBO_BLOCK_MAX = 9, // Max offload block [S]
SPINEL_PROP_PHY__BEGIN = 0x20,
SPINEL_PROP_PHY_ENABLED = SPINEL_PROP_PHY__BEGIN + 0, // [b]
SPINEL_PROP_PHY_CHAN = SPINEL_PROP_PHY__BEGIN + 1, // [C]
SPINEL_PROP_PHY_CHAN_SUPPORTED = SPINEL_PROP_PHY__BEGIN + 2, // [A(C)]
SPINEL_PROP_PHY_FREQ = SPINEL_PROP_PHY__BEGIN + 3, // kHz [L]
SPINEL_PROP_PHY_CCA_THRESHOLD = SPINEL_PROP_PHY__BEGIN + 4, // dBm [c]
SPINEL_PROP_PHY_TX_POWER = SPINEL_PROP_PHY__BEGIN + 5, // [c]
SPINEL_PROP_PHY_RSSI = SPINEL_PROP_PHY__BEGIN + 6, // dBm [c]
SPINEL_PROP_PHY_RAW_STREAM_ENABLED = SPINEL_PROP_PHY__BEGIN + 7, // [C]
SPINEL_PROP_PHY__END = 0x30,
SPINEL_PROP_MAC__BEGIN = 0x30,
SPINEL_PROP_MAC_SCAN_STATE = SPINEL_PROP_MAC__BEGIN + 0, // [C]
SPINEL_PROP_MAC_SCAN_MASK = SPINEL_PROP_MAC__BEGIN + 1, // [A(C)]
SPINEL_PROP_MAC_SCAN_PERIOD = SPINEL_PROP_MAC__BEGIN + 2, // ms-per-channel [S]
SPINEL_PROP_MAC_SCAN_BEACON = SPINEL_PROP_MAC__BEGIN + 3, // chan,rssi,(laddr,saddr,panid,lqi),(proto,xtra) [CcT(ESSC)T(i).]
SPINEL_PROP_MAC_15_4_LADDR = SPINEL_PROP_MAC__BEGIN + 4, // [E]
SPINEL_PROP_MAC_15_4_SADDR = SPINEL_PROP_MAC__BEGIN + 5, // [S]
SPINEL_PROP_MAC_15_4_PANID = SPINEL_PROP_MAC__BEGIN + 6, // [S]
SPINEL_PROP_MAC__END = 0x40,
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]
SPINEL_PROP_NET_STATE = SPINEL_PROP_NET__BEGIN + 2, // [C]
SPINEL_PROP_NET_ROLE = SPINEL_PROP_NET__BEGIN + 3, // [C]
SPINEL_PROP_NET_NETWORK_NAME = SPINEL_PROP_NET__BEGIN + 4, // [U]
SPINEL_PROP_NET_XPANID = SPINEL_PROP_NET__BEGIN + 5, // [D]
SPINEL_PROP_NET_MASTER_KEY = SPINEL_PROP_NET__BEGIN + 6, // [D]
SPINEL_PROP_NET_KEY_SEQUENCE = SPINEL_PROP_NET__BEGIN + 7, // [L]
SPINEL_PROP_NET_PARTITION_ID = SPINEL_PROP_NET__BEGIN + 8, // [L]
SPINEL_PROP_NET__END = 0x50,
SPINEL_PROP_THREAD__BEGIN = 0x50,
SPINEL_PROP_THREAD_LEADER = SPINEL_PROP_THREAD__BEGIN + 0, // [6]
SPINEL_PROP_THREAD_PARENT = SPINEL_PROP_THREAD__BEGIN + 1, // LADDR, SADDR [ES]
SPINEL_PROP_THREAD_CHILD_TABLE = SPINEL_PROP_THREAD__BEGIN + 2, // [A(T(ES))]
SPINEL_PROP_THREAD__END = 0x60,
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]
SPINEL_PROP_IPV6_ML_PREFIX = SPINEL_PROP_IPV6__BEGIN + 2, // [6C]
SPINEL_PROP_IPV6_ADDRESS_TABLE = SPINEL_PROP_IPV6__BEGIN + 3, // array(ipv6addr,prefixlen,flags) [A(6CL)]
SPINEL_PROP_IPV6_ROUTE_TABLE = SPINEL_PROP_IPV6__BEGIN + 4, // array(ipv6prefix,prefixlen,nexthop,flags) [A(6C6L)]
SPINEL_PROP_IPV6__END = 0x70,
SPINEL_PROP_STREAM__BEGIN = 112,
SPINEL_PROP_STREAM_DEBUG = SPINEL_PROP_STREAM__BEGIN + 0, // [U]
SPINEL_PROP_STREAM_RAW = SPINEL_PROP_STREAM__BEGIN + 1, // [D]
SPINEL_PROP_STREAM_NET = SPINEL_PROP_STREAM__BEGIN + 2, // [D]
SPINEL_PROP_STREAM_NET_INSECURE = SPINEL_PROP_STREAM__BEGIN + 3, // [D]
SPINEL_PROP_STREAM__END = 128,
SPINEL_PROP_15_4_PIB__BEGIN = 1024,
// For direct access to the 802.15.4 PID.
// Individual registers are fetched using
// `SPINEL_PROP_15_4_PIB__BEGIN+[PIB_IDENTIFIER]`
// Only supported if SPINEL_CAP_15_4_PIB is set.
SPINEL_PROP_15_4_PIB__END = 1280,
SPINEL_PROP_NEST__BEGIN = 15296,
SPINEL_PROP_NEST__END = 15360,
SPINEL_PROP_VENDOR__BEGIN = 15360,
SPINEL_PROP_VENDOR__END = 16384,
SPINEL_PROP_EXPERIMENTAL__BEGIN = 2000000,
SPINEL_PROP_EXPERIMENTAL__END = 2097152,
} spinel_prop_key_t;
// ----------------------------------------------------------------------------
#define SPINEL_HEADER_FLAG 0x80
#define SPINEL_HEADER_TID_SHIFT 0
#define SPINEL_HEADER_TID_MASK (15 << SPINEL_HEADER_TID_SHIFT)
#define SPINEL_HEADER_IID_SHIFT 4
#define SPINEL_HEADER_IID_MASK (3 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_IID_0 (0 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_IID_1 (1 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_IID_2 (2 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_IID_3 (3 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_GET_IID(x) (((x) & SPINEL_HEADER_IID_MASK) >> SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_GET_TID(x) (spinel_tid_t)(((x)&SPINEL_HEADER_TID_MASK)>>SPINEL_HEADER_TID_SHIFT)
#define SPINEL_GET_NEXT_TID(x) (spinel_tid_t)((x)>=0xF?1:(x)+1)
#define SPINEL_BEACON_THREAD_FLAG_VERSION_SHIFT 4
#define SPINEL_BEACON_THREAD_FLAG_VERSION_MASK (0xf << SPINEL_BEACON_THREAD_FLAG_VERSION_SHIFT)
#define SPINEL_BEACON_THREAD_FLAG_JOINABLE (1 << 0)
#define SPINEL_BEACON_THREAD_FLAG_NATIVE (1 << 3)
// ----------------------------------------------------------------------------
enum
{
SPINEL_DATATYPE_NULL_C = 0,
SPINEL_DATATYPE_VOID_C = '.',
SPINEL_DATATYPE_BOOL_C = 'b',
SPINEL_DATATYPE_UINT8_C = 'C',
SPINEL_DATATYPE_INT8_C = 'c',
SPINEL_DATATYPE_UINT16_C = 'S',
SPINEL_DATATYPE_INT16_C = 's',
SPINEL_DATATYPE_UINT32_C = 'L',
SPINEL_DATATYPE_INT32_C = 'l',
SPINEL_DATATYPE_UINT_PACKED_C = 'i',
SPINEL_DATATYPE_IPv6ADDR_C = '6',
SPINEL_DATATYPE_EUI64_C = 'E',
SPINEL_DATATYPE_EUI48_C = 'e',
SPINEL_DATATYPE_DATA_C = 'D',
SPINEL_DATATYPE_UTF8_C = 'U', //!< Zero-Terminated UTF8-Encoded String
SPINEL_DATATYPE_STRUCT_C = 'T',
SPINEL_DATATYPE_ARRAY_C = 'A',
};
typedef char spinel_datatype_t;
#define SPINEL_DATATYPE_NULL_S ""
#define SPINEL_DATATYPE_VOID_S "."
#define SPINEL_DATATYPE_BOOL_S "b"
#define SPINEL_DATATYPE_UINT8_S "C"
#define SPINEL_DATATYPE_INT8_S "c"
#define SPINEL_DATATYPE_UINT16_S "S"
#define SPINEL_DATATYPE_INT16_S "s"
#define SPINEL_DATATYPE_UINT32_S "L"
#define SPINEL_DATATYPE_INT32_S "l"
#define SPINEL_DATATYPE_UINT_PACKED_S "i"
#define SPINEL_DATATYPE_IPv6ADDR_S "6"
#define SPINEL_DATATYPE_EUI64_S "E"
#define SPINEL_DATATYPE_EUI48_S "e"
#define SPINEL_DATATYPE_DATA_S "D"
#define SPINEL_DATATYPE_UTF8_S "U" //!< Zero-Terminated UTF8-Encoded String
#define SPINEL_DATATYPE_STRUCT_S "T"
#define SPINEL_DATATYPE_ARRAY_S "A"
SPINEL_API_EXTERN spinel_ssize_t spinel_datatype_pack(uint8_t *data_out, spinel_size_t data_len,
const char *pack_format, ...);
SPINEL_API_EXTERN spinel_ssize_t spinel_datatype_vpack(uint8_t *data_out, spinel_size_t data_len,
const char *pack_format, va_list args);
SPINEL_API_EXTERN spinel_ssize_t spinel_datatype_unpack(const uint8_t *data_in, spinel_size_t data_len,
const char *pack_format, ...);
SPINEL_API_EXTERN spinel_ssize_t spinel_datatype_vunpack(const uint8_t *data_in, spinel_size_t data_len,
const char *pack_format, va_list args);
SPINEL_API_EXTERN spinel_ssize_t spinel_packed_uint_decode(const uint8_t *bytes, spinel_size_t len,
unsigned int *value);
SPINEL_API_EXTERN spinel_ssize_t spinel_packed_uint_encode(uint8_t *bytes, spinel_size_t len, unsigned int value);
SPINEL_API_EXTERN spinel_ssize_t spinel_packed_uint_size(unsigned int value);
SPINEL_API_EXTERN const char *spinel_next_packed_datatype(const char *pack_format);
// ----------------------------------------------------------------------------
__END_DECLS
#endif /* defined(SPINEL_HEADER_INCLUDED) */