1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-30 08:51:19 +01:00

Merge pull request #21603 from Teufelchen1/deprecate/lwmac

net/lwmac: Remove deprecated lwmac module
This commit is contained in:
Teufelchen 2025-07-18 08:34:57 +00:00 committed by GitHub
commit 1345452bbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 2 additions and 4340 deletions

View File

@ -1,7 +1,5 @@
# Add deprecated modules here
# Keep this list ALPHABETICALLY SORTED!!!!111elven
DEPRECATED_MODULES += gnrc_lwmac
DEPRECATED_MODULES += gnrc_mac
DEPRECATED_MODULES += gnrc_nettype_lorawan
DEPRECATED_MODULES += gnrc_nettype_lwmac
DEPRECATED_MODULES += sema_deprecated

View File

@ -172,12 +172,6 @@ PSEUDOMODULES += gnrc_nettype_ipv6_ext
PSEUDOMODULES += gnrc_nettype_lorawan
## @}
## @defgroup net_gnrc_nettype_lwmac gnrc_nettype_lwmac
## Enables @ref GNRC_NETTYPE_LWMAC
## @{
PSEUDOMODULES += gnrc_nettype_lwmac
## @}
## @defgroup net_gnrc_nettype_ndn gnrc_nettype_ndn
## Enables @ref GNRC_NETTYPE_NDN
## @{

View File

@ -1,113 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @ingroup net_gnrc_lwmac
* @{
*
* @file
* @brief Header definition LWMAC
* @internal
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
*/
#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
/** @} */

View File

@ -1,353 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @defgroup net_gnrc_lwmac LWMAC
* @ingroup net_gnrc
* @brief A Lightweight duty-cycling 802.15.4 MAC protocol
* @deprecated This module is deprecated and will be removed after the 2024.10 release.
* As an alternative MAC layer for IEEE 802.15.4, you can use @ref pkg_opendsme.
*
*
* ## 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 CONFIG_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>
*/
#include "net/gnrc/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup net_gnrc_lwmac_conf GNRC LWMAC compile configurations
* @ingroup net_gnrc_conf
* @{
*/
/**
* @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 CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US
#define CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US (200LU *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 CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US.
*/
#ifndef GNRC_LWMAC_PREAMBLE_DURATION_US
#define GNRC_LWMAC_PREAMBLE_DURATION_US ((13LU * CONFIG_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 CONFIG_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 CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US. If no WA is received
* during @ref CONFIG_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 CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US
#define CONFIG_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 CONFIG_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 (CONFIG_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 CONFIG_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 ((CONFIG_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 CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US apply
* here. In LWMAC, when a sender initiates a broadcast, it starts with sending
* a stream ofrepeated 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 (CONFIG_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 CONFIG_GNRC_LWMAC_WR_PREPARATION_US
#define CONFIG_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 CONFIG_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 CONFIG_GNRC_LWMAC_DATA_DELAY_US
#define CONFIG_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 CONFIG_GNRC_LWMAC_DATA_CSMA_RETRIES
#define CONFIG_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 CONFIG_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 CONFIG_GNRC_LWMAC_MAX_DATA_TX_RETRIES
#define CONFIG_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 follows:
*
* 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 CONFIG_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 \
(CONFIG_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 CONFIG_GNRC_LWMAC_MAX_RX_EXTENSION_NUM
#define CONFIG_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.
*
* @note Too many CSMA retries may lead to running out of destinations
* wake-up period.
*/
#ifndef CONFIG_GNRC_LWMAC_BROADCAST_CSMA_RETRIES
#define CONFIG_GNRC_LWMAC_BROADCAST_CSMA_RETRIES (3U)
#endif
/** @} */
/**
* @brief Maximum preamble attempts before re-initialize radio in LWMAC.
*
* After a long period of run time, a radio may be in wrong condition which needs to be
* re-calibrated. This is indicated by having a series of continuous preamble failure (no WA)
* in LWMAC. In case we have @ref CONFIG_GNRC_LWMAC_RADIO_REINIT_THRESHOLD number of preamble
* failure, then we re-initialize the radio, trying to re-calibrate the radio for bringing it
* back to normal condition.
*/
#ifndef CONFIG_GNRC_LWMAC_RADIO_REINIT_THRESHOLD
#define CONFIG_GNRC_LWMAC_RADIO_REINIT_THRESHOLD (10U)
#endif
/**
* @brief Creates an IEEE 802.15.4 LWMAC network interface
*
* @param[out] netif The interface. May not be `NULL`.
* @param[in] stack The stack for the LWMAC network interface's thread.
* @param[in] stacksize Size of @p stack.
* @param[in] priority Priority for the LWMAC network interface's thread.
* @param[in] name Name for the LWMAC network interface. May be NULL.
* @param[in] dev Device for the interface
*
* @see @ref gnrc_netif_create()
*
* @return 0 on success
* @return negative number on error
*/
int gnrc_netif_lwmac_create(gnrc_netif_t *netif, char *stack, int stacksize,
char priority, const char *name, netdev_t *dev);
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -1,100 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @ingroup net_gnrc_lwmac
* @{
*
* @file
* @brief Timeout handling of LWMAC
*
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
*/
#include <stdint.h>
#include <stdbool.h>
#include "net/gnrc/netif.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] netif the network interface
* @param[in] type LWMAC timeout type
* @param[in] offset timeout offset
*/
void gnrc_lwmac_set_timeout(gnrc_netif_t *netif,
gnrc_lwmac_timeout_type_t type,
uint32_t offset);
/**
* @brief Clear LWMAC timeout of type @p type.
*
* @param[in,out] netif the network interface
* @param[in] type LWMAC timeout type
*/
void gnrc_lwmac_clear_timeout(gnrc_netif_t *netif, gnrc_lwmac_timeout_type_t type);
/**
* @brief Check whether LWMAC timeout of type @p type is running.
*
* @param[in] netif the network interface
* @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_netif_t *netif,
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] netif the network interface
* @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_netif_t *netif, gnrc_lwmac_timeout_type_t type);
/**
* @brief Reset all LWMAC timeouts.
*
* @param[in,out] netif the network interface
*/
void gnrc_lwmac_reset_timeouts(gnrc_netif_t *netif);
/**
* @brief Make a specific LWMAC timeout expired.
*
* @param[in,out] timeout LWMAC timeout
*/
void gnrc_lwmac_timeout_make_expire(gnrc_lwmac_timeout_t *timeout);
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -1,218 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @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>
*/
#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)
/**
* @ingroup net_gnrc_lwmac_conf
* @{
*/
/**
* @brief The default largest number of parallel timeouts in LWMAC
*/
#ifndef CONFIG_GNRC_LWMAC_TIMEOUT_COUNT
#define CONFIG_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 disabled */
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 information (flags) */
gnrc_lwmac_timeout_t timeouts[CONFIG_GNRC_LWMAC_TIMEOUT_COUNT]; /**< Store timeouts used for protocol */
#if (GNRC_MAC_ENABLE_DUTYCYCLE_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
/** @} */

View File

@ -27,9 +27,6 @@
#include "net/gnrc/priority_pktqueue.h"
#include "net/ieee802154.h"
#include "net/gnrc/mac/mac.h"
#ifdef MODULE_GNRC_LWMAC
#include "net/gnrc/lwmac/types.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -72,12 +69,6 @@ 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;
/**
@ -169,16 +160,6 @@ 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 */
uint8_t preamble_fail_counts; /**< Preamble trial failure count. */
#endif
} gnrc_mac_tx_t;
/**

View File

@ -45,20 +45,6 @@ extern "C" {
*/
#define GNRC_NETIF_MAC_INFO_CSMA_ENABLED (0x0100U)
#if defined(MODULE_GNRC_LWMAC)
/**
* @brief Data type to hold MAC protocols
*/
typedef union {
#ifdef MODULE_GNRC_LWMAC
/**
* @brief LWMAC specific structure object for storing LWMAC internal states.
*/
gnrc_lwmac_t lwmac;
#endif
} gnrc_mac_prot_t;
#endif
/**
* @brief @ref net_gnrc_mac component of @ref gnrc_netif_mac_t
*/
@ -93,10 +79,6 @@ typedef struct {
*/
gnrc_mac_tx_t tx;
#endif /* ((GNRC_MAC_TX_QUEUE_SIZE != 0) || (CONFIG_GNRC_MAC_NEIGHBOR_COUNT == 0)) || DOXYGEN */
#if defined(MODULE_GNRC_LWMAC)
gnrc_mac_prot_t prot;
#endif
} gnrc_netif_mac_t;
#ifdef __cplusplus

View File

@ -65,14 +65,6 @@ typedef enum {
* @{
* @name Link layer
*/
#if IS_USED(MODULE_GNRC_NETTYPE_LWMAC) || defined(DOXYGEN)
/**
* @brief Protocol is lwMAC
* @deprecated @ref net_gnrc_lwmac was deprecated and will be removed after
* the 2024.10 release together with this protocol type.
*/
GNRC_NETTYPE_LWMAC,
#endif
#if IS_USED(MODULE_GNRC_NETTYPE_CUSTOM) || defined(DOXYGEN)
GNRC_NETTYPE_CUSTOM, /**< Custom ethertype */
#endif

View File

@ -9,7 +9,6 @@ menu "GNRC Network stack"
rsource "application_layer/dhcpv6/Kconfig"
rsource "link_layer/lorawan/Kconfig"
rsource "link_layer/lwmac/Kconfig"
rsource "link_layer/mac/Kconfig"
rsource "netif/Kconfig"
rsource "network_layer/ipv6/Kconfig"

View File

@ -55,9 +55,6 @@ endif
ifneq (,$(filter gnrc_pkt,$(USEMODULE)))
DIRS += pkt
endif
ifneq (,$(filter gnrc_lwmac,$(USEMODULE)))
DIRS += link_layer/lwmac
endif
ifneq (,$(filter gnrc_pktbuf_malloc,$(USEMODULE)))
DIRS += pktbuf_malloc
endif

View File

@ -499,11 +499,3 @@ endif
ifneq (,$(filter gnrc_netif_pktq,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter gnrc_lwmac,$(USEMODULE)))
USEMODULE += gnrc_netif
USEMODULE += gnrc_nettype_lwmac
USEMODULE += gnrc_mac
USEMODULE += xtimer
FEATURES_REQUIRED += periph_rtt
endif

View File

@ -1,150 +0,0 @@
# Copyright (c) 2020 Freie Universitaet 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.
#
menu "GNRC LWMAC"
depends on USEMODULE_GNRC_LWMAC
config GNRC_LWMAC_WAKEUP_INTERVAL_US
int "Time between consecutive wake-ups in microseconds"
default 200000
help
Configure 'CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US', time between
consecutive wake-ups in microseconds. This configuration 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
configuration 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.
config GNRC_LWMAC_TIME_BETWEEN_WR_US
int "Timeout to send the next WR in microseconds"
default 5000
help
Configure 'CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US', timeout to send the
next WR in case no WA has been received during that time in
microseconds.In LWMAC, when a sender initiates a transmission to a
receiver, it starts with sending a stream of repeated WR packets with
'CONFIG_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
'CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US'. If no WA is received during
'CONFIG_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.
config GNRC_LWMAC_WR_PREPARATION_US
int "WR preparation overhead time in microseconds"
default 3000
help
Configure 'CONFIG_GNRC_LWMAC_WR_PREPARATION_US', 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
destinations 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.
config GNRC_LWMAC_DATA_DELAY_US
int "Time to wait after a WA in microseconds"
default 10000
help
Configure 'CONFIG_GNRC_LWMAC_DATA_DELAY_US', time to wait after a WA
for data to arrive in microseconds. 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 senders transmission request. After
sending the WA, the receiver waits for the data packet from the sender,
with a timeout of 'CONFIG_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 senders 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 'NETDEV_EVENT_RX_STARTED' event (this can be
important for big packets).
config GNRC_LWMAC_DATA_CSMA_RETRIES
int "Number of CSMA retries for DATA packet after WR->WA success"
default 3
help
Configure 'CONFIG_GNRC_LWMAC_DATA_CSMA_RETRIES', number of CSMA retries
for DATA packet after WR->WA was successful. After receiving the WA
packet 'gnrc_lwmac_frame_wa_t' from the receiver, the sender starts
sending the data packet using CSMA/CA. This configuration 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).
config GNRC_LWMAC_MAX_DATA_TX_RETRIES
int "MAX number of TX retries for DATA packet"
default 3
help
Configure 'CONFIG_GNRC_LWMAC_MAX_DATA_TX_RETRIES', the maximum number
of 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
'CONFIG_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.
config GNRC_LWMAC_MAX_RX_EXTENSION_NUM
int "MAX number of bad listen period extensions"
default 3
help
Configure 'CONFIG_GNRC_LWMAC_MAX_RX_EXTENSION_NUM', the maximum
number of 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
'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.
config GNRC_LWMAC_BROADCAST_CSMA_RETRIES
int "Number of CSMA retries for broadcast packet"
default 3
help
Configure 'CONFIG_GNRC_LWMAC_BROADCAST_CSMA_RETRIES',the number of 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**.
config GNRC_LWMAC_TIMEOUT_COUNT
int "MAX number of number of parallel timeouts"
default 3
help
Configure 'CONFIG_GNRC_LWMAC_TIMEOUT_COUNT', the default value for the
maximum number of parallel timeouts in LWMAC.
config GNRC_LWMAC_RADIO_REINIT_THRESHOLD
int "Maximum preamble attempts before re-initialize radio"
default 10
help
Configure 'CONFIG_GNRC_LWMAC_RADIO_REINIT_THRESHOLD', the maximum preamble
attempts before re-initialize radio. After a long period of run time, a radio
may be in wrong condition which needs to be re-calibrated. This is indicated
by having a series of continuous preamble failure (no WA) in LWMAC. In case
we have @ref GNRC_LWMAC_RADIO_REINI_THRESHOLD number of preamble failure,
then we re-initialize the radio, trying to re-calibrate the radio for bringing
it back to normal condition.
endmenu # GNRC LWMAC

View File

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

View File

@ -1,392 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @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>
*/
#include <stdint.h>
#include "periph/rtt.h"
#include "net/gnrc/netif.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_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_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_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_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 @ref GNRC_LWMAC_TX_CONTINUE flag of the device
*
* @param[in] netif ptr to the network interface
* @param[in] tx_continue value for LWMAC tx-continue flag
*
*/
static inline void gnrc_lwmac_set_tx_continue(gnrc_netif_t *netif, bool tx_continue)
{
if (tx_continue) {
netif->mac.mac_info |= GNRC_LWMAC_TX_CONTINUE;
}
else {
netif->mac.mac_info &= ~GNRC_LWMAC_TX_CONTINUE;
}
}
/**
* @brief get the @ref GNRC_LWMAC_TX_CONTINUE flag of the device
*
* @param[in] netif ptr to the network interface
*
* @return true if tx continue
* @return false if tx will not continue
*/
static inline bool gnrc_lwmac_get_tx_continue(gnrc_netif_t *netif)
{
return (netif->mac.mac_info & GNRC_LWMAC_TX_CONTINUE);
}
/**
* @brief set the @ref GNRC_LWMAC_QUIT_TX flag of the device
*
* @param[in] netif ptr to the network interface
* @param[in] quit_tx value for @ref GNRC_LWMAC_QUIT_TX flag
*
*/
static inline void gnrc_lwmac_set_quit_tx(gnrc_netif_t *netif, bool quit_tx)
{
if (quit_tx) {
netif->mac.mac_info |= GNRC_LWMAC_QUIT_TX;
}
else {
netif->mac.mac_info &= ~GNRC_LWMAC_QUIT_TX;
}
}
/**
* @brief get the @ref GNRC_LWMAC_QUIT_TX flag of the device
*
* @param[in] netif ptr to the network interface
*
* @return true if quit tx
* @return false if will not quit tx
*/
static inline bool gnrc_lwmac_get_quit_tx(gnrc_netif_t *netif)
{
return (netif->mac.mac_info & GNRC_LWMAC_QUIT_TX);
}
/**
* @brief set the @ref GNRC_LWMAC_PHASE_BACKOFF flag of the device
*
* @param[in] netif ptr to the network interface
* @param[in] backoff value for LWMAC @ref GNRC_LWMAC_PHASE_BACKOFF flag
*
*/
static inline void gnrc_lwmac_set_phase_backoff(gnrc_netif_t *netif, bool backoff)
{
if (backoff) {
netif->mac.mac_info |= GNRC_LWMAC_PHASE_BACKOFF;
}
else {
netif->mac.mac_info &= ~GNRC_LWMAC_PHASE_BACKOFF;
}
}
/**
* @brief get the @ref GNRC_LWMAC_PHASE_BACKOFF flag of the device
*
* @param[in] netif ptr to the network interface
*
* @return true if will run phase-backoff
* @return false if will not run phase-backoff
*/
static inline bool gnrc_lwmac_get_phase_backoff(gnrc_netif_t *netif)
{
return (netif->mac.mac_info & GNRC_LWMAC_PHASE_BACKOFF);
}
/**
* @brief set the @ref GNRC_LWMAC_QUIT_RX flag of the device
*
* @param[in] netif ptr to the network interface
* @param[in] quit_rx value for LWMAC @ref GNRC_LWMAC_QUIT_RX flag
*
*/
static inline void gnrc_lwmac_set_quit_rx(gnrc_netif_t *netif, bool quit_rx)
{
if (quit_rx) {
netif->mac.mac_info |= GNRC_LWMAC_QUIT_RX;
}
else {
netif->mac.mac_info &= ~GNRC_LWMAC_QUIT_RX;
}
}
/**
* @brief get the @ref GNRC_LWMAC_QUIT_RX flag of the device
*
* @param[in] netif ptr to the network interface
*
* @return true if will quit rx
* @return false if will not quit rx
*/
static inline bool gnrc_lwmac_get_quit_rx(gnrc_netif_t *netif)
{
return (netif->mac.mac_info & GNRC_LWMAC_QUIT_RX);
}
/**
* @brief set the @ref GNRC_LWMAC_DUTYCYCLE_ACTIVE flag of LWMAC
*
* @param[in] netif ptr to the network interface
* @param[in] active value for LWMAC @ref GNRC_LWMAC_DUTYCYCLE_ACTIVE flag
*
*/
static inline void gnrc_lwmac_set_dutycycle_active(gnrc_netif_t *netif, bool active)
{
if (active) {
netif->mac.prot.lwmac.lwmac_info |= GNRC_LWMAC_DUTYCYCLE_ACTIVE;
}
else {
netif->mac.prot.lwmac.lwmac_info &= ~GNRC_LWMAC_DUTYCYCLE_ACTIVE;
}
}
/**
* @brief get the @ref GNRC_LWMAC_DUTYCYCLE_ACTIVE flag of LWMAC
*
* @param[in] netif ptr to the network interface
*
* @return true if active
* @return false if not active
*/
static inline bool gnrc_lwmac_get_dutycycle_active(gnrc_netif_t *netif)
{
return (netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_DUTYCYCLE_ACTIVE);
}
/**
* @brief set the @ref GNRC_LWMAC_NEEDS_RESCHEDULE flag of LWMAC
*
* @param[in] netif ptr to the network interface
* @param[in] reschedule value for @ref GNRC_LWMAC_NEEDS_RESCHEDULE flag
*
*/
static inline void gnrc_lwmac_set_reschedule(gnrc_netif_t *netif, bool reschedule)
{
if (reschedule) {
netif->mac.prot.lwmac.lwmac_info |= GNRC_LWMAC_NEEDS_RESCHEDULE;
}
else {
netif->mac.prot.lwmac.lwmac_info &= ~GNRC_LWMAC_NEEDS_RESCHEDULE;
}
}
/**
* @brief get the @ref GNRC_LWMAC_NEEDS_RESCHEDULE flag of LWMAC
*
* @param[in] netif ptr to the network interface
*
* @return true if needs rescheduling
* @return false if no need for rescheduling
*/
static inline bool gnrc_lwmac_get_reschedule(gnrc_netif_t *netif)
{
return (netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_NEEDS_RESCHEDULE);
}
/**
* @brief send a @ref net_gnrc_pkt "packet" over the network interface in LWMAC
*
* @internal
*
* @pre `netif != NULL && pkt != NULL`
*
* @note The function re-formats the content of @p pkt to a format expected
* by the netdev_driver_t::send() method of gnrc_netif_t::dev and
* releases the packet before returning (so no additional release
* should be required after calling this method).
*
* @param[in] netif The network interface.
* @param[in] pkt A packet to send.
*
* @return The number of bytes actually sent on success
* @return -EBADMSG, if the @ref net_gnrc_netif_hdr in @p pkt is missing
* or is in an unexpected format.
* @return -ENOTSUP, if sending @p pkt in the given format isn't supported
* (e.g. empty payload with Ethernet).
* @return Any negative error code reported by gnrc_netif_t::dev.
*/
int _gnrc_lwmac_transmit(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
/**
* @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] netif ptr to the network interface
*
* @return state of netdev
*/
netopt_state_t _gnrc_lwmac_get_netdev_state(gnrc_netif_t *netif);
/**
* @brief Shortcut to set the state of netdev
*
* @param[in] netif ptr to the network interface
* @param[in] devstate new state for netdev
*/
void _gnrc_lwmac_set_netdev_state(gnrc_netif_t *netif, 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(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US != 0);
return (ticks % RTT_US_TO_TICKS(CONFIG_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(CONFIG_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
/** @} */

View File

@ -1,57 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @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>
* @}
*/
#include "net/gnrc/pkt.h"
#include "net/gnrc/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Start LWMAC RX procedure to receive packet
*
* @param[in,out] netif ptr to the network interface
*
*/
void gnrc_lwmac_rx_start(gnrc_netif_t *netif);
/**
* @brief Stop LWMAC RX procedure
*
* @param[in,out] netif ptr to the network interface
*
*/
void gnrc_lwmac_rx_stop(gnrc_netif_t *netif);
/**
* @brief Update LWMAC RX procedure for packet reception
*
* @param[in,out] netif ptr to the network interface
*
*/
void gnrc_lwmac_rx_update(gnrc_netif_t *netif);
#ifdef __cplusplus
}
#endif

View File

@ -1,62 +0,0 @@
/*
* 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.
*/
#pragma once
/**
* @ingroup net_gnrc_lwmac
* @{
*
* @file
* @brief Implementation of TX state machine
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include "net/gnrc/pkt.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/mac/types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Start LWMAC TX procedure to transmit packet @p pkt to @p neighbor
*
* @param[in,out] netif ptr to the network interface
* @param[in] pkt packet to transmit
* @param[in] neighbor Tx neighbor
*
*/
void gnrc_lwmac_tx_start(gnrc_netif_t *netif,
gnrc_pktsnip_t *pkt,
gnrc_mac_tx_neighbor_t *neighbor);
/**
* @brief Stop LWMAC TX procedure
*
* @param[in,out] netif ptr to the network interface
*
*/
void gnrc_lwmac_tx_stop(gnrc_netif_t *netif);
/**
* @brief Update LWMAC TX procedure for transmission
*
* @param[in,out] netif ptr to the network interface
*
*/
void gnrc_lwmac_tx_update(gnrc_netif_t *netif);
#ifdef __cplusplus
}
#endif

View File

@ -1,970 +0,0 @@
/*
* 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 the LWMAC protocol
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "event.h"
#include "od.h"
#include "timex.h"
#include "random.h"
#include "periph/rtt.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netif/hdr.h"
#include "net/gnrc/netif/internal.h"
#include "net/gnrc/netif/ieee802154.h"
#include "net/netdev/ieee802154.h"
#include "net/gnrc/lwmac/types.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "net/gnrc/mac/internal.h"
#include "net/gnrc/lwmac/timeout.h"
#include "include/tx_state_machine.h"
#include "include/rx_state_machine.h"
#include "include/lwmac_internal.h"
#ifndef LOG_LEVEL
/**
* @brief Default log level define
*/
#define LOG_LEVEL LOG_WARNING
#endif
#include "log.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief LWMAC thread's PID
*/
kernel_pid_t lwmac_pid;
static void rtt_cb(void *arg);
static void lwmac_set_state(gnrc_netif_t *netif, gnrc_lwmac_state_t newstate);
static void lwmac_schedule_update(gnrc_netif_t *netif);
static void rtt_handler(uint32_t event, gnrc_netif_t *netif);
static int _lwmac_init(gnrc_netif_t *netif);
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif);
static void _lwmac_msg_handler(gnrc_netif_t *netif, msg_t *msg);
static const gnrc_netif_ops_t lwmac_ops = {
.init = _lwmac_init,
.send = _send,
.recv = _recv,
.get = gnrc_netif_get_from_netdev,
.set = gnrc_netif_set_from_netdev,
.msg_handler = _lwmac_msg_handler,
};
int gnrc_netif_lwmac_create(gnrc_netif_t *netif, char *stack, int stacksize,
char priority, const char *name, netdev_t *dev)
{
return gnrc_netif_create(netif, stack, stacksize, priority, name, dev,
&lwmac_ops);
}
static void lwmac_reinit_radio(gnrc_netif_t *netif)
{
/* Initialize low-level driver. */
netif->dev->driver->init(netif->dev);
/* Set MAC address length. */
uint16_t src_len = netif->l2addr_len;
netif->dev->driver->set(netif->dev, NETOPT_SRC_LEN, &src_len, sizeof(src_len));
/* Set the MAC address of the device. */
if (netif->l2addr_len == IEEE802154_LONG_ADDRESS_LEN) {
netif->dev->driver->set(netif->dev,
NETOPT_ADDRESS_LONG,
netif->l2addr,
sizeof(netif->l2addr));
}
else {
netif->dev->driver->set(netif->dev,
NETOPT_ADDR_LEN,
netif->l2addr,
sizeof(netif->l2addr));
}
/* Check if RX-start and TX-started and TX-END interrupts are supported */
if (IS_ACTIVE(DEVELHELP)) {
netopt_enable_t enable;
netif->dev->driver->get(netif->dev, NETOPT_RX_START_IRQ, &enable, sizeof(enable));
assert(enable == NETOPT_ENABLE);
netif->dev->driver->get(netif->dev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));
assert(enable == NETOPT_ENABLE);
}
}
static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr)
{
gnrc_pktsnip_t *snip;
uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
int src_len, dst_len;
le_uint16_t _pan_tmp; /* TODO: hand-up PAN IDs to GNRC? */
dst_len = ieee802154_get_dst(mhr, dst, &_pan_tmp);
src_len = ieee802154_get_src(mhr, src, &_pan_tmp);
if ((dst_len < 0) || (src_len < 0)) {
DEBUG("_make_netif_hdr: unable to get addresses\n");
return NULL;
}
/* allocate space for header */
snip = gnrc_netif_hdr_build(src, (size_t)src_len, dst, (size_t)dst_len);
if (snip == NULL) {
DEBUG("_make_netif_hdr: no space left in packet buffer\n");
return NULL;
}
/* set broadcast flag for broadcast destination */
if ((dst_len == 2) && (dst[0] == 0xff) && (dst[1] == 0xff)) {
gnrc_netif_hdr_t *hdr = snip->data;
hdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
}
return snip;
}
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
{
netdev_t *dev = netif->dev;
netdev_ieee802154_rx_info_t rx_info;
netdev_ieee802154_t *state = container_of(dev, netdev_ieee802154_t, netdev);
gnrc_pktsnip_t *pkt = NULL;
int bytes_expected = dev->driver->recv(dev, NULL, 0, NULL);
if (bytes_expected > 0) {
int nread;
pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
DEBUG("_recv_ieee802154: cannot allocate pktsnip.\n");
return NULL;
}
nread = dev->driver->recv(dev, pkt->data, bytes_expected, &rx_info);
if (nread <= 0) {
gnrc_pktbuf_release(pkt);
return NULL;
}
if (!(state->flags & NETDEV_IEEE802154_RAW)) {
gnrc_pktsnip_t *ieee802154_hdr, *netif_hdr;
gnrc_netif_hdr_t *hdr;
size_t mhr_len = ieee802154_get_frame_hdr_len(pkt->data);
if (mhr_len == 0) {
DEBUG("_recv_ieee802154: illegally formatted frame received\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
nread -= mhr_len;
/* mark IEEE 802.15.4 header */
ieee802154_hdr = gnrc_pktbuf_mark(pkt, mhr_len, GNRC_NETTYPE_UNDEF);
if (ieee802154_hdr == NULL) {
DEBUG("_recv_ieee802154: no space left in packet buffer\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
netif_hdr = _make_netif_hdr(ieee802154_hdr->data);
if (netif_hdr == NULL) {
DEBUG("_recv_ieee802154: no space left in packet buffer\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
hdr = netif_hdr->data;
#ifdef MODULE_L2FILTER
if (!l2filter_pass(dev->filter, gnrc_netif_hdr_get_src_addr(hdr),
hdr->src_l2addr_len)) {
gnrc_pktbuf_release(pkt);
gnrc_pktbuf_release(netif_hdr);
DEBUG("_recv_ieee802154: packet dropped by l2filter\n");
return NULL;
}
#endif
hdr->lqi = rx_info.lqi;
hdr->rssi = rx_info.rssi;
gnrc_netif_hdr_set_netif(hdr, netif);
pkt->type = state->proto;
if (IS_ACTIVE(ENABLE_DEBUG)) {
char src_str[GNRC_NETIF_HDR_L2ADDR_PRINT_LEN];
DEBUG("_recv_ieee802154: received packet from %s of length %u\n",
gnrc_netif_addr_to_str(gnrc_netif_hdr_get_src_addr(hdr),
hdr->src_l2addr_len,
src_str),
nread);
if (IS_USED(MODULE_OD)) {
od_hex_dump(pkt->data, nread, OD_WIDTH_DEFAULT);
}
}
gnrc_pktbuf_remove_snip(pkt, ieee802154_hdr);
pkt = gnrc_pkt_append(pkt, netif_hdr);
}
DEBUG("_recv_ieee802154: reallocating.\n");
gnrc_pktbuf_realloc_data(pkt, nread);
}
return pkt;
}
static gnrc_mac_tx_neighbor_t *_next_tx_neighbor(gnrc_netif_t *netif)
{
gnrc_mac_tx_neighbor_t *next = NULL;
uint32_t phase_nearest = GNRC_LWMAC_PHASE_MAX;
for (unsigned i = 0; i < CONFIG_GNRC_MAC_NEIGHBOR_COUNT; i++) {
if (gnrc_priority_pktqueue_length(&netif->mac.tx.neighbors[i].queue) > 0) {
/* Unknown destinations are initialized with their phase at the end
* of the local interval, so known destinations that still wakeup
* in this interval will be preferred. */
uint32_t phase_check = _gnrc_lwmac_ticks_until_phase(netif->mac.tx.neighbors[i].phase);
if (phase_check <= phase_nearest) {
next = &(netif->mac.tx.neighbors[i]);
phase_nearest = phase_check;
DEBUG("[LWMAC-int] Advancing queue #%u\n", i);
}
}
}
return next;
}
static uint32_t _next_inphase_event(uint32_t last, uint32_t interval)
{
/* Counter did overflow since last wakeup */
if (rtt_get_counter() < last) {
/* TODO: Not sure if this was tested :) */
uint32_t tmp = -last;
tmp /= interval;
tmp++;
last += tmp * interval;
}
/* Add margin to next wakeup so that it will be at least 2ms in the future */
while (last < (rtt_get_counter() + GNRC_LWMAC_RTT_EVENT_MARGIN_TICKS)) {
last += interval;
}
return last;
}
inline void lwmac_schedule_update(gnrc_netif_t *netif)
{
gnrc_lwmac_set_reschedule(netif, true);
}
void lwmac_set_state(gnrc_netif_t *netif, gnrc_lwmac_state_t newstate)
{
gnrc_lwmac_state_t oldstate = netif->mac.prot.lwmac.state;
if (newstate == oldstate) {
return;
}
if (newstate >= GNRC_LWMAC_STATE_COUNT) {
LOG_ERROR("ERROR: [LWMAC] Trying to set invalid state %u\n", newstate);
return;
}
/* Already change state, but might be reverted to oldstate when needed */
netif->mac.prot.lwmac.state = newstate;
/* Actions when leaving old state */
switch (oldstate) {
case GNRC_LWMAC_RECEIVING:
case GNRC_LWMAC_TRANSMITTING: {
/* Enable duty cycling again */
rtt_handler(GNRC_LWMAC_EVENT_RTT_RESUME, netif);
break;
}
case GNRC_LWMAC_SLEEPING: {
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);
break;
}
default:
break;
}
/* Actions when entering new state */
switch (newstate) {
/*********************** Operation states *********************************/
case GNRC_LWMAC_LISTENING: {
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
break;
}
case GNRC_LWMAC_SLEEPING: {
/* Put transceiver to sleep */
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_SLEEP);
/* We may have come here through RTT handler, so timeout may still be active */
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);
if (gnrc_lwmac_get_phase_backoff(netif)) {
gnrc_lwmac_set_phase_backoff(netif, false);
uint32_t alarm;
rtt_clear_alarm();
alarm = random_uint32_range(
RTT_US_TO_TICKS((3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)),
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US -
(3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)));
LOG_WARNING("WARNING: [LWMAC] phase backoffed: %lu us\n",
(unsigned long)RTT_TICKS_TO_US(alarm));
netif->mac.prot.lwmac.last_wakeup = netif->mac.prot.lwmac.last_wakeup + alarm;
alarm = _next_inphase_event(netif->mac.prot.lwmac.last_wakeup,
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US));
rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
}
/* Return immediately, so no rescheduling */
return;
}
/* Trying to send data */
case GNRC_LWMAC_TRANSMITTING: {
rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif); /**< No duty cycling while RXing */
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE); /**< Power up netdev */
break;
}
/* Receiving incoming data */
case GNRC_LWMAC_RECEIVING: {
rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif); /**< No duty cycling while TXing */
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE); /**< Power up netdev */
break;
}
case GNRC_LWMAC_STOPPED: {
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_OFF);
break;
}
/*********************** Control states ***********************************/
case GNRC_LWMAC_START: {
rtt_handler(GNRC_LWMAC_EVENT_RTT_START, netif);
lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
netif->mac.tx.preamble_fail_counts = 0;
break;
}
case GNRC_LWMAC_STOP: {
rtt_handler(GNRC_LWMAC_EVENT_RTT_STOP, netif);
lwmac_set_state(netif, GNRC_LWMAC_STOPPED);
break;
}
case GNRC_LWMAC_RESET: {
LOG_WARNING("WARNING: [LWMAC] Reset not yet implemented\n");
lwmac_set_state(netif, GNRC_LWMAC_STOP);
lwmac_set_state(netif, GNRC_LWMAC_START);
break;
}
/**************************************************************************/
default: {
LOG_DEBUG("[LWMAC] No actions for entering state %u\n", newstate);
return;
}
}
lwmac_schedule_update(netif);
}
static void _sleep_management(gnrc_netif_t *netif)
{
/* If a packet is scheduled, no other (possible earlier) packet can be
* sent before the first one is handled, even no broadcast
*/
if (!gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP)) {
gnrc_mac_tx_neighbor_t *neighbour;
/* Check if there is packet remaining for retransmission */
if (netif->mac.tx.current_neighbor != NULL) {
neighbour = netif->mac.tx.current_neighbor;
}
else {
/* Check if there are broadcasts to send and transmit immediately */
if (gnrc_priority_pktqueue_length(&(netif->mac.tx.neighbors[0].queue)) > 0) {
netif->mac.tx.current_neighbor = &(netif->mac.tx.neighbors[0]);
lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
return;
}
neighbour = _next_tx_neighbor(netif);
}
if (neighbour != NULL) {
/* if phase is unknown, send immediately. */
if (neighbour->phase > RTT_TICKS_TO_US(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US)) {
netif->mac.tx.current_neighbor = neighbour;
gnrc_lwmac_set_tx_continue(netif, false);
netif->mac.tx.tx_burst_count = 0;
lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
return;
}
/* Offset in microseconds when the earliest (phase) destination
* node wakes up that we have packets for. */
uint32_t time_until_tx = RTT_TICKS_TO_US(_gnrc_lwmac_ticks_until_phase(neighbour->phase));
/* If there's not enough time to prepare a WR to catch the phase
* postpone to next interval */
if (time_until_tx < CONFIG_GNRC_LWMAC_WR_PREPARATION_US) {
time_until_tx += CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US;
}
time_until_tx -= CONFIG_GNRC_LWMAC_WR_PREPARATION_US;
/* add a random time before goto TX, for avoiding one node for
* always holding the medium (if the receiver's phase is recorded earlier in this
* particular node) */
uint32_t random_backoff;
random_backoff = random_uint32_range(0, CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US);
time_until_tx = time_until_tx + random_backoff;
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP, time_until_tx);
/* Register neighbour to be the next */
netif->mac.tx.current_neighbor = neighbour;
/* Stop dutycycling, we're preparing to send. This prevents the
* timeout arriving late, so that the destination phase would
* be missed. */
/* TODO: bad for power savings */
rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif);
}
}
else if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP)) {
LOG_DEBUG("[LWMAC] Got timeout for dest wakeup, ticks: %" PRIu32 "\n", rtt_get_counter());
gnrc_lwmac_set_tx_continue(netif, false);
netif->mac.tx.tx_burst_count = 0;
lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
}
}
static void _rx_management_attempt_sleep(gnrc_netif_t *netif)
{
/* Here we check if we are close to the end of the cycle. If yes,
* go to sleep. Firstly, get the relative phase. */
uint32_t phase = rtt_get_counter();
if (phase < netif->mac.prot.lwmac.last_wakeup) {
phase = (RTT_US_TO_TICKS(GNRC_LWMAC_PHASE_MAX) - netif->mac.prot.lwmac.last_wakeup) +
phase;
}
else {
phase = phase - netif->mac.prot.lwmac.last_wakeup;
}
/* If the relative phase is beyond 4/5 cycle time, go to sleep. */
if (phase > (4 * RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US) / 5)) {
gnrc_lwmac_set_quit_rx(netif, true);
}
if (gnrc_lwmac_get_quit_rx(netif)) {
lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
}
else {
/* Go back to LISTENING for keep hearing on the channel */
lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
}
}
static void _rx_management_failed(gnrc_netif_t *netif)
{
/* This may happen frequently because we'll receive WA from
* every node in range. */
LOG_DEBUG("[LWMAC] Reception was NOT successful\n");
gnrc_lwmac_rx_stop(netif);
if (netif->mac.rx.rx_bad_exten_count >= CONFIG_GNRC_LWMAC_MAX_RX_EXTENSION_NUM) {
gnrc_lwmac_set_quit_rx(netif, true);
}
_rx_management_attempt_sleep(netif);
}
static void _rx_management_success(gnrc_netif_t *netif)
{
LOG_DEBUG("[LWMAC] Reception was successful\n");
gnrc_lwmac_rx_stop(netif);
/* Dispatch received packets, timing is not critical anymore */
gnrc_mac_dispatch(&netif->mac.rx);
_rx_management_attempt_sleep(netif);
}
static void _rx_management(gnrc_netif_t *netif)
{
gnrc_lwmac_rx_state_t state_rx = netif->mac.rx.state;
switch (state_rx) {
case GNRC_LWMAC_RX_STATE_STOPPED: {
gnrc_lwmac_rx_start(netif);
gnrc_lwmac_rx_update(netif);
break;
}
case GNRC_LWMAC_RX_STATE_FAILED: {
_rx_management_failed(netif);
break;
}
case GNRC_LWMAC_RX_STATE_SUCCESSFUL: {
_rx_management_success(netif);
break;
}
default:
gnrc_lwmac_rx_update(netif);
}
/* If state has changed, reschedule main state machine */
if (state_rx != netif->mac.rx.state) {
lwmac_schedule_update(netif);
}
}
static void _tx_management_stopped(gnrc_netif_t *netif)
{
/* If there is packet remaining for retransmission,
* retransmit it (i.e., the retransmission scheme of LWMAC). */
if (netif->mac.tx.packet != NULL) {
LOG_WARNING("WARNING: [LWMAC] TX %d times retry\n",
netif->mac.tx.tx_retry_count);
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_INIT;
netif->mac.tx.wr_sent = 0;
gnrc_lwmac_tx_update(netif);
}
else {
gnrc_pktsnip_t *pkt;
if ((pkt = gnrc_priority_pktqueue_pop(
&netif->mac.tx.current_neighbor->queue))) {
netif->mac.tx.tx_retry_count = 0;
gnrc_lwmac_tx_start(netif, pkt, netif->mac.tx.current_neighbor);
gnrc_lwmac_tx_update(netif);
}
else {
/* Shouldn't happen, but never observed this case */
lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
}
}
}
static void _tx_management_success(gnrc_netif_t *netif)
{
if (netif->mac.tx.current_neighbor == &(netif->mac.tx.neighbors[0])) {
LOG_INFO("[LWMAC] Broadcast transmission done\n");
}
gnrc_lwmac_tx_stop(netif);
/* In case have pending packets for the same receiver, continue to
* send immediately, before the maximum transmit-limit */
if ((gnrc_lwmac_get_tx_continue(netif)) &&
(netif->mac.tx.tx_burst_count < GNRC_LWMAC_MAX_TX_BURST_PKT_NUM)) {
lwmac_schedule_update(netif);
}
else {
lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
}
}
static void _tx_management(gnrc_netif_t *netif)
{
gnrc_lwmac_tx_state_t state_tx = netif->mac.tx.state;
switch (state_tx) {
case GNRC_LWMAC_TX_STATE_STOPPED:
_tx_management_stopped(netif);
break;
case GNRC_LWMAC_TX_STATE_FAILED:
/* If transmission failure, do not try burst transmissions and quit other
* transmission attempts in this cycle for collision avoidance */
gnrc_lwmac_set_tx_continue(netif, false);
gnrc_lwmac_set_quit_tx(netif, true);
/* TX packet will be dropped, no automatic resending here. */
/* Re-initialize the radio when needed. */
if (netif->mac.tx.preamble_fail_counts >= CONFIG_GNRC_LWMAC_RADIO_REINIT_THRESHOLD) {
netif->mac.tx.preamble_fail_counts = 0;
LOG_INFO("[LWMAC] Re-initialize radio.");
lwmac_reinit_radio(netif);
}
/* Intentionally falls through */
case GNRC_LWMAC_TX_STATE_SUCCESSFUL:
_tx_management_success(netif);
break;
default:
gnrc_lwmac_tx_update(netif);
break;
}
/* If state has changed, reschedule main state machine */
if (state_tx != netif->mac.tx.state) {
lwmac_schedule_update(netif);
}
}
static void _lwmac_update_listening(gnrc_netif_t *netif)
{
/* In case has pending packet to send, clear rtt alarm thus to goto
* transmission initialization (in SLEEPING management) right after the
* listening period */
if ((_next_tx_neighbor(netif) != NULL) ||
(netif->mac.tx.current_neighbor != NULL)) {
rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif);
}
/* Set timeout for if there's no successful rx transaction that will
* change state to SLEEPING. */
if (!gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD)) {
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD, GNRC_LWMAC_WAKEUP_DURATION_US);
}
else if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD)) {
/* Dispatch first as there still may be broadcast packets. */
gnrc_mac_dispatch(&netif->mac.rx);
netif->mac.prot.lwmac.state = GNRC_LWMAC_SLEEPING;
/* Enable duty cycling again */
rtt_handler(GNRC_LWMAC_EVENT_RTT_RESUME, netif);
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_SLEEP);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);
/* if there is a packet for transmission, schedule update to start
* transmission initialization immediately. */
gnrc_mac_tx_neighbor_t *neighbour = _next_tx_neighbor(netif);
if ((neighbour != NULL) || (netif->mac.tx.current_neighbor != NULL)) {
/* This triggers packet sending procedure in sleeping immediately. */
lwmac_schedule_update(netif);
return;
}
}
if (gnrc_priority_pktqueue_length(&netif->mac.rx.queue) > 0) {
/* Do wake-up extension in each packet reception. */
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);
lwmac_set_state(netif, GNRC_LWMAC_RECEIVING);
}
}
/* Main state machine. Call whenever something happens */
static bool lwmac_update(gnrc_netif_t *netif)
{
gnrc_lwmac_set_reschedule(netif, false);
switch (netif->mac.prot.lwmac.state) {
case GNRC_LWMAC_SLEEPING: {
/* Quit scheduling transmission if 'quit-tx' flag is found set, thus
* to avoid potential collisions with ongoing transmissions of other
* neighbor nodes */
if (gnrc_lwmac_get_quit_tx(netif)) {
return false;
}
_sleep_management(netif);
break;
}
case GNRC_LWMAC_LISTENING: {
_lwmac_update_listening(netif);
break;
}
case GNRC_LWMAC_RECEIVING: {
_rx_management(netif);
break;
}
case GNRC_LWMAC_TRANSMITTING: {
_tx_management(netif);
break;
}
default:
LOG_DEBUG("[LWMAC] No actions in state %u\n", netif->mac.prot.lwmac.state);
}
return gnrc_lwmac_get_reschedule(netif);
}
static void rtt_cb(void *arg)
{
msg_t msg;
msg.content.value = (uint16_t)((uintptr_t) arg);
msg.type = GNRC_LWMAC_EVENT_RTT_TYPE;
msg_send(&msg, lwmac_pid);
if (sched_context_switch_request) {
thread_yield();
}
}
void rtt_handler(uint32_t event, gnrc_netif_t *netif)
{
uint32_t alarm;
switch (event & 0xffff) {
case GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING: {
/* A new cycle starts, set sleep timing and initialize related MAC-info flags. */
netif->mac.prot.lwmac.last_wakeup = rtt_get_alarm();
alarm = _next_inphase_event(netif->mac.prot.lwmac.last_wakeup,
RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_DURATION_US));
rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING);
gnrc_lwmac_set_quit_tx(netif, false);
gnrc_lwmac_set_quit_rx(netif, false);
gnrc_lwmac_set_phase_backoff(netif, false);
netif->mac.rx.rx_bad_exten_count = 0;
lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
break;
}
case GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING: {
/* Set next wake-up timing. */
alarm = _next_inphase_event(netif->mac.prot.lwmac.last_wakeup,
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US));
rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
break;
}
/* Set initial wake-up alarm that starts the cycle */
case GNRC_LWMAC_EVENT_RTT_START: {
LOG_DEBUG("[LWMAC] RTT: Initialize duty cycling\n");
alarm = rtt_get_counter() + RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_DURATION_US);
rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING);
gnrc_lwmac_set_dutycycle_active(netif, true);
break;
}
case GNRC_LWMAC_EVENT_RTT_STOP:
case GNRC_LWMAC_EVENT_RTT_PAUSE: {
rtt_clear_alarm();
LOG_DEBUG("[LWMAC] RTT: Stop duty cycling, now in state %u\n",
netif->mac.prot.lwmac.state);
gnrc_lwmac_set_dutycycle_active(netif, false);
break;
}
case GNRC_LWMAC_EVENT_RTT_RESUME: {
LOG_DEBUG("[LWMAC] RTT: Resume duty cycling\n");
rtt_clear_alarm();
alarm = _next_inphase_event(netif->mac.prot.lwmac.last_wakeup,
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US));
rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
gnrc_lwmac_set_dutycycle_active(netif, true);
break;
}
default:
break;
}
}
/**
* @brief Function called by the device driver on device events
*
* @param dev netdev causing the event
* @param[in] event type of event
*/
static void _lwmac_event_cb(netdev_t *dev, netdev_event_t event)
{
gnrc_netif_t *netif = (gnrc_netif_t *) dev->context;
if (event == NETDEV_EVENT_ISR) {
event_post(&netif->evq[GNRC_NETIF_EVQ_INDEX_PRIO_LOW], &netif->event_isr);
}
else {
DEBUG("gnrc_netdev: event triggered -> %i\n", event);
switch (event) {
case NETDEV_EVENT_RX_STARTED: {
LOG_DEBUG("[LWMAC] NETDEV_EVENT_RX_STARTED\n");
gnrc_netif_set_rx_started(netif, true);
break;
}
case NETDEV_EVENT_RX_COMPLETE: {
LOG_DEBUG("[LWMAC] NETDEV_EVENT_RX_COMPLETE\n");
gnrc_pktsnip_t *pkt = netif->ops->recv(netif);
/* Prevent packet corruption when a packet is sent before the previous
* received packet has been downloaded. This happens e.g. when a timeout
* expires that causes the tx state machine to send a packet. When a
* packet arrives after the timeout, the notification is queued but the
* tx state machine continues to send and then destroys the received
* packet in the frame buffer. After completion, the queued notification
* will be handled a corrupted packet will be downloaded. Therefore
* keep track that RX_STARTED is followed by RX_COMPLETE.
*
* TODO: transceivers might have 2 frame buffers, so make this optional
*/
if (pkt == NULL) {
gnrc_netif_set_rx_started(netif, false);
break;
}
gnrc_netif_set_rx_started(netif, false);
if (!gnrc_mac_queue_rx_packet(&netif->mac.rx, 0, pkt)) {
LOG_ERROR("ERROR: [LWMAC] Can't push RX packet @ %p, memory full?\n", pkt);
gnrc_pktbuf_release(pkt);
break;
}
lwmac_schedule_update(netif);
break;
}
case NETDEV_EVENT_TX_STARTED: {
gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_UNDEF);
gnrc_netif_set_rx_started(netif, false);
break;
}
case NETDEV_EVENT_TX_COMPLETE: {
gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_SUCCESS);
gnrc_netif_set_rx_started(netif, false);
lwmac_schedule_update(netif);
break;
}
case NETDEV_EVENT_TX_NOACK: {
gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_NOACK);
gnrc_netif_set_rx_started(netif, false);
lwmac_schedule_update(netif);
break;
}
case NETDEV_EVENT_TX_MEDIUM_BUSY: {
gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_BUSY);
gnrc_netif_set_rx_started(netif, false);
lwmac_schedule_update(netif);
break;
}
default:
LOG_WARNING("WARNING: [LWMAC] Unhandled netdev event: %u\n", event);
}
}
/* Execute main state machine because something just happened*/
while (gnrc_lwmac_get_reschedule(netif)) {
lwmac_update(netif);
}
}
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, pkt)) {
gnrc_pktbuf_release(pkt);
LOG_WARNING("WARNING: [LWMAC] TX queue full, drop packet\n");
return -ENOBUFS;
}
lwmac_schedule_update(netif);
/* Execute main state machine because something just happened*/
while (gnrc_lwmac_get_reschedule(netif)) {
lwmac_update(netif);
}
return 0;
}
static void _lwmac_msg_handler(gnrc_netif_t *netif, msg_t *msg)
{
switch (msg->type) {
/* RTT raised an interrupt */
case GNRC_LWMAC_EVENT_RTT_TYPE: {
if (gnrc_lwmac_get_dutycycle_active(netif)) {
rtt_handler(msg->content.value, netif);
lwmac_schedule_update(netif);
}
else {
LOG_DEBUG("[LWMAC] Ignoring late RTT event while duty-cycling is off\n");
}
break;
}
/* An LWMAC timeout occurred */
case GNRC_LWMAC_EVENT_TIMEOUT_TYPE: {
gnrc_lwmac_timeout_make_expire((gnrc_lwmac_timeout_t *) msg->content.ptr);
lwmac_schedule_update(netif);
break;
}
#if (GNRC_MAC_ENABLE_DUTYCYCLE_RECORD == 1)
case GNRC_MAC_TYPE_GET_DUTYCYCLE: {
/* Output LWMAC's radio duty-cycle ratio */
uint64_t duty = (uint64_t) rtt_get_counter();
duty = ((uint64_t) netif->mac.prot.lwmac.awake_duration_sum_ticks) * 100 /
(duty - (uint64_t)netif->mac.prot.lwmac.system_start_time_ticks);
printf("[LWMAC]: achieved radio duty-cycle: %u %% \n", (unsigned) duty);
break;
}
#endif
default: {
DEBUG("[LWMAC]: unknown message type 0x%04x "
"(no message handler defined)\n", msg->type);
break;
}
}
/* Execute main state machine because something just happened*/
while (gnrc_lwmac_get_reschedule(netif)) {
lwmac_update(netif);
}
}
static int _lwmac_init(gnrc_netif_t *netif)
{
netdev_t *dev;
int res = gnrc_netif_default_init(netif);
if (res < 0) {
return res;
}
dev = netif->dev;
dev->event_callback = _lwmac_event_cb;
/* RTT is used for scheduling wakeup */
rtt_init();
/* Store pid globally, so that IRQ can use it to send msg */
lwmac_pid = netif->pid;
/* Enable RX- and TX-started interrupts */
netopt_enable_t enable = NETOPT_ENABLE;
dev->driver->set(dev, NETOPT_RX_START_IRQ, &enable, sizeof(enable));
dev->driver->set(dev, NETOPT_TX_START_IRQ, &enable, sizeof(enable));
dev->driver->set(dev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));
uint16_t src_len = IEEE802154_LONG_ADDRESS_LEN;
dev->driver->set(dev, NETOPT_SRC_LEN, &src_len, sizeof(src_len));
/* Get own address from netdev */
netif->l2addr_len = dev->driver->get(dev, NETOPT_ADDRESS_LONG,
&netif->l2addr,
IEEE802154_LONG_ADDRESS_LEN);
/* Initialize broadcast sequence number. This at least differs from board
* to board */
netif->mac.tx.bcast_seqnr = netif->l2addr[0];
/* Reset all timeouts just to be sure */
gnrc_lwmac_reset_timeouts(netif);
/* Start duty cycling */
lwmac_set_state(netif, GNRC_LWMAC_START);
#if (GNRC_MAC_ENABLE_DUTYCYCLE_RECORD == 1)
/* Start duty cycle recording */
netif->mac.prot.lwmac.system_start_time_ticks = rtt_get_counter();
netif->mac.prot.lwmac.last_radio_on_time_ticks = netif->mac.prot.lwmac.system_start_time_ticks;
netif->mac.prot.lwmac.awake_duration_sum_ticks = 0;
netif->mac.prot.lwmac.lwmac_info |= GNRC_LWMAC_RADIO_IS_ON;
#endif
return res;
}

View File

@ -1,274 +0,0 @@
/*
* 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 internal functions of LWMAC
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <assert.h>
#include <stdbool.h>
#include "periph/rtt.h"
#include "net/gnrc.h"
#include "net/gnrc/mac/mac.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "include/lwmac_internal.h"
#include "net/gnrc/netif/ieee802154.h"
#include "net/netdev/ieee802154.h"
#define ENABLE_DEBUG 0
#include "debug.h"
int _gnrc_lwmac_transmit(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
netdev_t *dev = netif->dev;
netdev_ieee802154_t *state = container_of(dev, netdev_ieee802154_t, netdev);
gnrc_netif_hdr_t *netif_hdr;
const uint8_t *src, *dst = NULL;
int res = 0;
size_t src_len, dst_len;
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
uint8_t flags = (uint8_t)(state->flags & NETDEV_IEEE802154_SEND_MASK);
le_uint16_t dev_pan = byteorder_htols(state->pan);
flags |= IEEE802154_FCF_TYPE_DATA;
if (pkt == NULL) {
DEBUG("_send_ieee802154: pkt was NULL\n");
return -EINVAL;
}
if (pkt->type != GNRC_NETTYPE_NETIF) {
DEBUG("_send_ieee802154: first header is not generic netif header\n");
return -EBADMSG;
}
netif_hdr = pkt->data;
/* prepare destination address */
if (netif_hdr->flags & /* If any of these flags is set assume broadcast */
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
dst = ieee802154_addr_bcast;
dst_len = IEEE802154_ADDR_BCAST_LEN;
}
else {
dst = gnrc_netif_hdr_get_dst_addr(netif_hdr);
dst_len = netif_hdr->dst_l2addr_len;
}
src_len = netif_hdr->src_l2addr_len;
if (src_len > 0) {
src = gnrc_netif_hdr_get_src_addr(netif_hdr);
}
else {
src_len = netif->l2addr_len;
src = netif->l2addr;
}
/* fill MAC header, seq should be set by device */
if ((res = ieee802154_set_frame_hdr(mhr, src, src_len,
dst, dst_len, dev_pan,
dev_pan, flags, state->seq++)) == 0) {
DEBUG("_send_ieee802154: Error preperaring frame\n");
return -EINVAL;
}
/* prepare packet for sending */
iolist_t iolist = {
.iol_next = (iolist_t *)pkt->next,
.iol_base = mhr,
.iol_len = (size_t)res
};
#ifdef MODULE_NETSTATS_L2
if (netif_hdr->flags &
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
netif->stats.tx_mcast_count++;
}
else {
netif->stats.tx_unicast_count++;
}
#endif
#ifdef MODULE_GNRC_MAC
if (netif->mac.mac_info & GNRC_NETIF_MAC_INFO_CSMA_ENABLED) {
res = csma_sender_csma_ca_send(dev, &iolist, &netif->mac.csma_conf);
}
else {
res = dev->driver->send(dev, &iolist);
}
#else
res = dev->driver->send(dev, &iolist);
#endif
/* release old data */
gnrc_pktbuf_release(pkt);
return res;
}
int _gnrc_lwmac_parse_packet(gnrc_pktsnip_t *pkt, gnrc_lwmac_packet_info_t *info)
{
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *lwmac_snip;
gnrc_lwmac_hdr_t *lwmac_hdr;
assert(info != NULL);
assert(pkt != NULL);
netif_hdr = (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF))->data;
if (netif_hdr == NULL) {
return -1;
}
/* Dissect LWMAC header, Every frame has header as first member */
lwmac_hdr = (gnrc_lwmac_hdr_t *) pkt->data;
switch (lwmac_hdr->type) {
case GNRC_LWMAC_FRAMETYPE_WR: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_wr_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_WA: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_wa_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_DATA_PENDING:
case GNRC_LWMAC_FRAMETYPE_DATA: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_data_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_BROADCAST: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_broadcast_t),
GNRC_NETTYPE_LWMAC);
break;
}
default: {
return -2;
}
}
/* Memory location may have changed while marking */
lwmac_hdr = lwmac_snip->data;
if (lwmac_hdr->type == GNRC_LWMAC_FRAMETYPE_WA) {
/* WA is broadcast, so get dst address out of header instead of netif */
info->dst_addr = ((gnrc_lwmac_frame_wa_t *)lwmac_hdr)->dst_addr;
}
else if (lwmac_hdr->type == GNRC_LWMAC_FRAMETYPE_WR) {
/* WR is broadcast, so get dst address out of header instead of netif */
info->dst_addr = ((gnrc_lwmac_frame_wr_t *)lwmac_hdr)->dst_addr;
}
else if (netif_hdr->dst_l2addr_len) {
info->dst_addr.len = netif_hdr->dst_l2addr_len;
memcpy(info->dst_addr.addr,
gnrc_netif_hdr_get_dst_addr(netif_hdr),
netif_hdr->dst_l2addr_len);
}
if (netif_hdr->src_l2addr_len) {
info->src_addr.len = netif_hdr->src_l2addr_len;
memcpy(info->src_addr.addr,
gnrc_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
}
info->header = lwmac_hdr;
return 0;
}
void _gnrc_lwmac_set_netdev_state(gnrc_netif_t *netif, netopt_state_t devstate)
{
netif->dev->driver->set(netif->dev,
NETOPT_STATE,
&devstate,
sizeof(devstate));
#if (GNRC_MAC_ENABLE_DUTYCYCLE_RECORD == 1)
if (devstate == NETOPT_STATE_IDLE) {
if (!(netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) {
netif->mac.prot.lwmac.last_radio_on_time_ticks = rtt_get_counter();
netif->mac.prot.lwmac.lwmac_info |= GNRC_LWMAC_RADIO_IS_ON;
}
return;
}
else if ((devstate == NETOPT_STATE_SLEEP) &&
(netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) {
netif->mac.prot.lwmac.radio_off_time_ticks = rtt_get_counter();
netif->mac.prot.lwmac.awake_duration_sum_ticks +=
(netif->mac.prot.lwmac.radio_off_time_ticks -
netif->mac.prot.lwmac.last_radio_on_time_ticks);
netif->mac.prot.lwmac.lwmac_info &= ~GNRC_LWMAC_RADIO_IS_ON;
}
#endif
}
netopt_state_t _gnrc_lwmac_get_netdev_state(gnrc_netif_t *netif)
{
netopt_state_t state;
if (0 < netif->dev->driver->get(netif->dev,
NETOPT_STATE,
&state,
sizeof(state))) {
return state;
}
return -1;
}
int _gnrc_lwmac_dispatch_defer(gnrc_pktsnip_t *buffer[], gnrc_pktsnip_t *pkt)
{
assert(buffer != NULL);
assert(pkt != NULL);
/* We care about speed here, so assume packet structure */
assert(pkt->next->type == GNRC_NETTYPE_LWMAC);
assert(pkt->next->next->type == GNRC_NETTYPE_NETIF);
gnrc_lwmac_frame_broadcast_t *bcast = NULL;
if (((gnrc_lwmac_hdr_t *)pkt->next->data)->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
bcast = pkt->next->data;
}
for (unsigned i = 0; i < GNRC_MAC_DISPATCH_BUFFER_SIZE; i++) {
/* Buffer will be filled bottom-up and emptied completely so no holes */
if (buffer[i] == NULL) {
buffer[i] = pkt;
return 0;
}
else if (bcast &&
(((gnrc_lwmac_hdr_t *)buffer[i]->next->data)->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) &&
(bcast->seq_nr == ((gnrc_lwmac_frame_broadcast_t *)buffer[i]->next->data)->seq_nr)) {
/* Filter same broadcasts, compare sequence number */
gnrc_netif_hdr_t *hdr_queued, *hdr_new;
hdr_new = pkt->next->next->data;
hdr_queued = buffer[i]->next->next->data;
/* Sequence numbers match, compare source addresses */
if ((hdr_new->src_l2addr_len == hdr_queued->src_l2addr_len) &&
(memcmp(gnrc_netif_hdr_get_src_addr(hdr_new),
gnrc_netif_hdr_get_src_addr(hdr_queued),
hdr_new->src_l2addr_len) == 0)) {
/* Source addresses match, same packet */
DEBUG("[LWMAC] Found duplicate broadcast packet, dropping\n");
gnrc_pktbuf_release(pkt);
return -2;
}
}
}
DEBUG("[LWMAC] Dispatch buffer full, dropping packet\n");
gnrc_pktbuf_release(pkt);
return -1;
}

View File

@ -1,439 +0,0 @@
/*
* 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 of LWMAC protocol
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <assert.h>
#include "net/gnrc.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "net/gnrc/mac/internal.h"
#include "net/gnrc/lwmac/timeout.h"
#include "include/rx_state_machine.h"
#include "include/lwmac_internal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#ifndef LOG_LEVEL
/**
* @brief Default log level define
*/
#define LOG_LEVEL LOG_WARNING
#endif
#include "log.h"
/**
* @brief Flag to track if the receiver has got a broadcast packet
*/
#define GNRC_LWMAC_RX_FOUND_BROADCAST (0x01U)
/**
* @brief Flag to track if the receiver has got a WR packet
*/
#define GNRC_LWMAC_RX_FOUND_WR (0x02U)
/**
* @brief Flag to track if the receiver has got a data packet
*/
#define GNRC_LWMAC_RX_FOUND_DATA (0x04U)
static uint8_t _packet_process_in_wait_for_wr(gnrc_netif_t *netif)
{
uint8_t rx_info = 0;
gnrc_pktsnip_t *pkt;
assert(netif != NULL);
while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) {
LOG_DEBUG("[LWMAC-rx] Inspecting pkt @ %p\n", pkt);
/* Parse packet */
gnrc_lwmac_packet_info_t info;
if (_gnrc_lwmac_parse_packet(pkt, &info) != 0) {
LOG_DEBUG("[LWMAC-rx] Packet could not be parsed\n");
gnrc_pktbuf_release(pkt);
continue;
}
if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
_gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt);
gnrc_mac_dispatch(&netif->mac.rx);
rx_info |= GNRC_LWMAC_RX_FOUND_BROADCAST;
/* quit listening period to avoid receiving duplicate broadcast packets */
gnrc_lwmac_set_quit_rx(netif, true);
/* quit TX in this cycle to avoid collisions with broadcast packets */
gnrc_lwmac_set_quit_tx(netif, true);
break;
}
if (info.header->type != GNRC_LWMAC_FRAMETYPE_WR) {
LOG_DEBUG("[LWMAC-rx] Packet is not WR: 0x%02x\n", info.header->type);
gnrc_pktbuf_release(pkt);
continue;
}
/* No need to keep pkt anymore */
gnrc_pktbuf_release(pkt);
if (!(memcmp(&info.dst_addr.addr, &netif->l2addr,
netif->l2addr_len) == 0)) {
LOG_DEBUG("[LWMAC-rx] Packet is WR but not for us\n");
/* quit TX in this cycle to avoid collisions with other senders, since
* found ongoing WR (preamble) stream */
gnrc_lwmac_set_quit_tx(netif, true);
continue;
}
/* If reach here, the node gets a WR for itself. */
/* Save source address for later addressing */
netif->mac.rx.l2_addr = info.src_addr;
rx_info |= GNRC_LWMAC_RX_FOUND_WR;
break;
}
return rx_info;
}
/* return false if send wa failed, otherwise return true */
static bool _send_wa(gnrc_netif_t *netif)
{
gnrc_pktsnip_t *pkt;
gnrc_pktsnip_t *pkt_lwmac;
gnrc_netif_hdr_t *nethdr_wa;
assert(netif != NULL);
assert(netif->mac.rx.l2_addr.len != 0);
/* if found ongoing transmission,
* quit sending WA for collision avoidance. */
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
netif->mac.rx.rx_bad_exten_count++;
return false;
}
/* Assemble WA packet */
gnrc_lwmac_frame_wa_t lwmac_hdr;
lwmac_hdr.header.type = GNRC_LWMAC_FRAMETYPE_WA;
lwmac_hdr.dst_addr = netif->mac.rx.l2_addr;
uint32_t phase_now = _gnrc_lwmac_phase_now();
/* Embed the current 'relative phase timing' (counted from the start of this cycle)
* of the receiver into its WA packet, thus to allow the sender to infer the
* receiver's exact wake-up timing */
if (phase_now > _gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup)) {
lwmac_hdr.current_phase = (phase_now -
_gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup));
}
else {
lwmac_hdr.current_phase = (phase_now +
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US)) -
_gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup);
}
pkt = gnrc_pktbuf_add(NULL, &lwmac_hdr, sizeof(lwmac_hdr), GNRC_NETTYPE_LWMAC);
if (pkt == NULL) {
LOG_ERROR("ERROR: [LWMAC-rx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
gnrc_lwmac_set_quit_rx(netif, true);
return false;
}
pkt_lwmac = pkt;
pkt = gnrc_pktbuf_add(pkt, NULL,
sizeof(gnrc_netif_hdr_t) + netif->mac.rx.l2_addr.len,
GNRC_NETTYPE_NETIF);
if (pkt == NULL) {
LOG_ERROR("ERROR: [LWMAC-rx] Cannot allocate pktbuf of type GNRC_NETTYPE_NETIF\n");
gnrc_pktbuf_release(pkt_lwmac);
gnrc_lwmac_set_quit_rx(netif, true);
return false;
}
/* We wouldn't get here if add the NETIF header had failed, so no
sanity checks needed */
nethdr_wa = (gnrc_netif_hdr_t *)(gnrc_pktsnip_search_type(pkt,
GNRC_NETTYPE_NETIF)->data);
/* Construct NETIF header and insert address for WA packet */
gnrc_netif_hdr_init(nethdr_wa, 0, netif->mac.rx.l2_addr.len);
/* Send WA as broadcast*/
nethdr_wa->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
/* Disable Auto ACK */
netopt_enable_t autoack = NETOPT_DISABLE;
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
sizeof(autoack));
/* Send WA */
if (_gnrc_lwmac_transmit(netif, pkt) < 0) {
LOG_ERROR("ERROR: [LWMAC-rx] Send WA failed.");
gnrc_pktbuf_release(pkt);
gnrc_lwmac_set_quit_rx(netif, true);
return false;
}
/* Enable Auto ACK again for data reception */
autoack = NETOPT_ENABLE;
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
sizeof(autoack));
return true;
}
static uint8_t _packet_process_in_wait_for_data(gnrc_netif_t *netif)
{
uint8_t rx_info = 0;
gnrc_pktsnip_t *pkt;
assert(netif != NULL);
pkt = NULL;
while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) {
LOG_DEBUG("[LWMAC-rx] Inspecting pkt @ %p\n", pkt);
/* Parse packet */
gnrc_lwmac_packet_info_t info;
if (_gnrc_lwmac_parse_packet(pkt, &info) != 0) {
LOG_DEBUG("[LWMAC-rx] Packet could not be parsed\n");
gnrc_pktbuf_release(pkt);
continue;
}
if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
_gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt);
gnrc_mac_dispatch(&netif->mac.rx);
/* quit listening period to avoid receiving duplicate broadcast packets */
gnrc_lwmac_set_quit_rx(netif, true);
continue;
}
if (!(memcmp(&info.src_addr.addr, &netif->mac.rx.l2_addr.addr,
netif->mac.rx.l2_addr.len) == 0)) {
LOG_DEBUG("[LWMAC-rx] Packet is not from destination\n");
gnrc_pktbuf_release(pkt);
/* Reset timeout to wait for the data packet */
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA, CONFIG_GNRC_LWMAC_DATA_DELAY_US);
continue;
}
if (!(memcmp(&info.dst_addr.addr, &netif->l2addr,
netif->l2addr_len) == 0)) {
LOG_DEBUG("[LWMAC-rx] Packet is not for us\n");
gnrc_pktbuf_release(pkt);
/* Reset timeout to wait for the data packet */
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA, CONFIG_GNRC_LWMAC_DATA_DELAY_US);
continue;
}
/* Sender maybe didn't get the WA */
if (info.header->type == GNRC_LWMAC_FRAMETYPE_WR) {
LOG_DEBUG("[LWMAC-rx] Found a WR while waiting for DATA\n");
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
rx_info |= GNRC_LWMAC_RX_FOUND_WR;
/* Push WR back to rx queue */
gnrc_mac_queue_rx_packet(&netif->mac.rx, 0, pkt);
break;
}
switch (info.header->type) {
case GNRC_LWMAC_FRAMETYPE_DATA:
case GNRC_LWMAC_FRAMETYPE_DATA_PENDING: {
/* Receiver gets the data packet */
_gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt);
gnrc_mac_dispatch(&netif->mac.rx);
LOG_DEBUG("[LWMAC-rx] Found DATA!\n");
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
rx_info |= GNRC_LWMAC_RX_FOUND_DATA;
return rx_info;
}
default: {
gnrc_pktbuf_release(pkt);
}
}
}
return rx_info;
}
void gnrc_lwmac_rx_start(gnrc_netif_t *netif)
{
if (netif == NULL) {
return;
}
/* RX address should have been reset, probably not stopped then */
assert(netif->mac.rx.l2_addr.len == 0);
/* Don't attempt to send a WA if channel is busy to get timings right */
netif->mac.mac_info &= ~GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
netopt_enable_t csma_disable = NETOPT_DISABLE;
netif->dev->driver->set(netif->dev, NETOPT_CSMA, &csma_disable,
sizeof(csma_disable));
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_INIT;
}
void gnrc_lwmac_rx_stop(gnrc_netif_t *netif)
{
if (!netif) {
return;
}
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_STOPPED;
netif->mac.rx.l2_addr.len = 0;
}
/* Returns whether rescheduling is needed or not */
static bool _lwmac_rx_update(gnrc_netif_t *netif)
{
bool reschedule = false;
if (!netif) {
return reschedule;
}
switch (netif->mac.rx.state) {
case GNRC_LWMAC_RX_STATE_INIT: {
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA);
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_WAIT_FOR_WR;
reschedule = true;
break;
}
case GNRC_LWMAC_RX_STATE_WAIT_FOR_WR: {
LOG_DEBUG("[LWMAC-rx] GNRC_LWMAC_RX_STATE_WAIT_FOR_WR\n");
uint8_t rx_info = _packet_process_in_wait_for_wr(netif);
/* if found broadcast packet, goto rx successful */
if (rx_info & GNRC_LWMAC_RX_FOUND_BROADCAST) {
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_SUCCESSFUL;
reschedule = true;
break;
}
if (!(rx_info & GNRC_LWMAC_RX_FOUND_WR)) {
LOG_DEBUG("[LWMAC-rx] No WR found, stop RX\n");
netif->mac.rx.rx_bad_exten_count++;
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_FAILED;
reschedule = true;
break;
}
gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
/* Found WR packet (preamble), goto next state to send WA (preamble-ACK) */
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_SEND_WA;
reschedule = true;
break;
}
case GNRC_LWMAC_RX_STATE_SEND_WA: {
LOG_DEBUG("[LWMAC-rx] GNRC_LWMAC_RX_STATE_SEND_WA\n");
if (!_send_wa(netif)) {
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_FAILED;
reschedule = true;
break;
}
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_WAIT_WA_SENT;
reschedule = false;
break;
}
case GNRC_LWMAC_RX_STATE_WAIT_WA_SENT: {
LOG_DEBUG("[LWMAC-rx] GNRC_LWMAC_RX_STATE_WAIT_WA_SENT\n");
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
LOG_DEBUG("[LWMAC-rx] WA not yet completely sent\n");
break;
}
/* When reach here, WA has been sent, set timeout for expected data arrival */
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA, CONFIG_GNRC_LWMAC_DATA_DELAY_US);
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_WAIT_FOR_DATA;
reschedule = false;
break;
}
case GNRC_LWMAC_RX_STATE_WAIT_FOR_DATA: {
LOG_DEBUG("[LWMAC-rx] GNRC_LWMAC_RX_STATE_WAIT_FOR_DATA\n");
uint8_t rx_info = _packet_process_in_wait_for_data(netif);
/* If WA got lost we wait for data but we will be hammered with WR
* packets. So a WR indicates a lost WA => reset RX state machine. */
if (rx_info & GNRC_LWMAC_RX_FOUND_WR) {
LOG_INFO("[LWMAC-rx] WA probably got lost, reset RX state machine\n");
/* Start over again */
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_INIT;
reschedule = true;
break;
}
/* Only timeout if no packet (presumably the expected data) is being
* received. This won't be blocked by WRs as they restart the state
* machine (see above).
*/
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_DATA)) {
if (!gnrc_netif_get_rx_started(netif)) {
LOG_INFO("[LWMAC-rx] DATA timed out\n");
netif->mac.rx.rx_bad_exten_count++;
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_FAILED;
reschedule = true;
}
else {
/* If radio is receiving packet, reset wait data timeout */
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_DATA,
CONFIG_GNRC_LWMAC_DATA_DELAY_US);
}
break;
}
if (!(rx_info & GNRC_LWMAC_RX_FOUND_DATA)) {
LOG_DEBUG("[LWMAC-rx] No DATA yet\n");
break;
}
netif->mac.rx.state = GNRC_LWMAC_RX_STATE_SUCCESSFUL;
reschedule = true;
break;
}
case GNRC_LWMAC_RX_STATE_SUCCESSFUL:
case GNRC_LWMAC_RX_STATE_FAILED: {
break;
}
case GNRC_LWMAC_RX_STATE_STOPPED: {
LOG_DEBUG("[LWMAC-rx] Reception state machine is stopped\n");
}
}
return reschedule;
}
void gnrc_lwmac_rx_update(gnrc_netif_t *netif)
{
/* Update until no rescheduling needed */
while (_lwmac_rx_update(netif)) {}
}

View File

@ -1,147 +0,0 @@
/*
* 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 protocol
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <assert.h>
#include <errno.h>
#include "net/gnrc/lwmac/timeout.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static const char *lwmac_timeout_names[] = {
[GNRC_LWMAC_TIMEOUT_DISABLED] = "DISABLED",
[GNRC_LWMAC_TIMEOUT_WR] = "WR",
[GNRC_LWMAC_TIMEOUT_NO_RESPONSE] = "NO_RESPONSE",
[GNRC_LWMAC_TIMEOUT_DATA] = "DATA",
[GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP] = "WAIT_FOR_DEST_WAKEUP",
[GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD] = "WAKEUP_PERIOD",
};
static inline void _lwmac_clear_timeout(gnrc_lwmac_timeout_t *timeout)
{
assert(timeout);
xtimer_remove(&(timeout->timer));
timeout->type = GNRC_LWMAC_TIMEOUT_DISABLED;
}
/* Return index >= 0 if found, -ENONENT if not found */
static int _lwmac_find_timeout(gnrc_lwmac_t *lwmac, gnrc_lwmac_timeout_type_t type)
{
assert(lwmac);
for (unsigned i = 0; i < CONFIG_GNRC_LWMAC_TIMEOUT_COUNT; i++) {
if (lwmac->timeouts[i].type == type) {
return i;
}
}
return -ENOENT;
}
inline bool gnrc_lwmac_timeout_is_running(gnrc_netif_t *netif,
gnrc_lwmac_timeout_type_t type)
{
assert(netif);
return (_lwmac_find_timeout(&netif->mac.prot.lwmac, type) >= 0);
}
bool gnrc_lwmac_timeout_is_expired(gnrc_netif_t *netif, gnrc_lwmac_timeout_type_t type)
{
assert(netif);
int index = _lwmac_find_timeout(&netif->mac.prot.lwmac, type);
if (index >= 0) {
if (netif->mac.prot.lwmac.timeouts[index].expired) {
_lwmac_clear_timeout(&netif->mac.prot.lwmac.timeouts[index]);
}
return netif->mac.prot.lwmac.timeouts[index].expired;
}
return false;
}
gnrc_lwmac_timeout_t *_lwmac_acquire_timeout(gnrc_netif_t *netif,
gnrc_lwmac_timeout_type_t type)
{
assert(netif);
if (gnrc_lwmac_timeout_is_running(netif, type)) {
return NULL;
}
for (unsigned i = 0; i < CONFIG_GNRC_LWMAC_TIMEOUT_COUNT; i++) {
if (netif->mac.prot.lwmac.timeouts[i].type == GNRC_LWMAC_TIMEOUT_DISABLED) {
netif->mac.prot.lwmac.timeouts[i].type = type;
return &netif->mac.prot.lwmac.timeouts[i];
}
}
return NULL;
}
void gnrc_lwmac_timeout_make_expire(gnrc_lwmac_timeout_t *timeout)
{
assert(timeout);
timeout->expired = true;
}
void gnrc_lwmac_clear_timeout(gnrc_netif_t *netif, gnrc_lwmac_timeout_type_t type)
{
assert(netif);
int index = _lwmac_find_timeout(&netif->mac.prot.lwmac, type);
if (index >= 0) {
_lwmac_clear_timeout(&netif->mac.prot.lwmac.timeouts[index]);
}
}
void gnrc_lwmac_set_timeout(gnrc_netif_t *netif,
gnrc_lwmac_timeout_type_t type,
uint32_t offset)
{
assert(netif);
gnrc_lwmac_timeout_t *timeout;
if ((timeout = _lwmac_acquire_timeout(netif, type))) {
DEBUG("[LWMAC] Set timeout %s in %" PRIu32 " us\n",
lwmac_timeout_names[type], offset);
timeout->expired = false;
timeout->msg.type = GNRC_LWMAC_EVENT_TIMEOUT_TYPE;
timeout->msg.content.ptr = (void *) timeout;
xtimer_set_msg(&(timeout->timer), offset,
&(timeout->msg), netif->pid);
}
else {
DEBUG("[LWMAC] Cannot set timeout %s, too many concurrent timeouts\n",
lwmac_timeout_names[type]);
}
}
void gnrc_lwmac_reset_timeouts(gnrc_netif_t *netif)
{
assert(netif);
for (unsigned i = 0; i < CONFIG_GNRC_LWMAC_TIMEOUT_COUNT; i++) {
if (netif->mac.prot.lwmac.timeouts[i].type != GNRC_LWMAC_TIMEOUT_DISABLED) {
_lwmac_clear_timeout(&netif->mac.prot.lwmac.timeouts[i]);
}
}
}

View File

@ -1,814 +0,0 @@
/*
* 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 TX state machine of LWMAC protocol
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <assert.h>
#include "periph/rtt.h"
#include "net/gnrc.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "random.h"
#include "net/gnrc/mac/internal.h"
#include "net/gnrc/lwmac/timeout.h"
#include "include/tx_state_machine.h"
#include "include/lwmac_internal.h"
#ifndef LOG_LEVEL
/**
* @brief Default log level define
*/
#define LOG_LEVEL LOG_WARNING
#endif
#include "log.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief Flag to track if send packet success
*/
#define GNRC_LWMAC_TX_SUCCESS (0x01U)
/**
* @brief Flag to track if send packet fail
*/
#define GNRC_LWMAC_TX_FAIL (0x02U)
static uint8_t _send_bcast(gnrc_netif_t *netif)
{
assert(netif != NULL);
uint8_t tx_info = 0;
gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
bool first = false;
if (gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) {
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) {
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST);
gnrc_pktbuf_release(pkt);
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_SUCCESS;
return tx_info;
}
}
else {
LOG_INFO("[LWMAC-tx] Initialize broadcasting\n");
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END,
GNRC_LWMAC_BROADCAST_DURATION_US);
gnrc_pktsnip_t *pkt_payload;
/* Prepare packet with LWMAC header*/
gnrc_lwmac_frame_broadcast_t hdr;
hdr.header.type = GNRC_LWMAC_FRAMETYPE_BROADCAST;
hdr.seq_nr = netif->mac.tx.bcast_seqnr++;
pkt_payload = pkt->next;
pkt->next = gnrc_pktbuf_add(pkt->next, &hdr, sizeof(hdr), GNRC_NETTYPE_LWMAC);
if (pkt->next == NULL) {
LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type FRAMETYPE_BROADCAST\n");
netif->mac.tx.packet->next = pkt_payload;
/* Drop the broadcast packet */
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the broadcast packet\n");
gnrc_pktbuf_release(netif->mac.tx.packet);
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
/* No Auto-ACK for broadcast packets */
netopt_enable_t autoack = NETOPT_DISABLE;
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
sizeof(autoack));
first = true;
}
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST) ||
first) {
/* if found ongoing transmission, quit this cycle for collision avoidance.
* Broadcast packet will be re-queued and try to send in the next cycle. */
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
/* save pointer to netif header */
gnrc_pktsnip_t *netif_snip = pkt->next->next;
/* remove LWMAC header */
pkt->next->next = NULL;
gnrc_pktbuf_release(pkt->next);
/* make append netif header after payload again */
pkt->next = netif_snip;
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
/* Don't let the packet be released yet, we want to send it again */
gnrc_pktbuf_hold(pkt, 1);
int res = _gnrc_lwmac_transmit(netif, pkt);
if (res < 0) {
LOG_ERROR("ERROR: [LWMAC-tx] Send broadcast pkt failed.");
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST,
GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US);
LOG_INFO("[LWMAC-tx] Broadcast sent\n");
}
return tx_info;
}
static uint8_t _send_wr(gnrc_netif_t *netif)
{
assert(netif != NULL);
uint8_t tx_info = 0;
gnrc_pktsnip_t *pkt;
gnrc_pktsnip_t *pkt_lwmac;
gnrc_netif_hdr_t *nethdr;
/* if found ongoing transmission, quit this cycle for collision avoidance.
* Data packet will be re-queued and try to send in the next cycle. */
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
/* Assemble WR */
gnrc_lwmac_frame_wr_t wr_hdr;
wr_hdr.header.type = GNRC_LWMAC_FRAMETYPE_WR;
memcpy(&(wr_hdr.dst_addr.addr), netif->mac.tx.current_neighbor->l2_addr,
netif->mac.tx.current_neighbor->l2_addr_len);
wr_hdr.dst_addr.len = netif->mac.tx.current_neighbor->l2_addr_len;
pkt = gnrc_pktbuf_add(NULL, &wr_hdr, sizeof(wr_hdr), GNRC_NETTYPE_LWMAC);
if (pkt == NULL) {
LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
/* track the location of this lwmac_frame_wr_t header */
pkt_lwmac = pkt;
pkt = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_netif_hdr_t), GNRC_NETTYPE_NETIF);
if (pkt == NULL) {
LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_NETIF\n");
gnrc_pktbuf_release(pkt_lwmac);
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
gnrc_pktbuf_release(netif->mac.tx.packet);
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
/* We wouldn't get here if adding the NETIF header had failed, so no
* sanity checks needed */
nethdr = (gnrc_netif_hdr_t *) (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF))->data;
/* Construct NETIF header and insert address for WR packet */
gnrc_netif_hdr_init(nethdr, 0, 0);
/* Send WR as broadcast*/
nethdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
/* Disable Auto ACK */
netopt_enable_t autoack = NETOPT_DISABLE;
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
sizeof(autoack));
/* Prepare WR, this will discard any frame in the transceiver that has
* possibly arrived in the meantime but we don't care at this point. */
int res = _gnrc_lwmac_transmit(netif, pkt);
if (res < 0) {
LOG_ERROR("ERROR: [LWMAC-tx] Send WR failed.");
gnrc_pktbuf_release(pkt);
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
return tx_info;
}
static uint8_t _packet_process_in_wait_for_wa(gnrc_netif_t *netif)
{
assert(netif != NULL);
uint8_t tx_info = 0;
gnrc_pktsnip_t *pkt;
bool found_wa = false;
bool postponed = false;
bool from_expected_destination = false;
while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) {
LOG_DEBUG("[LWMAC-tx] Inspecting pkt @ %p\n", pkt);
/* Parse packet */
gnrc_lwmac_packet_info_t info;
int ret = _gnrc_lwmac_parse_packet(pkt, &info);
if (ret != 0) {
LOG_DEBUG("[LWMAC-tx] Packet could not be parsed: %i\n", ret);
gnrc_pktbuf_release(pkt);
continue;
}
if (memcmp(&info.src_addr.addr, &netif->mac.tx.current_neighbor->l2_addr,
netif->mac.tx.current_neighbor->l2_addr_len) == 0) {
from_expected_destination = true;
}
if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
_gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt);
gnrc_mac_dispatch(&netif->mac.rx);
/* Drop pointer to it can't get released */
pkt = NULL;
continue;
}
/* Check if destination is talking to another node. It will sleep
* after a finished transaction so there's no point in trying any
* further now. */
if (!(memcmp(&info.dst_addr.addr, &netif->l2addr,
netif->l2addr_len) == 0) && from_expected_destination) {
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
postponed = true;
gnrc_pktbuf_release(pkt);
break;
}
/* if found anther node is also trying to send data,
* quit this cycle for collision avoidance. */
if (info.header->type == GNRC_LWMAC_FRAMETYPE_WR) {
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
postponed = true;
gnrc_pktbuf_release(pkt);
break;
}
if (info.header->type != GNRC_LWMAC_FRAMETYPE_WA) {
LOG_DEBUG("[LWMAC-tx] Packet is not WA: 0x%02x\n", info.header->type);
gnrc_pktbuf_release(pkt);
continue;
}
if (from_expected_destination) {
/* calculate the phase of the receiver based on WA */
netif->mac.tx.timestamp = _gnrc_lwmac_phase_now();
gnrc_lwmac_frame_wa_t *wa_hdr;
wa_hdr = (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_LWMAC))->data;
if (netif->mac.tx.timestamp >= wa_hdr->current_phase) {
netif->mac.tx.timestamp = netif->mac.tx.timestamp -
wa_hdr->current_phase;
}
else {
netif->mac.tx.timestamp +=
RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US);
netif->mac.tx.timestamp -= wa_hdr->current_phase;
}
uint32_t own_phase;
own_phase = _gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup);
if (own_phase >= netif->mac.tx.timestamp) {
own_phase = own_phase - netif->mac.tx.timestamp;
}
else {
own_phase = netif->mac.tx.timestamp - own_phase;
}
if ((own_phase < RTT_US_TO_TICKS((3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2))) ||
(own_phase > RTT_US_TO_TICKS(CONFIG_GNRC_LWMAC_WAKEUP_INTERVAL_US -
(3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)))) {
gnrc_lwmac_set_phase_backoff(netif, true);
LOG_WARNING("WARNING: [LWMAC-tx] phase close\n");
}
}
/* No need to keep pkt anymore */
gnrc_pktbuf_release(pkt);
if (!from_expected_destination) {
LOG_DEBUG("[LWMAC-tx] Packet is not from expected destination\n");
break;
}
/* All checks passed so this must be a valid WA */
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR);
found_wa = true;
break;
}
if (postponed) {
LOG_INFO("[LWMAC-tx] Destination is talking to another node, postpone\n");
tx_info |= GNRC_LWMAC_TX_FAIL;
return tx_info;
}
if (!found_wa) {
LOG_DEBUG("[LWMAC-tx] No WA yet\n");
return tx_info;
}
/* Save newly calculated phase for destination */
netif->mac.tx.current_neighbor->phase = netif->mac.tx.timestamp;
LOG_INFO("[LWMAC-tx] New phase: %" PRIu32 "\n", netif->mac.tx.timestamp);
/* We've got our WA, so discard the rest, TODO: no flushing */
gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
tx_info |= GNRC_LWMAC_TX_SUCCESS;
return tx_info;
}
/* return false if send data failed, otherwise return true */
static bool _send_data(gnrc_netif_t *netif)
{
assert(netif != NULL);
gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
gnrc_pktsnip_t *pkt_payload;
assert(pkt != NULL);
/* Enable Auto ACK again */
netopt_enable_t autoack = NETOPT_ENABLE;
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK,
&autoack, sizeof(autoack));
/* It's okay to retry sending DATA. Timing doesn't matter anymore and
* destination is waiting for a certain amount of time. */
uint8_t csma_retries = CONFIG_GNRC_LWMAC_DATA_CSMA_RETRIES;
netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
&csma_retries, sizeof(csma_retries));
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
netopt_enable_t csma_enable = NETOPT_ENABLE;
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
&csma_enable, sizeof(csma_enable));
pkt_payload = pkt->next;
/* Insert LWMAC header above NETIF header. The burst (consecutive) transmission
* scheme works here (sender side). If the sender finds it has pending packets
* for the receiver (and under burst limit), it sets the packet type to
* FRAMETYPE_DATA_PENDING, to notice the receiver for next incoming packet.
* In case the sender has no more packet for the receiver, it simply sets the
* data type to FRAMETYPE_DATA. */
gnrc_lwmac_hdr_t hdr;
if ((gnrc_priority_pktqueue_length(&netif->mac.tx.current_neighbor->queue) > 0) &&
(netif->mac.tx.tx_burst_count < GNRC_LWMAC_MAX_TX_BURST_PKT_NUM)) {
hdr.type = GNRC_LWMAC_FRAMETYPE_DATA_PENDING;
gnrc_lwmac_set_tx_continue(netif, true);
netif->mac.tx.tx_burst_count++;
}
else {
hdr.type = GNRC_LWMAC_FRAMETYPE_DATA;
gnrc_lwmac_set_tx_continue(netif, false);
}
pkt->next = gnrc_pktbuf_add(pkt->next, &hdr, sizeof(hdr), GNRC_NETTYPE_LWMAC);
if (pkt->next == NULL) {
LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
netif->mac.tx.packet->next = pkt_payload;
gnrc_pktbuf_release(netif->mac.tx.packet);
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
return false;
}
/* if found ongoing transmission, quit this cycle for collision avoidance.
* Data packet will be re-queued and try to send in the next cycle. */
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
/* save pointer to netif header */
gnrc_pktsnip_t *netif_snip = pkt->next->next;
/* remove LWMAC header */
pkt->next->next = NULL;
gnrc_pktbuf_release(pkt->next);
/* make append netif header after payload again */
pkt->next = netif_snip;
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
return false;
}
/* Send data */
int res = _gnrc_lwmac_transmit(netif, pkt);
if (res < 0) {
LOG_ERROR("ERROR: [LWMAC-tx] Send data failed.");
gnrc_pktbuf_release(pkt);
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
return false;
}
/* Packet has been released by netdev, so drop pointer */
netif->mac.tx.packet = NULL;
DEBUG("[LWMAC-tx]: spent %lu WR in TX\n",
(unsigned long)netif->mac.tx.wr_sent);
#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
netif->mac.prot.lwmac.pkt_start_sending_time_ticks =
rtt_get_counter() - netif->mac.prot.lwmac.pkt_start_sending_time_ticks;
DEBUG("[LWMAC-tx]: pkt sending delay in TX: %lu us\n",
RTT_TICKS_TO_US(netif->mac.prot.lwmac.pkt_start_sending_time_ticks));
#endif
return true;
}
void gnrc_lwmac_tx_start(gnrc_netif_t *netif,
gnrc_pktsnip_t *pkt,
gnrc_mac_tx_neighbor_t *neighbor)
{
assert(netif != NULL);
assert(pkt != NULL);
assert(neighbor != NULL);
if (netif->mac.tx.packet) {
LOG_WARNING("WARNING: [LWMAC-tx] Starting but tx.packet is still set\n");
gnrc_pktbuf_release(netif->mac.tx.packet);
}
netif->mac.tx.packet = pkt;
netif->mac.tx.current_neighbor = neighbor;
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_INIT;
netif->mac.tx.wr_sent = 0;
#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
netif->mac.prot.lwmac.pkt_start_sending_time_ticks = rtt_get_counter();
#endif
}
void gnrc_lwmac_tx_stop(gnrc_netif_t *netif)
{
assert(netif != NULL);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END);
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_STOPPED;
/* Release packet in case of failure */
if (netif->mac.tx.packet) {
if (netif->mac.tx.tx_retry_count >= CONFIG_GNRC_LWMAC_MAX_DATA_TX_RETRIES) {
netif->mac.tx.tx_retry_count = 0;
gnrc_pktbuf_release(netif->mac.tx.packet);
netif->mac.tx.packet = NULL;
LOG_WARNING("WARNING: [LWMAC-tx] Drop TX packet\n");
}
else {
netif->mac.tx.tx_retry_count++;
return;
}
}
if (!gnrc_lwmac_get_tx_continue(netif)) {
netif->mac.tx.current_neighbor = NULL;
}
}
/* Returns whether rescheduling is needed or not */
static bool _lwmac_tx_update(gnrc_netif_t *netif)
{
assert(netif != NULL);
bool reschedule = false;
switch (netif->mac.tx.state) {
case GNRC_LWMAC_TX_STATE_INIT: {
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST);
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END);
/* if found ongoing transmission,
* quit this cycle for collision avoidance. */
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
/* check if the packet is for broadcast */
if (gnrc_netif_hdr_get_flag(netif->mac.tx.packet) &
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
/* Set CSMA retries as configured and enable */
uint8_t csma_retries = CONFIG_GNRC_LWMAC_BROADCAST_CSMA_RETRIES;
netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
&csma_retries, sizeof(csma_retries));
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
netopt_enable_t csma_enable = NETOPT_ENABLE;
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
&csma_enable, sizeof(csma_enable));
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_BROADCAST;
reschedule = true;
break;
}
else {
/* Use CSMA for the first WR */
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
netopt_enable_t csma_disable = NETOPT_ENABLE;
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
&csma_disable, sizeof(csma_disable));
/* Set a timeout for the maximum transmission procedure */
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE, GNRC_LWMAC_PREAMBLE_DURATION_US);
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
reschedule = true;
break;
}
}
case GNRC_LWMAC_TX_STATE_SEND_BROADCAST: {
uint8_t tx_info = _send_bcast(netif);
if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
reschedule = true;
break;
}
if (tx_info & GNRC_LWMAC_TX_FAIL) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
break;
}
case GNRC_LWMAC_TX_STATE_SEND_WR: {
/* In case of no Tx-isr error (e.g., no Tx-isr), goto TX failure. */
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination, "
"probably no TX-ISR\n");
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_WR\n");
uint8_t tx_info = _send_wr(netif);
if (tx_info & GNRC_LWMAC_TX_FAIL) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_WR_SENT;
reschedule = false;
break;
}
case GNRC_LWMAC_TX_STATE_WAIT_WR_SENT: {
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_WR_SENT\n");
/* In case of no Tx-isr error (e.g., no Tx-isr), goto TX failure. */
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
LOG_DEBUG("[LWMAC-tx] WR not yet completely sent\n");
break;
}
/* If found ongoing transmission, goto TX failure, i.e., postpone transmission to
* next cycle. This is mainly for collision avoidance. */
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* clear packet point to avoid TX retry */
netif->mac.tx.packet = NULL;
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
if (netif->mac.tx.wr_sent == 0) {
/* Only the first WR use CSMA */
netif->mac.mac_info &= ~GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
netopt_enable_t csma_disable = NETOPT_DISABLE;
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
&csma_disable, sizeof(csma_disable));
}
netif->mac.tx.wr_sent++;
/* Set timeout for next WR in case no WA will be received */
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WR,
CONFIG_GNRC_LWMAC_TIME_BETWEEN_WR_US);
/* Debug WR timing */
LOG_DEBUG("[LWMAC-tx] Destination phase was: %" PRIu32 "\n",
netif->mac.tx.current_neighbor->phase);
LOG_DEBUG("[LWMAC-tx] Phase when sent was: %" PRIu32 "\n",
_gnrc_lwmac_ticks_to_phase(netif->mac.tx.timestamp));
LOG_DEBUG("[LWMAC-tx] Ticks when sent was: %" PRIu32 "\n",
netif->mac.tx.timestamp);
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FOR_WA;
reschedule = false;
break;
}
case GNRC_LWMAC_TX_STATE_WAIT_FOR_WA: {
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FOR_WA\n");
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
netif->mac.tx.preamble_fail_counts++;
break;
}
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WR)) {
/* In case the sender is in consecutive (burst) transmission to the receiver,
* meaning that the sender has already successfully sent at least one data to
* the receiver, then the sender will only spend one WR for triggering the next
* transmission procedure. And, if this WR doesn't work (no WA replied), the
* sender regards consecutive transmission failed.
*/
if (gnrc_lwmac_get_tx_continue(netif)) {
LOG_DEBUG("[LWMAC-tx] Tx burst fail\n");
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
gnrc_pktbuf_release(netif->mac.tx.packet);
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
}
/* drop pointer so it won't be free'd */
netif->mac.tx.packet = NULL;
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
else {
/* If this is the first transmission to the receiver for locating the
* latter's wake-up period, the sender just keep sending WRs until it
* finds the WA.
*/
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
reschedule = true;
break;
}
}
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
/* Wait for completion of frame reception */
break;
}
uint8_t tx_info = _packet_process_in_wait_for_wa(netif);
if (tx_info & GNRC_LWMAC_TX_FAIL) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_DATA;
reschedule = true;
netif->mac.tx.preamble_fail_counts = 0;
break;
}
else {
/* No WA yet */
break;
}
}
case GNRC_LWMAC_TX_STATE_SEND_DATA: {
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_DATA\n");
if (!_send_data(netif)) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK;
reschedule = false;
break;
}
case GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK: {
/* In case of no Tx-isr error, goto TX failure. */
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK\n");
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
break;
}
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_SUCCESS) {
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
reschedule = true;
break;
}
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_NOACK) {
LOG_ERROR("ERROR: [LWMAC-tx] Not ACKED\n");
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
LOG_ERROR("ERROR: [LWMAC-tx] Channel busy \n");
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
LOG_ERROR("ERROR: [LWMAC-tx] Tx feedback unhandled: %i\n",
gnrc_netif_get_tx_feedback(netif));
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
reschedule = true;
break;
}
case GNRC_LWMAC_TX_STATE_SUCCESSFUL:
case GNRC_LWMAC_TX_STATE_FAILED: {
break;
}
case GNRC_LWMAC_TX_STATE_STOPPED: {
LOG_DEBUG("[LWMAC-tx] Transmission state machine is stopped\n");
}
}
return reschedule;
}
void gnrc_lwmac_tx_update(gnrc_netif_t *netif)
{
/* Update until no rescheduling needed */
while (_lwmac_tx_update(netif)) {}
}

View File

@ -242,18 +242,6 @@ 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])) {

View File

@ -22,9 +22,6 @@
#include "log.h"
#include "board.h"
#include "net/gnrc/netif/ieee802154.h"
#ifdef MODULE_GNRC_LWMAC
#include "net/gnrc/lwmac/lwmac.h"
#endif
#include "net/gnrc.h"
#include "include/init_devs.h"
@ -55,15 +52,7 @@ static inline void _setup_netif(gnrc_netif_t *netif, void* netdev, void* stack,
if (netif == NULL || netdev == NULL) {
return;
}
#if defined(MODULE_GNRC_LWMAC)
gnrc_netif_lwmac_create(netif, stack,
AT86RF215_MAC_STACKSIZE,
prio, name, netdev);
#else
gnrc_netif_ieee802154_create(netif, stack,
AT86RF215_MAC_STACKSIZE,
prio, name, netdev);
#endif
gnrc_netif_ieee802154_create(netif, stack, AT86RF215_MAC_STACKSIZE, prio, name, netdev);
}
void auto_init_at86rf215(void)

View File

@ -20,9 +20,6 @@
#include "log.h"
#include "board.h"
#include "net/gnrc/netif/ieee802154.h"
#ifdef MODULE_GNRC_LWMAC
#include "net/gnrc/lwmac/lwmac.h"
#endif
#include "net/gnrc.h"
#include "include/init_devs.h"
@ -50,17 +47,10 @@ void auto_init_at86rf2xx(void)
LOG_DEBUG("[auto_init_netif] initializing at86rf2xx #%u\n", i);
at86rf2xx_setup(&at86rf2xx_devs[i], &at86rf2xx_params[i], i);
#if defined(MODULE_GNRC_LWMAC)
gnrc_netif_lwmac_create(&_netif[i], _at86rf2xx_stacks[i],
AT86RF2XX_MAC_STACKSIZE,
AT86RF2XX_MAC_PRIO, "at86rf2xx-lwmac",
&at86rf2xx_devs[i].netdev.netdev);
#else
gnrc_netif_ieee802154_create(&_netif[i], _at86rf2xx_stacks[i],
AT86RF2XX_MAC_STACKSIZE,
AT86RF2XX_MAC_PRIO, "at86rf2xx",
&at86rf2xx_devs[i].netdev.netdev);
#endif
}
}
/** @} */

View File

@ -24,10 +24,6 @@
#include "net/gnrc/netif/ieee802154.h"
#include "include/init_devs.h"
#ifdef MODULE_GNRC_LWMAC
#include "net/gnrc/lwmac/lwmac.h"
#endif
#include "kw41zrf.h"
/**
@ -56,15 +52,9 @@ void auto_init_kw41zrf(void)
LOG_DEBUG("[auto_init_netif] initializing kw41zrf #%u\n", i);
kw41zrf_setup(&kw41zrf_devs[i], i);
#if defined(MODULE_GNRC_LWMAC)
gnrc_netif_lwmac_create(&_netif[i], _kw41zrf_stacks[i], KW41ZRF_NETIF_STACKSIZE,
KW41ZRF_NETIF_PRIO, "kw41zrf-lwmac",
&kw41zrf_devs[i].netdev.netdev);
#else
gnrc_netif_ieee802154_create(&_netif[i], _kw41zrf_stacks[i], KW41ZRF_NETIF_STACKSIZE,
KW41ZRF_NETIF_PRIO, "kw41zrf",
&kw41zrf_devs[i].netdev.netdev);
#endif
}
}
/** @} */

View File

@ -4,7 +4,7 @@ ifneq (,$(filter ztimer_xtimer_compat,$(USEMODULE)))
PSEUDOMODULES += xtimer
endif
MODULES_ZTIMER_ON_RTT_CONFLICT = rtt_rtc gnrc_lwmac
MODULES_ZTIMER_ON_RTT_CONFLICT = rtt_rtc
# By defaul use highest possible RTT_FREQUENCY for platforms that allow it. This
# might not be the most optimized for conversion guarantees that ztimer_periph_rtt

View File

@ -1,38 +0,0 @@
# use samr21-xpro as default:
BOARD ?= samr21-xpro
include ../Makefile.net_common
# 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
# Modules to include:
USEMODULE += shell
USEMODULE += shell_cmds_default
USEMODULE += ps
# Use modules for networking
# gnrc is a meta module including all required, basic gnrc networking modules
USEMODULE += gnrc
# use the default network interface for the board
USEMODULE += netdev_default
# automatically initialize the network interface
USEMODULE += auto_init_gnrc_netif
# shell command to send L2 packets with a simple string
USEMODULE += gnrc_txtsnd
# the application dumps received packets to stdout
USEMODULE += gnrc_pktdump
# Use LWMAC
USEMODULE += gnrc_lwmac
include $(RIOTBASE)/Makefile.include
# We use only the lower layers of the GNRC network stack, hence, we can
# reduce the size of the packet buffer a bit
# Set GNRC_PKTBUF_SIZE via CFLAGS if not being set via Kconfig.
ifndef CONFIG_GNRC_PKTBUF_SIZE
CFLAGS += -DCONFIG_GNRC_PKTBUF_SIZE=512
endif
# Set a custom channel if needed
include $(RIOTMAKE)/default-radio-settings.inc.mk

View File

@ -1,53 +0,0 @@
LWMAC test application
======================
This application is a showcase for testing LWMAC communications. Using it
for your board, you should be able to interactively use any hardware
that is supported for communications among devices based on LWMAC.
Usage
=====
Build, flash and start the application:
```
export BOARD=your_board
make
make flash
make term
```
The `term` make target starts a terminal emulator for your board. It
connects to a default port so you can interact with the shell, usually
that is `/dev/ttyUSB0`. If your port is named differently, the
`PORT=/dev/yourport` variable can be used to override this.
Example output
==============
The `ifconfig` command will help you to configure all available network
interfaces. On an samr21 board it will print something like:
```
2015-09-16 16:58:37,762 - INFO # ifconfig
2015-09-16 16:58:37,766 - INFO # Iface 4 HWaddr: 9e:72 Channel: 26 NID: 0x23 TX-Power: 0dBm State: IDLE CSMA Retries: 4
2015-09-16 16:58:37,768 - INFO # Long HWaddr: 36:32:48:33:46:da:9e:72
2015-09-16 16:58:37,769 - INFO # AUTOACK CSMA
2015-09-16 16:58:37,770 - INFO # Source address length: 2
```
The `txtsnd` command allows you to send a simple string directly over the link
layer (here, it is LWMAC) using unicast or broadcast. The application will also automatically print
information about any received packet over the serial. This will look like:
```
2015-09-16 16:59:29,187 - INFO # PKTDUMP: data received:
2015-09-16 16:59:29,189 - INFO # ~~ SNIP 0 - size: 28 byte, type:
NETTYPE_UNDEF (0)
2015-09-16 16:59:29,190 - INFO # 000000 7b 3b 3a 02 85 00 e7 fb 00 00 00 00 01
02 5a 55
2015-09-16 16:59:29,192 - INFO # 000010 40 42 3e 62 f2 1a 00 00 00 00 00 00
2015-09-16 16:59:29,194 - INFO # ~~ SNIP 1 - size: 18 byte, type:
NETTYPE_NETIF (-1)
2015-09-16 16:59:29,195 - INFO # if_pid: 4 rssi: 49 lqi: 78
2015-09-16 16:59:29,196 - INFO # src_l2addr: 5a:55:40:42:3e:62:f2:1a
2015-09-16 16:59:29,197 - INFO # dst_l2addr: ff:ff
2015-09-16 16:59:29,198 - INFO # ~~ PKT - 2 snips, total size: 46 byte
```

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2008, 2009, 2010 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2013 INRIA
* Copyright (C) 2013 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for testing the LWMAC implementation
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include "thread.h"
#include "shell.h"
#include "net/gnrc/pktdump.h"
#include "net/gnrc.h"
int main(void)
{
puts("LWMAC test application");
gnrc_netreg_entry_t dump = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
gnrc_pktdump_pid);
gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump);
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}