mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #5949 from zhuoshuguo/add_timeout_module_to_gnrc_mac
gnrc_mac: add timeout module.
This commit is contained in:
commit
d3f8739a1e
@ -29,6 +29,7 @@ endif
|
||||
ifneq (,$(filter gnrc_mac,$(USEMODULE)))
|
||||
USEMODULE += gnrc_priority_pktqueue
|
||||
USEMODULE += csma_sender
|
||||
USEMODULE += evtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_gomach,$(USEMODULE)))
|
||||
|
147
sys/include/net/gnrc/mac/timeout.h
Normal file
147
sys/include/net/gnrc/mac/timeout.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs
|
||||
* 2017 INRIA
|
||||
*
|
||||
* 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_gnrc_mac
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Timeout APIs used by GNRC_MAC
|
||||
*
|
||||
* @author Daniel Krebs <github@daniel-krebs.net>
|
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef NET_GNRC_MAC_TIMEOUT_H
|
||||
#define NET_GNRC_MAC_TIMEOUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "evtimer_msg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief definition for GNRC_MAC timeout event type
|
||||
*/
|
||||
#define GNRC_MAC_EVENT_TIMEOUT_TYPE (0x4400)
|
||||
|
||||
/**
|
||||
* @brief Definitions of GNRC_MAC timeout types.
|
||||
*
|
||||
* This structure can be extended to contain more needed
|
||||
* timeout types of different MAC protocols. Please guard
|
||||
* them by appropriate \#ifdef directives when applicable.
|
||||
*/
|
||||
typedef enum {
|
||||
GNRC_MAC_TIMEOUT_DISABLED = 0, /**< Timeout is disabled, not in used. */
|
||||
} gnrc_mac_timeout_type_t;
|
||||
|
||||
/**
|
||||
* @brief Structure of the GNRC_MAC timeout event.
|
||||
*/
|
||||
typedef struct {
|
||||
evtimer_msg_event_t msg_event; /**< The timeout message event. */
|
||||
gnrc_mac_timeout_type_t type; /**< GNRC_MAC timeout type. */
|
||||
} gnrc_mac_timeout_event_t;
|
||||
|
||||
/**
|
||||
* @brief Structure holding the GNRC_MAC timeouts.
|
||||
*/
|
||||
typedef struct {
|
||||
evtimer_t evtimer; /**< evtimer entity which
|
||||
stores the timeout list. */
|
||||
gnrc_mac_timeout_event_t *timeouts; /**< The gnrc_mac timeout
|
||||
unites. */
|
||||
uint8_t timeout_num; /**< Timeout number. */
|
||||
} gnrc_mac_timeout_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the MAC timeout module of gnrc_mac before using,
|
||||
* it also sets the timeout callback function.
|
||||
*
|
||||
* @param[in,out] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] timeouts gnrc_mac timeouts
|
||||
* @param[in] num timeout number
|
||||
*/
|
||||
void gnrc_mac_init_timeouts(gnrc_mac_timeout_t *mac_timeout,
|
||||
gnrc_mac_timeout_event_t timeouts[],
|
||||
uint8_t num);
|
||||
|
||||
/**
|
||||
* @brief Set a MAC timeout of @p type.
|
||||
*
|
||||
* @param[in,out] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] type the MAC timeout type
|
||||
* @param[in] offset the timeout offset
|
||||
* @param[in] pid the targeted thread pid
|
||||
*/
|
||||
void gnrc_mac_set_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type,
|
||||
uint32_t offset, kernel_pid_t pid);
|
||||
|
||||
/**
|
||||
* @brief Find a MAC timeout of @p type.
|
||||
*
|
||||
* @param[in] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] type the MAC timeout type
|
||||
*
|
||||
* @return Return index >= 0 if found timeout, -ENONENT if not found
|
||||
*/
|
||||
int gnrc_mac_find_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Clear a MAC timeout of @p type.
|
||||
*
|
||||
* @param[in,out] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] type the MAC timeout type
|
||||
*/
|
||||
void gnrc_mac_clear_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Check whether a MAC timeout of @p type is running or not.
|
||||
*
|
||||
* @param[in] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] type the MAC timeout type
|
||||
*
|
||||
* @return true, if the time of @p type is running
|
||||
* @return false, if the time of @p type is not running, or not exist
|
||||
*/
|
||||
static inline bool gnrc_mac_timeout_is_running(gnrc_mac_timeout_t *mac_timeout,
|
||||
gnrc_mac_timeout_type_t type)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
return (gnrc_mac_find_timeout(mac_timeout, type) >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether a MAC timeout of @p type has expired or not.
|
||||
*
|
||||
* @param[in,out] mac_timeout gnrc_mac timeout management unit
|
||||
* @param[in] type the MAC timeout type
|
||||
*
|
||||
* @return true, if the MAC time of @p type is expired
|
||||
* @return false, if the MAC time of @p type is not expired, or not exist
|
||||
*/
|
||||
bool gnrc_mac_timeout_is_expired(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Reset all the MAC timeouts.
|
||||
*
|
||||
* @param[in,out] mac_timeout gnrc_mac timeout management unit
|
||||
*/
|
||||
void gnrc_mac_reset_timeouts(gnrc_mac_timeout_t *mac_timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_MAC_TIMEOUT_H */
|
147
sys/net/gnrc/link_layer/gnrc_mac/timeout.c
Normal file
147
sys/net/gnrc/link_layer/gnrc_mac/timeout.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs
|
||||
* 2017 INRIA
|
||||
*
|
||||
* 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_gnrc_mac
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of timeout module of GNRC_MAC
|
||||
*
|
||||
* @author Daniel Krebs <github@daniel-krebs.net>
|
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/mac/timeout.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
void gnrc_mac_init_timeouts(gnrc_mac_timeout_t *mac_timeout,
|
||||
gnrc_mac_timeout_event_t timeouts[],
|
||||
uint8_t num)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
assert(timeouts);
|
||||
assert(num);
|
||||
|
||||
mac_timeout->timeouts = timeouts;
|
||||
mac_timeout->timeout_num = num;
|
||||
|
||||
for (int i = 0; i < mac_timeout->timeout_num; i++) {
|
||||
mac_timeout->timeouts[i].msg_event.event.next = NULL;
|
||||
mac_timeout->timeouts[i].type = GNRC_MAC_TIMEOUT_DISABLED;
|
||||
}
|
||||
|
||||
evtimer_init_msg(&mac_timeout->evtimer);
|
||||
}
|
||||
|
||||
|
||||
int gnrc_mac_find_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
assert(mac_timeout->timeout_num);
|
||||
|
||||
for (unsigned i = 0; i < mac_timeout->timeout_num; i++) {
|
||||
if (mac_timeout->timeouts[i].type == type) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
gnrc_mac_timeout_event_t *_gnrc_mac_acquire_timeout(gnrc_mac_timeout_t *mac_timeout,
|
||||
gnrc_mac_timeout_type_t type)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
assert(mac_timeout->timeout_num);
|
||||
|
||||
if (gnrc_mac_timeout_is_running(mac_timeout, type)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < mac_timeout->timeout_num; i++) {
|
||||
if (mac_timeout->timeouts[i].type == GNRC_MAC_TIMEOUT_DISABLED) {
|
||||
mac_timeout->timeouts[i].type = type;
|
||||
return &mac_timeout->timeouts[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void gnrc_mac_set_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type,
|
||||
uint32_t offset, kernel_pid_t pid)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
|
||||
gnrc_mac_timeout_event_t *timeout_event;
|
||||
if ((timeout_event = _gnrc_mac_acquire_timeout(mac_timeout, type))) {
|
||||
DEBUG("[gnrc_mac] Set timeout type-%d in %" PRIu32 " us\n",
|
||||
type, offset);
|
||||
timeout_event->msg_event.event.offset = offset;
|
||||
timeout_event->msg_event.msg.type = GNRC_MAC_EVENT_TIMEOUT_TYPE;
|
||||
timeout_event->msg_event.msg.content.ptr = (void *) timeout_event;
|
||||
timeout_event->msg_event.msg.sender_pid = pid;
|
||||
evtimer_add(&mac_timeout->evtimer, &timeout_event->msg_event.event);
|
||||
}
|
||||
else {
|
||||
DEBUG("[gnrc_mac] Cannot set timeout type-%d, too many concurrent timeouts\n",
|
||||
type);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_mac_clear_timeout(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
|
||||
int index = gnrc_mac_find_timeout(mac_timeout, type);
|
||||
if (index >= 0) {
|
||||
mac_timeout->timeouts[index].type = GNRC_MAC_TIMEOUT_DISABLED;
|
||||
evtimer_del(&mac_timeout->evtimer,
|
||||
&mac_timeout->timeouts[index].msg_event.event);
|
||||
}
|
||||
}
|
||||
|
||||
bool gnrc_mac_timeout_is_expired(gnrc_mac_timeout_t *mac_timeout, gnrc_mac_timeout_type_t type)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
|
||||
int index = gnrc_mac_find_timeout(mac_timeout, type);
|
||||
if (index >= 0) {
|
||||
evtimer_event_t *list;
|
||||
list = (evtimer_event_t *)&mac_timeout->evtimer.events;
|
||||
while (list->next) {
|
||||
if (list->next == &mac_timeout->timeouts[index].msg_event.event) {
|
||||
return false;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* if we reach here, timeout is expired */
|
||||
mac_timeout->timeouts[index].type = GNRC_MAC_TIMEOUT_DISABLED;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void gnrc_mac_reset_timeouts(gnrc_mac_timeout_t *mac_timeout)
|
||||
{
|
||||
assert(mac_timeout);
|
||||
assert(mac_timeout->timeout_num);
|
||||
|
||||
for (unsigned i = 0; i < mac_timeout->timeout_num; i++) {
|
||||
if (mac_timeout->timeouts[i].type != GNRC_MAC_TIMEOUT_DISABLED) {
|
||||
mac_timeout->timeouts[i].type = GNRC_MAC_TIMEOUT_DISABLED;
|
||||
evtimer_del(&mac_timeout->evtimer,
|
||||
&mac_timeout->timeouts[i].msg_event.event);
|
||||
}
|
||||
}
|
||||
}
|
10
tests/gnrc_mac_timeout/Makefile
Normal file
10
tests/gnrc_mac_timeout/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
APPLICATION = gnrc_mac_timeout
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-mega2560 arduino-uno \
|
||||
chronos nucleo-f030r8 nucleo-f031k6 nucleo-f042k6 \
|
||||
nucleo-l031k6 nucleo-l053r8 stm32f0discovery waspmote-pro
|
||||
|
||||
USEMODULE += gnrc_mac
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
14
tests/gnrc_mac_timeout/README.md
Normal file
14
tests/gnrc_mac_timeout/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
Expected result
|
||||
===============
|
||||
|
||||
This is a test application for using the timeout module of gnrc_mac for setting timeouts.
|
||||
|
||||
When everything works as expected, you should see timeouts expired at the time they are set
|
||||
to be expired. Also, you should see the status of timeouts are corresponding to their real
|
||||
status, i.e., the system should state that a timeout is "running" when it is set and
|
||||
awaiting to be expired, and state "not running" when a timeout has expired and not set
|
||||
again.
|
||||
|
||||
Background
|
||||
==========
|
||||
Test for verifying the functionalities of the timeout module of gnrc_mac.
|
119
tests/gnrc_mac_timeout/main.c
Normal file
119
tests/gnrc_mac_timeout/main.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2017 INRIA
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief gnrc_mac timeout test application
|
||||
*
|
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/gnrc/mac/timeout.h"
|
||||
#include "thread.h"
|
||||
#include "msg.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define TIMEOUT_COUNT 3
|
||||
#define TIMEOUT_1_DURATION 1000
|
||||
#define TIMEOUT_2_DURATION 2538
|
||||
#define TIMEOUT_3_DURATION 3471
|
||||
static gnrc_mac_timeout_t mac_timeout;
|
||||
static gnrc_mac_timeout_event_t test_timeouts[TIMEOUT_COUNT];
|
||||
static gnrc_mac_timeout_type_t timeout_1;
|
||||
static gnrc_mac_timeout_type_t timeout_2;
|
||||
static gnrc_mac_timeout_type_t timeout_3;
|
||||
static uint32_t start_time;
|
||||
|
||||
static char worker_stack[THREAD_STACKSIZE_MAIN];
|
||||
|
||||
|
||||
/* This thread will print the drift to stdout once per second */
|
||||
void *worker_thread(void *arg)
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
(void) arg;
|
||||
|
||||
while (1) {
|
||||
msg_t m;
|
||||
uint32_t now;
|
||||
|
||||
msg_receive(&m);
|
||||
now = xtimer_now_usec() / US_PER_MS;
|
||||
|
||||
if (gnrc_mac_timeout_is_expired(&mac_timeout, timeout_1)) {
|
||||
printf("At %6" PRIu32 " ms received msg %i: timeout_1 (set at %" PRIu32 " ms) expired, "
|
||||
"supposed to be %" PRIu32 " ms!\n", now, count++, start_time, (TIMEOUT_1_DURATION + start_time));
|
||||
}
|
||||
|
||||
if (gnrc_mac_timeout_is_expired(&mac_timeout, timeout_2)) {
|
||||
printf("At %6" PRIu32 " ms received msg %i: timeout_2 (set at %" PRIu32 " ms) expired, "
|
||||
"supposed to be %" PRIu32 " ms!\n", now, count++, start_time, (TIMEOUT_2_DURATION + start_time));
|
||||
}
|
||||
|
||||
if (gnrc_mac_timeout_is_expired(&mac_timeout, timeout_3)) {
|
||||
printf("At %6" PRIu32 " ms received msg %i: timeout_3 (set at %" PRIu32 " ms) expired, "
|
||||
"supposed to be %" PRIu32 " ms!\n", now, count++, start_time, (TIMEOUT_3_DURATION + start_time));
|
||||
}
|
||||
|
||||
if (gnrc_mac_timeout_is_running(&mac_timeout, timeout_1)) {
|
||||
printf("At %6" PRIu32 " ms: timeout_1 is running.\n", now);
|
||||
}
|
||||
else {
|
||||
printf("At %6" PRIu32 " ms: timeout_1 is not running.\n", now);
|
||||
}
|
||||
|
||||
if (gnrc_mac_timeout_is_running(&mac_timeout, timeout_2)) {
|
||||
printf("At %6" PRIu32 " ms: timeout_2 is running.\n", now);
|
||||
}
|
||||
else {
|
||||
printf("At %6" PRIu32 " ms: timeout_2 is not running.\n", now);
|
||||
}
|
||||
|
||||
if (gnrc_mac_timeout_is_running(&mac_timeout, timeout_3)) {
|
||||
printf("At %6" PRIu32 " ms: timeout_3 is running.\n", now);
|
||||
}
|
||||
else {
|
||||
printf("At %6" PRIu32 " ms: timeout_3 is not running.\n", now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* create worker thread */
|
||||
kernel_pid_t pid = thread_create(worker_stack, sizeof(worker_stack),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
worker_thread, NULL, "worker");
|
||||
|
||||
timeout_1 = -1;
|
||||
timeout_2 = -2;
|
||||
timeout_3 = -3;
|
||||
|
||||
start_time = xtimer_now_usec() / US_PER_MS;
|
||||
gnrc_mac_init_timeouts(&mac_timeout, test_timeouts, TIMEOUT_COUNT);
|
||||
gnrc_mac_set_timeout(&mac_timeout, timeout_1, TIMEOUT_1_DURATION, pid);
|
||||
gnrc_mac_set_timeout(&mac_timeout, timeout_2, TIMEOUT_2_DURATION, pid);
|
||||
gnrc_mac_set_timeout(&mac_timeout, timeout_3, TIMEOUT_3_DURATION, pid);
|
||||
printf("Testing gnrc_mac timeout module (start time = %" PRIu32 " ms)\n", start_time);
|
||||
printf("Set timeout_1, should be expired at %" PRIu32 " ms)\n", TIMEOUT_1_DURATION + start_time);
|
||||
printf("Set timeout_2, should be expired at %" PRIu32 " ms)\n", TIMEOUT_2_DURATION + start_time);
|
||||
printf("Set timeout_3, should be expired at %" PRIu32 " ms)\n", TIMEOUT_3_DURATION + start_time);
|
||||
|
||||
|
||||
puts("Are the reception times of all 3 msgs close to the supposed values?\n");
|
||||
puts("If yes, the tests were successful");
|
||||
}
|
Loading…
Reference in New Issue
Block a user