Browse Source

pkg/openthread: add OpenThread core

master
José Ignacio Alamos 5 years ago
parent
commit
017280db13
  1. 5
      Makefile.dep
  2. 11
      drivers/at86rf2xx/at86rf2xx_netdev.c
  3. 19
      drivers/include/net/netdev.h
  4. 1
      makefiles/pseudomodules.inc.mk
  5. 32
      pkg/openthread/Makefile
  6. 11
      pkg/openthread/Makefile.include
  7. 3
      pkg/openthread/contrib/Makefile
  8. 3
      pkg/openthread/contrib/netdev/Makefile
  9. 186
      pkg/openthread/contrib/netdev/openthread_netdev.c
  10. 80
      pkg/openthread/contrib/openthread.c
  11. 68
      pkg/openthread/contrib/platform_alarm.c
  12. 38
      pkg/openthread/contrib/platform_diag.c
  13. 297
      pkg/openthread/contrib/platform_functions_wrapper.c
  14. 97
      pkg/openthread/contrib/platform_logging.c
  15. 36
      pkg/openthread/contrib/platform_misc.c
  16. 422
      pkg/openthread/contrib/platform_radio.c
  17. 51
      pkg/openthread/contrib/platform_random.c
  18. 72
      pkg/openthread/contrib/platform_settings.c
  19. 46
      pkg/openthread/contrib/platform_uart.c
  20. 153
      pkg/openthread/include/ot.h
  21. 8
      sys/auto_init/auto_init.c

5
Makefile.dep

@ -562,6 +562,11 @@ ifneq (,$(filter random,$(USEMODULE)))
endif
endif
ifneq (,$(filter openthread_contrib,$(USEMODULE)))
USEMODULE += openthread_contrib_netdev
FEATURES_REQUIRED += cpp
endif
ifneq (,$(filter emcute,$(USEMODULE)))
USEMODULE += core_thread_flags
USEMODULE += sock_udp

11
drivers/at86rf2xx/at86rf2xx_netdev.c

@ -565,11 +565,22 @@ static void _isr(netdev_t *netdev)
if (netdev->event_callback && (dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END)) {
switch (trac_status) {
#ifdef MODULE_OPENTHREAD
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
DEBUG("[at86rf2xx] TX SUCCESS\n");
break;
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE_DATA_PENDING);
DEBUG("[at86rf2xx] TX SUCCESS DATA PENDING\n");
break;
#else
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
DEBUG("[at86rf2xx] TX SUCCESS\n");
break;
#endif
case AT86RF2XX_TRX_STATE__TRAC_NO_ACK:
netdev->event_callback(netdev, NETDEV_EVENT_TX_NOACK);
DEBUG("[at86rf2xx] TX NO_ACK\n");

19
drivers/include/net/netdev.h

@ -70,15 +70,16 @@ enum {
* upper layer
*/
typedef enum {
NETDEV_EVENT_ISR, /**< driver needs it's ISR handled */
NETDEV_EVENT_RX_STARTED, /**< started to receive a packet */
NETDEV_EVENT_RX_COMPLETE, /**< finished receiving a packet */
NETDEV_EVENT_TX_STARTED, /**< started to transfer a packet */
NETDEV_EVENT_TX_COMPLETE, /**< finished transferring packet */
NETDEV_EVENT_TX_NOACK, /**< ACK requested but not received */
NETDEV_EVENT_TX_MEDIUM_BUSY, /**< couldn't transfer packet */
NETDEV_EVENT_LINK_UP, /**< link established */
NETDEV_EVENT_LINK_DOWN, /**< link gone */
NETDEV_EVENT_ISR, /**< driver needs it's ISR handled */
NETDEV_EVENT_RX_STARTED, /**< started to receive a packet */
NETDEV_EVENT_RX_COMPLETE, /**< finished receiving a packet */
NETDEV_EVENT_TX_STARTED, /**< started to transfer a packet */
NETDEV_EVENT_TX_COMPLETE, /**< transfer packet complete */
NETDEV_EVENT_TX_COMPLETE_DATA_PENDING, /**< transfer packet complete and data pending flag */
NETDEV_EVENT_TX_NOACK, /**< ACK requested but not received */
NETDEV_EVENT_TX_MEDIUM_BUSY, /**< couldn't transfer packet */
NETDEV_EVENT_LINK_UP, /**< link established */
NETDEV_EVENT_LINK_DOWN, /**< link gone */
/* expand this list if needed */
} netdev_event_t;

1
makefiles/pseudomodules.inc.mk

@ -41,6 +41,7 @@ PSEUDOMODULES += netstats_ipv6
PSEUDOMODULES += netstats_rpl
PSEUDOMODULES += newlib
PSEUDOMODULES += newlib_nano
PSEUDOMODULES += openthread
PSEUDOMODULES += pktqueue
PSEUDOMODULES += posix
PSEUDOMODULES += printf_float

32
pkg/openthread/Makefile

@ -0,0 +1,32 @@
PKG_NAME=openthread
PKG_URL=https://github.com/openthread/openthread.git
PKG_VERSION=fbfd76a990b81f007957e1bd774e51bce742e53e
PKG_BUILDDIR ?= $(BINDIRBASE)/pkg/$(BOARD)/$(PKG_NAME)
$(info Compile OpenThread for FTD device)
OPENTHREAD_ARGS+= --enable-cli-app=ftd --enable-application-coap
$(info $$OPENTHREAD_ARGS is [${OPENTHREAD_ARGS}])
.PHONY: all
OPENTHREAD_COMMON_FLAGS=-fdata-sections -ffunction-sections -Os
all: git-download
cd $(PKG_BUILDDIR) && PREFIX="/" ./bootstrap
cd $(PKG_BUILDDIR) && CPP="$(CPP)" CC="$(CC)" CXX="$(CXX)"\
OBJC="" OBJCXX="" AR="$(AR)" RANLIB="$(RANLIB)" NM="$(NM)" \
STRIP="$(STRIP)" \
CPPFLAGS="$(OPENTHREAD_COMMON_FLAGS) $(CFLAGS_CPU) " \
CFLAGS="$(OPENTHREAD_COMMON_FLAGS) $(CFLAGS_CPU) " \
CXXFLAGS="$(OPENTHREAD_COMMON_FLAGS) $(CFLAGS_CPU) -fno-exceptions -fno-rtti " \
LDFLAGS="$(OPENTHREAD_COMMON_FLAGS) $(CFLAGS_CPU) -nostartfiles -specs=nano.specs \
-specs=nosys.specs -Wl,--gc-sections -Wl,-Map=map.map " \
./configure --disable-docs --host=$(TARGET_ARCH) --target=$(TARGET_ARCH) \
--prefix=/ --enable-default-logging ${OPENTHREAD_ARGS}
cd $(PKG_BUILDDIR) && DESTDIR=$(PKG_BUILDDIR)/output PREFIX=/ make -j4 --no-print-directory install
cp $(PKG_BUILDDIR)/output/lib/libmbedcrypto.a ${BINDIR}/libmbedcrypto.a
cp $(PKG_BUILDDIR)/output/lib/libopenthread-ftd.a ${BINDIR}/libopenthread.a
cp $(PKG_BUILDDIR)/output/lib/libopenthread-cli-ftd.a ${BINDIR}/libopenthread-cli.a
sed -ie 's/BASE/_BASE/g' $(PKG_BUILDDIR)/output/include/openthread/types.h
include $(RIOTBASE)/pkg/pkg.mk

11
pkg/openthread/Makefile.include

@ -0,0 +1,11 @@
OPENTHREAD_DIR = $(RIOTBASE)/pkg/openthread
INCLUDES += -I$(OPENTHREAD_DIR)/include \
-I$(OPENTHREAD_DIR)/include/openthread \
-I$(BINDIRBASE)/pkg/$(BOARD)/openthread/output/include \
-I$(BINDIRBASE)/pkg/$(BOARD)/openthread/include/openthread \
ifneq (,$(filter openthread_contrib,$(USEMODULE)))
DIRS += $(OPENTHREAD_DIR)/contrib
DIRS += $(OPENTHREAD_DIR)/contrib/netdev
endif

3
pkg/openthread/contrib/Makefile

@ -0,0 +1,3 @@
MODULE := openthread_contrib
include $(RIOTBASE)/Makefile.base

3
pkg/openthread/contrib/netdev/Makefile

@ -0,0 +1,3 @@
MODULE := openthread_contrib_netdev
include $(RIOTBASE)/Makefile.base

186
pkg/openthread/contrib/netdev/openthread_netdev.c

@ -0,0 +1,186 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Netdev adoption for OpenThread
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include "msg.h"
#include "openthread/cli.h"
#include "openthread/instance.h"
#include "openthread/ip6.h"
#include "openthread/platform/alarm.h"
#include "openthread/platform/uart.h"
#include "openthread/tasklet.h"
#include "openthread/thread.h"
#include "random.h"
#include "ot.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define OPENTHREAD_QUEUE_LEN (8)
static msg_t _queue[OPENTHREAD_QUEUE_LEN];
static kernel_pid_t _pid;
static otInstance *sInstance;
/**
* @name Default configuration for OpenThread network
* @{
*/
#ifndef OPENTHREAD_PANID
#define OPENTHREAD_PANID 0x1234
#endif
#ifndef OPENTHREAD_CHANNEL
#define OPENTHREAD_CHANNEL (26U)
#endif
/** @} */
uint8_t ot_call_command(char* command, void *arg, void* answer) {
ot_job_t job;
job.command = command;
job.arg = arg;
job.answer = answer;
msg_t msg, reply;
msg.type = OPENTHREAD_JOB_MSG_TYPE_EVENT;
msg.content.ptr = &job;
msg_send_receive(&msg, &reply, openthread_get_pid());
return (uint8_t)reply.content.value;
}
/* OpenThread will call this when switching state from empty tasklet to non-empty tasklet. */
void otTaskletsSignalPending(otInstance *aInstance) {
otTaskletsProcess(aInstance);
}
static void *_openthread_event_loop(void *arg) {
_pid = thread_getpid();
/* enable OpenThread UART */
otPlatUartEnable();
/* init OpenThread */
sInstance = otInstanceInit();
msg_init_queue(_queue, OPENTHREAD_QUEUE_LEN);
netdev_t *dev;
msg_t msg, reply;
otCliUartInit(sInstance);
#if OPENTHREAD_ENABLE_DIAG
diagInit(sInstance);
#endif
/* Init default parameters */
otPanId panid = OPENTHREAD_PANID;
uint8_t channel = OPENTHREAD_CHANNEL;
otLinkSetPanId(sInstance, panid);
otLinkSetChannel(sInstance, channel);
/* Bring up the IPv6 interface */
otIp6SetEnabled(sInstance, true);
/* Start Thread protocol operation */
otThreadSetEnabled(sInstance, true);
uint8_t *buf;
ot_job_t *job;
while (1) {
msg_receive(&msg);
switch (msg.type) {
case OPENTHREAD_XTIMER_MSG_TYPE_EVENT:
/* Tell OpenThread a time event was received */
otPlatAlarmFired(sInstance);
break;
case OPENTHREAD_NETDEV_MSG_TYPE_EVENT:
/* Received an event from driver */
dev = msg.content.ptr;
dev->driver->isr(dev);
break;
case OPENTHREAD_SERIAL_MSG_TYPE_EVENT:
/* Tell OpenThread about the reception of a CLI command */
buf = msg.content.ptr;
otPlatUartReceived(buf, strlen((char *) buf));
break;
case OPENTHREAD_JOB_MSG_TYPE_EVENT:
job = msg.content.ptr;
reply.content.value = ot_exec_command(sInstance, job->command, job->arg, job->answer);
msg_reply(&msg, &reply);
break;
}
}
return NULL;
}
static void _event_cb(netdev_t *dev, netdev_event_t event) {
switch (event) {
case NETDEV_EVENT_ISR:
{
msg_t msg;
assert(_pid != KERNEL_PID_UNDEF);
msg.type = OPENTHREAD_NETDEV_MSG_TYPE_EVENT;
msg.content.ptr = dev;
if (msg_send(&msg, _pid) <= 0) {
DEBUG("openthread_netdev: possibly lost interrupt.\n");
}
break;
}
case NETDEV_EVENT_RX_COMPLETE:
DEBUG("openthread_netdev: Reception of a packet\n");
recv_pkt(sInstance, dev);
break;
case NETDEV_EVENT_TX_COMPLETE:
case NETDEV_EVENT_TX_NOACK:
case NETDEV_EVENT_TX_MEDIUM_BUSY:
DEBUG("openthread_netdev: Transmission of a packet\n");
send_pkt(sInstance, dev, event);
break;
default:
break;
}
}
/* get OpenThread thread pid */
kernel_pid_t openthread_get_pid(void) {
return _pid;
}
/* starts OpenThread thread */
int openthread_netdev_init(char *stack, int stacksize, char priority,
const char *name, netdev_t *netdev) {
netdev->driver->init(netdev);
netdev->event_callback = _event_cb;
netopt_enable_t enable = NETOPT_ENABLE;
netdev->driver->set(netdev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));
_pid = thread_create(stack, stacksize,
priority, THREAD_CREATE_STACKTEST,
_openthread_event_loop, NULL, name);
if (_pid <= 0) {
return -EINVAL;
}
return _pid;
}

80
pkg/openthread/contrib/openthread.c

@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread main functions
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <assert.h>
#include "openthread/platform/alarm.h"
#include "openthread/platform/uart.h"
#include "ot.h"
#include "random.h"
#include "thread.h"
#include "xtimer.h"
#ifdef MODULE_AT86RF2XX
#include "at86rf2xx.h"
#include "at86rf2xx_params.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifdef MODULE_AT86RF2XX /* is mutual exclusive with above ifdef */
#define OPENTHREAD_NETIF_NUMOF (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
#endif
#ifdef MODULE_AT86RF2XX
static at86rf2xx_t at86rf2xx_dev;
#endif
#define OPENTHREAD_NETDEV_BUFLEN (ETHERNET_MAX_LEN)
static uint8_t rx_buf[OPENTHREAD_NETDEV_BUFLEN];
static uint8_t tx_buf[OPENTHREAD_NETDEV_BUFLEN];
static char ot_thread_stack[2 * THREAD_STACKSIZE_MAIN];
/* init and run OpeanThread's UART simulation (stdio) */
void openthread_uart_run(void)
{
char buf[256];
msg_t msg;
msg.type = OPENTHREAD_SERIAL_MSG_TYPE_EVENT;
msg.content.ptr = buf;
buf[1] = 0;
while (1) {
char c = getchar();
buf[0] = c;
msg_send(&msg, openthread_get_pid());
}
}
void openthread_bootstrap(void)
{
/* init random */
ot_random_init();
/* setup netdev modules */
#ifdef MODULE_AT86RF2XX
at86rf2xx_setup(&at86rf2xx_dev, &at86rf2xx_params[0]);
netdev_t *netdev = (netdev_t *) &at86rf2xx_dev;
#endif
openthread_radio_init(netdev, tx_buf, rx_buf);
openthread_netdev_init(ot_thread_stack, sizeof(ot_thread_stack), THREAD_PRIORITY_MAIN - 5, "openthread", netdev);
}

68
pkg/openthread/contrib/platform_alarm.c

@ -0,0 +1,68 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread alarm platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <stdint.h>
#include "msg.h"
#include "openthread/platform/alarm.h"
#include "ot.h"
#include "thread.h"
#include "xtimer.h"
#include "timex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static xtimer_t ot_timer;
static msg_t ot_alarm_msg;
/**
* Set the alarm to fire at @p aDt milliseconds after @p aT0.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aT0 The reference time.
* @param[in] aDt The time delay in milliseconds from @p aT0.
*/
void otPlatAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
{
DEBUG("openthread: otPlatAlarmStartAt: aT0: %" PRIu32 ", aDT: %" PRIu32 "\n", aT0, aDt);
ot_alarm_msg.type = OPENTHREAD_XTIMER_MSG_TYPE_EVENT;
if (aDt == 0) {
msg_send(&ot_alarm_msg, thread_getpid());
}
else {
int dt = aDt * US_PER_MS;
xtimer_set_msg(&ot_timer, dt, &ot_alarm_msg, thread_getpid());
}
}
/* OpenThread will call this to stop alarms */
void otPlatAlarmStop(otInstance *aInstance)
{
DEBUG("openthread: otPlatAlarmStop\n");
xtimer_remove(&ot_timer);
}
/* OpenThread will call this for getting running time in millisecs */
uint32_t otPlatAlarmGetNow(void)
{
uint32_t now = xtimer_now_usec() / US_PER_MS;
DEBUG("openthread: otPlatAlarmGetNow: %" PRIu32 "\n", now);
return now;
}

38
pkg/openthread/contrib/platform_diag.c

@ -0,0 +1,38 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread diagnostics platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <stdbool.h>
#include <stdio.h>
static bool sDiagMode = false;
void otPlatDiagProcess(int argc, char *argv[], char *aOutput, size_t aOutputMaxLen)
{
/* add more plarform specific diagnostics features here */
(void)argc;
}
void otPlatDiagModeSet(bool aMode)
{
sDiagMode = aMode;
}
bool otPlatDiagModeGet(void)
{
return sDiagMode;
}

297
pkg/openthread/contrib/platform_functions_wrapper.c

@ -0,0 +1,297 @@
/*
* Copyright (C)
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread functions wrapper. They are used to call OT functions from OT thread
*
* @author Jose Ignacio Alamos <jialamos@inria.cl>
* @author Baptiste CLENET <bapclenet@gmail.com>
* @}
*/
#include <stdint.h>
#include <stdio.h>
#include "thread.h"
#include "openthread/ip6.h"
#include "openthread/thread.h"
#include "openthread/udp.h"
#include "ot.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
typedef uint8_t OT_COMMAND;
OT_COMMAND ot_channel(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_eui64(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_extaddr(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_ipaddr(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_masterkey(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_networkname(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_mode(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_panid(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_parent(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_state(otInstance* ot_instance, void* arg, void* answer);
OT_COMMAND ot_thread(otInstance* ot_instance, void* arg, void* answer);
/**
* @brief Struct containing an OpenThread job command
*/
typedef struct {
const char *name; /**< A pointer to the job name string. */
OT_COMMAND (*function)(otInstance*, void*, void*); /**< function to be called */
} ot_command_t;
const ot_command_t otCommands[] =
{
/* channel: arg NULL: get channel in answer | arg not NULL: set channel */
{ "channel", &ot_channel },
/* eui64 : arg NULL: get eui64 in answer | arg not NULL: set eui64 */
{ "eui64", &ot_eui64 },
/* extaddr: arg NULL: get extaddr in answer | arg not NULL: set extaddr */
{ "extaddr", &ot_extaddr },
/* ipaddr: arg NULL: get nb ipaddr in answer | arg not NULL: get ipaddr[arg] */
{ "ipaddr", &ot_ipaddr },
/* masterkey: arg NULL: get masterkey in answer | arg not NULL: set masterkey */
{ "masterkey", &ot_masterkey },
/* mode: arg NULL: get mode in answer | arg not NULL: set mode */
{ "mode", ot_mode },
/* networkname: arg NULL: get networkname in answer | arg not NULL: set networkname */
{ "networkname", &ot_networkname },
/* panid: arg NULL: get panid in answer | arg not NULL: set panid */
{ "panid", &ot_panid },
/* parent: arg NULL: get parent in answer */
{ "parent", &ot_parent },
/* state: arg NULL: get state in answer */
{ "state", &ot_state },
/* thread: arg "start"/"stop": start/stop thread operation */
{ "thread", &ot_thread },
};
uint8_t ot_exec_command(otInstance *ot_instance, const char* command, void *arg, void* answer) {
uint8_t res = 0xFF;
/* Check running thread */
if (openthread_get_pid() == thread_getpid()) {
for (uint8_t i = 0; i < sizeof(otCommands) / sizeof(otCommands[0]); i++) {
if (strcmp(command, otCommands[i].name) == 0) {
res = (*otCommands[i].function)(ot_instance, arg, answer);
break;
}
}
if (res == 0xFF) {
DEBUG("Wrong ot_COMMAND name\n");
res = 1;
}
} else {
DEBUG("ERROR: ot_exec_job needs to run in OpenThread thread\n");
}
return res;
}
void output_bytes(const char* name, const uint8_t *aBytes, uint8_t aLength)
{
DEBUG("%s: ", name);
for (int i = 0; i < aLength; i++) {
DEBUG("%02x", aBytes[i]);
}
DEBUG("\n");
}
OT_COMMAND ot_channel(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
*((uint8_t *) answer) = otLinkGetChannel(ot_instance);
DEBUG("Channel: %04x\n", *((uint8_t *) answer));
} else if (arg != NULL) {
uint8_t channel = *((uint8_t *) arg);
otLinkSetChannel(ot_instance, channel);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_eui64(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
otExtAddress address;
otLinkGetFactoryAssignedIeeeEui64(ot_instance, &address);
output_bytes("eui64", address.m8, OT_EXT_ADDRESS_SIZE);
*((otExtAddress *) answer) = address;
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_extaddr(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
answer = (void*)otLinkGetExtendedAddress(ot_instance);
output_bytes("extaddr", (const uint8_t *)answer, OT_EXT_ADDRESS_SIZE);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_ipaddr(otInstance* ot_instance, void* arg, void* answer) {
uint8_t cnt = 0;
for (const otNetifAddress *addr = otIp6GetUnicastAddresses(ot_instance); addr; addr = addr->mNext) {
if (arg != NULL && answer != NULL && cnt == *((uint8_t *) arg)) {
*((otNetifAddress *) answer) = *addr;
return 0;
}
cnt++;
}
if (answer != NULL) {
*((uint8_t *) answer) = cnt;
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_masterkey(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
const otMasterKey* masterkey = otThreadGetMasterKey(ot_instance);
*((otMasterKey *) answer) = *masterkey;
output_bytes("masterkey", (const uint8_t *)answer, OT_MASTER_KEY_SIZE);
} else if (arg != NULL) {
otThreadSetMasterKey(ot_instance, (otMasterKey*)arg);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_mode(otInstance* ot_instance, void* arg, void* answer) {
if (arg != NULL) {
otLinkModeConfig link_mode;
memset(&link_mode, 0, sizeof(otLinkModeConfig));
char mode[6];
memcpy(mode, (char*)arg, 5);
mode[5] = '\0';
for (char *arg = &mode[0]; *arg != '\0'; arg++) {
switch (*arg) {
case 'r':
link_mode.mRxOnWhenIdle = 1;
break;
case 's':
link_mode.mSecureDataRequests = 1;
break;
case 'd':
link_mode.mDeviceType = 1;
break;
case 'n':
link_mode.mNetworkData = 1;
break;
}
}
otThreadSetLinkMode(ot_instance, link_mode);
DEBUG("OT mode changed to %s\n", (char*)arg);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_networkname(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
const char* networkName = otThreadGetNetworkName(ot_instance);
strcpy((char*) answer, networkName);
DEBUG("networkname: %.*s\n", OT_NETWORK_NAME_MAX_SIZE, networkName);
} else if (arg != NULL) {
otThreadSetNetworkName(ot_instance, (char*) arg);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_panid(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
*((uint16_t *) answer) = otLinkGetPanId(ot_instance);
DEBUG("PanID: %04x\n", *((uint16_t *) answer));
} else if (arg != NULL) {
/* Thread operation needs to be stopped before setting panid */
otThreadSetEnabled(ot_instance, false);
uint16_t panid = *((uint16_t *) arg);
otLinkSetPanId(ot_instance, panid);
otThreadSetEnabled(ot_instance, true);
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_parent(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
otRouterInfo parentInfo;
otThreadGetParentInfo(ot_instance, &parentInfo);
output_bytes("parent", (const uint8_t *)parentInfo.mExtAddress.m8, sizeof(parentInfo.mExtAddress));
DEBUG("Rloc: %x\n", parentInfo.mRloc16);
*((otRouterInfo *) answer) = parentInfo;
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_state(otInstance* ot_instance, void* arg, void* answer) {
if (answer != NULL) {
uint8_t state = otThreadGetDeviceRole(ot_instance);
*((uint8_t *) answer) = state;
DEBUG("state: ");
switch (state) {
case kDeviceRoleOffline:
puts("offline");
break;
case kDeviceRoleDisabled:
puts("disabled");
break;
case kDeviceRoleDetached:
puts("detached");
break;
case kDeviceRoleChild:
puts("child");
break;
case kDeviceRoleRouter:
puts("router");
break;
case kDeviceRoleLeader:
puts("leader");
break;
default:
puts("invalid state");
break;
}
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}
OT_COMMAND ot_thread(otInstance* ot_instance, void* arg, void* answer) {
if (arg != NULL) {
if (strcmp((char*)arg, "start") == 0) {
otThreadSetEnabled(ot_instance, true);
DEBUG("Thread start\n");
} else if (strcmp((char*)arg, "stop") == 0) {
otThreadSetEnabled(ot_instance, false);
DEBUG("Thread stop\n");
} else {
DEBUG("ERROR: thread available args: start/stop\n");
}
} else {
DEBUG("ERROR: wrong argument\n");
}
return 0;
}

97
pkg/openthread/contrib/platform_logging.c

@ -0,0 +1,97 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread logging platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <ctype.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "openthread/platform/logging.h"
/* adapted from OpenThread posix example:
* See: https://github.com/openthread/openthread/blob/master/examples/platforms/posix/logging.c */
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
{
va_list args;
switch (aLogLevel) {
case kLogLevelNone:
fprintf(stderr, "NONE ");
break;
case kLogLevelCrit:
fprintf(stderr, "CRIT ");
break;
case kLogLevelWarn:
fprintf(stderr, "WARN ");
break;
case kLogLevelInfo:
fprintf(stderr, "INFO ");
break;
case kLogLevelDebg:
fprintf(stderr, "DEBG ");
break;
}
switch (aLogRegion) {
case kLogRegionApi:
fprintf(stderr, "API ");
break;
case kLogRegionMle:
fprintf(stderr, "MLE ");
break;
case kLogRegionArp:
fprintf(stderr, "ARP ");
break;
case kLogRegionNetData:
fprintf(stderr, "NETD ");
break;
case kLogRegionIp6:
fprintf(stderr, "IPV6 ");
break;
case kLogRegionIcmp:
fprintf(stderr, "ICMP ");
break;
case kLogRegionMac:
fprintf(stderr, "MAC ");
break;
case kLogRegionMem:
fprintf(stderr, "MEM ");
break;
default:
break;
}
va_start(args, aFormat);
vfprintf(stderr, aFormat, args);
fprintf(stderr, "\r");
va_end(args);
}

36
pkg/openthread/contrib/platform_misc.c

@ -0,0 +1,36 @@
/*
* Copyright (C) Baptiste Clenet
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread misc platform abstraction
*
* @author Baptiste Clenet <bapclenet@gmail.com>
* @}
*/
#include "openthread/types.h"
#include "openthread/platform/misc.h"
#include "periph/pm.h"
void otPlatReset(otInstance *aInstance)
{
(void)aInstance;
printf("reboot...\n");
pm_reboot();
}
otPlatResetReason otPlatGetResetReason(otInstance *aInstance)
{
(void)aInstance;
/* TODO: Write me! */
return kPlatResetReason_PowerOn;
}

422
pkg/openthread/contrib/platform_radio.c

@ -0,0 +1,422 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread radio platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "byteorder.h"
#include "errno.h"
#include "net/ethernet/hdr.h"
#include "net/ethertype.h"
#include "net/ieee802154.h"
#include "net/netdev/ieee802154.h"
#include "openthread/platform/radio.h"
#include "ot.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define RADIO_IEEE802154_FCS_LEN (2U)
static RadioPacket sTransmitFrame;
static RadioPacket sReceiveFrame;
static int8_t Rssi;
static netdev_t *_dev;
static bool sDisabled;
/* set 15.4 channel */
static int _set_channel(uint16_t channel)
{
return _dev->driver->set(_dev, NETOPT_CHANNEL, &channel, sizeof(uint16_t));
}
/*get transmission power from driver */
static int16_t _get_power(void)
{
int16_t power;
_dev->driver->get(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
return power;
}
/* set transmission power */
static int _set_power(int16_t power)
{
return _dev->driver->set(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
}
/* set IEEE802.15.4 PAN ID */
static int _set_panid(uint16_t panid)
{
return _dev->driver->set(_dev, NETOPT_NID, &panid, sizeof(uint16_t));
}
/* set extended HW address */
static int _set_long_addr(uint8_t *ext_addr)
{
return _dev->driver->set(_dev, NETOPT_ADDRESS_LONG, ext_addr, IEEE802154_LONG_ADDRESS_LEN);
}
/* set short address */
static int _set_addr(uint16_t addr)
{
return _dev->driver->set(_dev, NETOPT_ADDRESS, &addr, sizeof(uint16_t));
}
/* check the state of promiscuous mode */
static netopt_enable_t _is_promiscuous(void)
{
netopt_enable_t en;
_dev->driver->get(_dev, NETOPT_PROMISCUOUSMODE, &en, sizeof(en));
return en == NETOPT_ENABLE ? true : false;;
}
/* set the state of promiscuous mode */
static int _set_promiscuous(netopt_enable_t enable)
{
return _dev->driver->set(_dev, NETOPT_PROMISCUOUSMODE, &enable, sizeof(enable));
}
/* wrapper for setting device state */
static void _set_state(netopt_state_t state)
{
_dev->driver->set(_dev, NETOPT_STATE, &state, sizeof(netopt_state_t));
}
/* wrapper for getting device state */
static netopt_state_t _get_state(void)
{
netopt_state_t state;
_dev->driver->get(_dev, NETOPT_STATE, &state, sizeof(netopt_state_t));
return state;
}
/* sets device state to SLEEP */
static void _set_sleep(void)
{
_set_state(NETOPT_STATE_SLEEP);
}
/* set device state to IDLE */
static void _set_idle(void)
{
_set_state(NETOPT_STATE_IDLE);
}
/* init framebuffers and initial state */
void openthread_radio_init(netdev_t *dev, uint8_t *tb, uint8_t *rb)
{
sTransmitFrame.mPsdu = tb;
sTransmitFrame.mLength = 0;
sReceiveFrame.mPsdu = rb;
sReceiveFrame.mLength = 0;
_dev = dev;
}
/* Called upon NETDEV_EVENT_RX_COMPLETE event */
void recv_pkt(otInstance *aInstance, netdev_t *dev)
{
DEBUG("Openthread: Received pkt\n");
netdev_ieee802154_rx_info_t rx_info;
/* Read frame length from driver */
int len = dev->driver->recv(dev, NULL, 0, &rx_info);
Rssi = rx_info.rssi;
/* very unlikely */
if ((len > (unsigned) UINT16_MAX)) {
DEBUG("Len too high: %d\n", len);
otPlatRadioReceiveDone(aInstance, NULL, kThreadError_Abort);
return;
}
/* Fill OpenThread receive frame */
/* Openthread needs a packet length with FCS included,
* OpenThread do not use the data so we don't need to calculate FCS */
sReceiveFrame.mLength = len + RADIO_IEEE802154_FCS_LEN;
sReceiveFrame.mPower = _get_power();
/* Read received frame */
int res = dev->driver->recv(dev, (char *) sReceiveFrame.mPsdu, len, NULL);
DEBUG("Received message: len %d\n", (int) sReceiveFrame.mLength);
for (int i = 0; i < sReceiveFrame.mLength; ++i) {
DEBUG("%x ", sReceiveFrame.mPsdu[i]);
}
DEBUG("\n");
/* Tell OpenThread that receive has finished */
otPlatRadioReceiveDone(aInstance, res > 0 ? &sReceiveFrame : NULL, res > 0 ? kThreadError_None : kThreadError_Abort);
}
/* Called upon TX event */
void send_pkt(otInstance *aInstance, netdev_t *dev, netdev_event_t event)
{
/* Tell OpenThread transmission is done depending on the NETDEV event */
switch (event) {
case NETDEV_EVENT_TX_COMPLETE:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_None);
break;
case NETDEV_EVENT_TX_COMPLETE_DATA_PENDING:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE_DATA_PENDING\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, true, kThreadError_None);
break;
case NETDEV_EVENT_TX_NOACK:
DEBUG("openthread: NETDEV_EVENT_TX_NOACK\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_NoAck);
break;
case NETDEV_EVENT_TX_MEDIUM_BUSY:
DEBUG("openthread: NETDEV_EVENT_TX_MEDIUM_BUSY\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_ChannelAccessFailure);
break;
default:
break;
}
}
/* OpenThread will call this for setting PAN ID */
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
{
DEBUG("openthread: otPlatRadioSetPanId: setting PAN ID to %04x\n", panid);
_set_panid(panid);
}
/* OpenThread will call this for setting extended address */
void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *aExtendedAddress)
{
DEBUG("openthread: otPlatRadioSetExtendedAddress\n");
uint8_t reversed_addr[IEEE802154_LONG_ADDRESS_LEN];
for (int i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) {
reversed_addr[i] = aExtendedAddress[IEEE802154_LONG_ADDRESS_LEN - 1 - i];
}
_set_long_addr(reversed_addr);
}
/* OpenThread will call this for setting short address */
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
{
DEBUG("openthread: otPlatRadioSetShortAddress: setting address to %04x\n", aShortAddress);
_set_addr(((aShortAddress & 0xff) << 8) | ((aShortAddress >> 8) & 0xff));
}
/* OpenThread will call this for enabling the radio */
ThreadError otPlatRadioEnable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioEnable\n");
(void) aInstance;
if (sDisabled) {
sDisabled = false;
_set_idle();
}
return kThreadError_None;
}
/* OpenThread will call this for disabling the radio */
ThreadError otPlatRadioDisable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioDisable\n");
(void) aInstance;
if (!sDisabled) {
sDisabled = true;
_set_sleep();
}
return kThreadError_None;
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
DEBUG("otPlatRadioIsEnabled\n");
(void) aInstance;
netopt_state_t state = _get_state();
if (state == NETOPT_STATE_OFF || state == NETOPT_STATE_SLEEP) {
return false;
} else {
return true;
}
}
/* OpenThread will call this for setting device state to SLEEP */
ThreadError otPlatRadioSleep(otInstance *aInstance)
{
DEBUG("otPlatRadioSleep\n");
(void) aInstance;
_set_sleep();
return kThreadError_None;
}
/*OpenThread will call this for waiting the reception of a packet */
ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
DEBUG("openthread: otPlatRadioReceive. Channel: %i\n", aChannel);
(void) aInstance;
_set_idle();
_set_channel(aChannel);
return kThreadError_None;
}
/* OpenThread will call this function to get the transmit buffer */
RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioGetTransmitBuffer\n");
return &sTransmitFrame;
}
/* OpenThread will call this function to set the transmit power */
void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
_set_power(aPower);
}
/* OpenThread will call this for transmitting a packet*/
ThreadError otPlatRadioTransmit(otInstance *aInstance, RadioPacket *aPacket)
{
(void) aInstance;
struct iovec pkt;
/* Populate iovec with transmit data
* Unlike RIOT, OpenThread includes two bytes FCS (0x00 0x00) so
* these bytes are removed
*/
pkt.iov_base = aPacket->mPsdu;
pkt.iov_len = aPacket->mLength - RADIO_IEEE802154_FCS_LEN;
/*Set channel and power based on transmit frame */
DEBUG("otPlatRadioTransmit->channel: %i, length %d\n", (int) aPacket->mChannel, (int)aPacket->mLength);
for (int i = 0; i < aPacket->mLength; ++i) {
DEBUG("%x ", aPacket->mPsdu[i]);
}
DEBUG("\n");
_set_channel(aPacket->mChannel);
_set_power(aPacket->mPower);
/* send packet though netdev */
_dev->driver->send(_dev, &pkt, 1);
return kThreadError_None;
}
/* OpenThread will call this for getting the radio caps */
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioGetCaps\n");
/* all drivers should handle ACK, including call of NETDEV_EVENT_TX_NOACK */
return kRadioCapsNone;
}
/* OpenThread will call this for getting the state of promiscuous mode */
bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioGetPromiscuous\n");
return _is_promiscuous();
}
/* OpenThread will call this for setting the state of promiscuous mode */
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
{
DEBUG("openthread: otPlatRadioSetPromiscuous\n");
_set_promiscuous((aEnable) ? NETOPT_ENABLE : NETOPT_DISABLE);
}
int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
DEBUG("otPlatRadioGetRssi\n");
(void) aInstance;
return Rssi;
}
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
{
DEBUG("otPlatRadioEnableSrcMatch\n");
(void)aInstance;
(void)aEnable;
}
ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioAddSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return kThreadError_None;
}
ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
DEBUG("otPlatRadioAddSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return kThreadError_None;
}
ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioClearSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return kThreadError_None;
}
ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
DEBUG("otPlatRadioClearSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return kThreadError_None;
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchShortEntries\n");
(void)aInstance;
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchExtEntries\n");
(void)aInstance;
}
ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
DEBUG("otPlatRadioEnergyScan\n");
(void)aInstance;
(void)aScanChannel;
(void)aScanDuration;
return kThreadError_NotImplemented;
}
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeee64Eui64)
{
_dev->driver->get(_dev, NETOPT_IPV6_IID, aIeee64Eui64, sizeof(eui64_t));
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
return -100;
}

51
pkg/openthread/contrib/platform_random.c

@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread random platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <stdint.h>
#include "openthread/platform/random.h"
#include "periph/cpuid.h"
#include "random.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* init random */
void ot_random_init(void)
{
#ifdef CPUID_LEN
char cpu_id[CPUID_LEN];
cpuid_get(cpu_id);
uint32_t seed = 0;
for (unsigned i = 0; i < CPUID_LEN; i++) {
seed += cpu_id[i];
}
random_init(seed);
#else
#error "CPU not supported (current CPU doesn't provide CPUID, required for entropy)"
#endif
}