mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
opendsme: add initial support
This commit is contained in:
parent
efc0d3d3d9
commit
d7b51c687b
@ -376,6 +376,7 @@ PSEUDOMODULES += newlib_nano
|
||||
PSEUDOMODULES += nice
|
||||
## @}
|
||||
PSEUDOMODULES += nrf24l01p_ng_diagnostics
|
||||
PSEUDOMODULES += opendsme
|
||||
PSEUDOMODULES += openthread
|
||||
PSEUDOMODULES += picolibc
|
||||
PSEUDOMODULES += picolibc_stdout_buffered
|
||||
|
46
pkg/opendsme/Kconfig
Normal file
46
pkg/opendsme/Kconfig
Normal file
@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2022 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.
|
||||
#
|
||||
|
||||
menuconfig KCONFIG_USEPKG_OPENDSME
|
||||
bool "Configure openDSME"
|
||||
help
|
||||
Configure openDSME using Kconfig.
|
||||
|
||||
if KCONFIG_USEPKG_OPENDSME
|
||||
|
||||
config OPENDSME_MAX_NEIGHBOURS
|
||||
int "Maximum number of DSME neighbours"
|
||||
default 20
|
||||
|
||||
config OPENDSME_MAX_LOST_BEACONS
|
||||
int "Maximum number of lost beacons before assuming the device desynchronized"
|
||||
default 8
|
||||
help
|
||||
Sets the maximum number of lost beacons before the MAC triggers a
|
||||
de-association procedure. Higher values are beneficial in noisy
|
||||
environments, because the MAC will keep synchronization despite losing some
|
||||
beacons. However, lower values are better for mobile nodes, because devices
|
||||
may sinchronize faster to a new coordinator.
|
||||
|
||||
config OPENDSME_CAP_QUEUE_SIZE
|
||||
int "DSME CAP queue size (for CSMA/CA transmissions)"
|
||||
default 8
|
||||
help
|
||||
The CAP queue stores frames to be sent during the Contention Access Period
|
||||
using CSMA-CA. Because the transmission delay of CSMA-CA is lower compared to
|
||||
GTS transmissions, small values are preferred to reduce memory requirements.
|
||||
|
||||
config OPENDSME_CFP_QUEUE_SIZE
|
||||
int "DSME CFP queue size (for GTS transmissions)"
|
||||
default 22
|
||||
help
|
||||
The CFP queue stores frames to be sent during the Contention Free Period
|
||||
using a dedicated GTS. In contrast to CSMA-CA transmissions, GTS transmission
|
||||
take longer as a result of slot schedules. Therefore, the GTS queue should
|
||||
have more capacity than the CAP queue (OPENDSME_CAP_QUEUE_SIZE).
|
||||
|
||||
endif # KCONFIG_USEPKG_OPENDSME
|
58
pkg/opendsme/Makefile
Normal file
58
pkg/opendsme/Makefile
Normal file
@ -0,0 +1,58 @@
|
||||
PKG_NAME=opendsme
|
||||
PKG_URL=https://github.com/inetrg/openDSME.git
|
||||
PKG_VERSION=b1969296d0fc9a1556ecbef7c0b01538dff3e10c
|
||||
PKG_LICENSE=GPL
|
||||
|
||||
include $(RIOTBASE)/pkg/pkg.mk
|
||||
|
||||
OPENDSME_MODULES = \
|
||||
opendsme_dsmelayer \
|
||||
opendsme_acklayer \
|
||||
opendsme_associationmanager \
|
||||
opendsme_beaconmanager \
|
||||
opendsme_caplayer \
|
||||
opendsme_gtsmanager \
|
||||
opendsme_messagedispatcher \
|
||||
opendsme_messages \
|
||||
opendsme_datastructures \
|
||||
opendsme_mcps_sap \
|
||||
opendsme_mlme_sap \
|
||||
opendsme_pib \
|
||||
opendsme_adaption_layer \
|
||||
opendsme_adaption_layer_scheduling \
|
||||
#
|
||||
|
||||
CPPFLAGS += -Wno-deprecated-copy -Wno-unused-parameter -Wno-error
|
||||
|
||||
# dsmeLayer
|
||||
DIR_DSME_LAYER = dsmeLayer
|
||||
DIR_opendsme_dsmelayer = $(DIR_DSME_LAYER)
|
||||
DIR_opendsme_acklayer = $(DIR_DSME_LAYER)/ackLayer
|
||||
DIR_opendsme_associationmanager = $(DIR_DSME_LAYER)/associationManager
|
||||
DIR_opendsme_beaconmanager = $(DIR_DSME_LAYER)/beaconManager
|
||||
DIR_opendsme_caplayer = $(DIR_DSME_LAYER)/capLayer
|
||||
DIR_opendsme_gtsmanager = $(DIR_DSME_LAYER)/gtsManager
|
||||
DIR_opendsme_messagedispatcher = $(DIR_DSME_LAYER)/messageDispatcher
|
||||
DIR_opendsme_messages = $(DIR_DSME_LAYER)/messages
|
||||
|
||||
# MAC Services
|
||||
|
||||
DIR_MAC_SERVICES = mac_services
|
||||
DIR_opendsme_datastructures = $(DIR_MAC_SERVICES)/dataStructures
|
||||
DIR_opendsme_mcps_sap = $(DIR_MAC_SERVICES)/mcps_sap
|
||||
DIR_opendsme_mlme_sap = $(DIR_MAC_SERVICES)/mlme_sap
|
||||
DIR_opendsme_pib = $(DIR_MAC_SERVICES)/pib
|
||||
|
||||
# DSME Adoption Layer
|
||||
DIR_DSME_ADAPTION_LAYER = dsmeAdaptionLayer
|
||||
DIR_opendsme_adaption_layer = $(DIR_DSME_ADAPTION_LAYER)
|
||||
DIR_opendsme_adaption_layer_scheduling = $(DIR_DSME_ADAPTION_LAYER)/scheduling
|
||||
|
||||
.PHONY: opendsme_%
|
||||
|
||||
export SRCXXEXT=cc
|
||||
|
||||
all: $(OPENDSME_MODULES)
|
||||
|
||||
opendsme_%:
|
||||
$(QQ)"$(MAKE)" -C $(PKG_SOURCE_DIR)/$(DIR_$@) -f $(CURDIR)/Makefile.$@
|
40
pkg/opendsme/Makefile.dep
Normal file
40
pkg/opendsme/Makefile.dep
Normal file
@ -0,0 +1,40 @@
|
||||
FEATURES_REQUIRED += cpp
|
||||
|
||||
# Contrib code of openDSME
|
||||
USEMODULE += opendsme_riot_contrib
|
||||
|
||||
# Internal openDSME modules
|
||||
USEMODULE += opendsme_dsmelayer
|
||||
USEMODULE += opendsme_acklayer
|
||||
USEMODULE += opendsme_associationmanager
|
||||
USEMODULE += opendsme_beaconmanager
|
||||
USEMODULE += opendsme_caplayer
|
||||
USEMODULE += opendsme_gtsmanager
|
||||
USEMODULE += opendsme_messagedispatcher
|
||||
USEMODULE += opendsme_messages
|
||||
USEMODULE += opendsme_datastructures
|
||||
USEMODULE += opendsme_mcps_sap
|
||||
USEMODULE += opendsme_mlme_sap
|
||||
USEMODULE += opendsme_pib
|
||||
|
||||
# openDSME adaption layer modules
|
||||
USEMODULE += opendsme_adaption_layer
|
||||
USEMODULE += opendsme_adaption_layer_scheduling
|
||||
|
||||
# required RIOT modules
|
||||
USEMODULE += luid
|
||||
USEMODULE += gnrc
|
||||
USEMODULE += gnrc_netif
|
||||
USEMODULE += ieee802154
|
||||
USEMODULE += ztimer_usec
|
||||
|
||||
USEMODULE += cpp11-compat
|
||||
CXXEXFLAGS += -Wno-unused-parameter -Wno-pedantic -Wno-missing-field-initializers -Wno-unused-but-set-variable -Wno-maybe-uninitialized -Wno-unused-variable -Wno-reorder -Wno-address -Wno-sign-compare -Wno-unused-function
|
||||
FEATURES_REQUIRED += cpp # basic C++ support
|
||||
FEATURES_REQUIRED += libstdcpp # libstdc++ support (for #include <cstdio>)
|
||||
|
||||
|
||||
# Disable Auto-ACK (not supported by openDSME)
|
||||
CFLAGS += -DCONFIG_IEEE802154_AUTO_ACK_DISABLE=1
|
||||
|
||||
USEMODULE += random
|
4
pkg/opendsme/Makefile.include
Normal file
4
pkg/opendsme/Makefile.include
Normal file
@ -0,0 +1,4 @@
|
||||
INCLUDES += -I$(PKGDIRBASE)/opendsme
|
||||
INCLUDES += -I$(RIOTBASE)/pkg/opendsme/include
|
||||
|
||||
DIRS += $(RIOTBASE)/pkg/opendsme/contrib
|
3
pkg/opendsme/Makefile.opendsme_acklayer
Normal file
3
pkg/opendsme/Makefile.opendsme_acklayer
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_acklayer
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_adaption_layer
Normal file
3
pkg/opendsme/Makefile.opendsme_adaption_layer
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_adaption_layer
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
7
pkg/opendsme/Makefile.opendsme_adaption_layer_scheduling
Normal file
7
pkg/opendsme/Makefile.opendsme_adaption_layer_scheduling
Normal file
@ -0,0 +1,7 @@
|
||||
MODULE = opendsme_adaption_layer_scheduling
|
||||
|
||||
# Include TPS and StaticScheduling schedulers
|
||||
NO_AUTO_SRC := 1
|
||||
SRCXX += TPS.cc StaticScheduling.cc
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_associationmanager
Normal file
3
pkg/opendsme/Makefile.opendsme_associationmanager
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_associationmanager
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_beaconmanager
Normal file
3
pkg/opendsme/Makefile.opendsme_beaconmanager
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_beaconmanager
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_caplayer
Normal file
3
pkg/opendsme/Makefile.opendsme_caplayer
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_caplayer
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_datastructures
Normal file
3
pkg/opendsme/Makefile.opendsme_datastructures
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_datastructures
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_dsmelayer
Normal file
3
pkg/opendsme/Makefile.opendsme_dsmelayer
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_dsmelayer
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_gtsmanager
Normal file
3
pkg/opendsme/Makefile.opendsme_gtsmanager
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_gtsmanager
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_mcps_sap
Normal file
3
pkg/opendsme/Makefile.opendsme_mcps_sap
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_mcps_sap
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_messagedispatcher
Normal file
3
pkg/opendsme/Makefile.opendsme_messagedispatcher
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_messagedispatcher
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_messages
Normal file
3
pkg/opendsme/Makefile.opendsme_messages
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_messages
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_mlme_sap
Normal file
3
pkg/opendsme/Makefile.opendsme_mlme_sap
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_mlme_sap
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/opendsme/Makefile.opendsme_pib
Normal file
3
pkg/opendsme/Makefile.opendsme_pib
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_pib
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
161
pkg/opendsme/contrib/DSMEMessage.cpp
Normal file
161
pkg/opendsme/contrib/DSMEMessage.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
#include "assert.h"
|
||||
#include "opendsme/DSMEMessage.h"
|
||||
#include "net/gnrc/pktdump.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "opendsme/opendsme.h"
|
||||
|
||||
namespace dsme {
|
||||
|
||||
void DSMEMessage::prependFrom(DSMEMessageElement *msg)
|
||||
{
|
||||
gnrc_pktsnip_t *head = gnrc_pktbuf_add(pkt, NULL,
|
||||
msg->getSerializationLength(), GNRC_NETTYPE_UNDEF);
|
||||
|
||||
/* Hardcorded to O-QPSK */
|
||||
DSME_ASSERT(msg->getSerializationLength() <= IEEE802154_FRAME_LEN_MAX);
|
||||
DSME_ASSERT(head);
|
||||
int res = gnrc_pktbuf_merge(head);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
DSME_ASSERT(gnrc_pkt_len(head) <= IEEE802154_FRAME_LEN_MAX);
|
||||
pkt = head;
|
||||
assert(head);
|
||||
Serializer s((uint8_t *)head->data, SERIALIZATION);
|
||||
|
||||
msg->serialize(s);
|
||||
}
|
||||
|
||||
void DSMEMessage::decapsulateTo(DSMEMessageElement *me)
|
||||
{
|
||||
this->copyTo(me);
|
||||
this->dropHdr(me->getSerializationLength());
|
||||
}
|
||||
|
||||
void DSMEMessage::copyTo(DSMEMessageElement *msg)
|
||||
{
|
||||
Serializer s(this->getPayload(), DESERIALIZATION);
|
||||
|
||||
msg->serialize(s);
|
||||
DSME_ASSERT(this->getPayload() + msg->getSerializationLength() == s.getData());
|
||||
}
|
||||
|
||||
uint8_t DSMEMessage::getMPDUSymbols()
|
||||
{
|
||||
/* Not used by OpenDSME */
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DSMEMessage::loadBuffer(size_t len)
|
||||
{
|
||||
int res = -ENOBUFS;
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, len, GNRC_NETTYPE_UNDEF);
|
||||
|
||||
DSME_ASSERT(len <= IEEE802154_FRAME_LEN_MAX);
|
||||
if (pkt == NULL) {
|
||||
DSME_ASSERT(false);
|
||||
goto end;
|
||||
}
|
||||
this->pkt = pkt;
|
||||
res = 0;
|
||||
|
||||
end:
|
||||
return res;
|
||||
}
|
||||
|
||||
int DSMEMessage::loadBuffer(iolist_t *pkt)
|
||||
{
|
||||
int res = -ENOBUFS;
|
||||
|
||||
if (pkt == NULL) {
|
||||
DSME_ASSERT(false);
|
||||
goto end;
|
||||
}
|
||||
this->pkt = (gnrc_pktsnip_t *)pkt;
|
||||
res = 0;
|
||||
|
||||
end:
|
||||
return res;
|
||||
}
|
||||
|
||||
int DSMEMessage::dropHdr(size_t len)
|
||||
{
|
||||
gnrc_pktsnip_t *hdr = gnrc_pktbuf_mark(this->pkt, len, GNRC_NETTYPE_UNDEF);
|
||||
|
||||
if (!hdr) {
|
||||
DSME_ASSERT(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
gnrc_pktbuf_remove_snip(pkt, hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DSMEMessage::releaseMessage()
|
||||
{
|
||||
DSME_ASSERT(!free);
|
||||
if (pkt) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
free = true;
|
||||
delete this;
|
||||
}
|
||||
|
||||
iolist_t *DSMEMessage::getIolPayload()
|
||||
{
|
||||
return (iolist_t *)pkt;
|
||||
}
|
||||
|
||||
void DSMEMessage::clearMessage()
|
||||
{
|
||||
pkt = NULL;
|
||||
free = false;
|
||||
prepare();
|
||||
}
|
||||
|
||||
void DSMEMessage::dispatchMessage()
|
||||
{
|
||||
DSME_ASSERT(!free);
|
||||
uint16_t addr = getHeader().getSrcAddr().getShortAddress();
|
||||
uint8_t _addr[IEEE802154_SHORT_ADDRESS_LEN];
|
||||
_addr[0] = addr >> 8;
|
||||
_addr[1] = addr & 0xFF;
|
||||
|
||||
uint16_t dst_addr = getHeader().getDestAddr().getShortAddress();
|
||||
uint8_t _dst_addr[IEEE802154_SHORT_ADDRESS_LEN];
|
||||
_dst_addr[0] = dst_addr >> 8;
|
||||
_dst_addr[1] = dst_addr & 0xFF;
|
||||
|
||||
gnrc_pktsnip_t *netif_hdr = gnrc_netif_hdr_build((uint8_t *)_addr, IEEE802154_SHORT_ADDRESS_LEN,
|
||||
(uint8_t *)_dst_addr,
|
||||
IEEE802154_SHORT_ADDRESS_LEN);
|
||||
size_t mhr_len = ieee802154_get_frame_hdr_len(static_cast<uint8_t *>(pkt->data));
|
||||
|
||||
pkt->type = CONFIG_OPENDSME_GNRC_PKTSNIP_TYPE;
|
||||
gnrc_netif_hdr_t *hdr = static_cast<gnrc_netif_hdr_t *>(netif_hdr->data);
|
||||
|
||||
gnrc_netif_hdr_set_netif(hdr, this->netif);
|
||||
pkt = gnrc_pkt_append(pkt, netif_hdr);
|
||||
if (gnrc_netapi_dispatch_receive(CONFIG_OPENDSME_GNRC_PKTSNIP_TYPE, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt)) {
|
||||
/* Pass packet to GNRC */
|
||||
pkt = NULL;
|
||||
}
|
||||
releaseMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
763
pkg/opendsme/contrib/DSMEPlatform.cpp
Normal file
763
pkg/opendsme/contrib/DSMEPlatform.cpp
Normal file
@ -0,0 +1,763 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include "opendsme/opendsme.h"
|
||||
#include "opendsme/DSMEPlatform.h"
|
||||
#include "ztimer.h"
|
||||
#include "iolist.h"
|
||||
#include "event.h"
|
||||
#include "event/thread.h"
|
||||
#include "luid.h"
|
||||
#include "dsmeAdaptionLayer/scheduling/TPS.h"
|
||||
#include "dsmeAdaptionLayer/scheduling/StaticScheduling.h"
|
||||
#include "board.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
/* Use default openDSME value for TPS scheduler alpha */
|
||||
#define OPENDSME_TPS_ALPHA (0.1f)
|
||||
|
||||
/* Used for symbol counter calculation. Hardcoded to O-QPSK */
|
||||
#define OPENDSME_TIMER_MASK (0xF)
|
||||
#define OPENDSME_TIMER_OFFSET (4U)
|
||||
|
||||
namespace dsme {
|
||||
|
||||
/* The one and only openDSME instance */
|
||||
DSMEPlatform *DSMEPlatform::instance = nullptr;
|
||||
|
||||
/********************* C functions *********************/
|
||||
|
||||
static void _cca_ev_handler(event_t *ev);
|
||||
static void _acktimer_ev_handler(event_t *ev);
|
||||
static void _acktimer_cb(void *arg);
|
||||
static void _timer_ev_handler(event_t *ev);
|
||||
static void _tx_done_handler(event_t *ev);
|
||||
static void _rx_done_handler(event_t *ev);
|
||||
static void _handle_rx_offload(event_t *ev);
|
||||
static void _start_of_cfp_handler(event_t *ev);
|
||||
|
||||
/* Event used for ACK Timeout */
|
||||
static event_t acktimer_ev = {0, _acktimer_ev_handler};
|
||||
|
||||
/* Event used for CCA Done */
|
||||
static event_t cca_ev = {0, _cca_ev_handler};
|
||||
|
||||
/* Event used for timer events */
|
||||
static event_t timer_event = {0, _timer_ev_handler};
|
||||
|
||||
/* Event used for TX Done */
|
||||
static event_t tx_done_event = {0, _tx_done_handler};
|
||||
|
||||
/* Event used for RX Done */
|
||||
static event_t rx_done_event = {0, _rx_done_handler};
|
||||
|
||||
/* Event used for offloading the receive procedure */
|
||||
static event_t rx_offload_ev = {0, _handle_rx_offload};
|
||||
|
||||
/* Event used for offloading the start of a CFP */
|
||||
static event_t start_of_cfp_ev = {0, _start_of_cfp_handler};
|
||||
|
||||
void _handle_rx_offload(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->processRxOffload();
|
||||
}
|
||||
|
||||
void _start_of_cfp_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->getDSME().handleStartOfCFP();
|
||||
dsme::DSMEPlatform::instance->updateVisual();
|
||||
}
|
||||
|
||||
static void _cca_ev_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->processCCAEvent();
|
||||
}
|
||||
|
||||
static void _acktimer_ev_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->sendNow();
|
||||
}
|
||||
|
||||
static void _acktimer_cb(void *arg)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->offloadACKTimer();
|
||||
}
|
||||
|
||||
static void _timer_ev_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->getDSME().getEventDispatcher().timerInterrupt();
|
||||
}
|
||||
|
||||
static void _tx_done_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->processTXDoneEvent();
|
||||
}
|
||||
|
||||
static void _rx_done_handler(event_t *ev)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->processRxDone();
|
||||
}
|
||||
|
||||
static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status)
|
||||
{
|
||||
switch (status) {
|
||||
case IEEE802154_RADIO_CONFIRM_TX_DONE:
|
||||
dsme::DSMEPlatform::instance->offloadTXDoneEvent();
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_RX_START:
|
||||
dsme::DSMEPlatform::instance->indicateRxStart();
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_CRC_ERROR:
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_TX_START:
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_RX_DONE:
|
||||
dsme::DSMEPlatform::instance->offloadRXDoneEvent();
|
||||
break;
|
||||
case IEEE802154_RADIO_CONFIRM_CCA:
|
||||
dsme::DSMEPlatform::instance->offloadCCAEvent();
|
||||
break;
|
||||
default:
|
||||
DSME_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
/********************* C++ functions *********************/
|
||||
|
||||
void DSMEPlatform::processRxOffload()
|
||||
{
|
||||
IDSMEMessage *message = this->message;
|
||||
|
||||
this->message = nullptr;
|
||||
receiveFromAckLayerDelegate(message);
|
||||
}
|
||||
|
||||
void DSMEPlatform::processCCAEvent()
|
||||
{
|
||||
bool clear = ieee802154_radio_confirm_cca(this->radio);
|
||||
|
||||
this->setPlatformState(DSMEPlatform::STATE_READY);
|
||||
this->getDSME().dispatchCCAResult(clear);
|
||||
}
|
||||
|
||||
void DSMEPlatform::processTXDoneEvent()
|
||||
{
|
||||
int res = ieee802154_radio_confirm_transmit(this->radio, NULL);
|
||||
|
||||
this->pending_tx = false;
|
||||
DSME_ASSERT(res >= 0);
|
||||
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
|
||||
if (this->wait_for_ack) {
|
||||
this->wait_for_ack = false;
|
||||
ieee802154_radio_set_frame_filter_mode(this->radio, IEEE802154_FILTER_ACK_ONLY);
|
||||
}
|
||||
else {
|
||||
ieee802154_radio_set_frame_filter_mode(this->radio, IEEE802154_FILTER_ACCEPT);
|
||||
}
|
||||
this->txEndCallback(true);
|
||||
this->setPlatformState(DSMEPlatform::STATE_READY);
|
||||
}
|
||||
|
||||
void DSMEPlatform::processRxDone()
|
||||
{
|
||||
if (this->state != STATE_READY) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DSMEMessage *message = getEmptyMessage();
|
||||
|
||||
message->netif = this->netif;
|
||||
message->setStartOfFrameDelimiterSymbolCounter(rx_sfd);
|
||||
|
||||
int res;
|
||||
|
||||
res = ieee802154_radio_set_idle(this->radio, true);
|
||||
DSME_ASSERT(res == 0);
|
||||
int len = ieee802154_radio_len(this->radio);
|
||||
|
||||
if (len > 127 || len < 0) {
|
||||
ieee802154_radio_read(this->radio, NULL, 127, NULL);
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
return;
|
||||
}
|
||||
res = message->loadBuffer(len);
|
||||
DSME_ASSERT(res >= 0);
|
||||
ieee802154_rx_info_t info;
|
||||
|
||||
res = ieee802154_radio_read(this->radio, message->getPayload(), 127, &info);
|
||||
if (res < 0) {
|
||||
message->releaseMessage();
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
message->messageLQI = info.lqi;
|
||||
message->messageRSSI = info.rssi;
|
||||
const uint8_t *buf = message->getPayload();
|
||||
|
||||
bool success = message->getHeader().deserializeFrom(buf, len);
|
||||
|
||||
if (!success) {
|
||||
message->releaseMessage();
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
message->dropHdr(message->getHeader().getSerializationLength());
|
||||
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
|
||||
getDSME().getAckLayer().receive(message);
|
||||
}
|
||||
|
||||
void DSMEPlatform::offloadCCAEvent()
|
||||
{
|
||||
event_post(this->getEventQueue(), &cca_ev);
|
||||
}
|
||||
|
||||
void DSMEPlatform::offloadTXDoneEvent()
|
||||
{
|
||||
event_post(this->getEventQueue(), &tx_done_event);
|
||||
}
|
||||
|
||||
void DSMEPlatform::indicateRxStart()
|
||||
{
|
||||
this->rx_sfd = this->getSymbolCounter();
|
||||
}
|
||||
|
||||
void DSMEPlatform::offloadRXDoneEvent()
|
||||
{
|
||||
event_post(this->getEventQueue(), &rx_done_event);
|
||||
}
|
||||
|
||||
void DSMEPlatform::offloadTimerEvent()
|
||||
{
|
||||
event_post(this->getEventQueue(), &timer_event);
|
||||
}
|
||||
|
||||
void DSMEPlatform::offloadACKTimer()
|
||||
{
|
||||
event_post(this->getEventQueue(), &acktimer_ev);
|
||||
}
|
||||
|
||||
static void _timer_cb(void *arg)
|
||||
{
|
||||
dsme::DSMEPlatform::instance->offloadTimerEvent();
|
||||
}
|
||||
|
||||
void DSMEPlatform::sendFrame(uint16_t addr, iolist_t *pkt)
|
||||
{
|
||||
/* First 2 bytes are the ID */
|
||||
if (!this->mac_pib.macAssociatedPANCoord) {
|
||||
return;
|
||||
}
|
||||
|
||||
DSMEMessage *message = getEmptyMessage();
|
||||
|
||||
if (message->loadBuffer(pkt) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
IEEE802154MacAddress dst;
|
||||
|
||||
dst.setShortAddress(addr);
|
||||
mcps_sap::DATA::request_parameters params;
|
||||
|
||||
message->getHeader().setSrcAddrMode(SHORT_ADDRESS);
|
||||
message->getHeader().setDstAddrMode(SHORT_ADDRESS);
|
||||
message->getHeader().setDstAddr(dst);
|
||||
|
||||
message->getHeader().setSrcPANId(this->mac_pib.macPANId);
|
||||
message->getHeader().setDstPANId(this->mac_pib.macPANId);
|
||||
|
||||
this->dsmeAdaptionLayer.sendMessage(message);
|
||||
}
|
||||
|
||||
DSMEPlatform::DSMEPlatform() :
|
||||
phy_pib(),
|
||||
mac_pib(phy_pib),
|
||||
|
||||
mcps_sap(dsme),
|
||||
mlme_sap(dsme),
|
||||
dsmeAdaptionLayer(dsme),
|
||||
initialized(false),
|
||||
state(STATE_READY)
|
||||
{
|
||||
instance = this;
|
||||
this->timer.callback = _timer_cb;
|
||||
this->timer.arg = this;
|
||||
|
||||
this->acktimer.callback = _acktimer_cb;
|
||||
this->acktimer.arg = this;
|
||||
}
|
||||
|
||||
DSMEPlatform::~DSMEPlatform()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Creates an IEEE802154MacAddress out of an uint16_t short address
|
||||
*/
|
||||
void DSMEPlatform::translateMacAddress(uint16_t& from, IEEE802154MacAddress& to)
|
||||
{
|
||||
if (from == 0xFFFF) {
|
||||
to = IEEE802154MacAddress(IEEE802154MacAddress::SHORT_BROADCAST_ADDRESS);
|
||||
}
|
||||
else {
|
||||
to.setShortAddress(from);
|
||||
}
|
||||
}
|
||||
|
||||
void DSMEPlatform::initialize(bool pan_coord)
|
||||
{
|
||||
this->instance = this;
|
||||
this->dsme.setPHY_PIB(&(this->phy_pib));
|
||||
this->dsme.setMAC_PIB(&(this->mac_pib));
|
||||
this->dsme.setMCPS(&(this->mcps_sap));
|
||||
this->dsme.setMLME(&(this->mlme_sap));
|
||||
|
||||
/* Use all channels of the channel page 0 (O-QPSK) */
|
||||
constexpr uint8_t MAX_CHANNELS = 16;
|
||||
uint8_t channels[MAX_CHANNELS];
|
||||
|
||||
uint8_t num = MAX_CHANNELS;
|
||||
|
||||
channelList_t DSSS2450_channels(num);
|
||||
|
||||
for (uint8_t i = 0; i < num; i++) {
|
||||
DSSS2450_channels[i] = 11 + i;
|
||||
}
|
||||
|
||||
phy_pib.setDSSS2450ChannelPage(DSSS2450_channels);
|
||||
|
||||
/* Initialize Address */
|
||||
IEEE802154MacAddress address;
|
||||
|
||||
uint8_t ext_addr[IEEE802154_LONG_ADDRESS_LEN];
|
||||
network_uint16_t short_addr;
|
||||
|
||||
luid_base(ext_addr, sizeof(ext_addr));
|
||||
address.setA1((ext_addr[0] << 8) | ext_addr[1]);
|
||||
address.setA2((ext_addr[2] << 8) | ext_addr[3]);
|
||||
address.setA3((ext_addr[4] << 8) | ext_addr[5]);
|
||||
address.setA4((ext_addr[6] << 8) | ext_addr[7]);
|
||||
this->mac_pib.macExtendedAddress = address;
|
||||
|
||||
/* TODO: UGLY HACK! To be removed when gnrc_netif<->netdev dependency is
|
||||
* not granted */
|
||||
this->radio = (ieee802154_dev_t *)this->netif->dev;
|
||||
|
||||
this->radio->cb = _hal_radio_cb;
|
||||
|
||||
ieee802154_radio_request_on(this->radio);
|
||||
while (ieee802154_radio_confirm_on(this->radio) == -EAGAIN) {}
|
||||
/* Disable Auto CSMA-CA */
|
||||
ieee802154_radio_set_csma_params(this->radio, NULL, -1);
|
||||
|
||||
/* Accept all frames except ACK */
|
||||
ieee802154_radio_set_frame_filter_mode(this->radio, IEEE802154_FILTER_ACCEPT);
|
||||
|
||||
/* Call more radio configurations here if needed... */
|
||||
|
||||
this->mac_pib.macShortAddress = this->mac_pib.macExtendedAddress.getShortAddress();
|
||||
|
||||
short_addr.u8[0] = this->mac_pib.macExtendedAddress.getShortAddress() >> 8;
|
||||
short_addr.u8[1] = this->mac_pib.macExtendedAddress.getShortAddress() & 0xFF;
|
||||
|
||||
this->mac_pib.macIsPANCoord = pan_coord;
|
||||
this->mac_pib.macIsCoord = pan_coord;
|
||||
if (this->mac_pib.macIsPANCoord) {
|
||||
DEBUG("This node is PAN coordinator\n");
|
||||
this->mac_pib.macPANId = CONFIG_IEEE802154_DEFAULT_PANID;
|
||||
}
|
||||
ieee802154_radio_config_addr_filter(this->radio, IEEE802154_AF_PANID, &this->mac_pib.macPANId);
|
||||
ieee802154_radio_config_addr_filter(this->radio, IEEE802154_AF_SHORT_ADDR, &short_addr);
|
||||
ieee802154_radio_config_addr_filter(this->radio, IEEE802154_AF_EXT_ADDR, &ext_addr);
|
||||
|
||||
this->mac_pib.macCapReduction = CONFIG_IEEE802154_DSME_CAP_REDUCTION;
|
||||
|
||||
this->mac_pib.macAssociatedPANCoord = this->mac_pib.macIsPANCoord;
|
||||
this->mac_pib.macSuperframeOrder = CONFIG_IEEE802154_DSME_SUPERFRAME_ORDER;
|
||||
this->mac_pib.macMultiSuperframeOrder = CONFIG_IEEE802154_DSME_MULTISUPERFRAME_ORDER;
|
||||
this->mac_pib.macBeaconOrder = CONFIG_IEEE802154_DSME_BEACON_ORDER;
|
||||
|
||||
this->mac_pib.macMinBE = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE;
|
||||
this->mac_pib.macMaxBE = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE;
|
||||
this->mac_pib.macMaxCSMABackoffs = CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES;
|
||||
this->mac_pib.macMaxFrameRetries = CONFIG_IEEE802154_DEFAULT_MAX_FRAME_RETRANS;
|
||||
|
||||
this->mac_pib.macDSMEGTSExpirationTime = CONFIG_IEEE802154_DSME_GTS_EXPIRATION;
|
||||
this->mac_pib.macResponseWaitTime = CONFIG_IEEE802154_DSME_MAC_RESPONSE_WAIT_TIME;
|
||||
this->mac_pib.macChannelDiversityMode = Channel_Diversity_Mode::CHANNEL_HOPPING;
|
||||
|
||||
this->phy_pib.phyCurrentChannel = CONFIG_IEEE802154_DEFAULT_CHANNEL;
|
||||
|
||||
this->dsmeAdaptionLayer.setIndicationCallback(DELEGATE(&DSMEPlatform::
|
||||
handleDataMessageFromMCPSWrapper,
|
||||
*this));
|
||||
this->dsmeAdaptionLayer.setConfirmCallback(DELEGATE(&DSMEPlatform::handleConfirmFromMCPSWrapper,
|
||||
*this));
|
||||
|
||||
this->dsme.initialize(this);
|
||||
|
||||
channelList_t scanChannels;
|
||||
|
||||
scanChannels.add(CONFIG_IEEE802154_DEFAULT_CHANNEL);
|
||||
if (IS_ACTIVE(CONFIG_IEEE802154_DSME_STATIC_GTS)) {
|
||||
StaticScheduling *staticScheduling = new StaticScheduling(this->dsmeAdaptionLayer);
|
||||
staticScheduling->setNegotiateChannels(false);
|
||||
scheduling = staticScheduling;
|
||||
}
|
||||
else {
|
||||
TPS *tps = new TPS(this->dsmeAdaptionLayer);
|
||||
tps->setAlpha(OPENDSME_TPS_ALPHA);
|
||||
tps->setMinFreshness(this->mac_pib.macDSMEGTSExpirationTime);
|
||||
scheduling = tps;
|
||||
}
|
||||
|
||||
this->dsmeAdaptionLayer.initialize(scanChannels, CONFIG_IEEE802154_DSME_SCAN_DURATION,
|
||||
scheduling);
|
||||
this->initialized = true;
|
||||
}
|
||||
|
||||
#if IS_ACTIVE(CONFIG_IEEE802154_DSME_STATIC_GTS)
|
||||
void DSMEPlatform::allocateGTS(uint8_t superframeID, uint8_t slotID, uint8_t channelID,
|
||||
Direction direction, uint16_t address)
|
||||
{
|
||||
static_cast<StaticScheduling *>(scheduling)->allocateGTS(superframeID, slotID, channelID,
|
||||
direction, address);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DSMEPlatform::setGTSTransmission(bool gts)
|
||||
{
|
||||
this->dsmeAdaptionLayer.getMessageHelper().setGTSTransmission(gts);
|
||||
}
|
||||
|
||||
void DSMEPlatform::setAckReq(bool ackReq)
|
||||
{
|
||||
this->dsmeAdaptionLayer.getMessageHelper().setAckReq(ackReq);
|
||||
}
|
||||
|
||||
void DSMEPlatform::start()
|
||||
{
|
||||
DSME_ASSERT(this->initialized);
|
||||
this->dsme.start();
|
||||
this->dsmeAdaptionLayer.startAssociation();
|
||||
}
|
||||
|
||||
void DSMEPlatform::getShortAddress(network_uint16_t *addr)
|
||||
{
|
||||
addr->u8[0] = this->mac_pib.macExtendedAddress.getShortAddress() >> 8;
|
||||
addr->u8[1] = this->mac_pib.macExtendedAddress.getShortAddress() & 0xFF;
|
||||
}
|
||||
|
||||
bool DSMEPlatform::isAssociated()
|
||||
{
|
||||
return this->mac_pib.macAssociatedPANCoord;
|
||||
}
|
||||
|
||||
void DSMEPlatform::handleDataMessageFromMCPSWrapper(IDSMEMessage *msg)
|
||||
{
|
||||
this->handleDataMessageFromMCPS(static_cast<DSMEMessage *>(msg));
|
||||
}
|
||||
|
||||
void DSMEPlatform::handleConfirmFromMCPSWrapper(IDSMEMessage *msg,
|
||||
DataStatus::Data_Status dataStatus)
|
||||
{
|
||||
this->handleConfirmFromMCPS(static_cast<DSMEMessage *>(msg), dataStatus);
|
||||
}
|
||||
|
||||
void DSMEPlatform::handleConfirmFromMCPS(DSMEMessage *msg, DataStatus::Data_Status dataStatus)
|
||||
{
|
||||
if (dataStatus == DataStatus::Data_Status::SUCCESS) {
|
||||
/* TODO: Add to statistics */
|
||||
}
|
||||
IDSMEMessage *m = static_cast<IDSMEMessage *>(msg);
|
||||
|
||||
releaseMessage(m);
|
||||
}
|
||||
|
||||
void DSMEPlatform::handleDataMessageFromMCPS(DSMEMessage *msg)
|
||||
{
|
||||
msg->dispatchMessage();
|
||||
}
|
||||
|
||||
bool DSMEPlatform::isReceptionFromAckLayerPossible()
|
||||
{
|
||||
return this->state == STATE_READY;
|
||||
}
|
||||
|
||||
void DSMEPlatform::handleReceivedMessageFromAckLayer(IDSMEMessage *message)
|
||||
{
|
||||
DSME_ASSERT(receiveFromAckLayerDelegate);
|
||||
DSME_ASSERT(!this->message);
|
||||
this->message = message;
|
||||
event_post(this->getEventQueue(), &rx_offload_ev);
|
||||
}
|
||||
|
||||
DSMEMessage *DSMEPlatform::getEmptyMessage()
|
||||
{
|
||||
DSMEMessage *msg = new DSMEMessage();
|
||||
|
||||
DSME_ASSERT(msg);
|
||||
msg->clearMessage();
|
||||
signalNewMsg(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void DSMEPlatform::signalNewMsg(DSMEMessage *msg)
|
||||
{
|
||||
/* Not used */
|
||||
}
|
||||
|
||||
void DSMEPlatform::releaseMessage(IDSMEMessage *msg)
|
||||
{
|
||||
DSMEMessage *m = static_cast<DSMEMessage *>(msg);
|
||||
|
||||
m->releaseMessage();
|
||||
}
|
||||
|
||||
void DSMEPlatform::startTimer(uint32_t symbolCounterValue)
|
||||
{
|
||||
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||
uint32_t offset = now & OPENDSME_TIMER_MASK;
|
||||
/* This works even if there's an overflow */
|
||||
int32_t delta = ((symbolCounterValue - getSymbolCounter()) << OPENDSME_TIMER_OFFSET)
|
||||
- offset;
|
||||
|
||||
ztimer_set(ZTIMER_USEC, &timer, (uint32_t)delta);
|
||||
}
|
||||
|
||||
uint32_t DSMEPlatform::getSymbolCounter()
|
||||
{
|
||||
return ztimer_now(ZTIMER_USEC) >> OPENDSME_TIMER_OFFSET;
|
||||
}
|
||||
|
||||
void DSMEPlatform::scheduleStartOfCFP()
|
||||
{
|
||||
event_post(this->getEventQueue(), &start_of_cfp_ev);
|
||||
}
|
||||
|
||||
void DSMEPlatform::signalAckedTransmissionResult(bool success, uint8_t transmissionAttempts,
|
||||
IEEE802154MacAddress receiver)
|
||||
{
|
||||
/* Not used */
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal GTS allocation or deallocation
|
||||
*/
|
||||
void DSMEPlatform::signalGTSChange(bool deallocation, IEEE802154MacAddress counterpart,
|
||||
uint16_t superframeID, uint8_t gtSlotID, uint8_t channel,
|
||||
Direction direction)
|
||||
{}
|
||||
|
||||
void DSMEPlatform::signalQueueLength(uint32_t length)
|
||||
{}
|
||||
|
||||
/*
|
||||
* Number of packets sent per CAP
|
||||
*/
|
||||
void DSMEPlatform::signalPacketsPerCAP(uint32_t packets)
|
||||
{}
|
||||
|
||||
/*
|
||||
* Number of failed packets per CAP
|
||||
*/
|
||||
void DSMEPlatform::signalFailedPacketsPerCAP(uint32_t packets)
|
||||
{
|
||||
/* Not used */
|
||||
}
|
||||
|
||||
void DSMEPlatform::updateVisual()
|
||||
{
|
||||
/* Not used */
|
||||
}
|
||||
|
||||
bool DSMEPlatform::setChannelNumber(uint8_t channel)
|
||||
{
|
||||
ieee802154_phy_conf_t conf = {
|
||||
.phy_mode = IEEE802154_PHY_OQPSK,
|
||||
.channel = channel,
|
||||
.page = 0,
|
||||
.pow = CONFIG_IEEE802154_DEFAULT_TXPOWER,
|
||||
};
|
||||
int res;
|
||||
|
||||
res = ieee802154_radio_set_idle(this->radio, true);
|
||||
DSME_ASSERT(res == 0);
|
||||
res = ieee802154_radio_config_phy(this->radio, &conf);
|
||||
DSME_ASSERT(res == 0);
|
||||
|
||||
/* TODO: Find a better solution */
|
||||
ieee802154_radio_config_addr_filter(this->radio, IEEE802154_AF_PANID, &this->mac_pib.macPANId);
|
||||
|
||||
res = ieee802154_radio_set_rx(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t DSMEPlatform::getChannelNumber()
|
||||
{
|
||||
/* Apparently not used by OpenDSME */
|
||||
DSME_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DSMEPlatform::prepareSendingCopy(IDSMEMessage *msg, Delegate<void(bool)> txEndCallback)
|
||||
{
|
||||
DSMEMessage *m = (DSMEMessage *)msg;
|
||||
|
||||
this->state = DSMEPlatform::STATE_SEND;
|
||||
this->txEndCallback = txEndCallback;
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
uint8_t mhr_len = msg->getHeader().getSerializationLength();
|
||||
uint8_t *p = mhr;
|
||||
|
||||
msg->getHeader().serializeTo(p);
|
||||
iolist_t iol = {
|
||||
.iol_next = (iolist_t *)m->getIolPayload(),
|
||||
.iol_base = mhr,
|
||||
.iol_len = mhr_len,
|
||||
};
|
||||
|
||||
if (mhr[0] & IEEE802154_FCF_ACK_REQ) {
|
||||
this->wait_for_ack = true;
|
||||
}
|
||||
else {
|
||||
this->wait_for_ack = false;
|
||||
}
|
||||
|
||||
int res = ieee802154_radio_set_idle(this->radio, true);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
res = ieee802154_radio_write(this->radio, &iol);
|
||||
DSME_ASSERT(res == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSMEPlatform::sendNow()
|
||||
{
|
||||
int res = ieee802154_radio_request_transmit(this->radio);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
this->pending_tx = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSMEPlatform::abortPreparedTransmission()
|
||||
{
|
||||
/* Nothing to do here, since the Radio HAL will drop the frame if
|
||||
* the write function is called again */
|
||||
this->setPlatformState(DSMEPlatform::STATE_READY);
|
||||
}
|
||||
|
||||
bool DSMEPlatform::sendDelayedAck(IDSMEMessage *ackMsg, IDSMEMessage *receivedMsg,
|
||||
Delegate<void(bool)> txEndCallback)
|
||||
{
|
||||
DSMEMessage *m = (DSMEMessage *)ackMsg;
|
||||
|
||||
DSME_ASSERT(m != nullptr);
|
||||
|
||||
uint8_t ack[IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN];
|
||||
uint8_t mhr_len = ackMsg->getHeader().getSerializationLength();
|
||||
|
||||
DSME_ASSERT(mhr_len == sizeof(ack));
|
||||
|
||||
uint8_t *p = ack;
|
||||
|
||||
ackMsg->getHeader().serializeTo(p);
|
||||
|
||||
this->txEndCallback = txEndCallback;
|
||||
|
||||
iolist_t iol = {
|
||||
.iol_next = NULL,
|
||||
.iol_base = ack,
|
||||
.iol_len = mhr_len,
|
||||
};
|
||||
|
||||
int res = ieee802154_radio_set_idle(this->radio, true);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
res = ieee802154_radio_write(this->radio, &iol);
|
||||
DSME_ASSERT(res == 0);
|
||||
|
||||
/* Hardcoded to O-QPSK
|
||||
* Preamble (4) | SFD (1) | PHY Hdr (1) | MAC Payload | FCS (2)
|
||||
*/
|
||||
uint32_t endOfReception = receivedMsg->getStartOfFrameDelimiterSymbolCounter()
|
||||
+ receivedMsg->getTotalSymbols()
|
||||
- 2 * 4 /* Preamble */
|
||||
- 2 * 1; /* SFD */
|
||||
uint32_t ackTime = endOfReception + aTurnaroundTime;
|
||||
uint32_t now = getSymbolCounter();
|
||||
uint32_t diff = ackTime - now;
|
||||
|
||||
ztimer_set(ZTIMER_USEC, &this->acktimer, diff * aSymbolDuration);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSMEPlatform::setReceiveDelegate(receive_delegate_t receiveDelegate)
|
||||
{
|
||||
this->receiveFromAckLayerDelegate = receiveDelegate;
|
||||
}
|
||||
|
||||
bool DSMEPlatform::startCCA()
|
||||
{
|
||||
if (this->pending_tx) {
|
||||
return false;
|
||||
}
|
||||
ieee802154_radio_request_cca(this->radio);
|
||||
this->state = DSMEPlatform::STATE_CCA_WAIT;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSMEPlatform::turnTransceiverOn()
|
||||
{
|
||||
int res = ieee802154_radio_request_on(this->radio);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
res = ieee802154_radio_confirm_on(this->radio);
|
||||
DSME_ASSERT(res == 0);
|
||||
ieee802154_radio_set_cca_threshold(this->radio, CONFIG_IEEE802154_CCA_THRESH_DEFAULT);
|
||||
}
|
||||
|
||||
void DSMEPlatform::turnTransceiverOff()
|
||||
{
|
||||
int res = ieee802154_radio_off(this->radio);
|
||||
|
||||
DSME_ASSERT(res == 0);
|
||||
}
|
||||
|
||||
bool DSMEPlatform::isRxEnabledOnCap()
|
||||
{
|
||||
/* TODO: This feature is experimental. Enable RX on CAP for now... */
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
3
pkg/opendsme/contrib/Makefile
Normal file
3
pkg/opendsme/contrib/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = opendsme_riot_contrib
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
188
pkg/opendsme/contrib/gnrc_netif_opendsme.cpp
Normal file
188
pkg/opendsme/contrib/gnrc_netif_opendsme.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include "opendsme/DSMEPlatform.h"
|
||||
#include "opendsme/opendsme.h"
|
||||
#include "mac_services/DSME_Common.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
|
||||
dsme::DSMEPlatform m_dsme;
|
||||
|
||||
extern "C" {
|
||||
static bool _pan_coord;
|
||||
extern void heap_stats(void);
|
||||
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
/* Note that there the short address is assigned by the coordinator and the
|
||||
* user should not have control over it.
|
||||
* Given that, and the fact the current MAC does not communicate with
|
||||
* different PANs, we can always use the short address */
|
||||
uint8_t bcast[2] = { 0xFF, 0xFF };
|
||||
uint8_t *addr;
|
||||
|
||||
pkt = gnrc_pktbuf_start_write(pkt);
|
||||
gnrc_netif_hdr_t *hdr = (gnrc_netif_hdr_t *)pkt->data;
|
||||
|
||||
if (hdr->flags &= GNRC_NETIF_HDR_FLAGS_MULTICAST) {
|
||||
addr = static_cast<uint8_t *>(&bcast[0]);
|
||||
}
|
||||
else if (hdr->dst_l2addr_len == IEEE802154_LONG_ADDRESS_LEN) {
|
||||
addr = gnrc_netif_hdr_get_dst_addr(hdr)
|
||||
+ IEEE802154_LONG_ADDRESS_LEN
|
||||
- IEEE802154_SHORT_ADDRESS_LEN;
|
||||
}
|
||||
else if (hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) {
|
||||
addr = gnrc_netif_hdr_get_dst_addr(hdr);
|
||||
}
|
||||
else {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
uint16_t _addr = byteorder_ntohs(*((network_uint16_t *)addr));
|
||||
|
||||
pkt = gnrc_pktbuf_remove_snip(pkt, pkt);
|
||||
m_dsme.sendFrame(_addr, (iolist_t *)pkt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
|
||||
{
|
||||
/* Not used */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _get(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt)
|
||||
{
|
||||
gnrc_netif_acquire(netif);
|
||||
int res;
|
||||
network_uint16_t addr;
|
||||
le_uint64_t ext_addr;
|
||||
uint8_t *addr_ptr = static_cast<uint8_t *>(ext_addr.u8);
|
||||
|
||||
switch (opt->opt) {
|
||||
case NETOPT_MAX_PDU_SIZE:
|
||||
*((uint16_t *)opt->data) = IEEE802154_FRAME_LEN_MAX;
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
case NETOPT_ADDR_LEN:
|
||||
*((uint16_t *)opt->data) = IEEE802154_SHORT_ADDRESS_LEN;
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
case NETOPT_ADDRESS:
|
||||
assert(opt->data_len >= IEEE802154_SHORT_ADDRESS_LEN);
|
||||
m_dsme.getShortAddress(&addr);
|
||||
memcpy(opt->data, &addr, IEEE802154_SHORT_ADDRESS_LEN);
|
||||
res = IEEE802154_SHORT_ADDRESS_LEN;
|
||||
break;
|
||||
case NETOPT_ADDRESS_LONG: {
|
||||
assert(opt->data_len >= IEEE802154_LONG_ADDRESS_LEN);
|
||||
addr_ptr << m_dsme.getAddress();
|
||||
*((be_uint64_t *)opt->data) = byteorder_ltobll(ext_addr);
|
||||
res = IEEE802154_LONG_ADDRESS_LEN;
|
||||
break;
|
||||
}
|
||||
case NETOPT_LINK:
|
||||
assert(opt->data_len >= sizeof(netopt_enable_t));
|
||||
*((netopt_enable_t *)opt->data) = m_dsme.isAssociated()
|
||||
? NETOPT_ENABLE
|
||||
: NETOPT_DISABLE;
|
||||
return sizeof(netopt_enable_t);
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (opt->opt) {
|
||||
case NETOPT_LINK:
|
||||
m_dsme.initialize(_pan_coord);
|
||||
m_dsme.start();
|
||||
break;
|
||||
case NETOPT_PAN_COORD:
|
||||
if (*((bool *)opt->data) == true) {
|
||||
_pan_coord = true;
|
||||
}
|
||||
else {
|
||||
_pan_coord = false;
|
||||
}
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
#if IS_ACTIVE(CONFIG_IEEE802154_DSME_STATIC_GTS)
|
||||
case NETOPT_GTS_ALLOC: {
|
||||
ieee802154_dsme_alloc_t *alloc = (ieee802154_dsme_alloc_t *)opt->data;
|
||||
uint16_t _addr = byteorder_ntohs(alloc->addr);
|
||||
m_dsme.allocateGTS(alloc->superframe_id, alloc->slot_id, alloc->channel_id,
|
||||
alloc->tx ? dsme::Direction::TX : dsme::Direction::RX, _addr);
|
||||
res = sizeof(ieee802154_dsme_alloc_t);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case NETOPT_PROTO:
|
||||
assert(opt->data_len == sizeof(gnrc_nettype_t));
|
||||
res = sizeof(gnrc_nettype_t);
|
||||
break;
|
||||
case NETOPT_GTS_TX:
|
||||
assert(opt->data_len == sizeof(netopt_enable_t));
|
||||
m_dsme.setGTSTransmission(*((netopt_enable_t *)opt->data) ? true : false);
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
case NETOPT_ACK_REQ:
|
||||
assert(opt->data_len == sizeof(netopt_enable_t));
|
||||
m_dsme.setAckReq(*((netopt_enable_t *)opt->data) ? true : false);
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
case NETOPT_SRC_LEN:
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _init(gnrc_netif_t *netif)
|
||||
{
|
||||
netif->flags = 0;
|
||||
netif_register(&netif->netif);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const gnrc_netif_ops_t dsme_ops = {
|
||||
.init = _init,
|
||||
.send = _send,
|
||||
.recv = _recv,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
};
|
||||
|
||||
int gnrc_netif_opendsme_create(gnrc_netif_t *netif, char *stack, int stacksize,
|
||||
char priority, const char *name, netdev_t *dev)
|
||||
{
|
||||
m_dsme.setGNRCNetif(netif);
|
||||
return gnrc_netif_create(netif, stack, stacksize, priority, name, dev,
|
||||
&dsme_ops);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
340
pkg/opendsme/include/opendsme/DSMEMessage.h
Normal file
340
pkg/opendsme/include/opendsme/DSMEMessage.h
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 pkg_opendsme_dsmemessage DSME Message interface implementation.
|
||||
* @ingroup pkg_opendsme
|
||||
* @brief Implementation of the DSME Message interface for GNRC.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief DSME Message interface implementation for GNRC.
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENDSME_DSMEMESSAGE_H
|
||||
#define OPENDSME_DSMEMESSAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dsmeLayer/messages/IEEE802154eMACHeader.h"
|
||||
#include "interfaces/IDSMEMessage.h"
|
||||
#include "iolist.h"
|
||||
#include "mac_services/dataStructures/DSMEMessageElement.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
#include "opendsme/dsme_settings.h"
|
||||
#include "opendsme/dsme_platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
namespace dsme {
|
||||
|
||||
/**
|
||||
* @brief Forward declaration of DSMEPlatform class
|
||||
*/
|
||||
class DSMEPlatform;
|
||||
|
||||
/**
|
||||
* @brief DSME Message interface implementation for GNRC
|
||||
*/
|
||||
class DSMEMessage : public IDSMEMessage {
|
||||
public:
|
||||
/************* IDSMEMessage implementation *************/
|
||||
|
||||
/**
|
||||
* @brief prepend a header to current message
|
||||
*/
|
||||
void prependFrom(DSMEMessageElement *msg) override;
|
||||
|
||||
/**
|
||||
* @brief decapsulate header to a message
|
||||
*/
|
||||
void decapsulateTo(DSMEMessageElement *msg) override;
|
||||
|
||||
/**
|
||||
* @brief copy payload to DSME Message Element
|
||||
*/
|
||||
void copyTo(DSMEMessageElement *msg);
|
||||
|
||||
/**
|
||||
* @brief check whether the message has payload
|
||||
*/
|
||||
bool hasPayload()
|
||||
{
|
||||
return this->pkt != NULL && this->pkt->size > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the symbol counter at the end of the SFD
|
||||
*/
|
||||
uint32_t getStartOfFrameDelimiterSymbolCounter() override
|
||||
{
|
||||
return startOfFrameDelimiterSymbolCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the symbol counter at the end of the SFD
|
||||
*/
|
||||
void setStartOfFrameDelimiterSymbolCounter(uint32_t symbolCounter) override
|
||||
{
|
||||
startOfFrameDelimiterSymbolCounter = symbolCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the total number of symbols in current frame
|
||||
*/
|
||||
uint16_t getTotalSymbols()
|
||||
{
|
||||
DSME_ASSERT(pkt);
|
||||
/* Hardcoded to O-QPSK */
|
||||
uint16_t bytes = macHdr.getSerializationLength()
|
||||
+ pkt->size
|
||||
+ 2 /* FCS */
|
||||
+ 4 /* Preamble */
|
||||
+ 1 /* SFD */
|
||||
+ 1; /* PHY Header */
|
||||
|
||||
return bytes * 2; /* 4 bit per symbol */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get number of MPDU Symbols
|
||||
* @note not used by openDSME
|
||||
*/
|
||||
uint8_t getMPDUSymbols() override;
|
||||
|
||||
/**
|
||||
* @brief get IEEE 802.15.4 header
|
||||
*/
|
||||
IEEE802154eMACHeader& getHeader()
|
||||
{
|
||||
return macHdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get LQI of the message
|
||||
*/
|
||||
uint8_t getLQI() override
|
||||
{
|
||||
return messageLQI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check whether the message was received via MCPS
|
||||
*/
|
||||
bool getReceivedViaMCPS() override
|
||||
{
|
||||
return receivedViaMCPS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief indicated that message was received via MCPS
|
||||
*/
|
||||
void setReceivedViaMCPS(bool receivedViaMCPS) override
|
||||
{
|
||||
this->receivedViaMCPS = receivedViaMCPS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief whether the message is being sent
|
||||
*/
|
||||
bool getCurrentlySending() override
|
||||
{
|
||||
return currentlySending;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief indicate that the message is being sent
|
||||
*/
|
||||
void setCurrentlySending(bool currentlySending) override
|
||||
{
|
||||
this->currentlySending = currentlySending;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief increase retry counter for current message
|
||||
*/
|
||||
void increaseRetryCounter() override
|
||||
{
|
||||
this->retryCounter++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get retry counter
|
||||
*/
|
||||
uint8_t getRetryCounter() override
|
||||
{
|
||||
return this->retryCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get payload length
|
||||
*/
|
||||
uint8_t getPayloadLength()
|
||||
{
|
||||
DSME_ASSERT(pkt);
|
||||
return pkt->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get RSSI of frame
|
||||
*/
|
||||
int8_t getRSSI() override
|
||||
{
|
||||
return this->messageRSSI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief preallocate buffer with a given length
|
||||
*/
|
||||
int loadBuffer(size_t len);
|
||||
|
||||
/**
|
||||
* @brief load a GNRC packet into the internal openDSME message representation
|
||||
*/
|
||||
int loadBuffer(iolist_t *pkt);
|
||||
|
||||
/**
|
||||
* @brief get buffer associated to the current payload
|
||||
*/
|
||||
uint8_t *getPayload()
|
||||
{
|
||||
DSME_ASSERT(pkt);
|
||||
return (uint8_t *)pkt->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief drop a number of bytes from the header
|
||||
*/
|
||||
int dropHdr(size_t len);
|
||||
|
||||
/**
|
||||
* @brief release the message
|
||||
*/
|
||||
void releaseMessage();
|
||||
|
||||
/**
|
||||
* @brief dispatch the message to upper layers
|
||||
*/
|
||||
void dispatchMessage();
|
||||
|
||||
/**
|
||||
* @brief get the IOLIST representation of the message
|
||||
*/
|
||||
iolist_t *getIolPayload();
|
||||
|
||||
/**
|
||||
* @brief clear the message
|
||||
*/
|
||||
void clearMessage();
|
||||
|
||||
/**
|
||||
* @brief whether the message is being sent on the first try
|
||||
*/
|
||||
bool firstTry;
|
||||
|
||||
/**
|
||||
* @brief whether the message is free
|
||||
*/
|
||||
bool free;
|
||||
private:
|
||||
/**
|
||||
* @brief DSMEMessage constructor
|
||||
*/
|
||||
DSMEMessage() :
|
||||
messageRSSI(0),
|
||||
messageLQI(0),
|
||||
receivedViaMCPS(false),
|
||||
currentlySending(false),
|
||||
retryCounter(0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief DSMEMessage destructor
|
||||
*/
|
||||
~DSMEMessage()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief prepare message
|
||||
*/
|
||||
void prepare()
|
||||
{
|
||||
currentlySending = false;
|
||||
firstTry = true;
|
||||
receivedViaMCPS = false;
|
||||
retryCounter = 0;
|
||||
|
||||
macHdr.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief descriptor of the MAC header
|
||||
*/
|
||||
IEEE802154eMACHeader macHdr;
|
||||
|
||||
/**
|
||||
* @brief stores the RSSI of the received frame
|
||||
*/
|
||||
uint8_t messageRSSI;
|
||||
|
||||
/**
|
||||
* @brief stores the LQI of the received frame
|
||||
*/
|
||||
uint8_t messageLQI;
|
||||
|
||||
/**
|
||||
* @brief stores a pointer to the GNRC Pktbuf representation
|
||||
*/
|
||||
gnrc_pktsnip_t *pkt;
|
||||
|
||||
/**
|
||||
* @brief stores the timestamp of the preamble
|
||||
*/
|
||||
uint32_t startOfFrameDelimiterSymbolCounter;
|
||||
|
||||
/**
|
||||
* @brief stores whether the message was received via MCPS
|
||||
*/
|
||||
bool receivedViaMCPS;
|
||||
|
||||
/**
|
||||
* @brief stores whether the frame is currently being sent
|
||||
*/
|
||||
bool currentlySending;
|
||||
|
||||
/**
|
||||
* @brief number of retransmission attempts
|
||||
*/
|
||||
uint8_t retryCounter;
|
||||
|
||||
/**
|
||||
* @brief pointer to the GNRC network interface
|
||||
*/
|
||||
gnrc_netif_t *netif;
|
||||
|
||||
/* declare related classes as friends */
|
||||
friend class DSMEPlatform;
|
||||
friend class DSMEMessageElement;
|
||||
friend class DSMEPlatformBase;
|
||||
friend class DSMEMessageBuffer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENDSME_DSMEMESSAGE_H */
|
||||
/** @} */
|
546
pkg/opendsme/include/opendsme/DSMEPlatform.h
Normal file
546
pkg/opendsme/include/opendsme/DSMEPlatform.h
Normal file
@ -0,0 +1,546 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 pkg_opendsme_dsmeplatform DSME Platform interface implementation.
|
||||
* @ingroup pkg_opendsme
|
||||
* @brief Implementation of the DSME Platform interface.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief DSME Platform interface implementation
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENDSME_DSMEPLATFORM_H
|
||||
#define OPENDSME_DSMEPLATFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include "random.h"
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "dsmeAdaptionLayer/DSMEAdaptionLayer.h"
|
||||
#include "dsmeLayer/DSMELayer.h"
|
||||
#include "helper/DSMEDelegate.h"
|
||||
#include "interfaces/IDSMEPlatform.h"
|
||||
#include "mac_services/dataStructures/IEEE802154MacAddress.h"
|
||||
#include "mac_services/mcps_sap/MCPS_SAP.h"
|
||||
#include "mac_services/mlme_sap/MLME_SAP.h"
|
||||
#include "mac_services/pib/MAC_PIB.h"
|
||||
#include "mac_services/pib/PHY_PIB.h"
|
||||
#include "mac_services/pib/dsme_phy_constants.h"
|
||||
#include "mac_services/DSME_Common.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
#include "opendsme/dsme_settings.h"
|
||||
#include "opendsme/DSMEMessage.h"
|
||||
#include "ztimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
namespace dsme {
|
||||
|
||||
struct DSMESettings;
|
||||
class DSMELayer;
|
||||
class DSMEAdaptionLayer;
|
||||
|
||||
/**
|
||||
* @brief DSMEPlatform interface implementation for GNRC
|
||||
*/
|
||||
class DSMEPlatform : public IDSMEPlatform {
|
||||
public:
|
||||
/**
|
||||
* @brief DSMEPlatform constructor
|
||||
*/
|
||||
DSMEPlatform();
|
||||
/**
|
||||
* @brief DSMEPlatform destructor
|
||||
*/
|
||||
~DSMEPlatform();
|
||||
|
||||
/**
|
||||
* @brief pointer to the DSME instance
|
||||
*/
|
||||
static DSMEPlatform* instance;
|
||||
|
||||
/**
|
||||
* @brief initialize MAC with a role (PAN coordinator, child)
|
||||
*/
|
||||
void initialize(bool pan_coord);
|
||||
|
||||
/**
|
||||
* @brief to be called by the upper layer in order to send a frame
|
||||
*/
|
||||
void sendFrame(uint16_t addr, iolist_t *pkt);
|
||||
|
||||
/**
|
||||
* @brief start DSME
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief get the DSME layer
|
||||
*/
|
||||
DSMELayer& getDSME() {
|
||||
return dsme;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check whether the node associated
|
||||
*/
|
||||
bool isAssociated();
|
||||
|
||||
#if IS_ACTIVE(CONFIG_IEEE802154_DSME_STATIC_GTS) || DOXYGEN
|
||||
/**
|
||||
* @brief allocate a GTS slot
|
||||
*/
|
||||
void allocateGTS(uint8_t superframeID, uint8_t slotID, uint8_t channelID,
|
||||
Direction direction, uint16_t address);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief get short address
|
||||
*/
|
||||
void getShortAddress(network_uint16_t *addr);
|
||||
|
||||
/**
|
||||
* @brief set GTS or CAP transmission
|
||||
*/
|
||||
void setGTSTransmission(bool gts);
|
||||
|
||||
/**
|
||||
* @brief set ACK_REQ bit
|
||||
*/
|
||||
void setAckReq(bool ackReq);
|
||||
|
||||
/**
|
||||
* @brief request to offload the CCA Done event
|
||||
*/
|
||||
void offloadCCAEvent();
|
||||
|
||||
/**
|
||||
* @brief request to offload the TX Done event
|
||||
*/
|
||||
void offloadTXDoneEvent();
|
||||
|
||||
/**
|
||||
* @brief indicate the MAC layer that the reception started
|
||||
*/
|
||||
void indicateRxStart();
|
||||
|
||||
/**
|
||||
* @brief request to offload RX Done event
|
||||
*/
|
||||
void offloadRXDoneEvent();
|
||||
|
||||
/**
|
||||
* @brief request to offload ACK Timer event
|
||||
*/
|
||||
void offloadACKTimer();
|
||||
|
||||
/**
|
||||
* @brief request to offload Timer event
|
||||
*/
|
||||
void offloadTimerEvent();
|
||||
|
||||
/**
|
||||
* @brief set the platform state
|
||||
*/
|
||||
void setPlatformState(uint8_t state) {
|
||||
this->state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief process the CCA Done event
|
||||
*/
|
||||
void processCCAEvent();
|
||||
|
||||
/**
|
||||
* @brief process the TX Done event
|
||||
*/
|
||||
void processTXDoneEvent();
|
||||
|
||||
/**
|
||||
* @brief process the RX Done event from radio
|
||||
*/
|
||||
void processRxDone();
|
||||
|
||||
/**
|
||||
* @brief process the offload event of received frame
|
||||
*/
|
||||
void processRxOffload();
|
||||
|
||||
/**
|
||||
* @brief set the GNRC netif
|
||||
*/
|
||||
void setGNRCNetif(gnrc_netif_t *netif) {
|
||||
this->netif = netif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief state of the Platform layer
|
||||
*/
|
||||
enum {
|
||||
STATE_READY = 0, STATE_CCA_WAIT = 1, STATE_SEND = 2,
|
||||
};
|
||||
|
||||
/*********** IDSMEPlatform implementation ***********/
|
||||
|
||||
/**
|
||||
* @brief get channel number
|
||||
*/
|
||||
uint8_t getChannelNumber() override;
|
||||
|
||||
/**
|
||||
* @brief set channel number
|
||||
*/
|
||||
bool setChannelNumber(uint8_t k) override;
|
||||
|
||||
/**
|
||||
* @brief Directly send packet without delay and without CSMA
|
||||
* but keep the message (the caller has to ensure that the message is eventually released)
|
||||
* This might lead to an additional memory copy in the platform
|
||||
*/
|
||||
bool sendNow() override;
|
||||
|
||||
/**
|
||||
* @brief prepare the next transmission
|
||||
*/
|
||||
bool prepareSendingCopy(IDSMEMessage* msg, Delegate<void(bool)> txEndCallback) override;
|
||||
|
||||
/**
|
||||
* @brief prepare the next transmission
|
||||
*/
|
||||
bool prepareSendingCopy(DSMEMessage* msg, Delegate<void(bool)> txEndCallback);
|
||||
|
||||
/**
|
||||
* @brief abort an already prepared transmission
|
||||
*/
|
||||
void abortPreparedTransmission() override;
|
||||
|
||||
/**
|
||||
* @brief send an ACK message, delay until aTurnaRoundTime after reception_time has expired
|
||||
*/
|
||||
bool sendDelayedAck(IDSMEMessage *ackMsg, IDSMEMessage *receivedMsg,
|
||||
Delegate<void(bool)> txEndCallback) override;
|
||||
/**
|
||||
* @brief send an ACK message, delay until aTurnaRoundTime after reception_time has expired
|
||||
*/
|
||||
bool sendDelayedAck(DSMEMessage *ackMsg, DSMEMessage *receivedMsg,
|
||||
Delegate<void(bool)> txEndCallback);
|
||||
|
||||
/**
|
||||
* @brief set the receive callback
|
||||
*/
|
||||
void setReceiveDelegate(receive_delegate_t receiveDelegate) override;
|
||||
|
||||
/**
|
||||
* @brief check whether the ACK layer is busy
|
||||
*/
|
||||
bool isReceptionFromAckLayerPossible() override;
|
||||
|
||||
/**
|
||||
* @brief handle reception of frames from ACK Layer
|
||||
*/
|
||||
void handleReceivedMessageFromAckLayer(IDSMEMessage* message) override;
|
||||
|
||||
/**
|
||||
* @brief handle reception of frames from ACK Layer
|
||||
*/
|
||||
void handleReceivedMessageFromAckLayer(DSMEMessage* message);
|
||||
|
||||
/**
|
||||
* @brief get an empty message
|
||||
*/
|
||||
DSMEMessage* getEmptyMessage() override;
|
||||
|
||||
/**
|
||||
* @brief release a message
|
||||
*/
|
||||
void releaseMessage(IDSMEMessage* msg) override;
|
||||
|
||||
/**
|
||||
* @brief release a message
|
||||
*/
|
||||
void releaseMessage(DSMEMessage* msg);
|
||||
|
||||
/**
|
||||
* @brief start CCA procedure
|
||||
*/
|
||||
bool startCCA() override;
|
||||
|
||||
/**
|
||||
* @brief start timer
|
||||
*/
|
||||
void startTimer(uint32_t symbolCounterValue) override;
|
||||
|
||||
/**
|
||||
* @brief get elapsed number of symbols since initialization
|
||||
*/
|
||||
uint32_t getSymbolCounter() override;
|
||||
|
||||
/**
|
||||
* @brief get a uint16_t random number
|
||||
*/
|
||||
uint16_t getRandom() override {
|
||||
return (random_uint32() % UINT16_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief update visual components of openDSME
|
||||
* @note to be used in a simulation environment and therefore not used
|
||||
* in RIOT
|
||||
*/
|
||||
void updateVisual() override;
|
||||
|
||||
/**
|
||||
* @brief callback to offload the start of CFP
|
||||
*/
|
||||
void scheduleStartOfCFP();
|
||||
|
||||
/**
|
||||
* @brief Get the minimum LQI. Beacons with LQI lower than this will not be
|
||||
* considered when deciding for a coordinator to associate to.
|
||||
*/
|
||||
uint8_t getMinCoordinatorLQI() override{
|
||||
return CONFIG_IEEE802154_DSME_MIN_COORD_LQI;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief turn on transceiver
|
||||
*/
|
||||
void turnTransceiverOn();
|
||||
|
||||
/**
|
||||
* @brief turn off transceiver
|
||||
*/
|
||||
void turnTransceiverOff();
|
||||
|
||||
/**
|
||||
* @brief get extended address
|
||||
*/
|
||||
IEEE802154MacAddress& getAddress() {
|
||||
return this->mac_pib.macExtendedAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief signal finish of ACK'd transmission
|
||||
*/
|
||||
void signalAckedTransmissionResult(bool success, uint8_t transmissionAttempts,
|
||||
IEEE802154MacAddress receiver) override;
|
||||
|
||||
/**
|
||||
* @brief signal a change in GTS status
|
||||
*/
|
||||
void signalGTSChange(bool deallocation, IEEE802154MacAddress counterpart,
|
||||
uint16_t superframeID, uint8_t gtSlotID, uint8_t channel,
|
||||
Direction direction) override;
|
||||
|
||||
/**
|
||||
* @brief signal a change in queue length
|
||||
*/
|
||||
void signalQueueLength(uint32_t length) override;
|
||||
|
||||
/**
|
||||
* @brief signal the number of packets transmitted during the last CAP
|
||||
*/
|
||||
void signalPacketsPerCAP(uint32_t packets) override;
|
||||
|
||||
/**
|
||||
* @brief signal the number of failed packets transmitted during the last CAP
|
||||
*/
|
||||
void signalFailedPacketsPerCAP(uint32_t packets) override;
|
||||
|
||||
/**
|
||||
* @brief callback to check where RX is on during CAP
|
||||
*/
|
||||
bool isRxEnabledOnCap() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Copy constructor is not allowed.
|
||||
*/
|
||||
DSMEPlatform(const DSMEPlatform&);
|
||||
/**
|
||||
* @brief Assignment operator is not allowed.
|
||||
*/
|
||||
DSMEPlatform& operator=(const DSMEPlatform&);
|
||||
|
||||
/**
|
||||
* @brief delegate callback for TX end
|
||||
*/
|
||||
Delegate<void(bool)> txEndCallback;
|
||||
|
||||
/**
|
||||
* @brief signal creation of new message
|
||||
*/
|
||||
void signalNewMsg(DSMEMessage* msg);
|
||||
|
||||
/**
|
||||
* @brief signal release of message
|
||||
*/
|
||||
virtual void signalReleasedMsg(DSMEMessage* msg) {}
|
||||
|
||||
/**
|
||||
* @brief dSMEAdaptionLayer wrapper for MCPS Indication callbacks
|
||||
*/
|
||||
void handleDataMessageFromMCPSWrapper(IDSMEMessage* msg);
|
||||
|
||||
/**
|
||||
* @brief dSMEAdaptionLayer wrapper for MCPS Indication callbacks
|
||||
*/
|
||||
void handleDataMessageFromMCPS(DSMEMessage* msg);
|
||||
|
||||
/**
|
||||
* @brief dSMEAdaptionLayer wrapper for MCPS Confirm callbacks
|
||||
*/
|
||||
void handleConfirmFromMCPSWrapper(IDSMEMessage* msg, DataStatus::Data_Status dataStatus);
|
||||
|
||||
/**
|
||||
* @brief dSMEAdaptionLayer wrapper for MCPS Confirm callbacks
|
||||
*/
|
||||
void handleConfirmFromMCPS(DSMEMessage* msg, DataStatus::Data_Status dataStatus);
|
||||
|
||||
/**
|
||||
* @brief translate MAC Address representation
|
||||
*/
|
||||
void translateMacAddress(uint16_t& from, IEEE802154MacAddress& to);
|
||||
|
||||
/**
|
||||
* @brief get the event queue of the MAC
|
||||
*/
|
||||
event_queue_t *getEventQueue() {
|
||||
return &this->netif->evq[GNRC_NETIF_EVQ_INDEX_PRIO_LOW];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief holds the PHY Information Base
|
||||
*/
|
||||
PHY_PIB phy_pib;
|
||||
|
||||
/**
|
||||
* @brief holds the MAC Information Base
|
||||
*/
|
||||
MAC_PIB mac_pib;
|
||||
|
||||
/**
|
||||
* @brief descriptor of the DSME MAC
|
||||
*/
|
||||
DSMELayer dsme;
|
||||
|
||||
/**
|
||||
* @brief descriptor of the MCPS Service Access Point
|
||||
*/
|
||||
mcps_sap::MCPS_SAP mcps_sap;
|
||||
|
||||
/**
|
||||
* @brief descriptor of the MLME Service Access Point
|
||||
*/
|
||||
mlme_sap::MLME_SAP mlme_sap;
|
||||
|
||||
/**
|
||||
* @brief descriptor of the DSME Adaption Layer
|
||||
*/
|
||||
DSMEAdaptionLayer dsmeAdaptionLayer;
|
||||
|
||||
/**
|
||||
* @brief whether the MAC is initialized
|
||||
*/
|
||||
bool initialized;
|
||||
|
||||
/**
|
||||
* @brief whether there is a scan or sync in progress
|
||||
*/
|
||||
bool scanOrSyncInProgress{false};
|
||||
|
||||
/**
|
||||
* @brief whether the association is in progress
|
||||
*/
|
||||
bool associationInProgress{false};
|
||||
|
||||
/**
|
||||
* @brief whether the MAC is synchronized
|
||||
*/
|
||||
bool syncActive{false};
|
||||
|
||||
/**
|
||||
* @brief whether the MAC keeps the receiver on during CAP
|
||||
*/
|
||||
bool rx_on_cap{true};
|
||||
|
||||
/**
|
||||
* @brief delegate callback for passing frames to the ACK layer
|
||||
*/
|
||||
receive_delegate_t receiveFromAckLayerDelegate;
|
||||
|
||||
/**
|
||||
* @brief pointer to the GNRC interface
|
||||
*/
|
||||
gnrc_netif_t *netif;
|
||||
|
||||
/**
|
||||
* @brief timer used for the MAC
|
||||
*/
|
||||
ztimer_t timer;
|
||||
|
||||
/**
|
||||
* @brief used to hold an incoming message before passing it to the MAC
|
||||
*/
|
||||
IDSMEMessage *message;
|
||||
|
||||
/**
|
||||
* @brief pointer to the scheduler
|
||||
*/
|
||||
GTSScheduling* scheduling = nullptr;
|
||||
|
||||
/**
|
||||
* @brief timestamp (in number of symbols) of the last received preamble
|
||||
*/
|
||||
uint32_t rx_sfd;
|
||||
|
||||
/**
|
||||
* @brief timer used for ACK timeout events
|
||||
*/
|
||||
ztimer_t acktimer;
|
||||
|
||||
/**
|
||||
* @brief state of the platform layer
|
||||
*/
|
||||
uint8_t state;
|
||||
|
||||
/**
|
||||
* @brief whether the MAC expects an ACK frame
|
||||
*/
|
||||
bool wait_for_ack;
|
||||
|
||||
/**
|
||||
* @brief whether there is a pending TX frame
|
||||
*/
|
||||
bool pending_tx;
|
||||
|
||||
/**
|
||||
* @brief pointer to the IEEE 802.15.4 HAL descriptor
|
||||
*/
|
||||
ieee802154_dev_t *radio;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENDSME_DSMEPLATFORM_H */
|
||||
/** @} */
|
45
pkg/opendsme/include/opendsme/dsme_atomic.h
Normal file
45
pkg/opendsme/include/opendsme/dsme_atomic.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_opendsme
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENDSME_DSME_ATOMIC_H
|
||||
#define OPENDSME_DSME_ATOMIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Begin atomic operations on openDSME.
|
||||
*
|
||||
* @note Since openDSME runs on one thread, this is not required
|
||||
*/
|
||||
#define dsme_atomicBegin()
|
||||
|
||||
/**
|
||||
* @brief End atomic operations on openDSME.
|
||||
*
|
||||
* @note Since openDSME runs on one thread, this is not required
|
||||
*/
|
||||
#define dsme_atomicEnd()
|
||||
|
||||
#endif /* OPENDSME_DSME_ATOMIC_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/** @} */
|
52
pkg/opendsme/include/opendsme/dsme_platform.h
Normal file
52
pkg/opendsme/include/opendsme/dsme_platform.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_opendsme
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENDSME_DSME_PLATFORM_H
|
||||
#define OPENDSME_DSME_PLATFORM_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ASSERT(x) assert(x) /**< openDSME assert macro implementation */
|
||||
#define DSME_ASSERT(x) assert(x) /**< openDSME DSME assert macro implementation */
|
||||
#define DSME_SIM_ASSERT(x) /**< not used */
|
||||
|
||||
#define LOG_INFO(x) /**< not used */
|
||||
#define LOG_INFO_PURE(x) /**< not used */
|
||||
#define LOG_INFO_PREFIX /**< not used */
|
||||
#define LOG_ERROR(x) /**< not used */
|
||||
|
||||
#define HEXOUT std::hex /**< openDSME HEXOUT macro implementation */
|
||||
#define DECOUT std::dec /**< openDSME DECout macro implementation */
|
||||
|
||||
#define LOG_ENDL std::endl /**< openDSME log endline implementation */
|
||||
|
||||
#define LOG_DEBUG(x) /**< not used */
|
||||
#define LOG_DEBUG_PURE(x) /**< not used */
|
||||
#define LOG_DEBUG_PREFIX /**< not used */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENDSME_DSME_PLATFORM_H */
|
||||
/** @} */
|
166
pkg/opendsme/include/opendsme/dsme_settings.h
Normal file
166
pkg/opendsme/include/opendsme/dsme_settings.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_opendsme
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
#ifndef OPENDSME_DSME_SETTINGS_H
|
||||
#define OPENDSME_DSME_SETTINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "kernel_defines.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "opendsme.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief maximum number of lost beacons before leaving the network
|
||||
*/
|
||||
#define DSME_MAX_LOST_BEACONS CONFIG_OPENDSME_MAX_LOST_BEACONS
|
||||
|
||||
namespace dsme {
|
||||
|
||||
namespace const_redefines {
|
||||
/**
|
||||
* @brief fixed value, see Table 8-80 of IEEE 802.15.4-2015, this includes beacon, CAP and GTS
|
||||
*/
|
||||
constexpr uint8_t aNumSuperframeSlots = 16;
|
||||
/**
|
||||
* @brief fixed value, see 8.1.3 of IEEE 802.15.4-2011 (assuming no UWB PHY)
|
||||
*/
|
||||
constexpr uint8_t macSIFSPeriod = 12;
|
||||
|
||||
/**
|
||||
* @brief fixed value, see 8.1.3 of IEEE 802.15.4-2011 (assuming no UWB PHY)
|
||||
*/
|
||||
constexpr uint8_t macLIFSPeriod = 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief guard time before a DSME event
|
||||
*/
|
||||
constexpr uint8_t PRE_EVENT_SHIFT = const_redefines::macLIFSPeriod;
|
||||
|
||||
/**
|
||||
* @brief Minimum number of CSMA slots
|
||||
*/
|
||||
constexpr uint8_t MIN_CSMA_SLOTS = 0;
|
||||
|
||||
/**
|
||||
* @brief maximum number of GTS slots
|
||||
*/
|
||||
constexpr uint8_t MAX_GTSLOTS = const_redefines::aNumSuperframeSlots - MIN_CSMA_SLOTS - 1;
|
||||
|
||||
/**
|
||||
* @brief maximum number of IEEE 802.15.4 channels
|
||||
*/
|
||||
constexpr uint8_t MAX_CHANNELS = 16; /* For O-QPSK */
|
||||
|
||||
/**
|
||||
* @brief minimum number of IEEE 802.15.4 channels
|
||||
*/
|
||||
constexpr uint8_t MIN_CHANNEL = 11; /* For O-QPSK */
|
||||
|
||||
/**
|
||||
* @brief default MAC channel
|
||||
*/
|
||||
constexpr uint8_t MAC_DEFAULT_CHANNEL = CONFIG_IEEE802154_DEFAULT_CHANNEL; /* For O-QPSK */
|
||||
|
||||
/**
|
||||
* @brief maximum number of neighbors
|
||||
*/
|
||||
constexpr uint8_t MAX_NEIGHBORS = CONFIG_OPENDSME_MAX_NEIGHBOURS;
|
||||
|
||||
/**
|
||||
* @brief default PAN ID
|
||||
*/
|
||||
constexpr uint16_t MAC_DEFAULT_NWK_ID = CONFIG_IEEE802154_DEFAULT_PANID;
|
||||
|
||||
/**
|
||||
* @brief Minimum superframe order
|
||||
*/
|
||||
constexpr uint8_t MIN_SO = CONFIG_IEEE802154_DSME_SUPERFRAME_ORDER;
|
||||
|
||||
/**
|
||||
* @brief Maximum beacon order
|
||||
*/
|
||||
constexpr uint8_t MAX_BO = CONFIG_IEEE802154_DSME_BEACON_ORDER;
|
||||
|
||||
/**
|
||||
* @brief Maximum multi-superframe order
|
||||
*/
|
||||
constexpr uint8_t MAX_MO = CONFIG_IEEE802154_DSME_MULTISUPERFRAME_ORDER;
|
||||
|
||||
/**
|
||||
* @brief Maximum number of slots per superframe
|
||||
*/
|
||||
constexpr uint16_t MAX_SLOTS_PER_SUPERFRAMES = 1 << (uint16_t)(MAX_BO - MIN_SO);
|
||||
|
||||
/**
|
||||
* @brief Maximum number of superframes per beacon interval
|
||||
*/
|
||||
constexpr uint16_t MAX_TOTAL_SUPERFRAMES = 1 << (uint16_t)(MAX_BO - MIN_SO);
|
||||
|
||||
/**
|
||||
* @brief Maximum number of superframes per multi-superframe
|
||||
*/
|
||||
constexpr uint16_t MAX_SUPERFRAMES_PER_MULTI_SUPERFRAME = 1 << (uint16_t)(MAX_MO - MIN_SO);
|
||||
|
||||
/**
|
||||
* @brief Maximum number of GTS slots per superframe
|
||||
*/
|
||||
constexpr uint16_t MAX_OCCUPIED_SLOTS = MAX_SUPERFRAMES_PER_MULTI_SUPERFRAME*MAX_GTSLOTS*MAX_CHANNELS;
|
||||
|
||||
/**
|
||||
* @brief Maximum number of SAB units
|
||||
*/
|
||||
constexpr uint8_t MAX_SAB_UNITS = 1;
|
||||
|
||||
/**
|
||||
* @brief Size of the CAP queue
|
||||
*/
|
||||
constexpr uint16_t CAP_QUEUE_SIZE = CONFIG_OPENDSME_CAP_QUEUE_SIZE;
|
||||
|
||||
/**
|
||||
* @brief Size of the CFP queue
|
||||
*/
|
||||
constexpr uint16_t TOTAL_GTS_QUEUE_SIZE = CONFIG_OPENDSME_CFP_QUEUE_SIZE;
|
||||
|
||||
/**
|
||||
* @brief Size of the CAP queue
|
||||
*/
|
||||
constexpr uint16_t UPPER_LAYER_QUEUE_SIZE = 4;
|
||||
|
||||
/**
|
||||
* @brief Broadcast PAN ID
|
||||
*/
|
||||
constexpr uint16_t DSME_BROADCAST_PAN_ID = 0xffff;
|
||||
|
||||
/**
|
||||
* @brief Additional time to wait for an ACK
|
||||
*/
|
||||
constexpr uint8_t ADDITIONAL_ACK_WAIT_DURATION = 63;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENDSME_DSME_SETTINGS_H */
|
||||
/** @} */
|
284
pkg/opendsme/include/opendsme/opendsme.h
Normal file
284
pkg/opendsme/include/opendsme/opendsme.h
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 pkg_opendsme openDSME - IEEE 802.15.4 DSME
|
||||
* @ingroup pkg
|
||||
* @ingroup net
|
||||
* @brief Support for IEEE 802.15.4 Deterministic and Synchronous Multi-channel Extension.
|
||||
*
|
||||
* @author José I. Álamos <jose.alamos@haw-hamburg.de>
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* # About
|
||||
*
|
||||
* The IEEE 802.15.4 standard with its widespread usage in wireless sensor and
|
||||
* actuator networks was extended by several techniques that allow reliable data
|
||||
* transmission for critical applications, such as industrial plants. This
|
||||
* includes the Deterministic and Synchronous Multi-channel Extension (DSME) that
|
||||
* allows for distributed assignment of time slots on multiple channels.
|
||||
*
|
||||
* RIOT provides DSME support via the open source implementation
|
||||
* [openDSME](https://opendsme.org/).
|
||||
*
|
||||
* # Features
|
||||
* - Topology agnostic (peer-to-peer, star, mesh, etc).
|
||||
* - By design, a DSME network can be extended just by adding more coordinators near the edge.
|
||||
* - Automatic resolution of beacon collision
|
||||
* - Frame transmission using either CSMA-CA or multi-channel GTS (guaranteed time slot)
|
||||
* - Built-in slot negotiation (dynamic allocation) and static allocation.
|
||||
*
|
||||
* ## Network formation
|
||||
*
|
||||
* A PAN coordinator device initializes a DSME superframe structure which consists
|
||||
* of a series of superframes that repeat indefinitely. A superframe consists
|
||||
* of a Beacon Slot, a Contention Access Period and Contention Free Period.
|
||||
*
|
||||
* BS CAP CFP BS
|
||||
* +------------------------------------------------------+----
|
||||
* | | |--|--|--|--|--|--| | ...
|
||||
* | | |--|--|--|--|--|--| |
|
||||
* | | |--|--|--|--|--|--| | ...
|
||||
* | | |--|--|--|--|--|--| |
|
||||
* +---+--------------------------------+--+--+--+--+--+--+---+
|
||||
* <------------------- Superframe ----------------------->
|
||||
*
|
||||
* Each period of the superframe serves a dedicated purpose:
|
||||
* - Beacon Slot: Used for beacon transmission. PAN Coordinators and Coordinators
|
||||
* transmit beacons periodically in these beacon slots. All devices (except the
|
||||
* PAN coordinator) listen to their parent coordinator beacons and synchronize
|
||||
* their superframe structure accordingly. Each coordinator (including the PAN
|
||||
* Coordinator) transmits beacon periocally. To avoid beacon collisions, DSME
|
||||
* allows to set the beacon interval of all devices in multiples of the
|
||||
* superframe structure. This allows other coordinator devices to transmit
|
||||
* beacons in a different superframe offset and therefore avoid beacon
|
||||
* collisions. The beacon slot has a duration of one slot.
|
||||
* - Contention Access Period: During CAP, devices transmit using slotted
|
||||
* CSMA-CA. This means, the CAP is divided in a series of CCA slots. These
|
||||
* slots are aligned with the beginning of the CAP. A device can transmit
|
||||
* only if CCA assess clear channel on three consecutive slots. If there's
|
||||
* not enough CAP time left, the frame will be postponed until the next CAP
|
||||
* period. On CSMA-CA transmissions, the MAC put the message in a CAP queue
|
||||
* and transmits as soon as possible. By default, the CAP queue size is 8
|
||||
* frames. The CAP has a duration of 8 slots
|
||||
* - Contention Free Period: During CFP devices transmit using a dedicated
|
||||
* Guaranteed Time Slot. GTS are multi-channel, which allows concurrent
|
||||
* communication in the same GTS. On transmission schedule, the MAC puts
|
||||
* the message in a CFP queue and transmit in the next available GTS. By
|
||||
* default, the CFP queue size is 22. To (de)allocate a GTS, the upper layer
|
||||
* triggers a GTS Request to negotiate slots with a neighbour device. The GTS
|
||||
* Request is sent during CAP, as all MAC commands. The CFP has 7
|
||||
* multichannel GTS (each one with a duration of one slot) and the number of
|
||||
* channels depends on the underlying PHY (16 for O-QPSK). Note that slots
|
||||
* are unidirectional (TX or RX only) and cannot transmit neither broadcast
|
||||
* frames nor MAC commands.
|
||||
*
|
||||
* DSME allows to extend the number of GTS resources by combining superframes
|
||||
* into a multisuperframe structure. The number of superframes per multisuperframes
|
||||
* is configurable. This extend the number of GTS to seven times the number of
|
||||
* superframes per multisuperframe.
|
||||
*
|
||||
* Joining devices scan for beacons and perform the association procedure with
|
||||
* the the (PAN) coordinator. On success, the device is ready to communicate with
|
||||
* other devices in the DSME network.
|
||||
* To extend the network, coordinator devices can associate to any other
|
||||
* coordinator (including the PAN coordinator) and start emitting beacons in a
|
||||
* different Beacon Slot offset. Devices can then join the network via the new
|
||||
* coordinator. DSME manages beacon scheduling automatically and handles beacon
|
||||
* collisions accordingly.
|
||||
*
|
||||
* ## DSME superframe structure
|
||||
*
|
||||
* The DSME superframe structure relies on three configuration parameters:
|
||||
* Superframe Order (SO), Multisuperframe Order (MO) and Beacon Order (BO).
|
||||
* These parameters affect the slot duration (and therefore the superframe duration),
|
||||
* the number of superframes per multisuperframe and the beacon interval.
|
||||
*
|
||||
* The DSME standard defines the slot duration as
|
||||
* `slot_duration = aBaseSlotDuration * aSymbolDuration * 2^SO`. and the superframe
|
||||
* duration as "sf_duration = 16 * slot_duration".
|
||||
* `aBaseSlotDuration=60` as per standard and `aSymbolDuration` (us) depends on the
|
||||
* underlying PHY (16 for O-QPSK).
|
||||
*
|
||||
* The number of superframes per multisuperframe is given by
|
||||
* `sf_per_msf=2^(MO-SO)`.
|
||||
*
|
||||
* The beacon interval (in number of multisuperframes) is given by
|
||||
* `msf_per_bi=2^(BO-SO)`
|
||||
*
|
||||
* For example, an O-QPSK PHY with SO=3, MO=4 and BO=5 renders a slot duration
|
||||
* of 7.68 ms, a superframe duration of 122.8 ms, 2 superframes per multisuperframe
|
||||
* (msf_duration=245.7 ms) and a beacon interval of 2 multisuperframes
|
||||
* (beacon_interval=492 ms).
|
||||
*
|
||||
* The slot duration trades off maximum frame length and transmission delay during
|
||||
* GTS transmissions. A value equal or higher than 3 allows transmission of 127 bytes
|
||||
* frames.
|
||||
* Increasing the number of superframes per multisuperframe increases
|
||||
* on one hand transmission delay, because the period of a single GTS is the duration of the
|
||||
* multisuperframe. On the other hand it decreases energy consumption, because a
|
||||
* device transmit less often.
|
||||
* Increasing the beacon interval extends the number of coordinators in wireless
|
||||
* reach and reduces energy consumption. However, it slows the scanning and joining
|
||||
* procedure.
|
||||
*
|
||||
* The configuration of SO, MO and BO must be compliant with:
|
||||
* ```
|
||||
* 0 <= SO <= MO <= BO < 15
|
||||
* ```
|
||||
*
|
||||
* ## CAP Reduction
|
||||
*
|
||||
* With the purpose of reducing energy consumption and extending the GTS
|
||||
* resources even more, the MAC defines a CAP Reduction mode that turns
|
||||
* all CAP (except the first one in a multisuperframe) into CFP. This adds
|
||||
* 8 GTS per superframe that reduces CAP.
|
||||
*
|
||||
* With CAP Reduction on, increasing the number of superframes per multisuperframe
|
||||
* improves energy efficiency, because nodes spend less time on CAP. However,
|
||||
* note that this renders less CAP time which is required for slot negotiation.
|
||||
*
|
||||
* ## GTS coordinates
|
||||
*
|
||||
* A slot is defined by a superframe ID, a superframe slot and
|
||||
* a channel offset. The superframe ID is contained in `{0..n-1}`, where
|
||||
* `n` is the number of superframes per multisuperframe. The ID of the first superframe
|
||||
* (the one aligned with the start of a multisuperframe) is 0.
|
||||
*
|
||||
* The superframe slot values depend on the superframe ID.
|
||||
* ```
|
||||
* sf_slot = {0..6} if superframe_ID==0
|
||||
* sf_slot = {8..14} if superframe_ID!=0 && cap_reduction=0
|
||||
* sf_slot = {0..14} if superframe_ID!=0 && cap_reduction=1
|
||||
* ```
|
||||
*
|
||||
* The channel offset is `{0..m-1}`, with `m` the number of channels.
|
||||
*
|
||||
* # Usage in RIOT
|
||||
*
|
||||
* The RIOT implementation uses the `DSMEAdaptionLayer` wrapper internally (provided by
|
||||
* openDSME) to manage scanning/joining and automatic slot allocation. The MAC
|
||||
* implementation defines several scheduling strategies, but the default is
|
||||
* used (Traffic-aware and Predictive Scheduling).
|
||||
* The port introduces an openDSME GNRC Network Interface, that can be used via
|
||||
* @ref net_gnrc_netapi and @ref net_gnrc_netreg.
|
||||
*
|
||||
* The following network options (@ref net_netopt) are used for DSME setup.
|
||||
*
|
||||
* Configuration:
|
||||
* - @ref NETOPT_PAN_COORD. Set PAN coordinator or Child role
|
||||
* - @ref NETOPT_GTS_ALLOC. Allocate a GTS slot manually (only available via
|
||||
* @ref CONFIG_IEEE802154_DSME_STATIC_GTS).
|
||||
* - @ref NETOPT_GTS_TX. Set the next transmission to either GTS or CSMA-CA.
|
||||
* - @ref NETOPT_ACK_REQ. Set the ACK Request bit to enable confirmed
|
||||
* transmissions.
|
||||
* - @ref NETOPT_LINK. Start the DSME network (PAN Coordinator) or join an
|
||||
* existing network (Child).
|
||||
*
|
||||
* ## MAC configuration
|
||||
*
|
||||
*/
|
||||
#ifndef OPENDSME_OPENDSME_H
|
||||
#define OPENDSME_OPENDSME_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "byteorder.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
|
||||
/**
|
||||
* @brief default GNRC Pktsnip type for openDSME packets
|
||||
*/
|
||||
#ifndef CONFIG_OPENDSME_GNRC_PKTSNIP_TYPE
|
||||
#define CONFIG_OPENDSME_GNRC_PKTSNIP_TYPE GNRC_NETTYPE_UNDEF
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief maximum number of DSME neighbours
|
||||
*/
|
||||
#ifndef CONFIG_OPENDSME_MAX_NEIGHBOURS
|
||||
#define CONFIG_OPENDSME_MAX_NEIGHBOURS (20U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief maximum number of lost beacons before assuming the device desynchronized.
|
||||
*
|
||||
* Sets the maximum number of lost beacons before the MAC triggers a
|
||||
* de-association procedure. Higher values are beneficial in noisy
|
||||
* environments, because the MAC will keep synchronization despite losing some
|
||||
* beacons. However, lower values are better for mobile nodes, because devices
|
||||
* may sinchronize faster to a new coordinator.
|
||||
*/
|
||||
#ifndef CONFIG_OPENDSME_MAX_LOST_BEACONS
|
||||
#define CONFIG_OPENDSME_MAX_LOST_BEACONS (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DSME CAP queue size
|
||||
*
|
||||
* The CAP queue stores frames to be sent during the Contention Access Period
|
||||
* using CSMA-CA. Because the transmission delay of CSMA-CA is lower compared to
|
||||
* GTS transmissions, small values are preferred to reduce memory requirements.
|
||||
*/
|
||||
#ifndef CONFIG_OPENDSME_CAP_QUEUE_SIZE
|
||||
#define CONFIG_OPENDSME_CAP_QUEUE_SIZE (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DSME CFP queue size (for GTS transmissions)
|
||||
*
|
||||
* The CFP queue stores frames to be sent during the Contention Free Period
|
||||
* using a dedicated GTS. In contrast to CSMA-CA transmissions, GTS transmission
|
||||
* take longer as a result of slot schedules. Therefore, the GTS queue should have
|
||||
* more capacity than the CAP queue (@ref CONFIG_OPENDSME_CAP_QUEUE_SIZE)
|
||||
*/
|
||||
#ifndef CONFIG_OPENDSME_CFP_QUEUE_SIZE
|
||||
#define CONFIG_OPENDSME_CFP_QUEUE_SIZE (22U)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DSME Allocation descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
network_uint16_t addr; /**< neighbour address */
|
||||
uint8_t superframe_id; /**< superframe ID */
|
||||
uint8_t slot_id; /**< slot ID */
|
||||
uint8_t channel_id; /**< channel ID */
|
||||
bool tx; /**< whether the GTS is TX */
|
||||
} ieee802154_dsme_alloc_t;
|
||||
|
||||
/**
|
||||
* @brief Creates an openDSME network interface
|
||||
*
|
||||
* @param[out] netif The interface. May not be `NULL`.
|
||||
* @param[in] stack The stack for the network interface's thread.
|
||||
* @param[in] stacksize Size of @p stack.
|
||||
* @param[in] priority Priority for the network interface's thread.
|
||||
* @param[in] name Name for the network interface. May be NULL.
|
||||
* @param[in] dev Device for the interface
|
||||
*
|
||||
* @see @ref gnrc_netif_create()
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return negative number on error
|
||||
*/
|
||||
int gnrc_netif_opendsme_create(gnrc_netif_t *netif, char *stack, int stacksize,
|
||||
char priority, const char *name, netdev_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENDSME_OPENDSME_H */
|
||||
|
||||
/** @} */
|
@ -828,6 +828,25 @@ typedef enum {
|
||||
* @brief (array of byte arrays) Leave an link layer multicast group
|
||||
*/
|
||||
NETOPT_L2_GROUP_LEAVE,
|
||||
|
||||
/**
|
||||
* @brief (netopt_enable_t) Set/Get PAN coordinator role
|
||||
*/
|
||||
NETOPT_PAN_COORD,
|
||||
|
||||
/**
|
||||
* @brief (ieee802154_dsme_alloc_t) Allocate DSME GTS slot
|
||||
*/
|
||||
NETOPT_GTS_ALLOC,
|
||||
|
||||
/**
|
||||
* @brief (netopt_enable_t) Transmit frames using GTS transmission
|
||||
*
|
||||
* When set, frames are sent using a Guaranteed Time Slot (GTS). Otherwise
|
||||
* with CSMA/CA.
|
||||
*/
|
||||
NETOPT_GTS_TX,
|
||||
|
||||
/**
|
||||
* @brief maximum number of options defined here.
|
||||
*
|
||||
|
@ -133,6 +133,9 @@ static const char *_netopt_strmap[] = {
|
||||
[NETOPT_BATMON] = "NETOPT_BATMON",
|
||||
[NETOPT_L2_GROUP] = "NETOPT_L2_GROUP",
|
||||
[NETOPT_L2_GROUP_LEAVE] = "NETOPT_L2_GROUP_LEAVE",
|
||||
[NETOPT_PAN_COORD] = "NETOPT_PAN_COORD",
|
||||
[NETOPT_GTS_ALLOC] = "NETOPT_GTS_ALLOC",
|
||||
[NETOPT_GTS_TX] = "NETOPT_GTS_TX",
|
||||
[NETOPT_NUMOF] = "NETOPT_NUMOF",
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user