Merge pull request #15038 from jia200x/pr/openthread/refactor

pkg/openthread: migrate to event loop
This commit is contained in:
Alexandre Abadie 2020-09-29 10:48:07 +02:00 committed by GitHub
commit a2cf40aa76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 157 additions and 146 deletions

View File

@ -3,4 +3,5 @@ USEMODULE += openthread_contrib
USEMODULE += openthread_contrib_netdev USEMODULE += openthread_contrib_netdev
USEMODULE += l2util USEMODULE += l2util
USEMODULE += xtimer USEMODULE += xtimer
USEMODULE += event
FEATURES_REQUIRED += cpp FEATURES_REQUIRED += cpp

View File

@ -26,55 +26,79 @@
#include "openthread/ip6.h" #include "openthread/ip6.h"
#include "openthread/platform/alarm-milli.h" #include "openthread/platform/alarm-milli.h"
#include "openthread/platform/uart.h" #include "openthread/platform/uart.h"
#include "openthread/tasklet.h"
#include "openthread/thread.h" #include "openthread/thread.h"
#include "random.h" #include "random.h"
#include "ot.h" #include "ot.h"
#include "event.h"
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#include "debug.h" #include "debug.h"
#define OPENTHREAD_QUEUE_LEN (8) static otInstance *sInstance; /**< global OpenThread instance */
static msg_t _queue[OPENTHREAD_QUEUE_LEN]; static netdev_t *_dev; /**< netdev descriptor for OpenThread */
static event_queue_t ev_queue; /**< the event queue for OpenThread */
static kernel_pid_t _pid; static void _ev_isr_handler(event_t *event)
static otInstance *sInstance; {
(void) event;
uint8_t ot_call_command(char* command, void *arg, void* answer) { _dev->driver->isr(_dev);
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. */ static event_t ev_isr = {
void otTaskletsSignalPending(otInstance *aInstance) { .handler = _ev_isr_handler
(void) aInstance; };
event_queue_t *openthread_get_evq(void)
{
return &ev_queue;
} }
static void *_openthread_event_loop(void *arg) { otInstance* openthread_get_instance(void)
(void)arg; {
_pid = thread_getpid(); return sInstance;
}
/* enable OpenThread UART */ static void _event_cb(netdev_t *dev, netdev_event_t event) {
otPlatUartEnable(); switch (event) {
case NETDEV_EVENT_ISR:
event_post(&ev_queue, &ev_isr);
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;
}
}
static void *_openthread_event_loop(void *arg)
{
_dev = arg;
netdev_t *netdev = arg;
event_queue_init(&ev_queue);
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));
netdev->driver->set(netdev, NETOPT_RX_END_IRQ, &enable, sizeof(enable));
/* init OpenThread */ /* init OpenThread */
sInstance = otInstanceInitSingle(); sInstance = otInstanceInitSingle();
msg_init_queue(_queue, OPENTHREAD_QUEUE_LEN); /* enable OpenThread UART */
netdev_t *dev; otPlatUartEnable();
msg_t msg, reply;
#if defined(MODULE_OPENTHREAD_CLI) #if defined(MODULE_OPENTHREAD_CLI)
serial_msg_t* serialBuffer;
otCliUartInit(sInstance); otCliUartInit(sInstance);
/* Init default parameters */ /* Init default parameters */
otPanId panid = OPENTHREAD_PANID; otPanId panid = OPENTHREAD_PANID;
@ -91,94 +115,21 @@ static void *_openthread_event_loop(void *arg) {
diagInit(sInstance); diagInit(sInstance);
#endif #endif
ot_job_t *job;
while (1) { while (1) {
otTaskletsProcess(sInstance); event_loop(&ev_queue);
if (otTaskletsArePending(sInstance) == false) {
msg_receive(&msg);
switch (msg.type) {
case OPENTHREAD_XTIMER_MSG_TYPE_EVENT:
/* Tell OpenThread a time event was received */
otPlatAlarmMilliFired(sInstance);
break;
case OPENTHREAD_NETDEV_MSG_TYPE_EVENT:
/* Received an event from driver */
dev = msg.content.ptr;
dev->driver->isr(dev);
break;
#ifdef MODULE_OPENTHREAD_CLI
case OPENTHREAD_SERIAL_MSG_TYPE_EVENT:
/* Tell OpenThread about the reception of a CLI command */
serialBuffer = (serial_msg_t*)msg.content.ptr;
otPlatUartReceived((uint8_t*) serialBuffer->buf,serialBuffer->length);
serialBuffer->serial_buffer_status = OPENTHREAD_SERIAL_BUFFER_STATUS_FREE;
break;
#endif
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; 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 */ /* starts OpenThread thread */
int openthread_netdev_init(char *stack, int stacksize, char priority, int openthread_netdev_init(char *stack, int stacksize, char priority,
const char *name, netdev_t *netdev) { const char *name, netdev_t *netdev) {
netdev->driver->init(netdev); if (thread_create(stack, stacksize,
netdev->event_callback = _event_cb;
netopt_enable_t enable = NETOPT_ENABLE;
netdev->driver->set(netdev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));
netdev->driver->set(netdev, NETOPT_RX_END_IRQ, &enable, sizeof(enable));
_pid = thread_create(stack, stacksize,
priority, THREAD_CREATE_STACKTEST, priority, THREAD_CREATE_STACKTEST,
_openthread_event_loop, NULL, name); _openthread_event_loop, netdev, name) < 0) {
if (_pid <= 0) {
return -EINVAL; return -EINVAL;
} }
return _pid; return 0;
} }

View File

@ -28,8 +28,25 @@
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#include "debug.h" #include "debug.h"
static xtimer_t ot_timer; static void _ev_timer_handler(event_t *event)
static msg_t ot_alarm_msg; {
(void) event;
otPlatAlarmMilliFired(openthread_get_instance());
}
static event_t ev_timer = {
.handler = _ev_timer_handler
};
void _timeout_cb(void *arg)
{
(void) arg;
event_post(openthread_get_evq(), &ev_timer);
}
static xtimer_t ot_timer = {
.callback = _timeout_cb,
};
/** /**
* Set the alarm to fire at @p aDt milliseconds after @p aT0. * Set the alarm to fire at @p aDt milliseconds after @p aT0.
@ -44,14 +61,13 @@ void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
(void)aT0; (void)aT0;
DEBUG("openthread: otPlatAlarmStartAt: aT0: %" PRIu32 ", aDT: %" PRIu32 "\n", aT0, aDt); DEBUG("openthread: otPlatAlarmStartAt: aT0: %" PRIu32 ", aDT: %" PRIu32 "\n", aT0, aDt);
ot_alarm_msg.type = OPENTHREAD_XTIMER_MSG_TYPE_EVENT;
if (aDt == 0) { if (aDt == 0) {
msg_send(&ot_alarm_msg, thread_getpid()); event_post(openthread_get_evq(), &ev_timer);
} }
else { else {
int dt = aDt * US_PER_MS; int dt = aDt * US_PER_MS;
xtimer_set_msg(&ot_timer, dt, &ot_alarm_msg, thread_getpid()); xtimer_set(&ot_timer, dt);
} }
} }

View File

@ -77,13 +77,14 @@ const ot_command_t otCommands[] =
{ "thread", &ot_thread }, { "thread", &ot_thread },
}; };
uint8_t ot_exec_command(otInstance *ot_instance, const char* command, void *arg, void* answer) { void _exec_cmd(event_t *event) {
ot_job_t *job = (ot_job_t*) event;
uint8_t res = 0xFF; uint8_t res = 0xFF;
/* Check running thread */ /* Check running thread */
if (openthread_get_pid() == thread_getpid()) {
for (uint8_t i = 0; i < ARRAY_SIZE(otCommands); i++) { for (uint8_t i = 0; i < ARRAY_SIZE(otCommands); i++) {
if (strcmp(command, otCommands[i].name) == 0) { if (strcmp(job->command, otCommands[i].name) == 0) {
res = (*otCommands[i].function)(ot_instance, arg, answer); res = (*otCommands[i].function)(openthread_get_instance(), job->arg, job->answer);
break; break;
} }
} }
@ -91,12 +92,22 @@ uint8_t ot_exec_command(otInstance *ot_instance, const char* command, void *arg,
DEBUG("Wrong ot_COMMAND name\n"); DEBUG("Wrong ot_COMMAND name\n");
res = 1; res = 1;
} }
} else { job->status = res;
DEBUG("ERROR: ot_exec_job needs to run in OpenThread thread\n");
} }
return res;
uint8_t ot_call_command(char* command, void *arg, void* answer)
{
ot_job_t job = {.ev.handler = _exec_cmd};
job.command = command;
job.arg = arg;
job.answer = answer;
event_post(openthread_get_evq(), &job.ev);
return job.status;
} }
void output_bytes(const char* name, const uint8_t *aBytes, uint8_t aLength) void output_bytes(const char* name, const uint8_t *aBytes, uint8_t aLength)
{ {
#if ENABLE_DEBUG #if ENABLE_DEBUG

View File

@ -19,10 +19,31 @@
#include "openthread/platform/misc.h" #include "openthread/platform/misc.h"
#include "periph/pm.h" #include "periph/pm.h"
#include "ot.h"
#include "openthread/tasklet.h"
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#include "debug.h" #include "debug.h"
static void _ev_tasklets_handler(event_t *event)
{
(void) event;
otInstance *instance = openthread_get_instance();
while (otTaskletsArePending(instance)) {
otTaskletsProcess(instance);
}
}
static event_t ev_tasklet = {
.handler = _ev_tasklets_handler
};
/* OpenThread will call this when switching state from empty tasklet to non-empty tasklet. */
void otTaskletsSignalPending(otInstance *aInstance) {
(void) aInstance;
event_post(openthread_get_evq(), &ev_tasklet);
}
void otPlatReset(otInstance *aInstance) void otPlatReset(otInstance *aInstance)
{ {
(void)aInstance; (void)aInstance;

View File

@ -25,6 +25,7 @@
#include "periph/uart.h" #include "periph/uart.h"
#include "openthread/platform/uart.h" #include "openthread/platform/uart.h"
#include "ot.h" #include "ot.h"
#include "event.h"
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#include "debug.h" #include "debug.h"
@ -34,6 +35,18 @@
static serial_msg_t gSerialMessage[OPENTHREAD_NUMBER_OF_SERIAL_BUFFER]; static serial_msg_t gSerialMessage[OPENTHREAD_NUMBER_OF_SERIAL_BUFFER];
static uint16_t frameLength = 0; static uint16_t frameLength = 0;
static void _ev_serial_handler(event_t *event)
{
(void) event;
/* Tell OpenThread about the reception of a CLI command */
otPlatUartReceived((uint8_t*)gSerialMessage[0].buf, gSerialMessage[0].length);
gSerialMessage[0].serial_buffer_status = OPENTHREAD_SERIAL_BUFFER_STATUS_FREE;
}
static event_t ev_serial = {
.handler = _ev_serial_handler
};
static void uart_handler(void* arg, char c) { static void uart_handler(void* arg, char c) {
(void)arg; (void)arg;
@ -47,10 +60,7 @@ static void uart_handler(void* arg, char c) {
gSerialMessage[0].buf[frameLength] = c; gSerialMessage[0].buf[frameLength] = c;
frameLength++; frameLength++;
gSerialMessage[0].length = frameLength; gSerialMessage[0].length = frameLength;
msg_t msg; event_post(openthread_get_evq(), &ev_serial);
msg.type = OPENTHREAD_SERIAL_MSG_TYPE_EVENT;
msg.content.ptr = &gSerialMessage[0];
msg_send_int(&msg, openthread_get_pid());
frameLength = 0; frameLength = 0;
} }
break; break;

View File

@ -34,22 +34,7 @@ extern "C" {
#include "net/netdev.h" #include "net/netdev.h"
#include "thread.h" #include "thread.h"
#include "openthread/instance.h" #include "openthread/instance.h"
#include "event.h"
/**
* @name Openthread message types
* @{
*/
/** @brief xtimer message receiver event */
#define OPENTHREAD_XTIMER_MSG_TYPE_EVENT (0x2235)
/** @brief message received from driver */
#define OPENTHREAD_NETDEV_MSG_TYPE_EVENT (0x2236)
/** @brief event indicating a serial (UART) message was sent to OpenThread */
#define OPENTHREAD_SERIAL_MSG_TYPE_EVENT (0x2237)
/** @brief event for frame reception */
#define OPENTHREAD_MSG_TYPE_RECV (0x2238)
/** @brief event indicating an OT_JOB message */
#define OPENTHREAD_JOB_MSG_TYPE_EVENT (0x2240)
/** @} */
/** /**
* @name Openthread constants * @name Openthread constants
@ -90,6 +75,8 @@ typedef struct {
* @brief Struct containing an OpenThread job * @brief Struct containing an OpenThread job
*/ */
typedef struct { typedef struct {
event_t ev; /**< Event associated to the OpenThread job */
int status; /**< Status of the job */
const char *command; /**< A pointer to the job name string. */ const char *command; /**< A pointer to the job name string. */
void *arg; /**< arg for the job **/ void *arg; /**< arg for the job **/
void *answer; /**< answer from the job **/ void *answer; /**< answer from the job **/
@ -112,6 +99,20 @@ void recv_pkt(otInstance *aInstance, netdev_t *dev);
*/ */
void send_pkt(otInstance *aInstance, netdev_t *dev, netdev_event_t event); void send_pkt(otInstance *aInstance, netdev_t *dev, netdev_event_t event);
/**
* @brief Get OpenThread event queue
*
* @return pointer to the event queue
*/
event_queue_t *openthread_get_evq(void);
/**
* @brief Get pointer to the OpenThread instance
*
* @return pointer to the OpenThread instance
*/
otInstance* openthread_get_instance(void);
/** /**
* @brief Bootstrap OpenThread * @brief Bootstrap OpenThread
*/ */