1
0
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:
Martine Lenders 2019-01-22 10:34:30 +01:00 committed by GitHub
commit d3f8739a1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 438 additions and 0 deletions

View File

@ -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)))

View 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 */

View 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);
}
}
}

View 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

View 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.

View 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");
}