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:
commit
1345452bbe
@ -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
|
||||
|
||||
@ -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
|
||||
## @{
|
||||
|
||||
@ -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
|
||||
|
||||
/** @} */
|
||||
@ -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
|
||||
|
||||
/** @} */
|
||||
@ -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
|
||||
|
||||
/** @} */
|
||||
@ -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
|
||||
|
||||
/** @} */
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -1,3 +0,0 @@
|
||||
MODULE = gnrc_lwmac
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
@ -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
|
||||
|
||||
/** @} */
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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)) {}
|
||||
}
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)) {}
|
||||
}
|
||||
@ -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])) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
```
|
||||
@ -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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user