mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14950 from jia200x/pr/ieee802154/submac
ieee802154_submac: add initial support for common MAC sub layer
This commit is contained in:
commit
6cb8da7813
13
Makefile.dep
13
Makefile.dep
@ -103,6 +103,11 @@ ifneq (,$(filter netdev_ieee802154,$(USEMODULE)))
|
||||
USEMODULE += random
|
||||
endif
|
||||
|
||||
ifneq (,$(filter netdev_ieee802154_submac,$(USEMODULE)))
|
||||
USEMODULE += ieee802154_radio_hal
|
||||
USEMODULE += ieee802154_submac
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_dhcpv6_%, $(USEMODULE)))
|
||||
USEMODULE += gnrc_dhcpv6
|
||||
endif
|
||||
@ -186,6 +191,9 @@ ifneq (,$(filter gnrc_netif,$(USEMODULE)))
|
||||
USEMODULE += netif
|
||||
USEMODULE += l2util
|
||||
USEMODULE += fmt
|
||||
ifneq (,$(filter netdev_ieee802154_submac,$(USEMODULE)))
|
||||
USEMODULE += gnrc_netif_pktq
|
||||
endif
|
||||
ifneq (,$(filter netdev_ieee802154,$(USEMODULE)))
|
||||
USEMODULE += gnrc_netif_ieee802154
|
||||
endif
|
||||
@ -432,6 +440,11 @@ ifneq (,$(filter gnrc_pktdump,$(USEMODULE)))
|
||||
USEMODULE += od
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ieee802154_submac,$(USEMODULE)))
|
||||
USEMODULE += luid
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter od,$(USEMODULE)))
|
||||
USEMODULE += fmt
|
||||
endif
|
||||
|
70
drivers/include/net/netdev/ieee802154_submac.h
Normal file
70
drivers/include/net/netdev/ieee802154_submac.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_netdev_ieee802154_submac IEEE802.15.4 SubMAC netdev layer
|
||||
* @ingroup drivers_netdev_api
|
||||
* @experimental This API is experimental and in an early state - expect
|
||||
* changes!
|
||||
|
||||
* @brief This module defines implements the netdev API on top of the
|
||||
* IEEE 802.15.4 radio HAL
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
#ifndef NET_NETDEV_IEEE802154_SUBMAC_H
|
||||
#define NET_NETDEV_IEEE802154_SUBMAC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "net/netdev.h"
|
||||
#include "net/netdev/ieee802154.h"
|
||||
#include "net/ieee802154/submac.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "od.h"
|
||||
#include "event/thread.h"
|
||||
#include "event/callback.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define NETDEV_SUBMAC_FLAGS_ACK_TIMEOUT (1 << 0) /**< Flag for ACK Timeout event */
|
||||
#define NETDEV_SUBMAC_FLAGS_TX_DONE (1 << 1) /**< Flag for TX Done event */
|
||||
#define NETDEV_SUBMAC_FLAGS_RX_DONE (1 << 2) /**< Flag for RX Done event */
|
||||
|
||||
/**
|
||||
* @brief IEEE 802.15.4 SubMAC netdev descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
netdev_ieee802154_t dev; /**< IEEE 802.15.4 netdev descriptor */
|
||||
ieee802154_submac_t submac; /**< IEEE 802.15.4 SubMAC descriptor */
|
||||
xtimer_t ack_timer; /**< xtimer descriptor for the ACK timeout timer */
|
||||
int isr_flags; /**< netdev submac @ref NETDEV_EVENT_ISR flags */
|
||||
} netdev_ieee802154_submac_t;
|
||||
|
||||
/**
|
||||
* @brief Init the IEEE 802.15.4 SubMAC netdev adoption.
|
||||
*
|
||||
* @param[in] netdev_submac pointer to the netdev submac descriptor.
|
||||
* @param[in] dev pointer to the device associated to @p netdev_submac.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return negative errno on failure.
|
||||
*/
|
||||
int netdev_ieee802154_submac_init(netdev_ieee802154_submac_t *netdev_submac,
|
||||
ieee802154_dev_t *dev);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_NETDEV_IEEE802154_SUBMAC_H */
|
||||
/** @} */
|
1
drivers/netdev_ieee802154_submac/Makefile
Normal file
1
drivers/netdev_ieee802154_submac/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
326
drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c
Normal file
326
drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include "net/netdev/ieee802154_submac.h"
|
||||
#include "event/thread.h"
|
||||
|
||||
static const ieee802154_submac_cb_t _cb;
|
||||
|
||||
static const netdev_driver_t netdev_submac_driver;
|
||||
|
||||
static void _ack_timeout(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
netdev_ieee802154_submac_t *netdev_submac = arg;
|
||||
netdev_t *netdev = arg;
|
||||
|
||||
netdev_submac->isr_flags |= NETDEV_SUBMAC_FLAGS_ACK_TIMEOUT;
|
||||
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
|
||||
static netopt_state_t _get_submac_state(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_submac_state_t state = ieee802154_get_state(submac);
|
||||
|
||||
netopt_state_t netopt_state;
|
||||
switch (state) {
|
||||
case IEEE802154_STATE_OFF:
|
||||
netopt_state = NETOPT_STATE_SLEEP;
|
||||
break;
|
||||
case IEEE802154_STATE_IDLE:
|
||||
netopt_state = NETOPT_STATE_STANDBY;
|
||||
break;
|
||||
case IEEE802154_STATE_LISTEN:
|
||||
default:
|
||||
netopt_state = NETOPT_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return netopt_state;
|
||||
}
|
||||
|
||||
static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac = (netdev_ieee802154_submac_t *)netdev;
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_STATE:
|
||||
*((netopt_state_t*) value) = _get_submac_state(submac);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return netdev_ieee802154_get((netdev_ieee802154_t *)netdev, opt,
|
||||
value, max_len);
|
||||
}
|
||||
|
||||
static int _set_submac_state(ieee802154_submac_t *submac, netopt_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case NETOPT_STATE_STANDBY:
|
||||
return ieee802154_set_state(submac, IEEE802154_STATE_IDLE);
|
||||
case NETOPT_STATE_SLEEP:
|
||||
return ieee802154_set_state(submac, IEEE802154_STATE_OFF);
|
||||
case NETOPT_STATE_IDLE:
|
||||
return ieee802154_set_state(submac, IEEE802154_STATE_LISTEN);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int _set(netdev_t *netdev, netopt_t opt, const void *value,
|
||||
size_t value_len)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac =
|
||||
(netdev_ieee802154_submac_t *)netdev;
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
|
||||
int res;
|
||||
int16_t tx_power;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_ADDRESS:
|
||||
ieee802154_set_short_addr(submac, value);
|
||||
break;
|
||||
case NETOPT_ADDRESS_LONG:
|
||||
ieee802154_set_ext_addr(submac, value);
|
||||
break;
|
||||
case NETOPT_NID:
|
||||
ieee802154_set_panid(submac, value);
|
||||
break;
|
||||
case NETOPT_CHANNEL:
|
||||
ieee802154_set_channel_number(submac, *((uint16_t *)value));
|
||||
break;
|
||||
case NETOPT_TX_POWER:
|
||||
tx_power = *((int16_t *)value);
|
||||
res = ieee802154_set_tx_power(submac, tx_power);
|
||||
if (res >= 0) {
|
||||
netdev_submac->dev.txpower = tx_power;
|
||||
}
|
||||
return res;
|
||||
case NETOPT_STATE:
|
||||
return _set_submac_state(submac, *((netopt_state_t*) value));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return netdev_ieee802154_set((netdev_ieee802154_t *)netdev, opt,
|
||||
value, value_len);
|
||||
}
|
||||
|
||||
void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac, uint16_t us)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac = container_of(submac,
|
||||
netdev_ieee802154_submac_t,
|
||||
submac);
|
||||
|
||||
xtimer_set(&netdev_submac->ack_timer, us);
|
||||
}
|
||||
|
||||
void ieee802154_submac_ack_timer_cancel(ieee802154_submac_t *submac)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac = container_of(submac,
|
||||
netdev_ieee802154_submac_t,
|
||||
submac);
|
||||
|
||||
xtimer_remove(&netdev_submac->ack_timer);
|
||||
}
|
||||
|
||||
static int _send(netdev_t *netdev, const iolist_t *pkt)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac =
|
||||
(netdev_ieee802154_submac_t *)netdev;
|
||||
|
||||
return ieee802154_send(&netdev_submac->submac, pkt);
|
||||
}
|
||||
|
||||
static void _isr(netdev_t *netdev)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac =
|
||||
(netdev_ieee802154_submac_t *)netdev;
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
|
||||
do {
|
||||
irq_disable();
|
||||
int flags = netdev_submac->isr_flags;
|
||||
netdev_submac->isr_flags = 0;
|
||||
irq_enable();
|
||||
|
||||
if (flags & NETDEV_SUBMAC_FLAGS_ACK_TIMEOUT) {
|
||||
ieee802154_submac_ack_timeout_fired(&netdev_submac->submac);
|
||||
}
|
||||
|
||||
if (flags & NETDEV_SUBMAC_FLAGS_TX_DONE) {
|
||||
ieee802154_submac_tx_done_cb(&netdev_submac->submac);
|
||||
}
|
||||
|
||||
if (flags & NETDEV_SUBMAC_FLAGS_RX_DONE) {
|
||||
ieee802154_submac_rx_done_cb(submac);
|
||||
}
|
||||
} while (netdev_submac->isr_flags != 0);
|
||||
}
|
||||
|
||||
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac =
|
||||
(netdev_ieee802154_submac_t *)netdev;
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
ieee802154_rx_info_t rx_info;
|
||||
|
||||
if (buf == NULL && len == 0) {
|
||||
return ieee802154_get_frame_length(submac);
|
||||
}
|
||||
|
||||
int res = ieee802154_read_frame(submac, buf, len, &rx_info);
|
||||
|
||||
if (info) {
|
||||
netdev_ieee802154_rx_info_t *netdev_rx_info = info;
|
||||
netdev_rx_info->rssi = rx_info.rssi;
|
||||
netdev_rx_info->lqi = rx_info.lqi;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void submac_tx_done(ieee802154_submac_t *submac, int status,
|
||||
ieee802154_tx_info_t *info)
|
||||
{
|
||||
(void)status;
|
||||
(void)info;
|
||||
netdev_ieee802154_submac_t *netdev_submac = container_of(submac,
|
||||
netdev_ieee802154_submac_t,
|
||||
submac);
|
||||
netdev_t *netdev = (netdev_t *)netdev_submac;
|
||||
|
||||
switch (status) {
|
||||
case TX_STATUS_SUCCESS:
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
||||
break;
|
||||
case TX_STATUS_FRAME_PENDING:
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE_DATA_PENDING);
|
||||
break;
|
||||
case TX_STATUS_MEDIUM_BUSY:
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY);
|
||||
break;
|
||||
case TX_STATUS_NO_ACK:
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_NOACK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void submac_rx_done(ieee802154_submac_t *submac)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac = container_of(submac,
|
||||
netdev_ieee802154_submac_t,
|
||||
submac);
|
||||
netdev_t *netdev = (netdev_t *)netdev_submac;
|
||||
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
||||
}
|
||||
|
||||
static const ieee802154_submac_cb_t _cb = {
|
||||
.rx_done = submac_rx_done,
|
||||
.tx_done = submac_tx_done,
|
||||
};
|
||||
|
||||
/* Event Notification callback */
|
||||
static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status)
|
||||
{
|
||||
ieee802154_submac_t *submac = dev->ctx;
|
||||
netdev_ieee802154_submac_t *netdev_submac = container_of(submac,
|
||||
netdev_ieee802154_submac_t,
|
||||
submac);
|
||||
netdev_t *netdev = (netdev_t *)netdev_submac;
|
||||
|
||||
switch (status) {
|
||||
case IEEE802154_RADIO_CONFIRM_TX_DONE:
|
||||
netdev_submac->isr_flags |= NETDEV_SUBMAC_FLAGS_TX_DONE;
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_RX_DONE:
|
||||
netdev_submac->isr_flags |= NETDEV_SUBMAC_FLAGS_RX_DONE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
|
||||
static int _init(netdev_t *netdev)
|
||||
{
|
||||
netdev_ieee802154_submac_t *netdev_submac =
|
||||
(netdev_ieee802154_submac_t *)netdev;
|
||||
/* Call the init function of the device (this will be handled by
|
||||
* `auto_init`) */
|
||||
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
|
||||
ieee802154_submac_init(submac);
|
||||
|
||||
netdev_ieee802154_t *netdev_ieee802154 = (netdev_ieee802154_t *)netdev;
|
||||
|
||||
/* This function already sets the PAN ID to the default one */
|
||||
netdev_ieee802154_reset(netdev_ieee802154);
|
||||
|
||||
uint16_t chan = CONFIG_IEEE802154_DEFAULT_CHANNEL;
|
||||
int16_t tx_power = CONFIG_IEEE802154_DEFAULT_TXPOWER;
|
||||
|
||||
/* Initialise netdev_ieee802154_t struct */
|
||||
netdev_ieee802154_set(netdev_ieee802154, NETOPT_CHANNEL,
|
||||
&chan, sizeof(chan));
|
||||
netdev_ieee802154_set(netdev_ieee802154, NETOPT_ADDRESS,
|
||||
&submac->short_addr, sizeof(submac->short_addr));
|
||||
netdev_ieee802154_set(netdev_ieee802154, NETOPT_ADDRESS_LONG,
|
||||
&submac->ext_addr, sizeof(submac->ext_addr));
|
||||
|
||||
netdev_submac->dev.txpower = tx_power;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_ieee802154_submac_init(netdev_ieee802154_submac_t *netdev_submac,
|
||||
ieee802154_dev_t *dev)
|
||||
{
|
||||
netdev_t *netdev = (netdev_t *)netdev_submac;
|
||||
|
||||
netdev->driver = &netdev_submac_driver;
|
||||
ieee802154_submac_t *submac = &netdev_submac->submac;
|
||||
|
||||
submac->dev = dev;
|
||||
submac->cb = &_cb;
|
||||
submac->dev->ctx = submac;
|
||||
|
||||
/* Set the Event Notification */
|
||||
submac->dev->cb = _hal_radio_cb;
|
||||
|
||||
netdev_submac->ack_timer.callback = _ack_timeout;
|
||||
netdev_submac->ack_timer.arg = netdev_submac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const netdev_driver_t netdev_submac_driver = {
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
.send = _send,
|
||||
.recv = _recv,
|
||||
.isr = _isr,
|
||||
.init = _init,
|
||||
};
|
||||
|
||||
/** @} */
|
@ -60,6 +60,7 @@ PSEUDOMODULES += gnrc_txtsnd
|
||||
PSEUDOMODULES += heap_cmd
|
||||
PSEUDOMODULES += i2c_scan
|
||||
PSEUDOMODULES += ieee802154_radio_hal
|
||||
PSEUDOMODULES += ieee802154_submac
|
||||
PSEUDOMODULES += ina3221_alerts
|
||||
PSEUDOMODULES += l2filter_blacklist
|
||||
PSEUDOMODULES += l2filter_whitelist
|
||||
@ -131,6 +132,7 @@ PSEUDOMODULES += ztimer%
|
||||
|
||||
# ztimer's main module is called "ztimer_core"
|
||||
NO_PSEUDOMODULES += ztimer_core
|
||||
NO_PSEUDOMODULES += netdev_ieee802154_submac
|
||||
|
||||
# print ascii representation in function od_hex_dump()
|
||||
PSEUDOMODULES += od_string
|
||||
|
@ -239,6 +239,13 @@ extern const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN];
|
||||
#define CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE (5U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IEEE802.15.4 default value for CCA threshold (in dBm)
|
||||
*/
|
||||
#ifndef CONFIG_IEEE802154_CCA_THRESH_DEFAULT
|
||||
#define CONFIG_IEEE802154_CCA_THRESH_DEFAULT (-70)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes an IEEE 802.15.4 MAC frame header in @p buf.
|
||||
*
|
||||
|
391
sys/include/net/ieee802154/submac.h
Normal file
391
sys/include/net/ieee802154/submac.h
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_ieee802154_submac IEEE802.15.4 SubMAC layer
|
||||
* @ingroup net_ieee802154
|
||||
* @experimental This API is experimental and in an early state - expect
|
||||
* changes!
|
||||
|
||||
* @brief This module defines a common layer for handling the lower
|
||||
* part of the IEEE 802.15.4 MAC layer.
|
||||
*
|
||||
* This layer is responsible for:
|
||||
* - Handling CSMA-CA and retransmissions.
|
||||
* - Maintaining part of the MAC Information Base, e.g IEEE 802.15.4 addresses,
|
||||
* channel settings, CSMA-CA params, etc.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
#ifndef NET_IEEE802154_SUBMAC_H
|
||||
#define NET_IEEE802154_SUBMAC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#define IEEE802154_SUBMAC_MAX_RETRANSMISSIONS (4U) /**< maximum number of frame retransmissions */
|
||||
|
||||
/**
|
||||
* @brief IEEE 802.15.4 SubMAC forward declaration
|
||||
*/
|
||||
typedef struct ieee802154_submac ieee802154_submac_t;
|
||||
|
||||
/**
|
||||
* @brief SubMAC states
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief SubMAC and network devices are off.
|
||||
*
|
||||
* The corresponding network device is put in a state with the
|
||||
* lowest energy consumption.
|
||||
*/
|
||||
IEEE802154_STATE_OFF,
|
||||
|
||||
/**
|
||||
* @brief SubMAC is ready to be used.
|
||||
*/
|
||||
IEEE802154_STATE_IDLE,
|
||||
|
||||
/**
|
||||
* @brief SubMAC is ready to be used and listening to incoming frames.
|
||||
*/
|
||||
IEEE802154_STATE_LISTEN,
|
||||
} ieee802154_submac_state_t;
|
||||
|
||||
/**
|
||||
* @brief IEEE 802.15.4 SubMAC callbacks.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief RX done event
|
||||
*
|
||||
* This function is called from the SubMAC to indicate a IEEE 802.15.4
|
||||
* frame is ready to be fetched from the device.
|
||||
*
|
||||
* If @ref ieee802154_submac_t::state is @ref IEEE802154_STATE_LISTEN, the
|
||||
* SubMAC is ready to receive frames.
|
||||
*
|
||||
* @note ACK frames are automatically handled and discarded by the SubMAC.
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*/
|
||||
void (*rx_done)(ieee802154_submac_t *submac);
|
||||
/**
|
||||
* @brief TX done event
|
||||
*
|
||||
* This function is called from the SubMAC to indicate that the TX
|
||||
* procedure finished.
|
||||
*
|
||||
* If @ref ieee802154_submac_t::state is @ref IEEE802154_STATE_LISTEN, the
|
||||
* SubMAC is ready to receive frames.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[out] info TX information associated to the transmission (status,
|
||||
* number of retransmissions, pending bit, etc).
|
||||
*/
|
||||
void (*tx_done)(ieee802154_submac_t *submac, int status,
|
||||
ieee802154_tx_info_t *info);
|
||||
} ieee802154_submac_cb_t;
|
||||
|
||||
/**
|
||||
* @brief IEEE 802.15.4 SubMAC descriptor
|
||||
*/
|
||||
struct ieee802154_submac {
|
||||
eui64_t ext_addr; /**< IEEE 802.15.4 extended address */
|
||||
network_uint16_t short_addr; /**< IEEE 802.15.4 short address */
|
||||
ieee802154_dev_t *dev; /**< pointer to the 802.15.4 HAL descriptor */
|
||||
const ieee802154_submac_cb_t *cb; /**< pointer to the SubMAC callbacks */
|
||||
ieee802154_csma_be_t be; /**< CSMA-CA backoff exponent params */
|
||||
bool wait_for_ack; /**< SubMAC is waiting for an ACK frame */
|
||||
bool tx; /**< SubMAC is currently transmitting a frame */
|
||||
uint16_t panid; /**< IEEE 802.15.4 PAN ID */
|
||||
uint16_t channel_num; /**< IEEE 802.15.4 channel number */
|
||||
uint8_t channel_page; /**< IEEE 802.15.4 channel page */
|
||||
uint8_t retrans; /**< current number of retransmissions */
|
||||
uint8_t csma_retries_nb; /**< current number of CSMA-CA retries */
|
||||
uint8_t backoff_mask; /**< internal value used for random backoff calculation */
|
||||
uint8_t csma_retries; /**< maximum number of CSMA-CA retries */
|
||||
int8_t tx_pow; /**< Transmission power (in dBm) */
|
||||
ieee802154_submac_state_t state; /**< State of the SubMAC */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the internal state of the SubMAC
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*
|
||||
* @return the SubMAC state
|
||||
*/
|
||||
static inline ieee802154_submac_state_t ieee802154_get_state(ieee802154_submac_t *submac)
|
||||
{
|
||||
return submac->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the internal state of the SubMAC
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] state the desired state
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error.
|
||||
*/
|
||||
int ieee802154_set_state(ieee802154_submac_t *submac, ieee802154_submac_state_t state);
|
||||
|
||||
/**
|
||||
* @brief Transmit an IEEE 802.15.4 PSDU
|
||||
*
|
||||
* This function performs an IEEE 802.15.4 transmission, including CSMA-CA and
|
||||
* retransmissions (if ACK Request bit is set). When the transmission finishes
|
||||
* an @ref ieee802154_submac_cb_t::tx_done event is issued.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] iolist pointer to the PSDU frame (without FCS)
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist);
|
||||
|
||||
/**
|
||||
* @brief Set the IEEE 802.15.4 short address
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] short_addr IEEE 802.15.4 short address
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_short_addr(ieee802154_submac_t *submac,
|
||||
const network_uint16_t *short_addr)
|
||||
{
|
||||
int res = ieee802154_radio_set_hw_addr_filter(submac->dev, short_addr, NULL,
|
||||
NULL);
|
||||
|
||||
if (res >= 0) {
|
||||
memcpy(&submac->short_addr, short_addr, IEEE802154_SHORT_ADDRESS_LEN);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the IEEE 802.15.4 extended address
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] ext_addr IEEE 802.15.4 extended address
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_ext_addr(ieee802154_submac_t *submac,
|
||||
const eui64_t *ext_addr)
|
||||
{
|
||||
int res = ieee802154_radio_set_hw_addr_filter(submac->dev, NULL, ext_addr,
|
||||
NULL);
|
||||
|
||||
if (res >= 0) {
|
||||
memcpy(&submac->ext_addr, ext_addr, IEEE802154_LONG_ADDRESS_LEN);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the IEEE 802.15.4 PAN ID
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] panid IEEE 802.15.4 PAN ID
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_panid(ieee802154_submac_t *submac,
|
||||
const uint16_t *panid)
|
||||
{
|
||||
int res = ieee802154_radio_set_hw_addr_filter(submac->dev, NULL, NULL,
|
||||
panid);
|
||||
|
||||
if (res >= 0) {
|
||||
submac->panid = *panid;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set IEEE 802.15.4 PHY configuration (channel, TX power)
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] channel_num channel number
|
||||
* @param[in] channel_page channel page
|
||||
* @param[in] tx_pow transmission power (in dBm)
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -ENOTSUP if the PHY settings are not supported
|
||||
* @return negative errno on error
|
||||
*/
|
||||
int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num,
|
||||
uint8_t channel_page, int8_t tx_pow);
|
||||
|
||||
/**
|
||||
* @brief Set IEEE 802.15.4 channel number
|
||||
*
|
||||
* This is a shortcut to @ref ieee802154_set_phy_conf
|
||||
*
|
||||
* @param[in] submac pointer the SubMAC descriptor
|
||||
* @param[in] channel_num channel number
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -ENOTSUP if the channel number is not supported
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_channel_number(ieee802154_submac_t *submac,
|
||||
uint16_t channel_num)
|
||||
{
|
||||
return ieee802154_set_phy_conf(submac, channel_num, submac->channel_page,
|
||||
submac->tx_pow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set IEEE 802.15.4 channel page
|
||||
*
|
||||
* This is a shortcut to @ref ieee802154_set_phy_conf
|
||||
*
|
||||
* @param[in] submac pointer the SubMAC descriptor
|
||||
* @param[in] channel_page channel page
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -ENOTSUP if the channel page is not supported
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_channel_page(ieee802154_submac_t *submac,
|
||||
uint16_t channel_page)
|
||||
{
|
||||
return ieee802154_set_phy_conf(submac, submac->channel_num, channel_page,
|
||||
submac->tx_pow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set IEEE 802.15.4 transmission power
|
||||
*
|
||||
* This is a shortcut to @ref ieee802154_set_phy_conf
|
||||
*
|
||||
* @param[in] submac pointer the SubMAC descriptor
|
||||
* @param[in] tx_pow transmission power (in dBm)
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -ENOTSUP if the transmission power is not supported
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_set_tx_power(ieee802154_submac_t *submac,
|
||||
int8_t tx_pow)
|
||||
{
|
||||
return ieee802154_set_phy_conf(submac, submac->channel_num,
|
||||
submac->channel_page, tx_pow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the received frame length
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC
|
||||
*
|
||||
* @return length of the PSDU (excluding FCS length)
|
||||
*/
|
||||
static inline int ieee802154_get_frame_length(ieee802154_submac_t *submac)
|
||||
{
|
||||
return ieee802154_radio_len(submac->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the received frame
|
||||
*
|
||||
* This functions reads the received PSDU from the device (excluding FCS)
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[out] buf buffer to write into. If NULL, the packet is discarded
|
||||
* @param[in] len length of the buffer
|
||||
* @param[out] info RX information of the packet. If NULL, the information is not fetched.
|
||||
*
|
||||
* @return the number of bytes written to @p buf
|
||||
* @return negative errno on error
|
||||
*/
|
||||
static inline int ieee802154_read_frame(ieee802154_submac_t *submac, void *buf,
|
||||
size_t len, ieee802154_rx_info_t *info)
|
||||
{
|
||||
return ieee802154_radio_indication_rx(submac->dev, buf, len, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init the IEEE 802.15.4 SubMAC
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
int ieee802154_submac_init(ieee802154_submac_t *submac);
|
||||
|
||||
/**
|
||||
* @brief Set the ACK timeout timer
|
||||
*
|
||||
* @note This function should be implemented by the user of the SubMAC.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
* @param[in] us microseconds until the ACK timeout timer is fired
|
||||
*/
|
||||
extern void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac,
|
||||
uint16_t us);
|
||||
|
||||
/**
|
||||
* @brief Cancel the ACK timeout timer
|
||||
*
|
||||
* @note This function should be implemented by the user of the SubMAC.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*/
|
||||
extern void ieee802154_submac_ack_timer_cancel(ieee802154_submac_t *submac);
|
||||
|
||||
/**
|
||||
* @brief Indicate the SubMAC that the ACK timeout fired.
|
||||
*
|
||||
* This function must be called when the ACK timeout timer fires.
|
||||
*
|
||||
* @note this function should not be called inside ISR context.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*/
|
||||
void ieee802154_submac_ack_timeout_fired(ieee802154_submac_t *submac);
|
||||
|
||||
/**
|
||||
* @brief Indicate the SubMAC that the device received a frame.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*/
|
||||
void ieee802154_submac_rx_done_cb(ieee802154_submac_t *submac);
|
||||
|
||||
/**
|
||||
* @brief Indicate the SubMAC that the device finished the transmission procedure.
|
||||
*
|
||||
* @param[in] submac pointer to the SubMAC descriptor
|
||||
*/
|
||||
void ieee802154_submac_tx_done_cb(ieee802154_submac_t *submac);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_IEEE802154_SUBMAC_H */
|
||||
/** @} */
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "net/gnrc/netif/ieee802154.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
#include "net/netdev/ieee802154_submac.h"
|
||||
|
||||
#include "cc2538_rf.h"
|
||||
|
||||
@ -31,7 +33,12 @@
|
||||
#define CC2538_MAC_PRIO (GNRC_NETIF_PRIO)
|
||||
#endif
|
||||
|
||||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
extern ieee802154_dev_t cc2538_rf_dev;
|
||||
static netdev_ieee802154_submac_t cc2538_rf_submac;
|
||||
#else
|
||||
static cc2538_rf_t cc2538_rf_dev;
|
||||
#endif
|
||||
static char _cc2538_rf_stack[CC2538_MAC_STACKSIZE];
|
||||
static gnrc_netif_t _netif;
|
||||
|
||||
@ -39,10 +46,18 @@ void auto_init_cc2538_rf(void)
|
||||
{
|
||||
LOG_DEBUG("[auto_init_netif] initializing cc2538 radio\n");
|
||||
|
||||
netdev_t *netdev;
|
||||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
netdev_ieee802154_submac_init(&cc2538_rf_submac, &cc2538_rf_dev);
|
||||
netdev = (netdev_t*) &cc2538_rf_submac;
|
||||
cc2538_init();
|
||||
#else
|
||||
netdev = &cc2538_rf_dev.netdev.netdev;
|
||||
cc2538_setup(&cc2538_rf_dev);
|
||||
#endif
|
||||
gnrc_netif_ieee802154_create(&_netif, _cc2538_rf_stack,
|
||||
CC2538_MAC_STACKSIZE,
|
||||
CC2538_MAC_PRIO, "cc2538_rf",
|
||||
(netdev_t *)&cc2538_rf_dev);
|
||||
netdev);
|
||||
}
|
||||
/** @} */
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include "nrf802154.h"
|
||||
#include "net/gnrc/netif/ieee802154.h"
|
||||
|
||||
#include "net/ieee802154/radio.h"
|
||||
#include "net/netdev/ieee802154_submac.h"
|
||||
|
||||
/**
|
||||
* @brief Define stack parameters for the MAC layer thread
|
||||
* @{
|
||||
@ -37,13 +40,27 @@
|
||||
static char _stack[NRF802154_MAC_STACKSIZE];
|
||||
static gnrc_netif_t _netif;
|
||||
|
||||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
extern ieee802154_dev_t nrf802154_hal_dev;
|
||||
static netdev_ieee802154_submac_t nrf802154_submac;
|
||||
#endif
|
||||
|
||||
void auto_init_nrf802154(void)
|
||||
{
|
||||
LOG_DEBUG("[auto_init_netif] initializing nrf802154\n");
|
||||
|
||||
netdev_t *netdev;
|
||||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
netdev_ieee802154_submac_init(&nrf802154_submac, &nrf802154_hal_dev);
|
||||
netdev = (netdev_t*) &nrf802154_submac;
|
||||
nrf802154_init();
|
||||
#else
|
||||
netdev = (netdev_t*) &nrf802154_dev;
|
||||
#endif
|
||||
|
||||
gnrc_netif_ieee802154_create(&_netif, _stack,
|
||||
NRF802154_MAC_STACKSIZE,
|
||||
NRF802154_MAC_PRIO, "nrf802154",
|
||||
(netdev_t *)&nrf802154_dev);
|
||||
netdev);
|
||||
}
|
||||
/** @} */
|
||||
|
@ -1 +1,11 @@
|
||||
MODULE = ieee802154
|
||||
|
||||
SRC = \
|
||||
ieee802154.c \
|
||||
#
|
||||
|
||||
ifneq (,$(filter ieee802154_submac,$(USEMODULE)))
|
||||
SRC += submac.c
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
398
sys/net/link_layer/ieee802154/submac.c
Normal file
398
sys/net/link_layer/ieee802154/submac.c
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "net/ieee802154/submac.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "xtimer.h"
|
||||
#include "random.h"
|
||||
#include "luid.h"
|
||||
#include "kernel_defines.h"
|
||||
#include "errno.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define CSMA_SENDER_BACKOFF_PERIOD_UNIT_MS (320U)
|
||||
#define ACK_TIMEOUT_US (864U)
|
||||
|
||||
static void _handle_tx_no_ack(ieee802154_submac_t *submac);
|
||||
|
||||
static void _tx_end(ieee802154_submac_t *submac, int status,
|
||||
ieee802154_tx_info_t *info)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
ieee802154_radio_request_set_trx_state(dev, submac->state == IEEE802154_STATE_LISTEN ? IEEE802154_TRX_STATE_RX_ON : IEEE802154_TRX_STATE_TRX_OFF);
|
||||
|
||||
submac->tx = false;
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {}
|
||||
submac->cb->tx_done(submac, status, info);
|
||||
}
|
||||
|
||||
static inline bool _does_handle_ack(ieee802154_dev_t *dev)
|
||||
{
|
||||
return ieee802154_radio_has_frame_retrans(dev) ||
|
||||
ieee802154_radio_has_irq_ack_timeout(dev);
|
||||
}
|
||||
|
||||
static int _perform_csma_ca(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (submac->csma_retries_nb <= submac->csma_retries) {
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_TX_ON);
|
||||
/* delay for an adequate random backoff period */
|
||||
uint32_t bp = (random_uint32() & submac->backoff_mask) *
|
||||
CSMA_SENDER_BACKOFF_PERIOD_UNIT_MS;
|
||||
|
||||
xtimer_usleep(bp);
|
||||
|
||||
/* try to send after a CCA */
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {}
|
||||
|
||||
while (ieee802154_radio_request_transmit(dev) == -EBUSY) {}
|
||||
|
||||
/* Prepare for next iteration */
|
||||
if (submac->backoff_mask + 1 < submac->be.max) {
|
||||
submac->backoff_mask = (submac->backoff_mask << 1) | 1;
|
||||
}
|
||||
else {
|
||||
submac->backoff_mask = (1 << submac->be.max) - 1;
|
||||
}
|
||||
|
||||
submac->csma_retries_nb++;
|
||||
}
|
||||
else {
|
||||
ieee802154_radio_set_rx_mode(dev, IEEE802154_RX_AACK_ENABLED);
|
||||
_tx_end(submac, TX_STATUS_MEDIUM_BUSY, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform CSMA-CA transmission (possibly with retransmission)
|
||||
*
|
||||
* If radio supports @ref IEEE802154_CAP_FRAME_RETRANS, the device will automatically retransmit.
|
||||
* If radio supports @ref IEEE802154_CAP_AUTO_CSMA, this function will use the
|
||||
* internal CSMA-CA acceleration to perform the transmission.
|
||||
*
|
||||
* @param submac pointer to the SubMAC
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative errno on error
|
||||
*/
|
||||
int ieee802154_csma_ca_transmit(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
/* If radio has Auto CSMA-CA or Frame Retransmissions, simply send and wait for the transmit confirmation. */
|
||||
if (ieee802154_radio_has_auto_csma(dev) ||
|
||||
ieee802154_radio_has_frame_retrans(dev)) {
|
||||
|
||||
/* Make sure we are in TX_ON */
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_TX_ON);
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {}
|
||||
|
||||
int res;
|
||||
while ((res = ieee802154_radio_request_transmit(dev)) == -EBUSY) {}
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
submac->csma_retries_nb = 0;
|
||||
submac->backoff_mask = (1 << submac->be.min) - 1;
|
||||
_perform_csma_ca(submac);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool _has_retrans_left(ieee802154_submac_t *submac)
|
||||
{
|
||||
return submac->retrans < IEEE802154_SUBMAC_MAX_RETRANSMISSIONS;
|
||||
}
|
||||
|
||||
static void _perform_retrans(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (_has_retrans_left(submac)) {
|
||||
submac->retrans++;
|
||||
ieee802154_csma_ca_transmit(submac);
|
||||
}
|
||||
else {
|
||||
ieee802154_radio_set_rx_mode(dev, IEEE802154_RX_AACK_ENABLED);
|
||||
_tx_end(submac, TX_STATUS_NO_ACK, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee802154_submac_ack_timeout_fired(ieee802154_submac_t *submac)
|
||||
{
|
||||
/* This is required to avoid race conditions */
|
||||
if (submac->wait_for_ack) {
|
||||
_handle_tx_no_ack(submac);
|
||||
}
|
||||
}
|
||||
|
||||
/* All callbacks run in the same context */
|
||||
void ieee802154_submac_rx_done_cb(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (!_does_handle_ack(dev) && submac->wait_for_ack) {
|
||||
uint8_t ack[3];
|
||||
|
||||
if (ieee802154_radio_indication_rx(dev, ack, 3, NULL) &&
|
||||
ack[0] & IEEE802154_FCF_TYPE_ACK) {
|
||||
ieee802154_submac_ack_timer_cancel(submac);
|
||||
ieee802154_tx_info_t tx_info;
|
||||
tx_info.retrans = submac->retrans;
|
||||
bool fp = (ack[0] & IEEE802154_FCF_FRAME_PEND);
|
||||
submac->wait_for_ack = false;
|
||||
ieee802154_radio_set_rx_mode(submac->dev,
|
||||
IEEE802154_RX_AACK_ENABLED);
|
||||
_tx_end(submac, fp ? TX_STATUS_FRAME_PENDING : TX_STATUS_SUCCESS,
|
||||
&tx_info);
|
||||
}
|
||||
}
|
||||
else {
|
||||
submac->cb->rx_done(submac);
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_tx_success(ieee802154_submac_t *submac,
|
||||
ieee802154_tx_info_t *info)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON);
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {}
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans(dev) ||
|
||||
ieee802154_radio_has_irq_ack_timeout(dev) || !submac->wait_for_ack) {
|
||||
_tx_end(submac, info->status, info);
|
||||
}
|
||||
else {
|
||||
ieee802154_radio_set_rx_mode(dev, IEEE802154_RX_WAIT_FOR_ACK);
|
||||
|
||||
/* Handle ACK reception */
|
||||
ieee802154_submac_ack_timer_set(submac, ACK_TIMEOUT_US);
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_tx_medium_busy(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans(dev) ||
|
||||
ieee802154_radio_has_auto_csma(dev)) {
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON);
|
||||
_tx_end(submac, TX_STATUS_MEDIUM_BUSY, NULL);
|
||||
}
|
||||
else {
|
||||
/* CCA failed. Continue with the CSMA-CA algorithm */
|
||||
_perform_csma_ca(submac);
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_tx_no_ack(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans(dev)) {
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON);
|
||||
submac->wait_for_ack = false;
|
||||
_tx_end(submac, TX_STATUS_NO_ACK, NULL);
|
||||
}
|
||||
else {
|
||||
/* Perform retransmissions */
|
||||
_perform_retrans(submac);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee802154_submac_tx_done_cb(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
ieee802154_tx_info_t info;
|
||||
|
||||
ieee802154_radio_confirm_transmit(dev, &info);
|
||||
|
||||
switch (info.status) {
|
||||
case TX_STATUS_MEDIUM_BUSY:
|
||||
_handle_tx_medium_busy(submac);
|
||||
break;
|
||||
case TX_STATUS_NO_ACK:
|
||||
_handle_tx_no_ack(submac);
|
||||
break;
|
||||
case TX_STATUS_SUCCESS:
|
||||
case TX_STATUS_FRAME_PENDING:
|
||||
_handle_tx_success(submac, &info);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
uint8_t *buf = iolist->iol_base;
|
||||
bool cnf = buf[0] & IEEE802154_FCF_ACK_REQ;
|
||||
|
||||
if (submac->state == IEEE802154_STATE_OFF) {
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
if (submac->tx ||
|
||||
ieee802154_radio_request_set_trx_state(dev,
|
||||
IEEE802154_TRX_STATE_TX_ON) < 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
submac->tx = true;
|
||||
|
||||
ieee802154_radio_write(dev, iolist);
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {}
|
||||
|
||||
submac->wait_for_ack = cnf;
|
||||
submac->retrans = 0;
|
||||
|
||||
ieee802154_csma_ca_transmit(submac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee802154_submac_init(ieee802154_submac_t *submac)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
submac->tx = false;
|
||||
submac->state = IEEE802154_STATE_LISTEN;
|
||||
|
||||
ieee802154_radio_request_on(dev);
|
||||
|
||||
/* generate EUI-64 and short address */
|
||||
luid_get_eui64(&submac->ext_addr);
|
||||
luid_get_short(&submac->short_addr);
|
||||
submac->panid = CONFIG_IEEE802154_DEFAULT_PANID;
|
||||
|
||||
submac->be.min = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE;
|
||||
submac->csma_retries = CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES;
|
||||
submac->be.max = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE;
|
||||
|
||||
submac->tx_pow = CONFIG_IEEE802154_DEFAULT_TXPOWER;
|
||||
|
||||
if (ieee802154_radio_has_24_ghz(dev)) {
|
||||
submac->channel_num = CONFIG_IEEE802154_DEFAULT_CHANNEL;
|
||||
|
||||
/* 2.4 GHz only use page 0 */
|
||||
submac->channel_page = 0;
|
||||
}
|
||||
else {
|
||||
submac->channel_num = CONFIG_IEEE802154_DEFAULT_SUBGHZ_CHANNEL;
|
||||
submac->channel_page = CONFIG_IEEE802154_DEFAULT_SUBGHZ_PAGE;
|
||||
}
|
||||
|
||||
/* If the radio is still not in TRX_OFF state, spin */
|
||||
while (ieee802154_radio_confirm_on(dev) == -EAGAIN) {}
|
||||
|
||||
/* Enable Auto ACK */
|
||||
ieee802154_radio_set_rx_mode(dev, IEEE802154_RX_AACK_ENABLED);
|
||||
|
||||
/* Configure address filter */
|
||||
ieee802154_radio_set_hw_addr_filter(dev, &submac->short_addr,
|
||||
&submac->ext_addr, &submac->panid);
|
||||
|
||||
/* Configure PHY settings (channel, TX power) */
|
||||
ieee802154_phy_conf_t conf =
|
||||
{ .channel = CONFIG_IEEE802154_DEFAULT_CHANNEL,
|
||||
.page = CONFIG_IEEE802154_DEFAULT_CHANNEL,
|
||||
.pow = CONFIG_IEEE802154_DEFAULT_TXPOWER };
|
||||
|
||||
ieee802154_radio_config_phy(dev, &conf);
|
||||
assert(ieee802154_radio_set_cca_threshold(dev,
|
||||
CONFIG_IEEE802154_CCA_THRESH_DEFAULT) >= 0);
|
||||
|
||||
ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num,
|
||||
uint8_t channel_page, int8_t tx_pow)
|
||||
{
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
const ieee802154_phy_conf_t conf =
|
||||
{ .channel = channel_num, .page = channel_page, .pow = tx_pow };
|
||||
|
||||
if (submac->state == IEEE802154_STATE_OFF) {
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
int res = ieee802154_radio_config_phy(dev, &conf);
|
||||
|
||||
if (res >= 0) {
|
||||
submac->channel_num = channel_num;
|
||||
submac->channel_page = channel_page;
|
||||
submac->tx_pow = tx_pow;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ieee802154_set_state(ieee802154_submac_t *submac, ieee802154_submac_state_t state)
|
||||
{
|
||||
int res;
|
||||
|
||||
ieee802154_dev_t *dev = submac->dev;
|
||||
|
||||
if (submac->tx) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (state == submac->state) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
/* Wake up the radio if it was off */
|
||||
if (submac->state == IEEE802154_STATE_OFF) {
|
||||
if ((res = ieee802154_radio_request_on(dev)) < 0) {
|
||||
return res;
|
||||
}
|
||||
while (ieee802154_radio_confirm_on(dev) == -EAGAIN);
|
||||
}
|
||||
|
||||
if (state == IEEE802154_STATE_OFF) {
|
||||
res = ieee802154_radio_off(dev);
|
||||
}
|
||||
else {
|
||||
ieee802154_submac_state_t new_state =
|
||||
state == IEEE802154_STATE_IDLE
|
||||
? IEEE802154_TRX_STATE_TRX_OFF
|
||||
: IEEE802154_TRX_STATE_RX_ON;
|
||||
|
||||
if ((res = ieee802154_radio_request_set_trx_state(dev, new_state)) < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN);
|
||||
}
|
||||
|
||||
submac->state = state;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
28
tests/ieee802154_submac/Makefile
Normal file
28
tests/ieee802154_submac/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_WHITELIST := \
|
||||
adafruit-clue \
|
||||
adafruit-itsybitsy-nrf52 \
|
||||
arduino-nano-33-ble \
|
||||
cc2538dk \
|
||||
feather-nrf52840 \
|
||||
nrf52840dk \
|
||||
nrf52840dongle \
|
||||
nrf52840-mdk \
|
||||
omote \
|
||||
openmote-cc2538 \
|
||||
reel \
|
||||
remote-pa \
|
||||
remote-reva \
|
||||
remote-revb \
|
||||
#
|
||||
USEMODULE += od
|
||||
USEMODULE += shell
|
||||
USEMODULE += ps
|
||||
USEMODULE += event_thread_highest
|
||||
USEMODULE += netdev_ieee802154_submac
|
||||
USEMODULE += netdev_default
|
||||
|
||||
CFLAGS += -DEVENT_THREAD_HIGHEST_STACKSIZE=1024
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
1
tests/ieee802154_submac/common.h
Symbolic link
1
tests/ieee802154_submac/common.h
Symbolic link
@ -0,0 +1 @@
|
||||
../ieee802154_hal/common.h
|
1
tests/ieee802154_submac/init_devs.c
Symbolic link
1
tests/ieee802154_submac/init_devs.c
Symbolic link
@ -0,0 +1 @@
|
||||
../ieee802154_hal/init_devs.c
|
361
tests/ieee802154_submac/main.c
Normal file
361
tests/ieee802154_submac/main.c
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for AT86RF2xx network device driver
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sys/uio.h"
|
||||
#include "luid.h"
|
||||
|
||||
#include "net/netdev.h"
|
||||
#include "shell.h"
|
||||
#include "shell_commands.h"
|
||||
#include "net/ieee802154/submac.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/netdev/ieee802154_submac.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_LINE (80)
|
||||
|
||||
/* Only the first radio is supported so far */
|
||||
#define RADIO_DEFAULT_ID (0U)
|
||||
|
||||
netdev_ieee802154_submac_t netdev_submac;
|
||||
|
||||
void _ack_timeout(void *arg);
|
||||
|
||||
uint8_t buffer[IEEE802154_FRAME_LEN_MAX];
|
||||
uint8_t seq;
|
||||
|
||||
static int print_addr(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
uint8_t *_p = (uint8_t *)&netdev_submac.submac.ext_addr;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
printf("%02x", *_p++);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern const netdev_driver_t netdev_submac_driver;
|
||||
|
||||
static void _netdev_isr_handler(event_t *event)
|
||||
{
|
||||
(void)event;
|
||||
netdev_t *netdev = (netdev_t *)&netdev_submac;
|
||||
|
||||
netdev->driver->isr(netdev);
|
||||
}
|
||||
|
||||
void _print_addr(uint8_t *addr, size_t addr_len)
|
||||
{
|
||||
for (size_t i = 0; i < addr_len; i++) {
|
||||
if (i != 0) {
|
||||
printf(":");
|
||||
}
|
||||
printf("%02x", (unsigned)addr[i]);
|
||||
}
|
||||
}
|
||||
static event_t _netdev_ev = { .handler = _netdev_isr_handler };
|
||||
|
||||
void recv(netdev_t *dev)
|
||||
{
|
||||
uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
|
||||
size_t mhr_len, data_len, src_len, dst_len;
|
||||
netdev_ieee802154_rx_info_t rx_info;
|
||||
le_uint16_t src_pan, dst_pan;
|
||||
|
||||
putchar('\n');
|
||||
data_len = dev->driver->recv(dev, buffer, sizeof(buffer), &rx_info);
|
||||
mhr_len = ieee802154_get_frame_hdr_len(buffer);
|
||||
if (mhr_len == 0) {
|
||||
puts("Unexpected MHR for incoming packet");
|
||||
return;
|
||||
}
|
||||
dst_len = ieee802154_get_dst(buffer, dst, &dst_pan);
|
||||
src_len = ieee802154_get_src(buffer, src, &src_pan);
|
||||
switch (buffer[0] & IEEE802154_FCF_TYPE_MASK) {
|
||||
case IEEE802154_FCF_TYPE_BEACON:
|
||||
puts("BEACON");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_DATA:
|
||||
puts("DATA");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_ACK:
|
||||
puts("ACK");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_MACCMD:
|
||||
puts("MACCMD");
|
||||
break;
|
||||
default:
|
||||
puts("UNKNOWN");
|
||||
break;
|
||||
}
|
||||
printf("Dest. PAN: 0x%04x, Dest. addr.: ",
|
||||
byteorder_ntohs(byteorder_ltobs(dst_pan)));
|
||||
_print_addr(dst, dst_len);
|
||||
printf("\nSrc. PAN: 0x%04x, Src. addr.: ",
|
||||
byteorder_ntohs(byteorder_ltobs(src_pan)));
|
||||
_print_addr(src, src_len);
|
||||
printf("\nSecurity: ");
|
||||
if (buffer[0] & IEEE802154_FCF_SECURITY_EN) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("Frame pend.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_FRAME_PEND) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("ACK req.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("PAN comp.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_PAN_COMP) {
|
||||
puts("1");
|
||||
}
|
||||
else {
|
||||
puts("0");
|
||||
}
|
||||
printf("Version: ");
|
||||
printf("%u, ", (unsigned)((buffer[1] & IEEE802154_FCF_VERS_MASK) >> 4));
|
||||
printf("Seq.: %u\n", (unsigned)ieee802154_get_seq(buffer));
|
||||
od_hex_dump(buffer + mhr_len, data_len - mhr_len, 0);
|
||||
printf("txt: ");
|
||||
for (size_t i = mhr_len; i < data_len; i++) {
|
||||
if ((buffer[i] > 0x1F) && (buffer[i] < 0x80)) {
|
||||
putchar((char)buffer[i]);
|
||||
}
|
||||
else {
|
||||
putchar('?');
|
||||
}
|
||||
if (((((i - mhr_len) + 1) % (MAX_LINE - sizeof("txt: "))) == 1) &&
|
||||
(i - mhr_len) != 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("RSSI: %i, LQI: %u\n\n", rx_info.rssi, rx_info.lqi);
|
||||
}
|
||||
static void _event_cb(netdev_t *dev, netdev_event_t event)
|
||||
{
|
||||
(void)dev;
|
||||
if (event == NETDEV_EVENT_ISR) {
|
||||
event_post(EVENT_PRIO_HIGHEST, &_netdev_ev);
|
||||
}
|
||||
else {
|
||||
switch (event) {
|
||||
case NETDEV_EVENT_RX_COMPLETE:
|
||||
{
|
||||
recv(dev);
|
||||
return;
|
||||
}
|
||||
case NETDEV_EVENT_TX_COMPLETE:
|
||||
puts("Tx complete");
|
||||
break;
|
||||
case NETDEV_EVENT_TX_COMPLETE_DATA_PENDING:
|
||||
puts("Tx complete with pending data");
|
||||
break;
|
||||
case NETDEV_EVENT_TX_MEDIUM_BUSY:
|
||||
puts("Medium Busy");
|
||||
break;
|
||||
case NETDEV_EVENT_TX_NOACK:
|
||||
puts("No ACK");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
static int _init(void)
|
||||
{
|
||||
ieee802154_hal_test_init_devs();
|
||||
|
||||
netdev_t *dev = (netdev_t *)&netdev_submac;
|
||||
|
||||
dev->event_callback = _event_cb;
|
||||
netdev_ieee802154_submac_init(&netdev_submac,
|
||||
ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID));
|
||||
dev->driver->init(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t payload[] =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ornare lacinia mi elementum interdum ligula.";
|
||||
|
||||
static iolist_t iol_hdr;
|
||||
|
||||
static int send(uint8_t *dst, size_t dst_len,
|
||||
size_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
int mhr_len;
|
||||
|
||||
le_uint16_t src_pan, dst_pan;
|
||||
iolist_t iol_data = {
|
||||
.iol_base = payload,
|
||||
.iol_len = len,
|
||||
.iol_next = NULL,
|
||||
};
|
||||
|
||||
flags = IEEE802154_FCF_TYPE_DATA | 0x20;
|
||||
src_pan = byteorder_btols(byteorder_htons(0x23));
|
||||
dst_pan = byteorder_btols(byteorder_htons(0x23));
|
||||
uint8_t src_len = 8;
|
||||
void *src = &netdev_submac.submac.ext_addr;
|
||||
|
||||
/* fill MAC header, seq should be set by device */
|
||||
if ((mhr_len = ieee802154_set_frame_hdr(mhr, src, src_len,
|
||||
dst, dst_len,
|
||||
src_pan, dst_pan,
|
||||
flags, seq++)) < 0) {
|
||||
puts("txtsnd: Error preperaring frame");
|
||||
return 1;
|
||||
}
|
||||
|
||||
iol_hdr.iol_next = &iol_data;
|
||||
iol_hdr.iol_base = mhr;
|
||||
iol_hdr.iol_len = mhr_len;
|
||||
|
||||
netdev_t *dev = (netdev_t *)&netdev_submac;
|
||||
|
||||
dev->driver->send(dev, &iol_hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int _dehex(char c, int default_)
|
||||
{
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
else if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
else if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
else {
|
||||
return default_;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t _parse_addr(uint8_t *out, size_t out_len, const char *in)
|
||||
{
|
||||
const char *end_str = in;
|
||||
uint8_t *out_end = out;
|
||||
size_t count = 0;
|
||||
int assert_cell = 1;
|
||||
|
||||
if (!in || !*in) {
|
||||
return 0;
|
||||
}
|
||||
while (end_str[1]) {
|
||||
++end_str;
|
||||
}
|
||||
|
||||
while (end_str >= in) {
|
||||
int a = 0, b = _dehex(*end_str--, -1);
|
||||
if (b < 0) {
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
assert_cell = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert_cell = 0;
|
||||
|
||||
if (end_str >= in) {
|
||||
a = _dehex(*end_str--, 0);
|
||||
}
|
||||
|
||||
if (++count > out_len) {
|
||||
return 0;
|
||||
}
|
||||
*out_end++ = (a << 4) | b;
|
||||
}
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
/* out is reversed */
|
||||
|
||||
while (out < --out_end) {
|
||||
uint8_t tmp = *out_end;
|
||||
*out_end = *out;
|
||||
*out++ = tmp;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int txtsnd(int argc, char **argv)
|
||||
{
|
||||
uint8_t addr[8];
|
||||
size_t len;
|
||||
size_t res;
|
||||
|
||||
if (argc != 3) {
|
||||
puts("Usage: txtsnd <long_addr> <len>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = _parse_addr(addr, sizeof(addr), argv[1]);
|
||||
if (res == 0) {
|
||||
puts("Usage: txtsnd <long_addr> <len>");
|
||||
return 1;
|
||||
}
|
||||
len = atoi(argv[2]);
|
||||
return send(addr, res, len);
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "print_addr", "Print IEEE802.15.4 addresses", print_addr },
|
||||
{ "txtsnd", "Send IEEE 802.15.4 packet", txtsnd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_init();
|
||||
|
||||
/* start the shell */
|
||||
puts("Initialization successful - starting the shell now");
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user