Browse Source

LWMAC: a simple duty cycling 802.15.4 MAC protocol.

master
zhuoshuguo 6 years ago
parent
commit
a54655890e
  1. 6
      Makefile.dep
  2. 9
      sys/auto_init/netif/auto_init_at86rf2xx.c
  3. 115
      sys/include/net/gnrc/lwmac/hdr.h
  4. 324
      sys/include/net/gnrc/lwmac/lwmac.h
  5. 102
      sys/include/net/gnrc/lwmac/timeout.h
  6. 223
      sys/include/net/gnrc/lwmac/types.h
  7. 16
      sys/include/net/gnrc/mac/types.h
  8. 8
      sys/include/net/gnrc/netdev.h
  9. 11
      sys/include/net/gnrc/nettype.h
  10. 3
      sys/net/gnrc/Makefile
  11. 11
      sys/net/gnrc/link_layer/gnrc_mac/internal.c
  12. 3
      sys/net/gnrc/link_layer/lwmac/Makefile
  13. 370
      sys/net/gnrc/link_layer/lwmac/include/lwmac_internal.h
  14. 60
      sys/net/gnrc/link_layer/lwmac/include/rx_state_machine.h
  15. 65
      sys/net/gnrc/link_layer/lwmac/include/tx_state_machine.h
  16. 920
      sys/net/gnrc/link_layer/lwmac/lwmac.c
  17. 192
      sys/net/gnrc/link_layer/lwmac/lwmac_internal.c
  18. 437
      sys/net/gnrc/link_layer/lwmac/rx_state_machine.c
  19. 148
      sys/net/gnrc/link_layer/lwmac/timeout.c
  20. 810
      sys/net/gnrc/link_layer/lwmac/tx_state_machine.c

6
Makefile.dep

@ -524,6 +524,12 @@ ifneq (,$(filter netstats_%, $(USEMODULE)))
USEMODULE += netstats
endif
ifneq (,$(filter gnrc_lwmac,$(USEMODULE)))
USEMODULE += gnrc_mac
USEMODULE += gnrc_netdev
FEATURES_REQUIRED += periph_rtt
endif
ifneq (,$(filter pthread,$(USEMODULE)))
USEMODULE += xtimer
USEMODULE += timex

9
sys/auto_init/netif/auto_init_at86rf2xx.c

@ -23,6 +23,7 @@
#include "board.h"
#include "net/gnrc/netdev.h"
#include "net/gnrc/netdev/ieee802154.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "net/gnrc.h"
#include "at86rf2xx.h"
@ -58,11 +59,19 @@ void auto_init_at86rf2xx(void)
LOG_ERROR("[auto_init_netif] error initializing at86rf2xx radio #%u\n", i);
}
else {
#ifdef MODULE_GNRC_LWMAC
gnrc_lwmac_init(_at86rf2xx_stacks[i],
AT86RF2XX_MAC_STACKSIZE,
AT86RF2XX_MAC_PRIO,
"at86rf2xx-lwmac",
&gnrc_adpt[i]);
#else
gnrc_netdev_init(_at86rf2xx_stacks[i],
AT86RF2XX_MAC_STACKSIZE,
AT86RF2XX_MAC_PRIO,
"at86rf2xx",
&gnrc_adpt[i]);
#endif
}
}
}

115
sys/include/net/gnrc/lwmac/hdr.h

@ -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 */
/** @} */

324
sys/include/net/gnrc/lwmac/lwmac.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 */
/** @} */

102
sys/include/net/gnrc/lwmac/timeout.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 */
/** @} */

223
sys/include/net/gnrc/lwmac/types.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 */
/** @} */

16
sys/include/net/gnrc/mac/types.h

@ -29,6 +29,7 @@
#include "net/gnrc/priority_pktqueue.h"
#include "net/ieee802154.h"
#include "net/gnrc/mac/mac.h"
#include "net/gnrc/lwmac/types.h"
#ifdef __cplusplus
extern "C" {
@ -66,6 +67,12 @@ typedef struct {
#if (GNRC_MAC_DISPATCH_BUFFER_SIZE != 0) || defined(DOXYGEN)
gnrc_pktsnip_t *dispatch_buffer[GNRC_MAC_DISPATCH_BUFFER_SIZE]; /**< dispatch packet buffer */
#endif /* (GNRC_MAC_DISPATCH_BUFFER_SIZE != 0) || defined(DOXYGEN) */
#ifdef MODULE_GNRC_LWMAC
gnrc_lwmac_l2_addr_t l2_addr; /**< Records the sender's address */
gnrc_lwmac_rx_state_t state; /**< LWMAC specific internal reception state */
uint8_t rx_bad_exten_count; /**< Count how many unnecessary RX extensions have been executed */
#endif
} gnrc_mac_rx_t;
/**
@ -157,6 +164,15 @@ typedef struct {
gnrc_priority_pktqueue_node_t _queue_nodes[GNRC_MAC_TX_QUEUE_SIZE]; /**< Shared buffer for TX queue nodes */
gnrc_pktsnip_t *packet; /**< currently scheduled packet for sending */
#endif /* (GNRC_MAC_TX_QUEUE_SIZE != 0) || defined(DOXYGEN) */
#ifdef MODULE_GNRC_LWMAC
gnrc_lwmac_tx_state_t state; /**< LWMAC specific internal transmission state */
uint32_t wr_sent; /**< Count how many WRs were sent until WA received */
uint32_t timestamp; /**< Records the receiver's current phase */
uint8_t bcast_seqnr; /**< Sequence number for broadcast data to filter at receiver */
uint8_t tx_burst_count; /**< Count how many consecutive packets have been transmitted */
uint8_t tx_retry_count; /**< Count how many Tx-retrials have been executed before packet drop */
#endif
} gnrc_mac_tx_t;
/**

8
sys/include/net/gnrc/netdev.h

@ -152,6 +152,14 @@ typedef struct gnrc_netdev {
*/
gnrc_mac_tx_t tx;
#endif /* ((GNRC_MAC_TX_QUEUE_SIZE != 0) || (GNRC_MAC_NEIGHBOR_COUNT == 0)) || defined(DOXYGEN) */
#ifdef MODULE_GNRC_LWMAC
/**
* @brief LWMAC specific structure object for storing LWMAC internal states.
*/
gnrc_lwmac_t lwmac;
#endif
#endif /* MODULE_GNRC_MAC */
} gnrc_netdev_t;

11
sys/include/net/gnrc/nettype.h

@ -56,6 +56,17 @@ typedef enum {
GNRC_NETTYPE_SIXLOWPAN, /**< Protocol is 6LoWPAN */
#endif
/**
* @{
* @name Link layer
*/
#ifdef MODULE_GNRC_LWMAC
GNRC_NETTYPE_LWMAC, /**< Protocol is lwMAC */
#endif
/**
* @}
*/
/**
* @{
* @name Network layer

3
sys/net/gnrc/Makefile

@ -67,6 +67,9 @@ endif
ifneq (,$(filter gnrc_pkt,$(USEMODULE)))
DIRS += pkt
endif
ifneq (,$(filter gnrc_lwmac,$(USEMODULE)))
DIRS += link_layer/lwmac
endif
ifneq (,$(filter gnrc_pktbuf_static,$(USEMODULE)))
DIRS += pktbuf_static
endif

11
sys/net/gnrc/link_layer/gnrc_mac/internal.c

@ -241,6 +241,17 @@ void gnrc_mac_dispatch(gnrc_mac_rx_t *rx)
for (unsigned i = 0; i < GNRC_MAC_DISPATCH_BUFFER_SIZE; i++) {
if (rx->dispatch_buffer[i]) {
#ifdef MODULE_GNRC_LWMAC
/* save pointer to netif header */
gnrc_pktsnip_t *netif = rx->dispatch_buffer[i]->next->next;
/* remove lwmac header */
rx->dispatch_buffer[i]->next->next = NULL;
gnrc_pktbuf_release(rx->dispatch_buffer[i]->next);
/* make append netif header after payload again */
rx->dispatch_buffer[i]->next = netif;
#endif
if (!gnrc_netapi_dispatch_receive(rx->dispatch_buffer[i]->type,
GNRC_NETREG_DEMUX_CTX_ALL,
rx->dispatch_buffer[i])) {

3
sys/net/gnrc/link_layer/lwmac/Makefile

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

370
sys/net/gnrc/link_layer/lwmac/include/lwmac_internal.h

@ -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)
/**
* @brief Flag to track if the device needs to quit the wake-up (listening) procedure.
*
* LWMAC adopts an auto wake-up extension scheme. That is, normally, after each data
* reception in the wake-up period, it extends the wake-up period to another basic
* duration, thus to receive more potential incoming packets, which is also correlated to
* the pending-bit transmission scheme to support burst transmissions to boost throughput.
* However, in some situations, like receiving broadcast (stream) packet, the receiver
* should immediately goto sleep (by setting up this flag) after one reception, thus not
* to receive duplicate broadcast packets.
*/
#define GNRC_NETDEV_LWMAC_QUIT_RX (0x0040U)
/**
* @brief Type to pass information about parsing.
*/
typedef struct {
gnrc_lwmac_hdr_t *header; /**< LWMAC header of packet */
gnrc_lwmac_l2_addr_t src_addr; /**< copied source address of packet */
gnrc_lwmac_l2_addr_t dst_addr; /**< copied destination address of packet */
} gnrc_lwmac_packet_info_t;
/**
* @brief Next RTT event must be at least this far in the future.
*
* When setting an RTT alarm to short in the future it could be possible that
* the counter already passed the calculated alarm before it could be set.
*/
#define GNRC_LWMAC_RTT_EVENT_MARGIN_TICKS (RTT_MS_TO_TICKS(2))
/**
* @brief set the TX-continue flag of the device
*
* @param[in] dev ptr to netdev device
* @param[in] tx_continue value for LWMAC tx-continue flag
*
*/
static inline void gnrc_netdev_lwmac_set_tx_continue(gnrc_netdev_t *dev, bool tx_continue)
{
if (tx_continue) {
dev->mac_info |= GNRC_NETDEV_LWMAC_TX_CONTINUE;
}
else {
dev->mac_info &= ~GNRC_NETDEV_LWMAC_TX_CONTINUE;
}
}
/**
* @brief get the TX-continue flag of the device
*
* @param[in] dev ptr to netdev device
*
* @return true if tx continue
* @return false if tx will continue
*/
static inline bool gnrc_netdev_lwmac_get_tx_continue(gnrc_netdev_t *dev)
{
return (dev->mac_info & GNRC_NETDEV_LWMAC_TX_CONTINUE);
}
/**
* @brief set the quit-TX flag of the device
*
* @param[in] dev ptr to netdev device
* @param[in] quit_tx value for LWMAC quit-TX flag
*
*/
static inline void gnrc_netdev_lwmac_set_quit_tx(gnrc_netdev_t *dev, bool quit_tx)
{
if (quit_tx) {
dev->mac_info |= GNRC_NETDEV_LWMAC_QUIT_TX;
}
else {
dev->mac_info &= ~GNRC_NETDEV_LWMAC_QUIT_TX;
}
}
/**
* @brief get the quit-TX flag of the device
*
* @param[in] dev ptr to netdev device
*
* @return true if quit tx
* @return false if will not quit tx
*/
static inline bool gnrc_netdev_lwmac_get_quit_tx(gnrc_netdev_t *dev)
{
return (dev->mac_info & GNRC_NETDEV_LWMAC_QUIT_TX);
}
/**
* @brief set the phase-backoff flag of the device
*
* @param[in] dev ptr to netdev device
* @param[in] backoff value for LWMAC phase-backoff flag
*
*/
static inline void gnrc_netdev_lwmac_set_phase_backoff(gnrc_netdev_t *dev, bool backoff)
{
if (backoff) {
dev->mac_info |= GNRC_NETDEV_LWMAC_PHASE_BACKOFF;
}
else {
dev->mac_info &= ~GNRC_NETDEV_LWMAC_PHASE_BACKOFF;
}
}
/**
* @brief get the phase-backoff of the device
*
* @param[in] dev ptr to netdev device
*
* @return true if will run phase-backoff
* @return false if will not run phase-backoff
*/
static inline bool gnrc_netdev_lwmac_get_phase_backoff(gnrc_netdev_t *dev)
{
return (dev->mac_info & GNRC_NETDEV_LWMAC_PHASE_BACKOFF);
}
/**
* @brief set the quit-RX flag of the device
*
* @param[in] dev ptr to netdev device
* @param[in] quit_rx value for LWMAC quit-Rx flag
*
*/
static inline void gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev_t *dev, bool quit_rx)
{
if (quit_rx) {
dev->mac_info |= GNRC_NETDEV_LWMAC_QUIT_RX;
}
else {
dev->mac_info &= ~GNRC_NETDEV_LWMAC_QUIT_RX;
}
}
/**
* @brief get the quit-RX flag of the device
*
* @param[in] dev ptr to netdev device
*
* @return true if will quit rx
* @return false if will not quit rx
*/
static inline bool gnrc_netdev_lwmac_get_quit_rx(gnrc_netdev_t *dev)
{
return (dev->mac_info & GNRC_NETDEV_LWMAC_QUIT_RX);
}
/**
* @brief set the duty-cycle-active flag of LWMAC
*
* @param[in] dev ptr to netdev device
* @param[in] active value for LWMAC duty-cycle-active flag
*
*/
static inline void gnrc_netdev_lwmac_set_dutycycle_active(gnrc_netdev_t *dev, bool active)
{
if (active) {
dev->lwmac.lwmac_info |= GNRC_LWMAC_DUTYCYCLE_ACTIVE;
}
else {
dev->lwmac.lwmac_info &= ~GNRC_LWMAC_DUTYCYCLE_ACTIVE;
}
}
/**
* @brief get the duty-cycle-active flag of LWMAC
*
* @param[in] dev ptr to netdev device
*
* @return true if active
* @return false if not active
*/
static inline bool gnrc_netdev_lwmac_get_dutycycle_active(gnrc_netdev_t *dev)
{
return (dev->lwmac.lwmac_info & GNRC_LWMAC_DUTYCYCLE_ACTIVE);
}
/**
* @brief set the needs-rescheduling flag of LWMAC
*
* @param[in] dev ptr to netdev device
* @param[in] reschedule value for LWMAC needs-rescheduling flag
*
*/
static inline void gnrc_netdev_lwmac_set_reschedule(gnrc_netdev_t *dev, bool reschedule)
{
if (reschedule) {
dev->lwmac.lwmac_info |= GNRC_LWMAC_NEEDS_RESCHEDULE;
}
else {
dev->lwmac.lwmac_info &= ~GNRC_LWMAC_NEEDS_RESCHEDULE;
}
}
/**
* @brief get the needs-rescheduling flag of LWMAC
*
* @param[in] dev ptr to netdev device
*
* @return true if needs rescheduling
* @return false if no need for rescheduling
*/
static inline bool gnrc_netdev_lwmac_get_reschedule(gnrc_netdev_t *dev)
{
return (dev->lwmac.lwmac_info & GNRC_LWMAC_NEEDS_RESCHEDULE);
}
/**
* @brief Parse an incoming packet and extract important information.
*
* Copies addresses into @p info, but header points inside @p pkt.
*
* @param[in] pkt packet that will be parsed
* @param[out] info structure that will hold parsed information
*
* @return 0 if correctly parsed
* @return <0 on error
*/
int _gnrc_lwmac_parse_packet(gnrc_pktsnip_t *pkt, gnrc_lwmac_packet_info_t *info);
/**
* @brief Shortcut to get the state of netdev.
*
* @param[in] gnrc_netdev gnrc_netdev structure
*
* @return state of netdev
*/
netopt_state_t _gnrc_lwmac_get_netdev_state(gnrc_netdev_t *gnrc_netdev);
/**
* @brief Shortcut to set the state of netdev
*
* @param[in] gnrc_netdev gnrc_netdev structure
* @param[in] devstate new state for netdev
*/
void _gnrc_lwmac_set_netdev_state(gnrc_netdev_t *gnrc_netdev, netopt_state_t devstate);
/**
* @brief Convert RTT ticks to device phase
*
* @param[in] ticks RTT ticks
*
* @return device phase
*/
static inline uint32_t _gnrc_lwmac_ticks_to_phase(uint32_t ticks)
{
assert(GNRC_LWMAC_WAKEUP_INTERVAL_US != 0);
return (ticks % RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US));
}
/**
* @brief Get device's current phase
*
* @return device phase
*/
static inline uint32_t _gnrc_lwmac_phase_now(void)
{
return _gnrc_lwmac_ticks_to_phase(rtt_get_counter());
}
/**
* @brief Calculate how many ticks remaining to the targeted phase in the future
*
* @param[in] phase device phase
*
* @return RTT ticks
*/
static inline uint32_t _gnrc_lwmac_ticks_until_phase(uint32_t phase)
{
long int tmp = phase - _gnrc_lwmac_phase_now();
if (tmp < 0) {
/* Phase in next interval */
tmp += RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US);
}
return (uint32_t)tmp;
}
/**
* @brief Store the received packet to the dispatch buffer and remove possible
* duplicate packets.
*
* @param[in,out] buffer RX dispatch packet buffer
* @param[in] pkt received packet
*
* @return 0 if correctly stored
* @return <0 on error
*/
int _gnrc_lwmac_dispatch_defer(gnrc_pktsnip_t * buffer[], gnrc_pktsnip_t * pkt);
#ifdef __cplusplus
}
#endif
#endif /* LWMAC_INTERNAL_H */
/** @} */

60
sys/net/gnrc/link_layer/lwmac/include/rx_state_machine.h

@ -0,0 +1,60 @@
/*
* 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 Implementation of RX state machine
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#ifndef RX_STATE_MACHINE_H
#define RX_STATE_MACHINE_H
#include "net/gnrc/pkt.h"
#include "net/gnrc/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Start LWMAC RX procedure to receive packet
*
* @param[in,out] gnrc_netdev gnrc_netdev structure
*
*/
void gnrc_lwmac_rx_start(gnrc_netdev_t *gnrc_netdev);
/**
* @brief Stop LWMAC RX procedure
*
* @param[in,out] gnrc_netdev gnrc_netdev structure
*
*/
void gnrc_lwmac_rx_stop(gnrc_netdev_t *gnrc_netdev);
/**
* @brief Update LWMAC RX procedure for packet reception
*
* @param[in,out] gnrc_netdev gnrc_netdev structure
*
*/
void gnrc_lwmac_rx_update(gnrc_netdev_t *gnrc_netdev);
#ifdef __cplusplus
}
#endif
#endif /* RX_STATE_MACHINE_H */

65
sys/net/gnrc/link_layer/lwmac/include/tx_state_machine.h

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015 Daniel Krebs