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
2017-06-01 13:44:05 -04:00

423 lines
12 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 <assert.h>
#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/netdev/ieee802154.h"
#include "openthread/platform/radio.h"
#include "ot.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define RADIO_IEEE802154_FCS_LEN (2U)
static RadioPacket sTransmitFrame;
static RadioPacket sReceiveFrame;
static int8_t Rssi;
static netdev_t *_dev;
static bool sDisabled;
/* set 15.4 channel */
static int _set_channel(uint16_t channel)
{
return _dev->driver->set(_dev, NETOPT_CHANNEL, &channel, sizeof(uint16_t));
}
/*get transmission power from driver */
static int16_t _get_power(void)
{
int16_t power;
_dev->driver->get(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
return power;
}
/* set transmission power */
static int _set_power(int16_t power)
{
return _dev->driver->set(_dev, NETOPT_TX_POWER, &power, sizeof(int16_t));
}
/* 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;
}
/* 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, &rx_info);
Rssi = rx_info.rssi;
/* very unlikely */
if ((len > (unsigned) UINT16_MAX)) {
DEBUG("Len too high: %d\n", len);
otPlatRadioReceiveDone(aInstance, NULL, kThreadError_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;
sReceiveFrame.mPower = _get_power();
/* Read received frame */
int res = dev->driver->recv(dev, (char *) sReceiveFrame.mPsdu, len, NULL);
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 ? kThreadError_None : kThreadError_Abort);
}
/* Called upon TX event */
void send_pkt(otInstance *aInstance, netdev_t *dev, netdev_event_t event)
{
/* Tell OpenThread transmission is done depending on the NETDEV event */
switch (event) {
case NETDEV_EVENT_TX_COMPLETE:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_None);
break;
case NETDEV_EVENT_TX_COMPLETE_DATA_PENDING:
DEBUG("openthread: NETDEV_EVENT_TX_COMPLETE_DATA_PENDING\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, true, kThreadError_None);
break;
case NETDEV_EVENT_TX_NOACK:
DEBUG("openthread: NETDEV_EVENT_TX_NOACK\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_NoAck);
break;
case NETDEV_EVENT_TX_MEDIUM_BUSY:
DEBUG("openthread: NETDEV_EVENT_TX_MEDIUM_BUSY\n");
otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, kThreadError_ChannelAccessFailure);
break;
default:
break;
}
}
/* OpenThread will call this for setting PAN ID */
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
{
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, uint8_t *aExtendedAddress)
{
DEBUG("openthread: otPlatRadioSetExtendedAddress\n");
uint8_t reversed_addr[IEEE802154_LONG_ADDRESS_LEN];
for (int i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) {
reversed_addr[i] = aExtendedAddress[IEEE802154_LONG_ADDRESS_LEN - 1 - i];
}
_set_long_addr(reversed_addr);
}
/* OpenThread will call this for setting short address */
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
{
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 */
ThreadError otPlatRadioEnable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioEnable\n");
(void) aInstance;
if (sDisabled) {
sDisabled = false;
_set_idle();
}
return kThreadError_None;
}
/* OpenThread will call this for disabling the radio */
ThreadError otPlatRadioDisable(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioDisable\n");
(void) aInstance;
if (!sDisabled) {
sDisabled = true;
_set_sleep();
}
return kThreadError_None;
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
DEBUG("otPlatRadioIsEnabled\n");
(void) aInstance;
netopt_state_t state = _get_state();
if (state == NETOPT_STATE_OFF || state == NETOPT_STATE_SLEEP) {
return false;
} else {
return true;
}
}
/* OpenThread will call this for setting device state to SLEEP */
ThreadError otPlatRadioSleep(otInstance *aInstance)
{
DEBUG("otPlatRadioSleep\n");
(void) aInstance;
_set_sleep();
return kThreadError_None;
}
/*OpenThread will call this for waiting the reception of a packet */
ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
DEBUG("openthread: otPlatRadioReceive. Channel: %i\n", aChannel);
(void) aInstance;
_set_idle();
_set_channel(aChannel);
return kThreadError_None;
}
/* OpenThread will call this function to get the transmit buffer */
RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *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);
}
/* OpenThread will call this for transmitting a packet*/
ThreadError otPlatRadioTransmit(otInstance *aInstance, RadioPacket *aPacket)
{
(void) aInstance;
struct iovec pkt;
/* Populate iovec with transmit data
* Unlike RIOT, OpenThread includes two bytes FCS (0x00 0x00) so
* these bytes are removed
*/
pkt.iov_base = aPacket->mPsdu;
pkt.iov_len = aPacket->mLength - RADIO_IEEE802154_FCS_LEN;
/*Set channel and power based on transmit frame */
DEBUG("otPlatRadioTransmit->channel: %i, length %d\n", (int) aPacket->mChannel, (int)aPacket->mLength);
for (int i = 0; i < aPacket->mLength; ++i) {
DEBUG("%x ", aPacket->mPsdu[i]);
}
DEBUG("\n");
_set_channel(aPacket->mChannel);
_set_power(aPacket->mPower);
/* send packet though netdev */
_dev->driver->send(_dev, &pkt, 1);
return kThreadError_None;
}
/* OpenThread will call this for getting the radio caps */
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
{
DEBUG("openthread: otPlatRadioGetCaps\n");
/* all drivers should handle ACK, including call of NETDEV_EVENT_TX_NOACK */
return kRadioCapsNone;
}
/* OpenThread will call this for getting the state of promiscuous mode */
bool otPlatRadioGetPromiscuous(otInstance *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)
{
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;
}
ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioAddSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return kThreadError_None;
}
ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
DEBUG("otPlatRadioAddSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return kThreadError_None;
}
ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
DEBUG("otPlatRadioClearSrcMatchShortEntry\n");
(void)aInstance;
(void)aShortAddress;
return kThreadError_None;
}
ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
DEBUG("otPlatRadioClearSrcMatchExtEntry\n");
(void)aInstance;
(void)aExtAddress;
return kThreadError_None;
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchShortEntries\n");
(void)aInstance;
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
DEBUG("otPlatRadioClearSrcMatchExtEntries\n");
(void)aInstance;
}
ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
DEBUG("otPlatRadioEnergyScan\n");
(void)aInstance;
(void)aScanChannel;
(void)aScanDuration;
return kThreadError_NotImplemented;
}
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeee64Eui64)
{
_dev->driver->get(_dev, NETOPT_IPV6_IID, aIeee64Eui64, sizeof(eui64_t));
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
return -100;
}