

28 changed files with 1106 additions and 913 deletions
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) |
||||
USEMODULE += nrfmin
|
||||
endif |
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universitรคt Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup drivers_nrf51822_nrfmin NRF Minimal Radio Driver |
||||
* @ingroup drivers_netdev |
||||
* @brief Minimal driver for the NRF51822 radio |
||||
* |
||||
* This driver enables the use of the NRF51822 radio in a IEEE802.15.4 like |
||||
* fashion. In the current state, the driver is only be meant to be used with |
||||
* the netdev/netapi based network stack, while only being able to communicate |
||||
* with other NRF51822 devices using the same driver. |
||||
* |
||||
* The driver is using a Nordic proprietary physical layer, configured to for a |
||||
* bitrate of 2Mbit. The payload length is set to a maximum length of 250 byte. |
||||
* The proprietary frame format used has the following format: |
||||
* |
||||
* byte0 | byte1 - byte2 | byte3 - byte4 | byte5 byte6 | byte7 - byteN |
||||
* ------ | ------------- | ------------- | ------------- | ------------- |
||||
* length | src_addr | dst_addr | proto | payload... |
||||
* |
||||
* An IEEE802.15.4 like behavior is reflected in the following way: the driver |
||||
* configures the radio device to use a fixed 5 byte addressing scheme. On this |
||||
* addresses, the first byte is set to a constant value, the same for all |
||||
* devices that use this driver. The next two bytes are set to the configured |
||||
* PAN ID, hereby simulating the use of PAN IDs. The last two bytes are set to |
||||
* a 16-bit short address, simulating IEEE802.15.4 short addresses. |
||||
* |
||||
* There is no support for EUIDs. Further there is no support for anything else |
||||
* than IEEE802.15.4 data frames, so no PAN coordinators, etc. |
||||
* |
||||
* The driver supports: |
||||
* - short address (16-bit) |
||||
* - using CPU-ID for default address |
||||
* - address broadcast (broadcast address is ff:ff) |
||||
* - PAN IDs (0 to 0xffff), PAN ID broadcast is not supported |
||||
* - setting of channel (0 to 0x3f) |
||||
* - setting of TX power (+4dBm to -20dBm) |
||||
* - packet type labeling |
||||
* - setting device state (RX, SLEEP) |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface definition for the nrfmin NRF51822 radio driver |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef NRFMIN_H_ |
||||
#define NRFMIN_H_ |
||||
|
||||
#include "net/gnrc/netdev.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Default PAN ID used after initialization |
||||
*/ |
||||
#define NRFMIN_DEFAULT_PAN (0x0550) |
||||
|
||||
/**
|
||||
* @brief Default channel set after initialization |
||||
*/ |
||||
#define NRFMIN_DEFAULT_CHANNEL (1U) /* 2401MHz */ |
||||
|
||||
/**
|
||||
* @brief Default transmission power used |
||||
*/ |
||||
#define NRFMIN_DEFAULT_TXPOWER (0) /* 0dBm */ |
||||
|
||||
/**
|
||||
* @brief Reference to the netdev driver interface |
||||
*/ |
||||
extern const gnrc_netdev_driver_t nrfmin_driver; |
||||
|
||||
/**
|
||||
* @brief Initialize the NRF51822 radio |
||||
* |
||||
* The initialization uses static configuration values. |
||||
* |
||||
* @param[out] dev pointer to the netdev device descriptor |
||||
* |
||||
* @return 0 on success |
||||
* @return -ENODEV if @p dev is invalid |
||||
*/ |
||||
int nrfmin_init(gnrc_netdev_t *dev); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NRFMIN_H_ */ |
||||
/** @} */ |
@ -1,3 +0,0 @@
|
||||
MODULE = radio_nrfmin
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -1,723 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universitรคt Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup drivers_nrf51822_nrfmin |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Implementation of the nrfmin NRF51822 minimal radio driver |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "cpu.h" |
||||
#include "mutex.h" |
||||
#include "periph_conf.h" |
||||
#include "periph/cpuid.h" |
||||
#include "nrfmin.h" |
||||
#include "net/gnrc.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
/**
|
||||
* @brief Driver specific device configuration |
||||
* @{ |
||||
*/ |
||||
#define CONF_MODE RADIO_MODE_MODE_Nrf_2Mbit |
||||
#define CONF_PAYLOAD_LEN (250U) |
||||
#define CONF_LEN (8U) |
||||
#define CONF_S0 (0U) |
||||
#define CONF_S1 (0U) |
||||
#define CONF_STATLEN (0U) |
||||
#define CONF_BASE_ADDR_LEN (4U) |
||||
#define CONF_ENDIAN RADIO_PCNF1_ENDIAN_Big |
||||
#define CONF_WHITENING RADIO_PCNF1_WHITEEN_Disabled |
||||
#define CONF_CRC_LEN (2U) |
||||
#define CONF_CRC_POLY (0x11021) |
||||
#define CONF_CRC_INIT (0xf0f0f0) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Driver specific address configuration |
||||
* @{ |
||||
*/ |
||||
#define CONF_ADDR_PREFIX0 (0xE7E7E7E7) |
||||
#define CONF_ADDR_BCAST (0xffff) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Driver specific (interrupt) events (not all of them used currently) |
||||
* @{ |
||||
*/ |
||||
#define ISR_EVENT_RX_START (0x0001) |
||||
#define ISR_EVENT_RX_DONE (0x0002) |
||||
#define ISR_EVENT_TX_START (0x0004) |
||||
#define ISR_EVENT_TX_DONE (0x0008) |
||||
#define ISR_EVENT_WRONG_CHKSUM (0x0010) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Payload types to use in driver specific framed format |
||||
* |
||||
* We expect the radio to carry either raw link layer data (UNDEF) or network |
||||
* layer data, so no need to map transport layer protocols etc... |
||||
* @{ |
||||
*/ |
||||
#define NRFTYPE_UNDEF (0x01) |
||||
#define NRFTYPE_SIXLOWPAN (0x02) |
||||
#define NRFTYPE_IPV6 (0x03) |
||||
#define NRFTYPE_ICMPV6 (0x04) |
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Possible internal device states |
||||
*/ |
||||
typedef enum { |
||||
STATE_OFF, /**< device is powered off */ |
||||
STATE_IDLE, /**< device is in idle mode */ |
||||
STATE_RX, /**< device is in receive mode */ |
||||
STATE_TX, /**< device is transmitting data */ |
||||
} state_t; |
||||
|
||||
/**
|
||||
* @brief In-memory structure of a nrfmin radio packet |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t length; /**< packet length */ |
||||
uint8_t src_addr[2]; /**< source address of the packet */ |
||||
uint8_t dst_addr[2]; /**< destination address */ |
||||
uint8_t proto; /**< protocol of payload */ |
||||
uint8_t payload[CONF_PAYLOAD_LEN]; /**< actual payload */ |
||||
} packet_t; |
||||
|
||||
/**
|
||||
* @brief Pointer to the MAC layer event callback |
||||
*/ |
||||
static gnrc_netdev_t *_netdev = NULL; |
||||
|
||||
/**
|
||||
* @brief Current state of the device |
||||
*/ |
||||
static volatile state_t _state = STATE_OFF; |
||||
|
||||
/**
|
||||
* @brief Address of the device |
||||
*/ |
||||
static uint16_t _addr; |
||||
|
||||
/**
|
||||
* @brief Transmission buffer |
||||
*/ |
||||
static packet_t _tx_buf; |
||||
|
||||
/**
|
||||
* @brief Hold the state before sending to return to it afterwards |
||||
*/ |
||||
static state_t _tx_prestate; |
||||
|
||||
/**
|
||||
* @brief Double receive buffers |
||||
*/ |
||||
static packet_t _rx_buf[2]; |
||||
|
||||
/**
|
||||
* @brief Pointer to the free receive buffer |
||||
*/ |
||||
static volatile int _rx_next = 0; |
||||
|
||||
/*
|
||||
* Create an internal mapping between NETTYPE and NRFTYPE |
||||
*/ |
||||
static inline gnrc_nettype_t _nrftype_to_nettype(uint8_t nrftype) |
||||
{ |
||||
switch (nrftype) { |
||||
#ifdef MODULE_GNRC_SIXLOWPAN |
||||
case NRFTYPE_SIXLOWPAN: |
||||
return GNRC_NETTYPE_SIXLOWPAN; |
||||
#endif |
||||
#ifdef MODULE_GNRC_IPV6 |
||||
case NRFTYPE_IPV6: |
||||
return GNRC_NETTYPE_IPV6; |
||||
#endif |
||||
#ifdef MODULE_GNRC_ICMPV6 |
||||
case NRFTYPE_ICMPV6: |
||||
return GNRC_NETTYPE_ICMPV6; |
||||
#endif |
||||
default: |
||||
return GNRC_NETTYPE_UNDEF; |
||||
} |
||||
} |
||||
|
||||
static inline uint8_t _nettype_to_nrftype(gnrc_nettype_t nettype) |
||||
{ |
||||
switch (nettype) { |
||||
#ifdef MODULE_GNRC_SIXLOWPAN |
||||
case GNRC_NETTYPE_SIXLOWPAN: |
||||
return NRFTYPE_SIXLOWPAN; |
||||
#endif |
||||
#ifdef MODULE_GNRC_IPV6 |
||||
case GNRC_NETTYPE_IPV6: |
||||
return NRFTYPE_IPV6; |
||||
#endif |
||||
#ifdef MODULE_GNRC_ICMPV6 |
||||
case GNRC_NETTYPE_ICMPV6: |
||||
return NRFTYPE_ICMPV6; |
||||
#endif |
||||
default: |
||||
return NRFTYPE_UNDEF; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Functions for controlling the radios state |
||||
*/ |
||||
static void _switch_to_idle(void) |
||||
{ |
||||
/* witch to idle state */ |
||||
NRF_RADIO->EVENTS_DISABLED = 0; |
||||
NRF_RADIO->TASKS_DISABLE = 1; |
||||
while (NRF_RADIO->EVENTS_DISABLED == 0) {} |
||||
_state = STATE_IDLE; |
||||
} |
||||
|
||||
static void _switch_to_rx(void) |
||||
{ |
||||
/* set pointer to receive buffer */ |
||||
NRF_RADIO->PACKETPTR = (uint32_t)&(_rx_buf[_rx_next]); |
||||
/* set address */ |
||||
NRF_RADIO->BASE0 &= ~(0xffff); |
||||
NRF_RADIO->BASE0 |= _addr; |
||||
/* switch int RX mode */ |
||||
NRF_RADIO->TASKS_RXEN = 1; |
||||
_state = STATE_RX; |
||||
} |
||||
|
||||
/*
|
||||
* Getter and Setter functions |
||||
*/ |
||||
int _get_state(uint8_t *val, size_t max_len) |
||||
{ |
||||
netopt_state_t state; |
||||
|
||||
if (max_len < sizeof(netopt_state_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
switch (_state) { |
||||
case STATE_OFF: |
||||
state = NETOPT_STATE_OFF; |
||||
break; |
||||
case STATE_IDLE: |
||||
state = NETOPT_STATE_SLEEP; |
||||
break; |
||||
case STATE_RX: |
||||
state = NETOPT_STATE_IDLE; |
||||
break; |
||||
case STATE_TX: |
||||
state = NETOPT_STATE_TX; |
||||
break; |
||||
default: |
||||
return -ECANCELED; |
||||
} |
||||
memcpy(val, &state, sizeof(netopt_state_t)); |
||||
return sizeof(netopt_state_t); |
||||
} |
||||
|
||||
int _set_state(uint8_t *val, size_t len) |
||||
{ |
||||
netopt_state_t state; |
||||
|
||||
if (len != sizeof(netopt_state_t)) { |
||||
return -EINVAL; |
||||
} |
||||
/* get target state */ |
||||
memcpy(&state, val, len); |
||||
/* switch to target state */ |
||||
switch (state) { |
||||
case NETOPT_STATE_SLEEP: |
||||
_switch_to_idle(); |
||||
break; |
||||
case NETOPT_STATE_IDLE: |
||||
_switch_to_rx(); |
||||
break; |
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
return sizeof(netopt_state_t); |
||||
} |
||||
|
||||
int _get_address(uint8_t *val, size_t max_len) |
||||
{ |
||||
/* check parameters */ |
||||
if (max_len < 2) { |
||||
return -EOVERFLOW; |
||||
} |
||||
/* get address */ |
||||
val[0] = (uint8_t)(_addr >> 8); |
||||
val[1] = (uint8_t)(_addr); |
||||
return 2; |
||||
} |
||||
|
||||
int _set_address(uint8_t *val, size_t len) |
||||
{ |
||||
int is_rx = 0; |
||||
|
||||
/* check parameters */ |
||||
if (len != 2) { |
||||
return -EINVAL; |
||||
} |
||||
/* keep track of state */ |
||||
while (_state == STATE_TX) {} |
||||
if (_state == STATE_RX) { |
||||
is_rx = 1; |
||||
_switch_to_idle(); |
||||
} |
||||
/* set address */ |
||||
_addr = (((uint16_t)val[0]) << 8) | val[1]; |
||||
NRF_RADIO->BASE0 &= ~(0xffff); |
||||
NRF_RADIO->BASE0 |= _addr; |
||||
/* restore old state */ |
||||
if (is_rx) { |
||||
_switch_to_rx(); |
||||
} |
||||
return 2; |
||||
} |
||||
|
||||
int _get_channel(uint8_t *val, size_t max_len) |
||||
{ |
||||
/* check parameters */ |
||||
if (max_len < 2) { |
||||
return -EOVERFLOW; |
||||
} |
||||
/* get channel */ |
||||
val[0] = (0x3f & NRF_RADIO->FREQUENCY); |
||||
val[1] = 0; |
||||
return 2; |
||||
} |
||||
|
||||
int _set_channel(uint8_t *val, size_t len) |
||||
{ |
||||
int is_rx = 0; |
||||
|
||||
/* check parameter */ |
||||
if (len != 2 || val[0] > 0x3f) { |
||||
return -EINVAL; |
||||
} |
||||
/* remember state */ |
||||
while (_state == STATE_TX) {} |
||||
if (_state == STATE_RX) { |
||||
is_rx = 1; |
||||
_switch_to_idle(); |
||||
} |
||||
/* set channel */ |
||||
NRF_RADIO->FREQUENCY = val[0]; |
||||
/* restore state */ |
||||
if (is_rx) { |
||||
_switch_to_rx(); |
||||
} |
||||
return 2; |
||||
} |
||||
|
||||
int _get_pan(uint8_t *val, size_t max_len) |
||||
{ |
||||
/* check parameters */ |
||||
if (max_len < 2) { |
||||
return -EOVERFLOW; |
||||
} |
||||
/* get PAN ID */ |
||||
val[0] = (uint8_t)((NRF_RADIO->BASE0 & 0x00ff0000) >> 16); |
||||
val[1] = (uint8_t)((NRF_RADIO->BASE0 & 0xff000000) >> 24); |
||||
return 2; |
||||
} |
||||
|
||||
int _set_pan(uint8_t *val, size_t len) |
||||
{ |
||||
int is_rx = 0; |
||||
uint32_t pan; |
||||
|
||||
/* check parameter */ |
||||
if (len != 2) { |
||||
return -EINVAL; |
||||
} |
||||
/* remember state */ |
||||
while (_state == STATE_TX) {} |
||||
if (_state == STATE_RX) { |
||||
is_rx = 1; |
||||
_switch_to_idle(); |
||||
} |
||||
/* set new PAN ID */ |
||||
pan = ((uint32_t)val[1] << 24) | ((uint32_t)val[0] << 16); |
||||
NRF_RADIO->BASE0 = pan | _addr; |
||||
NRF_RADIO->BASE1 = pan | CONF_ADDR_BCAST; |
||||
/* restore state */ |
||||
if (is_rx) { |
||||
_switch_to_rx(); |
||||
} |
||||
return 2; |
||||
} |
||||
|
||||
int _get_txpower(uint8_t *val, size_t len) |
||||
{ |
||||
/* check parameters */ |
||||
if (len < 2) { |
||||
return 0; |
||||
} |
||||
/* get value */ |
||||
val[0] = NRF_RADIO->TXPOWER; |
||||
if (val[0] & 0x80) { |
||||
val[1] = 0xff; |
||||
} |
||||
else { |
||||
val[1] = 0x00; |
||||
} |
||||
return 2; |
||||
} |
||||
|
||||
int _set_txpower(uint8_t *val, size_t len) |
||||
{ |
||||
int8_t power; |
||||
|
||||
/* check parameters */ |
||||
if (len < 2) { |
||||
return -EINVAL; |
||||
} |
||||
/* get TX power value */ |
||||
power = (int8_t)val[0]; |
||||
|
||||
if (power > 2) { |
||||
power = 4; |
||||
} |
||||
else if (power > -2) { |
||||
power = 0; |
||||
} |
||||
else if (power > -6) { |
||||
power = -4; |
||||
} |
||||
else if (power > -10) { |
||||
power = -8; |
||||
} |
||||
else if (power > -14) { |
||||
power = -12; |
||||
} |
||||
else if (power > -18) { |
||||
power = -16; |
||||
} |
||||
else { |
||||
power = -20; |
||||
} |
||||
NRF_RADIO->TXPOWER = power; |
||||
return 2; |
||||
} |
||||
|
||||
/*
|
||||
* Radio interrupt routine |
||||
*/ |
||||
void isr_radio(void) |
||||
{ |
||||
msg_t msg; |
||||
|
||||
if (NRF_RADIO->EVENTS_END == 1) { |
||||
NRF_RADIO->EVENTS_END = 0; |
||||
/* did we just send or receive something? */ |
||||
if (_state == STATE_RX) { |
||||
/* drop packet on invalid CRC */ |
||||
if (NRF_RADIO->CRCSTATUS != 1) { |
||||
return; |
||||
} |
||||
msg.type = GNRC_NETDEV_MSG_TYPE_EVENT; |
||||
msg.content.value = ISR_EVENT_RX_DONE; |
||||
msg_send_int(&msg, _netdev->mac_pid); |
||||
/* switch buffer */ |
||||
_rx_next = _rx_next ^ 1; |
||||
NRF_RADIO->PACKETPTR = (uint32_t)&(_rx_buf[_rx_next]); |
||||
/* go back into receive mode */ |
||||
NRF_RADIO->TASKS_START = 1; |
||||
} |
||||
else if (_state == STATE_TX) { |
||||
/* disable radio again */ |
||||
_switch_to_idle(); |
||||
/* if radio was receiving before, go back into RX state */ |
||||
if (_tx_prestate == STATE_RX) { |
||||
_switch_to_rx(); |
||||
} |
||||
} |
||||
} |
||||
cortexm_isr_end(); |
||||
} |
||||
|
||||
/*
|
||||
* Event handlers |
||||
*/ |
||||
static void _receive_data(void) |
||||
{ |
||||
packet_t *data; |
||||
gnrc_pktsnip_t *pkt_head; |
||||
gnrc_pktsnip_t *pkt; |
||||
gnrc_netif_hdr_t *hdr; |
||||
gnrc_nettype_t nettype; |
||||
|
||||
/* only read data if we have somewhere to send it to */ |
||||
if (_netdev->event_cb == NULL) { |
||||
return; |
||||
} |
||||
|
||||
/* get pointer to RX data buffer */ |
||||
data = &(_rx_buf[_rx_next ^ 1]); |
||||
|
||||
/* allocate and fill netif header */ |
||||
pkt_head = gnrc_pktbuf_add(NULL, NULL, sizeof(gnrc_netif_hdr_t) + 4, |
||||
GNRC_NETTYPE_UNDEF); |
||||
if (pkt_head == NULL) { |
||||
DEBUG("nrfmin: Error allocating netif header on RX\n"); |
||||
return; |
||||
} |
||||
hdr = (gnrc_netif_hdr_t *)pkt_head->data; |
||||
gnrc_netif_hdr_init(hdr, 2, 2); |
||||
hdr->if_pid = _netdev->mac_pid; |
||||
gnrc_netif_hdr_set_src_addr(hdr, data->src_addr, 2); |
||||
gnrc_netif_hdr_set_dst_addr(hdr, data->dst_addr, 2); |
||||
|
||||
/* allocate and fill payload */ |
||||
nettype = _nrftype_to_nettype(data->proto); |
||||
pkt = gnrc_pktbuf_add(pkt_head, data->payload, data->length - 6, nettype); |
||||
if (pkt == NULL) { |
||||
DEBUG("nrfmin: Error allocating packet payload on RX\n"); |
||||
gnrc_pktbuf_release(pkt_head); |
||||
return; |
||||
} |
||||
|
||||
/* pass on the received packet */ |
||||
_netdev->event_cb(NETDEV_EVENT_RX_COMPLETE, pkt); |
||||
} |
||||
|
||||
/*
|
||||
* Public interface functions |
||||
*/ |
||||
int nrfmin_init(gnrc_netdev_t *dev) |
||||
{ |
||||
uint8_t cpuid[CPUID_LEN]; |
||||
uint8_t tmp; |
||||
int i; |
||||
|
||||
/* check given device descriptor */ |
||||
if (dev == NULL) { |
||||
return -ENODEV; |
||||
} |
||||
/* set initial values */ |
||||
dev->driver = &nrfmin_driver; |
||||
dev->event_cb = NULL; |
||||
dev->mac_pid = KERNEL_PID_UNDEF; |
||||
/* keep a pointer for future reference */ |
||||
_netdev = dev; |
||||
|
||||
/* power on the NRFs radio */ |
||||
NRF_RADIO->POWER = 1; |
||||
/* load driver specific configuration */ |
||||
NRF_RADIO->MODE = CONF_MODE; |
||||
/* configure variable parameters to default values */ |
||||
NRF_RADIO->TXPOWER = NRFMIN_DEFAULT_TXPOWER; |
||||
NRF_RADIO->FREQUENCY = NRFMIN_DEFAULT_CHANNEL; |
||||
/* get default address from CPU ID */ |
||||
cpuid_get(cpuid); |
||||
tmp = 0; |
||||
for (i = 0; i < (CPUID_LEN / 2); i++) { |
||||
tmp ^= cpuid[i]; |
||||
} |
||||
_addr = ((uint16_t)tmp) << 8; |
||||
tmp = 0; |
||||
for (; i < CPUID_LEN; i++) { |
||||
tmp ^= cpuid[i]; |
||||
} |
||||
_addr |= tmp; |
||||
/* pre-configure radio addresses */ |
||||
NRF_RADIO->PREFIX0 = CONF_ADDR_PREFIX0; |
||||
NRF_RADIO->BASE0 = (NRFMIN_DEFAULT_PAN << 16) | _addr; |
||||
NRF_RADIO->BASE1 = (NRFMIN_DEFAULT_PAN << 16) | CONF_ADDR_BCAST; |
||||
NRF_RADIO->TXADDRESS = 0x00UL; /* always send from address 0 */ |
||||
NRF_RADIO->RXADDRESSES = 0x03UL; /* listen to addresses 0 and 1 */ |
||||
/* configure data fields and packet length whitening and endianess */ |
||||
NRF_RADIO->PCNF0 = (CONF_S1 << RADIO_PCNF0_S1LEN_Pos) | |
||||
(CONF_S0 << RADIO_PCNF0_S0LEN_Pos) | |
||||
(CONF_LEN << RADIO_PCNF0_LFLEN_Pos); |
||||
NRF_RADIO->PCNF1 = (CONF_WHITENING << RADIO_PCNF1_WHITEEN_Pos) | |
||||
(CONF_ENDIAN << RADIO_PCNF1_ENDIAN_Pos) | |
||||
(CONF_BASE_ADDR_LEN << RADIO_PCNF1_BALEN_Pos) | |
||||
(CONF_STATLEN << RADIO_PCNF1_STATLEN_Pos) | |
||||
(CONF_PAYLOAD_LEN << RADIO_PCNF1_MAXLEN_Pos); |
||||
/* configure CRC unit */ |
||||
NRF_RADIO->CRCCNF = CONF_CRC_LEN; |
||||
NRF_RADIO->CRCPOLY = CONF_CRC_POLY; |
||||
NRF_RADIO->CRCINIT = CONF_CRC_INIT; |
||||
/* set shortcuts for more efficient transfer */ |
||||
NRF_RADIO->SHORTS = (1 << RADIO_SHORTS_READY_START_Pos); |
||||
/* enable interrupts */ |
||||
NVIC_SetPriority(RADIO_IRQn, RADIO_IRQ_PRIO); |
||||
NVIC_EnableIRQ(RADIO_IRQn); |
||||
/* enable END interrupt */ |
||||
NRF_RADIO->EVENTS_END = 0; |
||||
NRF_RADIO->INTENSET = (1 << RADIO_INTENSET_END_Pos); |
||||
/* put device in receive mode */ |
||||
_switch_to_rx(); |
||||
return 0; |
||||
} |
||||
|
||||
int _send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt) |
||||
{ |
||||
(void)dev; |
||||
size_t size; |
||||
size_t pos = 0; |
||||
uint8_t *dst_addr; |
||||
gnrc_netif_hdr_t *hdr; |
||||
gnrc_pktsnip_t *payload; |
||||
|
||||
/* check packet */ |
||||
if (pkt == NULL || pkt->next == NULL) { |
||||
DEBUG("nrfmin: Error sending packet: packet incomplete\n"); |
||||
return -ENOMSG; |
||||
} |
||||
|
||||
/* check if payload is withing length bounds */ |
||||
size = gnrc_pkt_len(pkt->next); |
||||
if (size > CONF_PAYLOAD_LEN) { |
||||
gnrc_pktbuf_release(pkt); |
||||
DEBUG("nrfmin: Error sending packet: payload to large\n"); |
||||
return -EOVERFLOW; |
||||
} |
||||
/* get netif header and check address length */ |
||||
hdr = (gnrc_netif_hdr_t *)pkt->data; |
||||
if (hdr->dst_l2addr_len != 2) { |
||||
DEBUG("nrfmin: Error sending packet: dest address has invalid size\n"); |
||||
gnrc_pktbuf_release(pkt); |
||||
return -ENOMSG; |
||||
} |
||||
dst_addr = gnrc_netif_hdr_get_dst_addr(hdr); |
||||
|
||||
DEBUG("nrfmin: Sending packet to %02x:%02x - size %u\n", |
||||
dst_addr[0], dst_addr[1], size); |
||||
|
||||
/* wait for any ongoing transmission to finish */ |
||||
while (_state == STATE_TX) {} |
||||
/* write data into TX buffer */ |
||||
payload = pkt->next; |
||||
_tx_buf.length = 6 + size; |
||||
_tx_buf.src_addr[0] = (uint8_t)(_addr >> 8); |
||||
_tx_buf.src_addr[1] = (uint8_t)(_addr); |
||||
_tx_buf.dst_addr[0] = dst_addr[0]; |
||||
_tx_buf.dst_addr[1] = dst_addr[1]; |
||||
_tx_buf.proto = _nettype_to_nrftype(payload->type); |
||||
while (payload) { |
||||
memcpy(&(_tx_buf.payload[pos]), payload->data, payload->size); |
||||
pos += payload->size; |
||||
payload = payload->next; |
||||
} |
||||
|
||||
/* save old state and switch to idle if applicable */ |
||||
_tx_prestate = _state; |
||||
if (_tx_prestate == STATE_RX) { |
||||
_switch_to_idle(); |
||||
} |
||||
/* set packet pointer to TX buffer and write destination address */ |
||||
NRF_RADIO->PACKETPTR = (uint32_t)(&_tx_buf); |
||||
NRF_RADIO->BASE0 &= ~(0xffff); |
||||
NRF_RADIO->BASE0 |= ((((uint16_t)dst_addr[0]) << 8) | dst_addr[1]); |
||||
/* start transmission */ |
||||
_state = STATE_TX; |
||||
NRF_RADIO->TASKS_TXEN = 1; |
||||
|
||||
/* release packet */ |
||||
gnrc_pktbuf_release(pkt); |
||||
return (int)size; |
||||
} |
||||
|
||||
int _add_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb) |
||||
{ |
||||
if (dev->event_cb != NULL) { |
||||
return -ENOBUFS; |
||||
} |
||||
dev->event_cb = cb; |
||||
return 0; |
||||
} |
||||
|
||||
int _rem_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb) |
||||
{ |
||||
if (dev->event_cb == cb) { |
||||
dev->event_cb = NULL; |
||||
return 0; |
||||
} |
||||
return -ENOENT; |
||||
} |
||||
|
||||
int _get(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t max_len) |
||||
{ |
||||
(void)dev; |
||||
|
||||
switch (opt) { |
||||
case NETOPT_ADDRESS: |
||||
return _get_address(value, max_len); |
||||
case NETOPT_CHANNEL: |
||||
return _get_channel(value, max_len); |
||||
case NETOPT_NID: |
||||
return _get_pan(value, max_len); |
||||
case NETOPT_TX_POWER: |
||||
return _get_txpower(value, max_len); |
||||
case NETOPT_STATE: |
||||
return _get_state(value, max_len); |
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
} |
||||
|
||||
int _set(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t value_len) |
||||
{ |
||||
(void)dev; |
||||
|
||||
switch (opt) { |
||||
case NETOPT_ADDRESS: |
||||
return _set_address(value, value_len); |
||||
case NETOPT_CHANNEL: |
||||
return _set_channel(value, value_len); |
||||
case NETOPT_NID: |
||||
return _set_pan(value, value_len); |
||||
case NETOPT_TX_POWER: |
||||
return _set_txpower(value, value_len); |
||||
case NETOPT_STATE: |
||||
return _set_state(value, value_len); |
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
} |
||||
|
||||
void _isr_event(gnrc_netdev_t *dev, uint32_t event_type) |
||||
{ |
||||
switch (event_type) { |
||||
case ISR_EVENT_RX_DONE: |
||||
_receive_data(); |
||||
break; |
||||
default: |
||||
/* do nothing */ |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Mapping of netdev interface |
||||
*/ |
||||
const gnrc_netdev_driver_t nrfmin_driver = { |
||||
.send_data = _send, |
||||
.add_event_callback = _add_event_cb, |
||||
.rem_event_callback = _rem_event_cb, |
||||
.get = _get, |
||||
.set = _set, |
||||
.isr_event = _isr_event, |
||||
}; |
||||
//
|
@ -1,3 +1,8 @@
|
||||
DIRS = periph
|
||||
|
||||
# build one of the radio drivers, if enabled
|
||||
ifneq (,$(filter nrfmin,$(USEMODULE))) |
||||
DIRS += radio/nrfmin
|
||||
endif |
||||
|
||||
include $(RIOTBASE)/Makefile.base |
||||
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Freie Universitรคt Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup drivers_nrf5x_nrfmin NRF Minimal Radio Driver |
||||
* @ingroup drivers_netdev2 |
||||
* @brief Minimal driver for the NRF51 radio |
||||
* |
||||
* This driver uses the nRF5x radio in a proprietary/custom way, defining our |
||||
* own custom link layer. This custom link layer resembles some characteristics |
||||
* of the IEEE802.15.4 link layer, but is not at all compatible to it. |
||||
* |
||||
* One key point is, that this custom link layer is only meant to operate |
||||
* between nRF5x devices, which let's us make some very nice assumptions: |
||||
* - all communicating hosts are little-endian |
||||
* -> we define host byte order := network byte order |
||||
* |
||||
* The driver is using a Nordic proprietary physical layer, configured to a |
||||
* bitrate of 2Mbit. The maximum payload length can be freely configured, but |
||||
* the maximal supported value is 250 byte (default is 200 byte). |
||||
* |
||||
* We define the nrfmin link layer to use 16-bit addresses. On the physical |
||||
* layer we encode these addresses by putting these addresses into the 2 least |
||||
* significant bytes of the supported 5-byte addresses, while setting the other |
||||
* 3 bytes to 0xe7. |
||||
* |
||||
* For out custom link layer, we define our own proprietary link layer format |
||||
* (all fields are in host byte order (little endian)): |
||||
* |
||||
* byte0 | byte1 - byte2 | byte3 - byte4 | byte5 | byte7 - byteN |
||||
* ------ | ------------- | ------------- | ----- | ------------- |
||||
* length | src_addr | dst_addr | proto | payload... |
||||
* |
||||
* With: |
||||
* - length: length of the packet, including the header -> payload len + 6 |
||||
* - src_addr: 16-bit source address |
||||
* - dst_addr: 16-bit destination address |
||||
* - proto: type of data transferred (similar to an Ethertype field) |
||||
* |
||||
* SUMMARY: |
||||
* This driver / link layer supports: |
||||
* - 16-bit addressing (16-bit) |
||||
* -> extract default address from CPU ID |
||||
* - broadcast (broadcast address is ff:ff) |
||||
* - channels from 0 to 31 [2400MHz to 2524MHz, 4MHz per channel] |
||||
* - setting of TX power [+4dBm to -20dBm, in ~4dBm steps] |
||||
* - 8-bit packet type/proto field (to be used as seen fit) |
||||
* - setting device state (RX, SLEEP) |
||||
* |
||||
* But so far no support for: |
||||
* - link layer ACKs |
||||
* - retransmissions |
||||
* |
||||
* @todo So far the driver uses only a single RX buffer that is locked |
||||
* until the data was read/discarded. This can potentially lead to |
||||
* a lot of packet loss -> using more than one buffer would help |
||||
* here... |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface definition for the nrfmin NRF51822 radio driver |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef NRFMIN_H_ |
||||
#define NRFMIN_H_ |
||||
|
||||
#include "net/netdev2.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief nrfmin channel configuration |
||||
* @{ |
||||
*/ |
||||
#define NRFMIN_CHAN_MIN (0U) |
||||
#define NRFMIN_CHAN_DEFAULT (0U) /* 2400MHz */ |
||||
#define NRFMIN_CHAN_MAX (32) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Default transmission power used |
||||
*/ |
||||
#define NRFMIN_TXPOWER_DEFAULT (0) /* 0dBm */ |
||||
|
||||
/**
|
||||
* @brief Export the default nrfmin broadcast address |
||||
*/ |
||||
#define NRFMIN_ADDR_BCAST (0xffff) |
||||
|
||||
/**
|
||||
* @brief Default maximum payload length (must be <= 250) |
||||
*/ |
||||
#ifndef NRFMIN_PAYLOAD_MAX |
||||
#define NRFMIN_PAYLOAD_MAX (200U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Export some information on header and packet lengths |
||||
* @{ |
||||
*/ |
||||
#define NRFMIN_HDR_LEN (sizeof(nrfmin_hdr_t)) |
||||
#define NRFMIN_PKT_MAX (NRFMIN_HDR_LEN + NRFMIN_PAYLOAD_MAX) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Header format used for our custom nrfmin link layer |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t len; /**< packet length, including this header */ |
||||
uint16_t src_addr; /**< source address of the packet */ |
||||
uint16_t dst_addr; /**< destination address */ |
||||
uint8_t proto; /**< protocol of payload */ |
||||
} nrfmin_hdr_t; |
||||
|
||||
/**
|
||||
* @brief In-memory structure of a nrfmin radio packet |
||||
*/ |
||||
typedef union { |
||||
struct __attribute__((packed)) { |
||||
nrfmin_hdr_t hdr; /**< the nrfmin header */ |
||||
uint8_t payload[NRFMIN_PAYLOAD_MAX]; /**< actual payload */ |
||||
} pkt; /**< typed packet access */ |
||||
uint8_t raw[NRFMIN_PKT_MAX]; /**< raw packet access */ |
||||
} nrfmin_pkt_t; |
||||
|
||||
/**
|
||||
* @brief Export the netdev2 device descriptor |
||||
*/ |
||||
extern netdev2_t nrfmin_dev; |
||||
|
||||
/**
|
||||
* @brief Reference to the netdev driver interface |
||||
*/ |
||||
extern const netdev2_driver_t nrfmin_netdev; |
||||
|
||||
/**
|
||||
* @brief Setup the device driver's data structures |
||||
*/ |
||||
void nrfmin_setup(void); |
||||
|
||||
/**
|
||||
* @brief Get the currently active address |
||||
|
||||
* @return the 16-bit node address |
||||
*/ |
||||
uint16_t nrfmin_get_addr(void); |
||||
|
||||
/**
|
||||
* @brief Set the 16-bit radio address |
||||
* |
||||
* @param[in] addr address to set |
||||
*/ |
||||
void nrfmin_set_addr(uint16_t addr); |
||||
|
||||
/**
|
||||
* @brief Get a pseudo 64-bit long address (needed by IPv6 and 6LoWPAN) |
||||
* |
||||
* As we do not support 64-bit addresses, we just make one up, for this we |
||||
* simply return 4 times concatenated the 16-bit address. |
||||
* |
||||
* @param[out] addr 64-bit pseudo long address, as array of 4 * 16-bit |
||||
*/ |
||||
void nrfmin_get_pseudo_long_addr(uint16_t *addr); |
||||
|
||||
/**
|
||||
* @brief Get the IID build from the 16-bit node address |
||||
* |
||||
* @param[out] iid the 64-bit IID, as array of 4 * 16-bit |
||||
*/ |
||||
void nrfmin_get_iid(uint16_t *iid); |
||||
|
||||
/**
|
||||
* @brief Get the current channel |
||||
* |
||||
* @return currently active channel |
||||
*/ |
||||
uint16_t nrfmin_get_channel(void); |
||||
|
||||
/**
|
||||
* @brief Set the active channel |
||||
* |
||||
* @param[in] chan targeted channel [0-31] |
||||
* |
||||
* @return sizeof(uint16_t) on success |
||||
* @return -EOVERFLOW if channel is not applicable |
||||
*/ |
||||
int nrfmin_set_channel(uint16_t chan); |
||||
|
||||
/**
|
||||
* @brief Get the current radio state |
||||
* |
||||
* @return state the radio is currently in |
||||
*/ |
||||
netopt_state_t nrfmin_get_state(void); |
||||
|
||||
/**
|
||||
* @brief Put the device into the given state |
||||
* |
||||
* @param[in] val target state |
||||
* |
||||
* @return sizeof(netopt_state_t) on success |
||||
* @return -ENOTSUP if target state is not applicable |
||||
*/ |
||||
int nrfmin_set_state(netopt_state_t val); |
||||
|
||||
/**
|
||||
* @brief Get the current transmit power |
||||
* |
||||
* @return transmission power in [dBm] |
||||
*/ |
||||
int16_t nrfmin_get_txpower(void); |
||||
|
||||
/**
|
||||
* @brief Set the used transmission power |
||||
* |
||||
* @param[in] power targeted power, in [dBm] |
||||
*/ |
||||
void nrfmin_set_txpower(int16_t power); |
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NRFMIN_H_ */ |
||||
/** @} */ |
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universitรคt Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup drivers_nrf5x_nrfmin_gnrc GNRC adapter for nrfmin |
||||
* @ingroup drivers_nrf5x_nrfmin |
||||
* @brief Minimal driver for the NRF51 radio |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief GNRC adapter for nrfmin devices (e.g. nRF5x radios) |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef NRFMIN_GNRC_H_ |
||||
#define NRFMIN_GNRC_H_ |
||||
|
||||
#include "nrfmin.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Initialize the nrfmin GNRC adapter, also takes care of the nrfmin |
||||
* driver setup |
||||
* |
||||
* As we have never more than 1 nrfmin device on a board, we can make some |
||||
* simplifications when it come to allocating device descriptors and adapter |
||||
* data structures -> we do this right in the driver/adapter code, so this |
||||
* function can be called from auto_init as is, without the need for external |
||||
* memory allocation. |
||||
*/ |
||||
void gnrc_netdev2_nrfmin_init(void); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NRFMIN_GNRC_H_ */ |
||||
/** @} */ |
@ -0,0 +1,9 @@
|
||||
MODULE = nrfmin
|
||||
|
||||
SRC = nrfmin.c
|
||||
|
||||
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) |
||||
SRC += nrfmin_gnrc.c
|
||||
endif |
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Freie Universitรคt Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup drivers_nrf5x_nrfmin |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Implementation of the nrfmin radio driver for nRF51 radios |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
#include "cpu.h" |
||||
#include "mutex.h" |
||||
#include "assert.h" |
||||
|
||||
#include "periph_conf.h" |
||||
#include "periph/cpuid.h" |
||||
|
||||
#include "nrfmin.h" |
||||
#include "net/netdev2.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
/**
|
||||
* @brief Driver specific device configuration |
||||
* @{ |
||||
*/ |
||||
#define CONF_MODE RADIO_MODE_MODE_Nrf_1Mbit |
||||
#define CONF_LEN (8U) |
||||
#define CONF_S0 (0U) |
||||
#define CONF_S1 (0U) |
||||
#define CONF_STATLEN (0U) |
||||
#define CONF_BASE_ADDR_LEN (4U) |
||||
#define CONF_ENDIAN RADIO_PCNF1_ENDIAN_Big |
||||
#define CONF_WHITENING RADIO_PCNF1_WHITEEN_Disabled |
||||
#define CONF_CRC_LEN (2U) |
||||
#define CONF_CRC_POLY (0x11021) |
||||
#define CONF_CRC_INIT (0xf0f0f0) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Driver specific address configuration |
||||
* @{ |
||||
*/ |
||||
#define CONF_ADDR_PREFIX0 (0xe7e7e7e7) |
||||
#define CONF_ADDR_BASE (0xe7e70000) |
||||
#define CONF_ADDR_BCAST (CONF_ADDR_BASE | NRFMIN_ADDR_BCAST) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief We define a pseudo NID for compliance to 6LoWPAN |
||||
*/ |
||||
#define CONF_PSEUDO_NID (0xaffe) |
||||
|
||||
/**
|
||||
* @brief Driver specific (interrupt) events (not all of them used currently) |
||||
* @{ |
||||
*/ |
||||
#define ISR_EVENT_RX_START (0x0001) |
||||
#define ISR_EVENT_RX_DONE (0x0002) |
||||
#define ISR_EVENT_TX_START (0x0004) |
||||
#define ISR_EVENT_TX_DONE (0x0008) |
||||
#define ISR_EVENT_WRONG_CHKSUM (0x0010) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Possible internal device states |
||||
*/ |
||||
typedef enum { |
||||
STATE_OFF, /**< device is powered off */ |
||||
STATE_IDLE, /**< device is in idle mode */ |
||||
STATE_RX, /**< device is in receive mode */ |
||||
STATE_TX, /**< device is transmitting data */ |
||||
} state_t; |
||||
|
||||
|
||||
/**
|
||||
* @brief Since there can only be 1 nrfmin device, we allocate it right here |
||||
*/ |
||||
netdev2_t nrfmin_dev; |
||||
|
||||
/**
|
||||
* @brief For faster lookup we remember our own 16-bit address |
||||
*/ |
||||
static uint16_t my_addr; |
||||
|
||||
/**
|
||||
* @brief We need to keep track of the radio state in SW (-> PAN ID 20) |
||||
* |
||||
* See nRF51822 PAN ID 20: RADIO State Register is not functional. |
||||
*/ |
||||
static volatile state_t state = STATE_OFF; |
||||
|
||||
/**
|
||||
* @brief We also remember the 'long-term' state, so we can resume after TX |
||||
*/ |
||||
static volatile state_t target_state = STATE_OFF; |
||||
|
||||
/**
|
||||
* @brief When sending out data, the data needs to be in one continuous memory |
||||
* region. So we need to buffer outgoing data on the driver level. |
||||
*/ |
||||
static nrfmin_pkt_t tx_buf; |
||||
|
||||
/**
|
||||
* @brief As the device is memory mapped, we need some space to save incoming |
||||
* data to. |
||||
* |
||||
* @todo Improve the RX buffering to at least use double buffering |
||||
*/ |
||||
static nrfmin_pkt_t rx_buf; |
||||
|
||||
/**
|
||||
* @brief While we listen for incoming data, we lock the RX buffer |
||||
*/ |
||||
static volatile uint8_t rx_lock = 0; |
||||
|
||||
/**
|
||||
* @brief Set radio into idle (DISABLED) state |
||||
*/ |
||||
static void go_idle(void) |
||||
{ |
||||
/* set device into basic disabled state */ |
||||
NRF_RADIO->EVENTS_DISABLED = 0; |
||||
NRF_RADIO->TASKS_DISABLE = 1; |
||||
while (NRF_RADIO->EVENTS_DISABLED == 0) {} |
||||
/* also release any existing lock on the RX buffer */ |
||||
rx_lock = 0; |
||||
state = STATE_IDLE; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Set radio into the target state as defined by `target_state` |
||||
* |
||||
* Trick here is, that the driver can go back to it's previous state after a |
||||
* send operation, so it can differentiate if the driver was in DISABLED |