1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/openthread/contrib/platform_radio.c
2020-11-02 21:49:39 +01:00

472 lines
13 KiB
C

/*
* Copyright (C) 2017 Fundacion Inria Chile
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Implementation of OpenThread radio platform abstraction
*
* @author Jose Ignacio Alamos <jialamos@uc.cl>
* @}
*/
#include <stdio.h>
#include <string.h>
#include "byteorder.h"
#include "errno.h"
#include "net/ethernet/hdr.h"
#include "net/ethertype.h"
#include "net/ieee802154.h"
#include "net/l2util.h"
#include "net/netdev/ieee802154.h"
#include "openthread/platform/diag.h"
#include "openthread/platform/radio.h"
#include "ot.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define RADIO_IEEE802154_FCS_LEN (2U)
static otRadioFrame sTransmitFrame;
static otRadioFrame sReceiveFrame;
static int8_t Rssi;
static netdev_t *_dev;
/* set 15.4 channel */
static int _set_channel(uint16_t channel)
{
return _dev->driver->set(_dev, NETOPT_CHANNEL, &channel, sizeof(uint16_t));
}
/* set transmission power */
static int _set_power(int16_t power)
{
return _dev->driver->set(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
}
static int _get_power(void)
{
int16_t power;
_dev->driver->get(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
return power;
}
/* set IEEE802.15.4 PAN ID */
static int _set_panid(uint16_t panid)
{
return _dev->driver->set(_dev, NETOPT_NID, &panid, sizeof(uint16_t));
}
/* set extended HW address */
static int _set_long_addr(uint8_t *ext_addr)
{
return _dev->driver->set(_dev, NETOPT_ADDRESS_LONG, ext_addr, IEEE802154_LONG_ADDRESS_LEN);
}
/* set short address */
static int _set_addr(uint16_t addr)
{
return _dev->driver->set(_dev, NETOPT_ADDRESS, &addr, sizeof(uint16_t));
}
/* check the state of promiscuous mode */
static netopt_enable_t _is_promiscuous(void)
{
netopt_enable_t en;
_dev->driver->get(_dev, NETOPT_PROMISCUOUSMODE, &en, sizeof(en));
return en == NETOPT_ENABLE ? true : false;;
}
/* set the state of promiscuous mode */
static int _set_promiscuous(netopt_enable_t enable)
{
return _dev->driver->set(_dev, NETOPT_PROMISCUOUSMODE, &enable, sizeof(enable));
}
/* wrapper for setting device state */
static void _set_state(netopt_state_t state)
{
_dev->driver->set(_dev, NETOPT_STATE, &state, sizeof(netopt_state_t));
}
/* wrapper for getting device state */
static netopt_state_t _get_state(void)
{
netopt_state_t state;
_dev->driver->get(_dev, NETOPT_STATE, &state, sizeof(netopt_state_t));
return state;
}
static void _set_off(void)
{
_set_state(NETOPT_STATE_OFF);
}
/* sets device state to SLEEP */
static void _set_sleep(void)
{
_set_state(NETOPT_STATE_SLEEP);
}
/* set device state to IDLE */
static void _set_idle(void)
{
_set_state(NETOPT_STATE_IDLE);
}
/* init framebuffers and initial state */
void openthread_radio_init(netdev_t *dev, uint8_t *tb, uint8_t *rb)
{
sTransmitFrame.mPsdu = tb;
sTransmitFrame.mLength = 0;
sReceiveFrame.mPsdu = rb;
sReceiveFrame.mLength = 0;
_dev = dev;
}
/* Called upon NETDEV_EVENT_RX_COMPLETE event */
void recv_pkt(otInstance *aInstance, netdev_t *dev)
{
DEBUG("Openthread: Received pkt\n");
netdev_ieee802154_rx_info_t rx_info;
/* Read frame length from driver */
int len = dev->driver->recv(dev, NULL, 0, NULL);
/* very unlikely */
if ((len < 0) || ((uint32_t)len > UINT16_MAX)) {
DEBUG("Invalid len: %d\n", len);
otPlatRadioReceiveDone(aInstance, NULL, OT_ERROR_ABORT);
return;
}
/* Fill OpenThread receive frame */
/* Openthread needs a packet length with FCS included,
* OpenThread do not use the data so we don't need to calculate FCS */
sReceiveFrame.mLength = len + RADIO_IEEE802154_FCS_LEN;
/* Read received frame */
int res = dev->driver->recv(dev, (char *) sReceiveFrame.mPsdu, len, &rx_info);
/* Get RSSI from a radio driver. RSSI should be in [dBm] */
Rssi = (int8_t)rx_info.rssi;
if (IS_ACTIVE(ENABLE_DEBUG)) {
DEBUG("Received message: len %d\n", (int) sReceiveFrame.mLength);
for (int i = 0; i < sReceiveFrame.mLength; ++i) {
DEBUG("%x ", sReceiveFrame.mPsdu[i]);
}
DEBUG("\n");
}
/* Tell OpenThread that receive has finished */
otPlatRadioReceiveDone(aInstance, res > 0 ? &sReceiveFrame : NULL, res > 0 ? OT_ERROR_NONE : OT_ERROR_ABORT);
}
/* Called upon TX event */
void send_pkt(otInstance *aInstance, netdev_t *dev, netdev_event_t event)
{
(void)dev;
/* Tell OpenThread transmission is done depending on the NETDEV event */
switch (event) {
case NETDEV_EVENT_TX_COMPLETE:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE\n");
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NONE);
break;
case NETDEV_EVENT_TX_COMPLETE_DATA_PENDING:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE_DATA_PENDING\n");
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NONE);
break;
case NETDEV_EVENT_TX_NOACK:
DEBUG("openthread: NETDEV_EVENT_TX_NOACK\n");
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NO_ACK);
break;
case NETDEV_EVENT_TX_MEDIUM_BUSY:
DEBUG("openthread: NETDEV_EVENT_TX_MEDIUM_BUSY\n");
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_CHANNEL_ACCESS_FAILURE);
break;
default:
break;
}
}
/* OpenThread will call this for setting PAN ID */
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioSetPanId: setting PAN ID to %04x\n", panid);
_set_panid(panid);
}
/* OpenThread will call this for setting extended address */
void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioSetExtendedAddress\n");
char reversed_addr[IEEE802154_LONG_ADDRESS_LEN];
for (unsigned i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) {
reversed_addr[i] = (uint8_t) ((uint8_t *)aExtAddress)[IEEE802154_LONG_ADDRESS_LEN - 1 - i];
}
if (IS_ACTIVE(ENABLE_DEBUG)) {
for (unsigned i = 0; i < IEEE802154_LONG_ADDRESS_LEN; ++i) {
DEBUG("%x ", (uint8_t) ((uint8_t *)reversed_addr)[i]);
}
DEBUG("\n");
}
_set_long_addr((uint8_t*) reversed_addr);
}
/* OpenThread will call this for setting short address */
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioSetShortAddress: setting address to %04x\n", aShortAddress);
_set_addr(((aShortAddress & 0xff) << 8) | ((aShortAddress >> 8) & 0xff));
}
/* OpenThread will call this for enabling the radio */
otError otPlatRadioEnable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioEnable\n");
(void)aInstance;
if (!otPlatRadioIsEnabled(aInstance)) {
_set_sleep();
}
return OT_ERROR_NONE;
}
/* OpenThread will call this for disabling the radio */
otError otPlatRadioDisable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioDisable\n");
(void)aInstance;
if (otPlatRadioIsEnabled(aInstance)) {
_set_off();
}
return OT_ERROR_NONE;
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
DEBUG("otPlatRadioIsEnabled\n");
(void)aInstance;
netopt_state_t state = _get_state();
if (state == NETOPT_STATE_OFF) {
return false;
} else {
return true;
}
}
/* OpenThread will call this for setting device state to SLEEP */
otError otPlatRadioSleep(otInstance *aInstance)
{
DEBUG("otPlatRadioSleep\n");
(void)aInstance;
_set_sleep();
return OT_ERROR_NONE;
}
/*OpenThread will call this for waiting the reception of a packet */
otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
DEBUG("openthread: otPlatRadioReceive. Channel: %i\n", aChannel);
(void)aInstance;
_set_idle();
_set_channel(aChannel);
sReceiveFrame.mChannel = aChannel;
return OT_ERROR_NONE;
}
/* OpenThread will call this function to get the transmit buffer */
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioGetTransmitBuffer\n");
return &sTransmitFrame;
}
/* OpenThread will call this function to set the transmit power */
void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
_set_power(aPower);
}
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
(void)aInstance;
if (aPower == NULL) {
return OT_ERROR_INVALID_ARGS;
}
*aPower = _get_power();
return OT_ERROR_NONE;
}
otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
_set_power(aPower);
return OT_ERROR_NONE;
}
/* OpenThread will call this for transmitting a packet*/
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aPacket)
{
(void) aInstance;
/* Populate iolist with transmit data
* Unlike RIOT, OpenThread includes two bytes FCS (0x00 0x00) so
* these bytes are removed
*/
iolist_t iolist = {
.iol_base = aPacket->mPsdu,
.iol_len = (aPacket->mLength - RADIO_IEEE802154_FCS_LEN)
};
/*Set channel and power based on transmit frame */
if (IS_ACTIVE(ENABLE_DEBUG)) {
DEBUG("otPlatRadioTransmit->channel: %i, length %d\n",
(int) aPacket->mChannel, (int)aPacket->mLength);
for (size_t i = 0; i < aPacket->mLength; ++i) {
DEBUG("%x ", aPacket->mPsdu[i]);
}
DEBUG("\n");
}
_set_channel(aPacket->mChannel);
/* send packet though netdev */
_dev->driver->send(_dev, &iolist);
otPlatRadioTxStarted(aInstance, aPacket);
return OT_ERROR_NONE;
}
/* OpenThread will call this for getting the radio caps */
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioGetCaps\n");
/* all drivers should handle ACK, including call of NETDEV_EVENT_TX_NOACK */
return OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_ACK_TIMEOUT;
}
/* OpenThread will call this for getting the state of promiscuous mode */
bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioGetPromiscuous\n");
return _is_promiscuous();
}
/* OpenThread will call this for setting the state of promiscuous mode */
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
DEBUG("openthread: otPlatRadioSetPromiscuous\n");
_set_promiscuous((aEnable) ? NETOPT_ENABLE : NETOPT_DISABLE);
}
int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
DEBUG("otPlatRadioGetRssi\n");
(void)aInstance;
return Rssi;
}
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
{
DEBUG("otPlatRadioEnableSrcMatch\n");
(void)aInstance;
(void)aEnable;
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioAddSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
{
DEBUG("otPlatRadioAddSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioClearSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
{
DEBUG("otPlatRadioClearSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return OT_ERROR_NONE;
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchShortEntries\n");
(void)aInstance;
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchExtEntries\n");
(void)aInstance;
}
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
DEBUG("otPlatRadioEnergyScan\n");
(void)aInstance;
(void)aScanChannel;
(void)aScanDuration;
return OT_ERROR_NOT_IMPLEMENTED;
}
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeee64Eui64)
{
uint8_t addr[IEEE802154_LONG_ADDRESS_LEN];
(void)aInstance;
_dev->driver->get(_dev, NETOPT_ADDRESS_LONG, addr, sizeof(addr));
l2util_ipv6_iid_from_addr(NETDEV_TYPE_IEEE802154,
addr, sizeof(eui64_t),
(eui64_t *)aIeee64Eui64);
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void) aInstance;
return -100;
}