

27 changed files with 4387 additions and 0 deletions
@ -0,0 +1,61 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_networking_mac
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= samr21-xpro
|
||||
|
||||
# Currently, LWMAC is only tested and evaluated through on samr21-xpro.
|
||||
# Once LWMAC has also been tested through on other boards, the whitelist should be
|
||||
# then accordingly extended.
|
||||
BOARD_WHITELIST := samr21-xpro
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# Include packages that pull up and auto-init the link layer.
|
||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||
USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_udp
|
||||
# Add a routing protocol
|
||||
USEMODULE += gnrc_rpl
|
||||
USEMODULE += auto_init_gnrc_rpl
|
||||
# This application dumps received packets to STDIO using the pktdump module
|
||||
USEMODULE += gnrc_pktdump
|
||||
# Additional networking modules that can be dropped if not needed
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
# Add also the shell, some shell commands
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
USEMODULE += netstats_l2
|
||||
USEMODULE += netstats_ipv6
|
||||
USEMODULE += netstats_rpl
|
||||
# Use LWMAC as the MAC layer protocol
|
||||
USEMODULE += gnrc_lwmac
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
CFLAGS += -DDEVELHELP
|
||||
|
||||
# Uncomment the following 2 lines to specify static link lokal IPv6 address
|
||||
# this might be useful for testing, in cases where you cannot or do not want to
|
||||
# run a shell with ifconfig to get the real link lokal address.
|
||||
#IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
|
||||
#CFLAGS += -DGNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
|
||||
|
||||
# Uncomment this to join RPL DODAGs even if DIOs do not contain
|
||||
# DODAG Configuration Options (see the doc for more info)
|
||||
# CFLAGS += -DGNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include |
||||
|
||||
# Set a custom channel
|
||||
DEFAULT_CHANNEL ?= 26
|
||||
CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL)
|
@ -0,0 +1,79 @@
|
||||
# gnrc_networking_mac example |
||||
|
||||
This example shows you how to try out communications between RIOT instances with LWMAC as the MAC layer ptotocol for IEEE 802.15.4 devices. |
||||
This example is generally based on `gnrc_networking` but embeds LWMAC to support low duty-cycle operation to conserve power. Also, it intends to show that the duty-cycled LWMAC can support popular upper layer protocols like UDP and RPL. |
||||
Currently, it seems that you can only use the samr21-xpro board to test this MAC, since some certain features of the protocol are only available on that platform. Also, the current implementation of LWMAC uses RTT as the underlying timer source. So, currently, LWMAC cannot run on nodes that don't have RTT. But, as a long-term plan, we will replace RTT by a general timer API as the underlying timer to make LWMAC available for more devices, when the related implementations are ready. |
||||
|
||||
|
||||
## Usage |
||||
|
||||
Build, flash and start the application: |
||||
``` |
||||
export BOARD=your_board |
||||
make |
||||
make flash |
||||
make term |
||||
``` |
||||
|
||||
## Print out the achieved duty-cyle of LWMAC |
||||
|
||||
You can print out the radio duty-cyle (a roughly one) of LWMAC by setting the `LWMAC_ENABLE_DUTYCYLE_RECORD` flag in `sys/include/net/gnrc/lwmac/types.h` to "1". By doing so, each time when a device sends or receives a packet, it will print out its radio duty-cycle value. |
||||
Also, by further enabling the debug flag in `sys/net/gnrc/link_layer/lwmac/tx_state_machine.c`, you will get the printout of how many preamble (WR) and time (sending delay) cost for sending this packet in the TX procedure of LWMAC. |
||||
|
||||
|
||||
## Try UDP transmissions with LWMAC |
||||
|
||||
In the RIOT shell, get to know the IP address of one node: |
||||
|
||||
2017-06-06 15:05:48,279 - INFO # ifconfig |
||||
2017-06-06 15:05:48,284 - INFO # Iface 7 HWaddr: 79:f6 Channel: 26 Page: 0 NID: 0x23 |
||||
2017-06-06 15:05:48,288 - INFO # Long HWaddr: 79:67:35:7e:54:3a:79:f6 |
||||
2017-06-06 15:05:48,297 - INFO # TX-Power: 0dBm State: SLEEP max. Retrans.: 3 CSMA Retries: 4 |
||||
2017-06-06 15:05:48,303 - INFO # CSMA MTU:1280 HL:64 6LO RTR IPHC |
||||
2017-06-06 15:05:48,306 - INFO # Source address length: 8 |
||||
2017-06-06 15:05:48,309 - INFO # Link type: wireless |
||||
2017-06-06 15:05:48,314 - INFO # inet6 addr: ff02::1/128 scope: local [multicast] |
||||
2017-06-06 15:05:48,320 - INFO # inet6 addr: fe80::7b67:357e:543a:79f6/64 scope: local |
||||
2017-06-06 15:05:48,326 - INFO # inet6 addr: ff02::1:ff3a:79f6/128 scope: local [multicast] |
||||
2017-06-06 15:05:48,331 - INFO # inet6 addr: ff02::1a/128 scope: local [multicast] |
||||
|
||||
and start a UDP server. |
||||
|
||||
> udp server start 8808 |
||||
|
||||
This node is now ready to receive data on port `8808`. |
||||
|
||||
In a second terminal, start a second RIOT instance, in the RIOT shell, you can now send a message to the first RIOT instance: |
||||
|
||||
> udp send fe80::7b67:357e:543a:79f6 8808 testmessage |
||||
|
||||
In your first terminal (the receiver side), you should now see output that looks like this: |
||||
|
||||
2017-06-06 15:00:06,894 - INFO # [LWMAC]: achieved duty-cycle: 10 % |
||||
2017-06-06 15:00:06,896 - INFO # PKTDUMP: data received: |
||||
2017-06-06 15:00:06,901 - INFO # ~~ SNIP 0 - size: 11 byte, type: NETTYPE_UNDEF (0) |
||||
2017-06-06 15:00:06,907 - INFO # 00000000 74 65 73 74 6D 65 73 73 61 67 65 |
||||
2017-06-06 15:00:06,911 - INFO # ~~ SNIP 1 - size: 8 byte, type: NETTYPE_UDP (5) |
||||
2017-06-06 15:00:06,914 - INFO # src-port: 8808 dst-port: 8808 |
||||
2017-06-06 15:00:06,917 - INFO # length: 19 cksum: 0xf729 |
||||
2017-06-06 15:00:06,921 - INFO # ~~ SNIP 2 - size: 40 byte, type: NETTYPE_IPV6 (3) |
||||
2017-06-06 15:00:06,925 - INFO # traffic class: 0x00 (ECN: 0x0, DSCP: 0x00) |
||||
2017-06-06 15:00:06,927 - INFO # flow label: 0x00000 |
||||
2017-06-06 15:00:06,930 - INFO # length: 19 next header: 17 hop limit: 64 |
||||
2017-06-06 15:00:06,934 - INFO # source address: fe80::7b67:877:19f:331e |
||||
2017-06-06 15:00:06,938 - INFO # destination address: fe80::7b67:357e:543a:79f6 |
||||
2017-06-06 15:00:06,943 - INFO # ~~ SNIP 3 - size: 24 byte, type: NETTYPE_NETIF (-1) |
||||
2017-06-06 15:00:06,945 - INFO # if_pid: 7 rssi: 51 lqi: 255 |
||||
2017-06-06 15:00:06,946 - INFO # flags: 0x0 |
||||
2017-06-06 15:00:06,949 - INFO # src_l2addr: 79:67:08:77:01:9f:33:1e |
||||
2017-06-06 15:00:06,952 - INFO # dst_l2addr: 79:67:35:7e:54:3a:79:f6 |
||||
2017-06-06 15:00:06,956 - INFO # ~~ PKT - 4 snips, total size: 83 byte |
||||
|
||||
|
||||
In your second terminal (the sender side), you should now see output that looks like this: |
||||
|
||||
2017-06-06 15:00:06,871 - INFO # udp send fe80::7b67:357e:543a:79f6 8808 testmessage |
||||
2017-06-06 15:00:06,877 - INFO # Success: sent 11 byte(s) to [fe80::7b67:357e:543a:79f6]:8808 |
||||
2017-06-06 15:00:06,890 - INFO # [LWMAC-tx]: spent 1 WR in TX |
||||
2017-06-06 15:00:06,894 - INFO # [LWMAC-tx]: pkt sending delay in TX: 8422 us |
||||
2017-06-06 15:00:06,898 - INFO # [LWMAC]: achieved duty-cycle: 10 % |
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universitรคt Berlin |
||||
* |
||||
* 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 examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Example application for demonstrating the RIOT network stack |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include "shell.h" |
||||
#include "msg.h" |
||||
|
||||
#define MAIN_QUEUE_SIZE (8) |
||||
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; |
||||
|
||||
extern int udp_cmd(int argc, char **argv); |
||||
|
||||
static const shell_command_t shell_commands[] = { |
||||
{ "udp", "send data over UDP and listen on UDP ports", udp_cmd }, |
||||
{ NULL, NULL, NULL } |
||||
}; |
||||
|
||||
int main(void) |
||||
{ |
||||
/* we need a message queue for the thread running the shell in order to
|
||||
* receive potentially fast incoming networking packets */ |
||||
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); |
||||
puts("RIOT network stack example application"); |
||||
|
||||
/* start shell */ |
||||
puts("All up, running the shell now"); |
||||
char line_buf[SHELL_DEFAULT_BUFSIZE]; |
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); |
||||
|
||||
/* should be never reached */ |
||||
return 0; |
||||
} |
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universitรคt Berlin |
||||
* |
||||
* 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 examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Demonstrating the sending and receiving of UDP data |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include "net/gnrc.h" |
||||
#include "net/gnrc/ipv6.h" |
||||
#include "net/gnrc/udp.h" |
||||
#include "net/gnrc/pktdump.h" |
||||
#include "timex.h" |
||||
#include "xtimer.h" |
||||
|
||||
static gnrc_netreg_entry_t server = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, |
||||
KERNEL_PID_UNDEF); |
||||
|
||||
|
||||
static void send(char *addr_str, char *port_str, char *data, unsigned int num, |
||||
unsigned int delay) |
||||
{ |
||||
uint16_t port; |
||||
ipv6_addr_t addr; |
||||
|
||||
/* parse destination address */ |
||||
if (ipv6_addr_from_str(&addr, addr_str) == NULL) { |
||||
puts("Error: unable to parse destination address"); |
||||
return; |
||||
} |
||||
/* parse port */ |
||||
port = (uint16_t)atoi(port_str); |
||||
if (port == 0) { |
||||
puts("Error: unable to parse destination port"); |
||||
return; |
||||
} |
||||
|
||||
for (unsigned int i = 0; i < num; i++) { |
||||
gnrc_pktsnip_t *payload, *udp, *ip; |
||||
unsigned payload_size; |
||||
/* allocate payload */ |
||||
payload = gnrc_pktbuf_add(NULL, data, strlen(data), GNRC_NETTYPE_UNDEF); |
||||
if (payload == NULL) { |
||||
puts("Error: unable to copy data to packet buffer"); |
||||
return; |
||||
} |
||||
/* store size for output */ |
||||
payload_size = (unsigned)payload->size; |
||||
/* allocate UDP header, set source port := destination port */ |
||||
udp = gnrc_udp_hdr_build(payload, port, port); |
||||
if (udp == NULL) { |
||||
puts("Error: unable to allocate UDP header"); |
||||
gnrc_pktbuf_release(payload); |
||||
return; |
||||
} |
||||
/* allocate IPv6 header */ |
||||
ip = gnrc_ipv6_hdr_build(udp, NULL, &addr); |
||||
if (ip == NULL) { |
||||
puts("Error: unable to allocate IPv6 header"); |
||||
gnrc_pktbuf_release(udp); |
||||
return; |
||||
} |
||||
/* send packet */ |
||||
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip)) { |
||||
puts("Error: unable to locate UDP thread"); |
||||
gnrc_pktbuf_release(ip); |
||||
return; |
||||
} |
||||
/* access to `payload` was implicitly given up with the send operation above
|
||||
* => use temporary variable for output */ |
||||
printf("Success: sent %u byte(s) to [%s]:%u\n", payload_size, addr_str, |
||||
port); |
||||
xtimer_usleep(delay); |
||||
} |
||||
} |
||||
|
||||
static void start_server(char *port_str) |
||||
{ |
||||
uint16_t port; |
||||
|
||||
/* check if server is already running */ |
||||
if (server.target.pid != KERNEL_PID_UNDEF) { |
||||
printf("Error: server already running on port %" PRIu32 "\n", |
||||
server.demux_ctx); |
||||
return; |
||||
} |
||||
/* parse port */ |
||||
port = (uint16_t)atoi(port_str); |
||||
if (port == 0) { |
||||
puts("Error: invalid port specified"); |
||||
return; |
||||
} |
||||
/* start server (which means registering pktdump for the chosen port) */ |
||||
server.target.pid = gnrc_pktdump_pid; |
||||
server.demux_ctx = (uint32_t)port; |
||||
gnrc_netreg_register(GNRC_NETTYPE_UDP, &server); |
||||
printf("Success: started UDP server on port %" PRIu16 "\n", port); |
||||
} |
||||
|
||||
static void stop_server(void) |
||||
{ |
||||
/* check if server is running at all */ |
||||
if (server.target.pid == KERNEL_PID_UNDEF) { |
||||
printf("Error: server was not running\n"); |
||||
return; |
||||
} |
||||
/* stop server */ |
||||
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &server); |
||||
server.target.pid = KERNEL_PID_UNDEF; |
||||
puts("Success: stopped UDP server"); |
||||
} |
||||
|
||||
int udp_cmd(int argc, char **argv) |
||||
{ |
||||
if (argc < 2) { |
||||
printf("usage: %s [send|server]\n", argv[0]); |
||||
return 1; |
||||
} |
||||
|
||||
if (strcmp(argv[1], "send") == 0) { |
||||
uint32_t num = 1; |
||||
uint32_t delay = 1000000; |
||||
if (argc < 5) { |
||||
printf("usage: %s send <addr> <port> <data> [<num> [<delay in us>]]\n", |
||||
argv[0]); |
||||
return 1; |
||||
} |
||||
if (argc > 5) { |
||||
num = (uint32_t)atoi(argv[5]); |
||||
} |
||||
if (argc > 6) { |
||||
delay = (uint32_t)atoi(argv[6]); |
||||
} |
||||
send(argv[2], argv[3], argv[4], num, delay); |
||||
} |
||||
else if (strcmp(argv[1], "server") == 0) { |
||||
if (argc < 3) { |
||||
printf("usage: %s server [start|stop]\n", argv[0]); |
||||
return 1; |
||||
} |
||||
if (strcmp(argv[2], "start") == 0) { |
||||
if (argc < 4) { |
||||
printf("usage %s server start <port>\n", argv[0]); |
||||
return 1; |
||||
} |
||||
start_server(argv[3]); |
||||
} |
||||
else if (strcmp(argv[2], "stop") == 0) { |
||||
stop_server(); |
||||
} |
||||
else { |
||||
puts("error: invalid command"); |
||||
} |
||||
} |
||||
else { |
||||
puts("error: invalid command"); |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs |
||||
* 2016 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_lwmac |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Header definition LWMAC |
||||
* @internal |
||||
* @author Daniel Krebs <github@daniel-krebs.net> |
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr> |
||||
*/ |
||||
|
||||
#ifndef NET_GNRC_LWMAC_HDR_H |
||||
#define NET_GNRC_LWMAC_HDR_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "net/ieee802154.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief LWMAC WR (wake-up request packet, i.e., preamble packet) frame type |
||||
*/ |
||||
#define GNRC_LWMAC_FRAMETYPE_WR (0x01U) |
||||
|
||||
/**
|
||||
* @brief LWMAC WA (wake-up answer packet, i.e., preamble-ACK packet) frame type |
||||
*/ |
||||
#define GNRC_LWMAC_FRAMETYPE_WA (0x02U) |
||||
|
||||
/**
|
||||
* @brief LWMAC data frame type |
||||
*/ |
||||
#define GNRC_LWMAC_FRAMETYPE_DATA (0x03U) |
||||
|
||||
/**
|
||||
* @brief LWMAC data frame type with pending data transmission request |
||||
*/ |
||||
#define GNRC_LWMAC_FRAMETYPE_DATA_PENDING (0x04U) |
||||
|
||||
/**
|
||||
* @brief LWMAC broadcast frame type |
||||
*/ |
||||
#define GNRC_LWMAC_FRAMETYPE_BROADCAST (0x05U) |
||||
|
||||
/**
|
||||
* @brief LWMAC internal L2 address structure |
||||
*/ |
||||
typedef struct { |
||||
uint8_t addr[IEEE802154_LONG_ADDRESS_LEN]; /**< address of node */ |
||||
uint8_t len; /**< address */ |
||||
} gnrc_lwmac_l2_addr_t; |
||||
|
||||
/**
|
||||
* @brief Static initializer for l2_addr_t. |
||||
*/ |
||||
#define GNRC_LWMAC_L2_ADDR_INITIAL { { 0 }, 0 } |
||||
|
||||
/**
|
||||
* @brief LWMAC header |
||||
*/ |
||||
typedef struct { |
||||
uint8_t type; /**< type of frame */ |
||||
} gnrc_lwmac_hdr_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC WR (wake-up request packet, i.e., preamble packet) frame |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
gnrc_lwmac_hdr_t header; /**< WR packet header type */ |
||||
gnrc_lwmac_l2_addr_t dst_addr; /**< WR is broadcast, so destination address needed */ |
||||
} gnrc_lwmac_frame_wr_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC WA (wake-up answer packet, i.e., preamble-ACK packet) frame |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
gnrc_lwmac_hdr_t header; /**< WA packet header type */ |
||||
gnrc_lwmac_l2_addr_t dst_addr; /**< WA is broadcast, so destination address needed */ |
||||
uint32_t current_phase; /**< Node's current phase value */ |
||||
} gnrc_lwmac_frame_wa_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC broadcast data frame |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
gnrc_lwmac_hdr_t header; /**< Broadcast packet header type */ |
||||
uint8_t seq_nr; /**< Broadcast sequence */ |
||||
} gnrc_lwmac_frame_broadcast_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC unicast data frame |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
gnrc_lwmac_hdr_t header; /**< Data packet header type */ |
||||
} gnrc_lwmac_frame_data_t; |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NET_GNRC_LWMAC_HDR_H */ |
||||
/** @} */ |
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs |
||||
* 2016 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_lwmac Simplest possible MAC layer |
||||
* @ingroup net_gnrc |
||||
* @brief Lightweight MAC protocol that allows for duty cycling to save |
||||
* energy. |
||||
* |
||||
* ## LWMAC implementation |
||||
* |
||||
* ## Radio duty cycling |
||||
* LWMAC adopts the radio duty-cycle scheme to conserve power. Namely, in each |
||||
* cycle period (MAC superframe), a node device wakes up for a short period of |
||||
* time (called listen period or wake-up period) for receiving possible incoming |
||||
* packets from other devices. Outside the listen period, the node device turns |
||||
* off its radio to conserve power. |
||||
* |
||||
* ## Phase-lock scheme |
||||
* LWMAC adopts the phase-lock scheme to further reduce power consumption. Each |
||||
* node device in LWMAC will try to record/track its Tx-neighbor's wake-up phase. |
||||
* This is called phase-lock. After phase-locking, the sender node will (likely) |
||||
* spend less preamble packets (also called WR packet, i.e., wake-up-request, in |
||||
* LWMAC) for initiating a hand-shaking procedure for transmitting a data packet, |
||||
* compared to the first time it talks to the receiver. |
||||
* |
||||
* ## Burst transmission |
||||
* LWMAC adopts pending-bit technique to enhance its throughput. Namely, in case |
||||
* of having multi packets for the receiver, a sender uses the pending-bit flag |
||||
* embedded in the MAC header to instruct this situation, and the buffered packets |
||||
* will be transmitted in a continuous sequence, back to back, to the receiver in |
||||
* one shot. |
||||
* |
||||
* ## Auto wake-up extension |
||||
* LWMAC adopts auto wake-up extension scheme based on timeout (like T-MAC). In short, |
||||
* when a packet is successfully received at the receiver side, the receiver will |
||||
* reset the wake-up timeout to extend its wake-up period for receiving more potential |
||||
* incoming packets. This is to be compatible with the pending-bit technique to allow |
||||
* the receiver to absorb more packets when needed, thus boosts the throughput. |
||||
* |
||||
* ## Simple retransmission scheme |
||||
* LWMAC adopts a simple retransmission scheme to enhance link reliability. The data |
||||
* packet will only be dropped in case the retransmission counter gets larger than |
||||
* @ref GNRC_LWMAC_MAX_DATA_TX_RETRIES. |
||||
* |
||||
* ## Automatic phase backoff scheme |
||||
* LWMAC adopts an automatic phase backoff scheme to reduce WR (preamble) collision |
||||
* probability. In multi-hop scenarios, let's say, nodes A <---B <----C (which is |
||||
* common in multi-hop data collection networks), in which B has packets for A, and |
||||
* C has packets for B. In case A and B's wake-up phases are too close (overlapping). |
||||
* Then, especially in high traffic conditions, B and C may initiate transmissions |
||||
* at the same time (B sends to A, and C sends to B), a link of either will be |
||||
* definitely interfered, leading to collisions and link throughput reduction. To |
||||
* this end, by using the automatic phase backoff scheme, if a sender finds its |
||||
* receiver's phase is too close to its own phase, it will run a backoff scheme to |
||||
* randomly reselect a new wake-up phase for itself. |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface definition for the LWMAC protocol |
||||
* |
||||
* @author Daniel Krebs <github@daniel-krebs.net> |
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr> |
||||
*/ |
||||
|
||||
#ifndef NET_GNRC_LWMAC_LWMAC_H |
||||
#define NET_GNRC_LWMAC_LWMAC_H |
||||
|
||||
#include "kernel_types.h" |
||||
#include "net/gnrc/netdev.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Time between consecutive wake-ups. |
||||
* |
||||
* This macro governs power consumption, latency and throughput! |
||||
* In LWMAC, devices adopt duty-cycle scheme to conserve power. That is, |
||||
* time is divided into repeated cycles (or, superframes), and in each |
||||
* cycle, a node only wakes up for a period of time for receiving potential |
||||
* incoming packets for itself. This macro defines the wake-up interval, or, |
||||
* in other words, defines the cycle duration used in LWMAC. If the wake-up interval |
||||
* is short, nodes will wake up more frequently, which also increases |
||||
* the chances for receiving packets from neighbors (i.e., leads to higher |
||||
* throughput), but also results in higher power consumption. |
||||
* In LWMAC, by default, we regard the wake-up period as the beginning of a cycle. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_WAKEUP_INTERVAL_US |
||||
#define GNRC_LWMAC_WAKEUP_INTERVAL_US (100LU * US_PER_MS) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The Maximum WR (preamble packet @ref gnrc_lwmac_frame_wr_t) duration time. |
||||
* |
||||
* Since LWMAC adopts duty-cycle scheme, a node only wakes up for a short |
||||
* period in each cycle. Thus, to probe where is the wake-up period of the |
||||
* receiver, a sender sends WR (preamble) packets to notice the receiver for |
||||
* communication. To ensure that the receiver will catch at least one WR |
||||
* packet in one cycle, the sender repeatedly broadcasts a stream of WR packets |
||||
* with the broadcast duration (preamble duration) slightly longer period than |
||||
* @ref GNRC_LWMAC_WAKEUP_INTERVAL_US. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_PREAMBLE_DURATION_US |
||||
#define GNRC_LWMAC_PREAMBLE_DURATION_US ((13LU * GNRC_LWMAC_WAKEUP_INTERVAL_US) / 10) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Timeout to send the next WR in case no WA has been received during that |
||||
* time. |
||||
* |
||||
* In LWMAC, when a sender initiates a transmission to a receiver, it starts with |
||||
* sending a stream of repeated WR packets with @ref GNRC_LWMAC_TIME_BETWEEN_WR_US interval |
||||
* between two consecutive WRs. After sending one WR (preamble) packet, the sender turns |
||||
* to the listen mode to receive the potential incoming WA (preamble-ACK) packet with |
||||
* a timeout of @ref GNRC_LWMAC_TIME_BETWEEN_WR_US. If no WA is received during |
||||
* @ref GNRC_LWMAC_TIME_BETWEEN_WR_US, the sender starts sending the next WR. |
||||
* It is referenced to the beginning of both WRs, but due to internal |
||||
* overhead, the exact spacing is slightly higher. |
||||
* The minimum possible value depends on the time it takes to completely |
||||
* send a WR with the given hardware (including processor) and data rate. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_TIME_BETWEEN_WR_US |
||||
#define GNRC_LWMAC_TIME_BETWEEN_WR_US (5U * US_PER_MS) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief How long a node in LWMAC should keep awake and listen on the channel in one cycle. |
||||
* |
||||
* LWMAC adopts the duty-cycle scheme that a node only wakes up for a short |
||||
* period of @ref GNRC_LWMAC_WAKEUP_DURATION_US in each cycle. In the rest of the cycle, the node |
||||
* turns off the radio to conserve power. @ref GNRC_LWMAC_WAKEUP_DURATION_US is set to twice the |
||||
* duration of @ref GNRC_LWMAC_TIME_BETWEEN_WR_US, to guarantee that the wake-up period is long |
||||
* enough that receiver will not miss the WR (preamble) packet. |
||||
* Receiver needs to support @ref NETDEV_EVENT_RX_STARTED event in order to use time-between-WR |
||||
* as a sensible default here. Otherwise the duration of WRs as well as longest |
||||
* possible data broadcasts need to be taken into account. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_WAKEUP_DURATION_US |
||||
#define GNRC_LWMAC_WAKEUP_DURATION_US (GNRC_LWMAC_TIME_BETWEEN_WR_US * 2) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief How long broadcast packets @ref gnrc_lwmac_frame_broadcast_t will be sent to make sure |
||||
* every participant has received at least one copy. |
||||
* |
||||
* Since LWMAC adopts duty-cycle scheme, a node only wakes up for a short period in |
||||
* each cycle. Thus, when a node wants to broadcast a packet, it repeatedly broadcasts the |
||||
* packet for one @ref GNRC_LWMAC_BROADCAST_DURATION_US duration which is slightly longer |
||||
* than @ref GNRC_LWMAC_WAKEUP_INTERVAL_US. This is to ensure that all neighbors will not miss |
||||
* the broadcast procedure of the sender and catch at least one copy of the broadcast packet. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_BROADCAST_DURATION_US |
||||
#define GNRC_LWMAC_BROADCAST_DURATION_US ((GNRC_LWMAC_WAKEUP_INTERVAL_US * 11) / 10) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Time to idle between two successive broadcast packets, referenced to the |
||||
* start of the packet. |
||||
* |
||||
* The same limitation as for @ref GNRC_LWMAC_TIME_BETWEEN_WR_US apply here. |
||||
* In LWMAC, when a sender initiates a broadcast, it starts with sending a stream of |
||||
* repeated broadcast packets with @ref GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US interval |
||||
* between two consecutive broadcast packets. After sending one broadcast packet, the sender |
||||
* turns to the listen mode with a timeout of @ref GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US. When this |
||||
* timeout expires, the sender sends the next broadcast packet until reaching the maximum |
||||
* broadcast duration of @ref GNRC_LWMAC_BROADCAST_DURATION_US. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US |
||||
#define GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US (GNRC_LWMAC_TIME_BETWEEN_WR_US) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief WR preparation overhead before it can be sent (higher with debugging output). |
||||
* |
||||
* In LWMAC, when a sender wants to send a data packet to the receiver, it starts |
||||
* sending the WR stream a little bit earlier (advance) to the beginning edge |
||||
* of destination's wake-up phase over time. The idea is not to miss the wake-up |
||||
* period of the receiver, otherwise will lead to a long WR procedure. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_WR_PREPARATION_US |
||||
#define GNRC_LWMAC_WR_PREPARATION_US ((3U * US_PER_MS)) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief How long to wait after a WA for data to come in. |
||||
* |
||||
* When a node in LWMAC gets a WR during its wake-up period, it immediately |
||||
* replies a WA packet to the sender for acknowledging the sender's transmission |
||||
* request. After sending the WA, the receiver waits for the data packet from the |
||||
* sender, with a timeout of @ref GNRC_LWMAC_DATA_DELAY_US duration. In case no data will be |
||||
* received in this period, the receiver regards reception failed and go back to |
||||
* normal listen mode. However, in case the receiver receives other unintended packets, |
||||
* like WR/WA packets from other neighbor communication pairs, the receiver resets |
||||
* this timeout and continues to wait for the data packet, with the consideration that |
||||
* the sender's data transmission might be delayed due to other ongoing transmissions |
||||
* (the data packet is transmitted with CSMA/CA). |
||||
* This data timeout is long enough to catch the beginning of the packet if the transceiver |
||||
* supports @ref NETDEV_EVENT_RX_STARTED event (this can be important for big packets). |
||||
*/ |
||||
#ifndef GNRC_LWMAC_DATA_DELAY_US |
||||
#define GNRC_LWMAC_DATA_DELAY_US (10U * US_PER_MS) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief CSMA retries for DATA packet after WR->WA was successful. |
||||
* |
||||
* After receiving the WA packet @ref gnrc_lwmac_frame_wa_t from the receiver, the sender |
||||
* starts sending the data packet using CSMA/CA. This macro defines how many CSMA retries |
||||
* a sender will be allowed to execute for sending its data, before the data is successfully |
||||
* sent (gets data ACK from the receiver). |
||||
*/ |
||||
#ifndef GNRC_LWMAC_DATA_CSMA_RETRIES |
||||
#define GNRC_LWMAC_DATA_CSMA_RETRIES (3U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Maximum TX transmission retries for DATA packet in case of no response from the receiver. |
||||
* |
||||
* When a data packet is scheduled for transmission, i.e., pushed into TX for sending, |
||||
* LWMAC defines a maximum of @ref GNRC_LWMAC_MAX_DATA_TX_RETRIES retries for transmission of the |
||||
* packet. That is, in case of transmission failure in TX due to no WA from the receiver, |
||||
* the sender will not drop the packet, but keeps it and retries to send the data packet |
||||
* in the following cycles, until the sender reaches the maximum retries limit defined here. |
||||
* Then, the packet will be dropped. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_MAX_DATA_TX_RETRIES |
||||
#define GNRC_LWMAC_MAX_DATA_TX_RETRIES (3U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief MAX burst transmission packet number in one shot. |
||||
* |
||||
* LWMAC supports burst transmission based on the pending-bit technique, and this macro |
||||
* here defines the largest number of packets allowed to be sent in one consecutive |
||||
* sequence. In case a sender has multi packets for one receiver,the burst transmission |
||||
* procedure is as follow: |
||||
* 1. The sender first uses WR stream to locate the receiver's wake-up period (if the |
||||
* sender has already phase-locked the receiver's phase, normally the sender only cost |
||||
* one WR to get the first WA from the receiver) and then sends its first data. |
||||
* 2. After the transmission of the first data, the sender immediately sends a WR to |
||||
* the receiver for starting the second round of transmission of the second data. The |
||||
* receiver should also immediately reply WA for continue receiving data packets. In |
||||
* case the sender doesn't receive WA during @ref GNRC_LWMAC_TIME_BETWEEN_WR_US, it regards the |
||||
* consecutive (burst) transmission failed and quits TX procedure (the data will be queued |
||||
* back to the transmission queue for normal transmission attempt in following cycles). |
||||
* 3. In case the second transmission succeeds, the sender repeats step (2) to send all the |
||||
* following pending packets. |
||||
* In short, in burst transmission mode, the sender doesn't tolerate no-WA event. ALl the |
||||
* pending data packets should be sent with only one WR cost for leading the transmission. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_MAX_TX_BURST_PKT_NUM |
||||
#define GNRC_LWMAC_MAX_TX_BURST_PKT_NUM (GNRC_LWMAC_WAKEUP_INTERVAL_US / GNRC_LWMAC_WAKEUP_DURATION_US) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief MAX bad Listen period extensions a node can tolerate. |
||||
* |
||||
* In LWMAC, to allow burst transmissions, when in the wake-up period and by default, a node |
||||
* will extend its wake-up period to another @ref GNRC_LWMAC_WAKEUP_DURATION_US after each packet |
||||
* reception (except for broadcast packet). However, in some cases, a receiver may |
||||
* overhear other unintended packets, e.g., WR or WA packets for other nodes, these are |
||||
* called bad extensions for the receiver. If a receiver reaches the maximum bad listen |
||||
* extension limit defined here, it goes to sleep mode with the consideration that the |
||||
* channel is currently unavailable/busy. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_MAX_RX_EXTENSION_NUM |
||||
#define GNRC_LWMAC_MAX_RX_EXTENSION_NUM (3U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief CSMA retries for broadcast packet. |
||||
* |
||||
* Currently, each broadcast packet is sent with CSMA/CA for collision avoidance. |
||||
* Too many CSMA retries may lead to running out of destinations wake-up period. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_BROADCAST_CSMA_RETRIES |
||||
#define GNRC_LWMAC_BROADCAST_CSMA_RETRIES (3U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Default message queue size to use for the LWMAC thread. |
||||
* |
||||
* The value of this macro should be enough for supporting the manipulation of |
||||
* LWMAC. |
||||
* |
||||
*/ |
||||
#ifndef GNRC_LWMAC_IPC_MSG_QUEUE_SIZE |
||||
#define GNRC_LWMAC_IPC_MSG_QUEUE_SIZE (8U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Initialize an instance of the LWMAC layer |
||||
* |
||||
* The initialization starts a new thread that connects to the given netdev |
||||
* device and starts a link layer event loop. |
||||
* |
||||
* @param[in] stack stack for the control thread |
||||
* @param[in] stacksize size of *stack* |
||||
* @param[in] priority priority for the thread housing the LWMAC instance |
||||
* @param[in] name name of the thread housing the LWMAC instance |
||||
* @param[in] dev netdev device, needs to be already initialized |
||||
* |
||||
* @return PID of LWMAC thread on success |
||||
* @return -EINVAL if creation of thread fails |
||||
* @return -ENODEV if *dev* is invalid |
||||
*/ |
||||
kernel_pid_t gnrc_lwmac_init(char *stack, int stacksize, char priority, |
||||
const char *name, gnrc_netdev_t *dev); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NET_GNRC_LWMAC_LWMAC_H */ |
||||
/** @} */ |
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs |
||||
* 2016 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_lwmac |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Timeout handling of LWMAC |
||||
* |
||||
* |
||||
* @author Daniel Krebs <github@daniel-krebs.net> |
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr> |
||||
*/ |
||||
|
||||
#ifndef NET_GNRC_LWMAC_TIMEOUT_H |
||||
#define NET_GNRC_LWMAC_TIMEOUT_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "net/gnrc/netdev.h" |
||||
#include "net/gnrc/lwmac/types.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Static initializer for @ref gnrc_lwmac_timeout_t. |
||||
*/ |
||||
#define GNRC_LWMAC_TIMEOUT_INITIAL { {}, {}, false, TIMEOUT_DISABLED } |
||||
|
||||
/**
|
||||
* @brief Set LWMAC timeout of type @p type of offset @p offset. |
||||
* |
||||
* @param[in,out] gnrc_netdev gnrc_netdev structure |
||||
* @param[in] type LWMAC timeout type |
||||
* @param[in] offset timeout offset |
||||
*/ |
||||
void gnrc_lwmac_set_timeout(gnrc_netdev_t *gnrc_netdev, |
||||
gnrc_lwmac_timeout_type_t type, |
||||
uint32_t offset); |
||||
|
||||
/**
|
||||
* @brief Clear LWMAC timeout of type @p type. |
||||
* |
||||
* @param[in,out] gnrc_netdev gnrc_netdev structure |
||||
* @param[in] type LWMAC timeout type |
||||
*/ |
||||
void gnrc_lwmac_clear_timeout(gnrc_netdev_t *gnrc_netdev, gnrc_lwmac_timeout_type_t type); |
||||
|
||||
/**
|
||||
* @brief Check whether LWMAC timeout of type @p type is running. |
||||
* |
||||
* @param[in] gnrc_netdev gnrc_netdev structure |
||||
* @param[in] type LWMAC timeout type |
||||
* |
||||
* @return true, if timeout of type @p type is running. |
||||
* @return false, if timeout of type @p type is not running. |
||||
*/ |
||||
bool gnrc_lwmac_timeout_is_running(gnrc_netdev_t *gnrc_netdev, |
||||
gnrc_lwmac_timeout_type_t type); |
||||
|
||||
/**
|
||||
* @brief Check whether LWMAC timeout of type @p type is expired. It will clear |
||||
* the timeout once it is found expired. |
||||
* |
||||
* @param[in,out] gnrc_netdev gnrc_netdev structure |
||||
* @param[in] type LWMAC timeout type |
||||
* |
||||
* @return true, if timeout of type @p type is expired. |
||||
* @return false, if timeout of type @p type is not expired, or not exist. |
||||
*/ |
||||
bool gnrc_lwmac_timeout_is_expired(gnrc_netdev_t *gnrc_netdev, gnrc_lwmac_timeout_type_t type); |
||||
|
||||
/**
|
||||
* @brief Reset all LWMAC timeouts. |
||||
* |
||||
* @param[in,out] gnrc_netdev gnrc_netdev structure |
||||
*/ |
||||
void gnrc_lwmac_reset_timeouts(gnrc_netdev_t *gnrc_netdev); |
||||
|
||||
/**
|
||||
* @brief Make a specific LWMAC timeout expired. |
||||
* |
||||
* @param[in,out] timeout LWMAC tiemout |
||||
*/ |
||||
void gnrc_lwmac_timeout_make_expire(gnrc_lwmac_timeout_t *timeout); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NET_GNRC_LWMAC_TIMEOUT_H */ |
||||
/** @} */ |
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs |
||||
* 2016 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_lwmac |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Definition of internal types used by LWMAC |
||||
* |
||||
* |
||||
* @author Daniel Krebs <github@daniel-krebs.net> |
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr> |
||||
*/ |
||||
|
||||
#ifndef NET_GNRC_LWMAC_TYPES_H |
||||
#define NET_GNRC_LWMAC_TYPES_H |
||||
|
||||
#include "msg.h" |
||||
#include "xtimer.h" |
||||
#include "net/gnrc/lwmac/hdr.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_TYPE (0x4300) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT start event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_START (0x4301) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT stop event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_STOP (0x4302) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT pause event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_PAUSE (0x4303) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT resume event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_RESUME (0x4304) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT wakeup pending event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING (0x4305) |
||||
|
||||
/**
|
||||
* @brief LWMAC RTT sleep pending event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING (0x4306) |
||||
|
||||
/**
|
||||
* @brief LWMAC timeout event type. |
||||
*/ |
||||
#define GNRC_LWMAC_EVENT_TIMEOUT_TYPE (0x4400) |
||||
|
||||
/**
|
||||
* @brief LWMAC duty-cycle active flag. |
||||
* |
||||
* Keep track of duty cycling to avoid late RTT events after stopping. |
||||
*/ |
||||
#define GNRC_LWMAC_DUTYCYCLE_ACTIVE (0x01) |
||||
|
||||
/**
|
||||
* @brief LWMAC needs reschedule flag. |
||||
* |
||||
* Used internally for rescheduling state machine update, e.g. after state |
||||
* transition caused in update. |
||||
*/ |
||||
#define GNRC_LWMAC_NEEDS_RESCHEDULE (0x02) |
||||
|
||||
/**
|
||||
* @brief LWMAC check radio's on/off state flag. |
||||
*/ |
||||
#define GNRC_LWMAC_RADIO_IS_ON (0x04) |
||||
|
||||
/**
|
||||
* @brief Enable/disable duty-cycle record and print out. |
||||
* Set "1" to enable, set "0" to disable. |
||||
*/ |
||||
#ifndef GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD |
||||
#define GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD (0U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The default largest number of parallel timeouts in LWMAC |
||||
*/ |
||||
#ifndef GNRC_LWMAC_TIMEOUT_COUNT |
||||
#define GNRC_LWMAC_TIMEOUT_COUNT (3U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Internal states of LWMAC |
||||
*/ |
||||
typedef enum { |
||||
GNRC_LWMAC_UNDEF = -1, /**< Undefined state of LWMAC */ |
||||
GNRC_LWMAC_STOPPED, /**< LWMAC's main state machine has been stopped */ |
||||
GNRC_LWMAC_START, /**< Start LWMAC's main state machine */ |
||||
GNRC_LWMAC_STOP, /**< Stop LWMAC's main state machine */ |
||||
GNRC_LWMAC_RESET, /**< Reset LWMAC's main state machine */ |
||||
GNRC_LWMAC_LISTENING, /**< Listen the channel for receiving packets */ |
||||
GNRC_LWMAC_RECEIVING, /**< RX is handled in own state machine */ |
||||
GNRC_LWMAC_TRANSMITTING, /**< TX is handled in own state machine */ |
||||
GNRC_LWMAC_SLEEPING, /**< Turn off radio to conserve power */ |
||||
GNRC_LWMAC_STATE_COUNT /**< Count of LWMAC's states */ |
||||
} gnrc_lwmac_state_t; |
||||
|
||||
/**
|
||||
* @brief TX states of LWMAC |
||||
*/ |
||||
typedef enum { |
||||
GNRC_LWMAC_TX_STATE_STOPPED, /**< Tx schedule stopped, stop sending packet */ |
||||
GNRC_LWMAC_TX_STATE_INIT, /**< Initiate transmission */ |
||||
GNRC_LWMAC_TX_STATE_SEND_BROADCAST, /**< directly goes to SUCCESSFUL or FAILED when finished */ |
||||
GNRC_LWMAC_TX_STATE_SEND_WR, /**< Send a wakeup request */ |
||||
GNRC_LWMAC_TX_STATE_WAIT_WR_SENT, /**< Wait until WR sent to set timeout */ |
||||
GNRC_LWMAC_TX_STATE_WAIT_FOR_WA, /**< Wait for dest node's wakeup ackknowledge */ |
||||
GNRC_LWMAC_TX_STATE_SEND_DATA, /**< Send the actual payload data */ |
||||
GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK, /**< Wait if packet was ACKed */ |
||||
GNRC_LWMAC_TX_STATE_SUCCESSFUL, /**< Transmission has finished successfully */ |
||||
GNRC_LWMAC_TX_STATE_FAILED /**< Payload data couldn't be delivered to dest */ |
||||
} gnrc_lwmac_tx_state_t; |
||||
|
||||
/**
|
||||
* @brief Static initializer for gnrc_lwmac_tx_state_t. |
||||
*/ |
||||
#define GNRC_LWMAC_TX_STATE_INITIAL GNRC_LWMAC_TX_STATE_STOPPED |
||||
|
||||
/**
|
||||
* @brief RX states of LWMAC |
||||
*/ |
||||
typedef enum { |
||||
GNRC_LWMAC_RX_STATE_STOPPED, /**< Rx schedule stopped */ |
||||
GNRC_LWMAC_RX_STATE_INIT, /**< Initiate reception */ |
||||
GNRC_LWMAC_RX_STATE_WAIT_FOR_WR, /**< Wait for a wakeup request */ |
||||
GNRC_LWMAC_RX_STATE_SEND_WA, /**< Send wakeup ackknowledge to requesting node */ |
||||
GNRC_LWMAC_RX_STATE_WAIT_WA_SENT, /**< Wait until WA sent to set timeout */ |
||||
GNRC_LWMAC_RX_STATE_WAIT_FOR_DATA, /**< Wait for actual payload data */ |
||||
GNRC_LWMAC_RX_STATE_SUCCESSFUL, /**< Recption has finished successfully */ |
||||
GNRC_LWMAC_RX_STATE_FAILED /**< Reception over, but nothing received */ |
||||
} gnrc_lwmac_rx_state_t; |
||||
|
||||
/**
|
||||
* @brief Static initializer for gnrc_lwmac_rx_state_t. |
||||
*/ |
||||
#define GNRC_LWMAC_RX_STATE_INITIAL GNRC_LWMAC_RX_STATE_STOPPED |
||||
|
||||
/**
|
||||
* @brief LWMAC uninitialized phase value |
||||
*/ |
||||
#define GNRC_LWMAC_PHASE_UNINITIALIZED (0) |
||||
|
||||
/**
|
||||
* @brief LWMAC max phase value |
||||
*/ |
||||
#define GNRC_LWMAC_PHASE_MAX (-1) |
||||
|
||||
/**
|
||||
* @brief LWMAC timeout types |
||||
*/ |
||||
typedef enum { |
||||
GNRC_LWMAC_TIMEOUT_DISABLED, /**< Timeout is diabled */ |
||||
GNRC_LWMAC_TIMEOUT_WR, /**< WR timeout, waiting WA */ |
||||
GNRC_LWMAC_TIMEOUT_NO_RESPONSE, /**< Maximum WR duration timeout awaiting WA */ |
||||
GNRC_LWMAC_TIMEOUT_DATA, /**< Timeout awaiting data packet from receiver */ |
||||
GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP, /**< Timeout for waiting receiver's wake-up phase */ |
||||
GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD, /**< Wake up period timeout for going to sleep */ |
||||
GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST, /**< Timeout for waiting to send the next broadcast packet */ |
||||
GNRC_LWMAC_TIMEOUT_BROADCAST_END, /**< Timeout awaiting the end of the whole broadcast period */ |
||||
} gnrc_lwmac_timeout_type_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC timeout structure |
||||
*/ |
||||
typedef struct { |
||||
xtimer_t timer; /**< xtimer entity */ |
||||
msg_t msg; /**< msg entity */ |
||||
bool expired; /**< If type != DISABLED, this indicates if timeout has expired */ |
||||
gnrc_lwmac_timeout_type_t type; /**< timeout type */ |
||||
} gnrc_lwmac_timeout_t; |
||||
|
||||
/**
|
||||
* @brief LWMAC specific structure for storing internal states. |
||||
*/ |
||||
typedef struct lwmac { |
||||
gnrc_lwmac_state_t state; /**< Internal state of MAC layer */ |
||||
uint32_t last_wakeup; /**< Used to calculate wakeup times */ |
||||
uint8_t lwmac_info; /**< LWMAC's internal informations (flags) */ |
||||
gnrc_lwmac_timeout_t timeouts[GNRC_LWMAC_TIMEOUT_COUNT]; /**< Store timeouts used for protocol */ |
||||
|
||||
#if (GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD == 1) |
||||
/* Parameters for recording duty-cycle */ |
||||
uint32_t last_radio_on_time_ticks; /**< The last time in ticks when radio is on */ |
||||
uint32_t radio_off_time_ticks; /**< The time in ticks when radio is off */ |
||||
uint32_t system_start_time_ticks; /**< The time in ticks when chip is started */ |
||||
uint32_t awake_duration_sum_ticks; /**< The sum of time in ticks when radio is on */ |
||||
uint32_t pkt_start_sending_time_ticks; /**< The time in ticks when the packet is started
|
||||
to be sent */ |
||||
#endif |
||||
} gnrc_lwmac_t; |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NET_GNRC_LWMAC_TYPES_H */ |
||||
/** @} */ |
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_lwmac
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Daniel Krebs |
||||
* 2016 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_lwmac |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface definition for internal functions of LWMAC protocol |
||||
* |
||||
* @author Daniel Krebs <github@daniel-krebs.net> |
||||
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr> |
||||
*/ |
||||
|
||||
#ifndef LWMAC_INTERNAL_H |
||||
#define LWMAC_INTERNAL_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "periph/rtt.h" |
||||
#include "net/gnrc/netdev.h" |
||||
#include "net/gnrc/mac/types.h" |
||||
#include "net/gnrc/lwmac/types.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Flag to track if the sender can continue to transmit packet to |
||||
* the receiver in its TX procedure. |
||||
* |
||||
* LWMAC supports burst transmission based on the pending-bit technique. |
||||
* Namely, if the sender has multi packets for the same receiver, it can |
||||
* successively transmit its packets back to back with this flag set up, |
||||
* with the awareness that the receiver will also keep awake for receptions. |
||||
*/ |
||||
#define GNRC_NETDEV_LWMAC_TX_CONTINUE (0x0008U) |
||||
|
||||
/**
|
||||
* @brief Flag to track if the sender should quit Tx in current cycle. |
||||
* |
||||
* This flag is mainly for collision avoidance. In case a node overhears |
||||
* ongoing broadcast packets stream or other ongoing transmissions of |
||||
* other communication pairs during its wake-up period, it sets up this |
||||
* flag, which quits all its potential transmission attempts in this current |
||||
* cycle (started by the wake-up period), thus not to collide with other |
||||
* (neighbor) nodes' transmissions. |
||||
*/ |
||||
#define GNRC_NETDEV_LWMAC_QUIT_TX (0x0010U) |
||||
|
||||
/**
|
||||
* @brief Flag to track if the device need to reselect a new wake-up phase. |
||||
* |
||||
* This flag is mainly for potential collision avoidance. In multi-hop scenario, |
||||
* it could be dangerous that a sender's wake-up phase is close to its receiver's, |
||||
* which may lead to collisions when the sender is sending to the receiver while |
||||
* the sender's son nodes are also sending to the sender. To avoid this, in case a |
||||
* sender finds its phase close to its receiver's, it sets up this flag and then |
||||
* randomly reselects a new wake-up phase. |
||||
*/ |
||||
#define GNRC_NETDEV_LWMAC_PHASE_BACKOFF (0x0020U) |
||||
|
||||
/**
|
||||