2017-01-31 17:25:32 +01:00
|
|
|
/*
|
|
|
|
* 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 "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"
|
|
|
|
|
|
|
|
#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 send packet success
|
|
|
|
*/
|
|
|
|
#define GNRC_LWMAC_TX_SUCCESS (0x01U)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Flag to track if send packet fail
|
|
|
|
*/
|
|
|
|
#define GNRC_LWMAC_TX_FAIL (0x02U)
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
static uint8_t _send_bcast(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
uint8_t tx_info = 0;
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
|
2017-01-31 17:25:32 +01:00
|
|
|
bool first = false;
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
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);
|
2017-01-31 17:25:32 +01:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
tx_info |= GNRC_LWMAC_TX_SUCCESS;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG_INFO("[LWMAC-tx] Initialize broadcasting\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END,
|
|
|
|
GNRC_LWMAC_BROADCAST_DURATION_US);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
gnrc_pktsnip_t *pkt_payload;
|
|
|
|
|
|
|
|
/* Prepare packet with LWMAC header*/
|
2017-11-29 14:44:30 +01:00
|
|
|
gnrc_lwmac_frame_broadcast_t hdr;
|
2017-01-31 17:25:32 +01:00
|
|
|
hdr.header.type = GNRC_LWMAC_FRAMETYPE_BROADCAST;
|
2017-10-19 19:40:58 +02:00
|
|
|
hdr.seq_nr = netif->mac.tx.bcast_seqnr++;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
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");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet->next = pkt_payload;
|
2017-01-31 17:25:32 +01:00
|
|
|
/* Drop the broadcast packet */
|
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the broadcast packet\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
tx_info |= GNRC_LWMAC_TX_FAIL;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No Auto-ACK for broadcast packets */
|
|
|
|
netopt_enable_t autoack = NETOPT_DISABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
|
|
|
|
sizeof(autoack));
|
2017-01-31 17:25:32 +01:00
|
|
|
first = true;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST) ||
|
2017-01-31 17:25:32 +01:00
|
|
|
first) {
|
|
|
|
/* if found ongoing transmission, quit this cycle for collision avoidance.
|
2017-10-19 19:40:58 +02:00
|
|
|
* Broadcast packet will be re-queued and try to send in the next cycle. */
|
|
|
|
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
|
2017-01-31 17:25:32 +01:00
|
|
|
/* save pointer to netif header */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktsnip_t *netif_snip = pkt->next->next;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* remove LWMAC header */
|
|
|
|
pkt->next->next = NULL;
|
|
|
|
gnrc_pktbuf_release(pkt->next);
|
|
|
|
|
|
|
|
/* make append netif header after payload again */
|
2017-10-19 19:40:58 +02:00
|
|
|
pkt->next = netif_snip;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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);
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
int res = _gnrc_lwmac_transmit(netif, pkt);
|
2017-01-31 17:25:32 +01:00
|
|
|
if (res < 0) {
|
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Send broadcast pkt failed.");
|
|
|
|
tx_info |= GNRC_LWMAC_TX_FAIL;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST,
|
|
|
|
GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_INFO("[LWMAC-tx] Broadcast sent\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
static uint8_t _send_wr(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
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. */
|
2017-10-19 19:40:58 +02:00
|
|
|
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);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
tx_info |= GNRC_LWMAC_TX_FAIL;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assemble WR */
|
2017-11-29 14:44:30 +01:00
|
|
|
gnrc_lwmac_frame_wr_t wr_hdr;
|
2017-01-31 17:25:32 +01:00
|
|
|
wr_hdr.header.type = GNRC_LWMAC_FRAMETYPE_WR;
|
2017-10-19 19:40:58 +02:00
|
|
|
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;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
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");
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
|
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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");
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
|
|
|
|
sizeof(autoack));
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* Prepare WR, this will discard any frame in the transceiver that has
|
2017-10-19 19:40:58 +02:00
|
|
|
* possibly arrived in the meantime but we don't care at this point. */
|
|
|
|
int res = _gnrc_lwmac_transmit(netif, pkt);
|
2017-01-31 17:25:32 +01:00
|
|
|
if (res < 0) {
|
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Send WR failed.");
|
2019-09-20 09:01:01 +02:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2017-01-31 17:25:32 +01:00
|
|
|
tx_info |= GNRC_LWMAC_TX_FAIL;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
|
2017-01-31 17:25:32 +01:00
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
static uint8_t _packet_process_in_wait_for_wa(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
uint8_t tx_info = 0;
|
|
|
|
gnrc_pktsnip_t *pkt;
|
|
|
|
bool found_wa = false;
|
|
|
|
bool postponed = false;
|
|
|
|
bool from_expected_destination = false;
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) {
|
2017-01-31 17:25:32 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (memcmp(&info.src_addr.addr, &netif->mac.tx.current_neighbor->l2_addr,
|
|
|
|
netif->mac.tx.current_neighbor->l2_addr_len) == 0) {
|
2017-01-31 17:25:32 +01:00
|
|
|
from_expected_destination = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
|
2017-10-19 19:40:58 +02:00
|
|
|
_gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt);
|
|
|
|
gnrc_mac_dispatch(&netif->mac.rx);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* 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. */
|
2017-10-19 19:40:58 +02:00
|
|
|
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);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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) {
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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 */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.timestamp = _gnrc_lwmac_phase_now();
|
2017-01-31 17:25:32 +01:00
|
|
|
gnrc_lwmac_frame_wa_t *wa_hdr;
|
|
|
|
wa_hdr = (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_LWMAC))->data;
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (netif->mac.tx.timestamp >= wa_hdr->current_phase) {
|
|
|
|
netif->mac.tx.timestamp = netif->mac.tx.timestamp -
|
|
|
|
wa_hdr->current_phase;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.timestamp += RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US);
|
|
|
|
netif->mac.tx.timestamp -= wa_hdr->current_phase;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t own_phase;
|
2016-04-10 20:17:45 +02:00
|
|
|
own_phase = _gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (own_phase >= netif->mac.tx.timestamp) {
|
|
|
|
own_phase = own_phase - netif->mac.tx.timestamp;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-19 19:40:58 +02:00
|
|
|
own_phase = netif->mac.tx.timestamp - own_phase;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((own_phase < RTT_US_TO_TICKS((3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2))) ||
|
|
|
|
(own_phase > RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US -
|
|
|
|
(3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)))) {
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_phase_backoff(netif, true);
|
2017-01-31 17:25:32 +01:00
|
|
|
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 */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
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 */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.current_neighbor->phase = netif->mac.tx.timestamp;
|
|
|
|
LOG_INFO("[LWMAC-tx] New phase: %" PRIu32 "\n", netif->mac.tx.timestamp);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* We've got our WA, so discard the rest, TODO: no flushing */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
tx_info |= GNRC_LWMAC_TX_SUCCESS;
|
|
|
|
return tx_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return false if send data failed, otherwise return true */
|
2017-11-16 18:06:46 +01:00
|
|
|
static bool _send_data(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
|
2017-01-31 17:25:32 +01:00
|
|
|
gnrc_pktsnip_t *pkt_payload;
|
|
|
|
|
2017-11-16 15:07:08 +01:00
|
|
|
assert(pkt != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* Enable Auto ACK again */
|
|
|
|
netopt_enable_t autoack = NETOPT_ENABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_AUTOACK,
|
|
|
|
&autoack, sizeof(autoack));
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* 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 = GNRC_LWMAC_DATA_CSMA_RETRIES;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
|
|
|
|
&csma_retries, sizeof(csma_retries));
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
|
2017-01-31 17:25:32 +01:00
|
|
|
netopt_enable_t csma_enable = NETOPT_ENABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
|
|
|
|
&csma_enable, sizeof(csma_enable));
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
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;
|
2017-10-19 19:40:58 +02:00
|
|
|
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)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
hdr.type = GNRC_LWMAC_FRAMETYPE_DATA_PENDING;
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_tx_continue(netif, true);
|
|
|
|
netif->mac.tx.tx_burst_count++;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
hdr.type = GNRC_LWMAC_FRAMETYPE_DATA;
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_tx_continue(netif, false);
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet->next = pkt_payload;
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
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. */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
|
2017-01-31 17:25:32 +01:00
|
|
|
/* save pointer to netif header */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktsnip_t *netif_snip = pkt->next->next;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* remove LWMAC header */
|
|
|
|
pkt->next->next = NULL;
|
|
|
|
gnrc_pktbuf_release(pkt->next);
|
|
|
|
|
|
|
|
/* make append netif header after payload again */
|
2017-10-19 19:40:58 +02:00
|
|
|
pkt->next = netif_snip;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send data */
|
2017-10-19 19:40:58 +02:00
|
|
|
int res = _gnrc_lwmac_transmit(netif, pkt);
|
2017-01-31 17:25:32 +01:00
|
|
|
if (res < 0) {
|
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Send data failed.");
|
2017-11-16 15:07:08 +01:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2017-01-31 17:25:32 +01:00
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Packet has been released by netdev, so drop pointer */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2018-07-19 14:08:07 +02:00
|
|
|
DEBUG("[LWMAC-tx]: spent %lu WR in TX\n",
|
|
|
|
(unsigned long)netif->mac.tx.wr_sent);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
|
2016-04-10 20:17:45 +02:00
|
|
|
netif->mac.prot.lwmac.pkt_start_sending_time_ticks =
|
|
|
|
rtt_get_counter() - netif->mac.prot.lwmac.pkt_start_sending_time_ticks;
|
2017-01-31 17:25:32 +01:00
|
|
|
DEBUG("[LWMAC-tx]: pkt sending delay in TX: %lu us\n",
|
2016-04-10 20:17:45 +02:00
|
|
|
RTT_TICKS_TO_US(netif->mac.prot.lwmac.pkt_start_sending_time_ticks));
|
2017-01-31 17:25:32 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
void gnrc_lwmac_tx_start(gnrc_netif_t *netif,
|
2017-01-31 17:25:32 +01:00
|
|
|
gnrc_pktsnip_t *pkt,
|
|
|
|
gnrc_mac_tx_neighbor_t *neighbor)
|
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
assert(pkt != NULL);
|
|
|
|
assert(neighbor != NULL);
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (netif->mac.tx.packet) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] Starting but tx.packet is still set\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
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;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
|
2016-04-10 20:17:45 +02:00
|
|
|
netif->mac.prot.lwmac.pkt_start_sending_time_ticks = rtt_get_counter();
|
2017-01-31 17:25:32 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
void gnrc_lwmac_tx_stop(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
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;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* Release packet in case of failure */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (netif->mac.tx.packet) {
|
|
|
|
if (netif->mac.tx.tx_retry_count >= 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;
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] Drop TX packet\n");
|
|
|
|
}
|
|
|
|
else {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.tx_retry_count++;
|
2017-01-31 17:25:32 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_lwmac_get_tx_continue(netif)) {
|
|
|
|
netif->mac.tx.current_neighbor = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns whether rescheduling is needed or not */
|
2017-11-16 18:06:46 +01:00
|
|
|
static bool _lwmac_tx_update(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
2017-10-19 19:40:58 +02:00
|
|
|
assert(netif != NULL);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
bool reschedule = false;
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
switch (netif->mac.tx.state) {
|
2017-01-31 17:25:32 +01:00
|
|
|
case GNRC_LWMAC_TX_STATE_INIT: {
|
2017-10-19 19:40:58 +02:00
|
|
|
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);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* if found ongoing transmission,
|
|
|
|
* quit this cycle for collision avoidance. */
|
2017-10-19 19:40:58 +02:00
|
|
|
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);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the packet is for broadcast */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_netif_hdr_get_flag(netif->mac.tx.packet) &
|
2017-01-31 17:25:32 +01:00
|
|
|
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
|
|
|
|
/* Set CSMA retries as configured and enable */
|
|
|
|
uint8_t csma_retries = GNRC_LWMAC_BROADCAST_CSMA_RETRIES;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
|
|
|
|
&csma_retries, sizeof(csma_retries));
|
2017-11-16 18:06:46 +01:00
|
|
|
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
|
2017-01-31 17:25:32 +01:00
|
|
|
netopt_enable_t csma_enable = NETOPT_ENABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
|
|
|
|
&csma_enable, sizeof(csma_enable));
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_BROADCAST;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Use CSMA for the first WR */
|
2017-11-16 18:06:46 +01:00
|
|
|
netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
|
2017-01-31 17:25:32 +01:00
|
|
|
netopt_enable_t csma_disable = NETOPT_ENABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
|
|
|
|
&csma_disable, sizeof(csma_disable));
|
2017-01-31 17:25:32 +01:00
|
|
|
/* Set a timeout for the maximum transmission procedure */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE, GNRC_LWMAC_PREAMBLE_DURATION_US);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case GNRC_LWMAC_TX_STATE_SEND_BROADCAST: {
|
2017-10-19 19:40:58 +02:00
|
|
|
uint8_t tx_info = _send_bcast(netif);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tx_info & GNRC_LWMAC_TX_FAIL) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
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. */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination, "
|
2017-10-19 19:40:58 +02:00
|
|
|
"probably no TX-ISR\n");
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_WR\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
uint8_t tx_info = _send_wr(netif);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
if (tx_info & GNRC_LWMAC_TX_FAIL) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_WR_SENT;
|
2017-01-31 17:25:32 +01:00
|
|
|
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. */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
|
2017-01-31 17:25:32 +01:00
|
|
|
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. */
|
2017-11-16 18:06:46 +01:00
|
|
|
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
|
|
|
/* clear packet point to avoid TX retry */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (netif->mac.tx.wr_sent == 0) {
|
2017-01-31 17:25:32 +01:00
|
|
|
/* Only the first WR use CSMA */
|
2017-11-16 18:06:46 +01:00
|
|
|
netif->mac.mac_info &= ~GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
|
2017-01-31 17:25:32 +01:00
|
|
|
netopt_enable_t csma_disable = NETOPT_DISABLE;
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->dev->driver->set(netif->dev, NETOPT_CSMA,
|
|
|
|
&csma_disable, sizeof(csma_disable));
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.wr_sent++;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* Set timeout for next WR in case no WA will be received */
|
2017-10-19 19:40:58 +02:00
|
|
|
gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WR, GNRC_LWMAC_TIME_BETWEEN_WR_US);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
/* Debug WR timing */
|
|
|
|
LOG_DEBUG("[LWMAC-tx] Destination phase was: %" PRIu32 "\n",
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.current_neighbor->phase);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_DEBUG("[LWMAC-tx] Phase when sent was: %" PRIu32 "\n",
|
2017-10-19 19:40:58 +02:00
|
|
|
_gnrc_lwmac_ticks_to_phase(netif->mac.tx.timestamp));
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_DEBUG("[LWMAC-tx] Ticks when sent was: %" PRIu32 "\n",
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.timestamp);
|
|
|
|
_gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FOR_WA;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GNRC_LWMAC_TX_STATE_WAIT_FOR_WA: {
|
|
|
|
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FOR_WA\n");
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WR)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_get_tx_continue(netif)) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_DEBUG("[LWMAC-tx] Tx burst fail\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
|
|
|
|
gnrc_pktbuf_release(netif->mac.tx.packet);
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
|
|
|
|
}
|
2019-10-23 21:16:23 +02:00
|
|
|
/* drop pointer so it won't be free'd */
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.packet = NULL;
|
2017-01-31 17:25:32 +01:00
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
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.
|
|
|
|
*/
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
|
2017-01-31 17:25:32 +01:00
|
|
|
/* Wait for completion of frame reception */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
uint8_t tx_info = _packet_process_in_wait_for_wa(netif);
|
2017-01-31 17:25:32 +01:00
|
|
|
|
|
|
|
if (tx_info & GNRC_LWMAC_TX_FAIL) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_DATA;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* No WA yet */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case GNRC_LWMAC_TX_STATE_SEND_DATA: {
|
|
|
|
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_DATA\n");
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
if (!_send_data(netif)) {
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK: {
|
|
|
|
/* In case of no Tx-isr error, goto TX failure. */
|
2017-10-19 19:40:58 +02:00
|
|
|
if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
|
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK\n");
|
2017-11-16 18:06:46 +01:00
|
|
|
if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
|
2017-01-31 17:25:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-11-16 18:06:46 +01:00
|
|
|
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_SUCCESS) {
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
2017-11-16 18:06:46 +01:00
|
|
|
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_NOACK) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Not ACKED\n");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
2017-11-16 18:06:46 +01:00
|
|
|
else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
|
2017-01-31 17:25:32 +01:00
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Channel busy \n");
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
reschedule = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_ERROR("ERROR: [LWMAC-tx] Tx feedback unhandled: %i\n",
|
2017-11-16 18:06:46 +01:00
|
|
|
gnrc_netif_get_tx_feedback(netif));
|
2017-10-19 19:40:58 +02:00
|
|
|
netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
|
2017-01-31 17:25:32 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
void gnrc_lwmac_tx_update(gnrc_netif_t *netif)
|
2017-01-31 17:25:32 +01:00
|
|
|
{
|
|
|
|
/* Update until no rescheduling needed */
|
2017-10-19 19:40:58 +02:00
|
|
|
while (_lwmac_tx_update(netif)) {}
|
2017-01-31 17:25:32 +01:00
|
|
|
}
|