mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
7309171303
cpu, sam0_common: fix unused parameter in periph/spi cpu, kinetis_common: fix unused parameter in periph/spi cpu, cc2538: fix unused param in periph/i2c cpu, cc2538: fix unused param in periph/spi cpu, sam3: fix unused param in periph/spi cpu, stm32_common: fix unused param in periph/pm cpu, stm32f3: fix unused params in periph/i2c cpu, nrf5x_common: fix unused param in periph/gpio cpu, nrf5x_common: fix unused param in periph/spi cpu, lpc2387: fix unused params in periph/spi cpu, cc2538: fix unused params in radio/netdev cpu, cc2650: fix unused params in periph/uart cpu, lm4f120: fix unused param in periph/spi cpu, lm4f120: fix unused params in periph/timer cpu, lm4f120: fix unused params in periph/uart cpu, stm32_common: fix unused params in periph/dac cpu, stm32l0: fix unused params in periph/i2c cpu, msp430fxyz: fix unused params in periph/uart cpu, mips: fix unused params cpu, cc430: fix unused-params in periph/timer cpu, msp430fxyz: fix unused params in periph/spi drivers, cc2420: fix unused param cpu, mips32r2_common: fix unused params in periph/timer cpu, cc2538: fix unused-param in periph/i2c cpu, mips32r2_common: fix unused-param in periph/timer cpu, msp430fxyz: fix unused params in periph/timer cpu, atmega_common: fix unused params in periph/spi driver, nrfmin: fix unused params cpu, cc2538_rf: fix unused params driver, netdev_ieee802514: fix unused param cpu, mip_pic32m: fix unused params cpu, lpc2387: fix unused params in periph/pwm tests/driver_sdcard_spi: fix unused params cpu, sam3: fix unused param in periph/pwm tests/driver_dynamixel: fix unused params, and style issues cpu, cc430: fix unused param in periph/rtc cpu, atmega_common: fix unused params in periph/i2c
410 lines
11 KiB
C
410 lines
11 KiB
C
/*
|
|
* Copyright (C) 2016 MUTEX NZ Ltd
|
|
*
|
|
* 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 cpu_cc2538
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Netdev adaption for the CC2538 RF driver
|
|
*
|
|
* @author Aaron Sowry <aaron@mutex.nz>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include "net/gnrc.h"
|
|
#include "net/netdev.h"
|
|
|
|
#include "cc2538_rf.h"
|
|
#include "cc2538_rf_netdev.h"
|
|
#include "cc2538_rf_internal.h"
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
#include "debug.h"
|
|
|
|
#define _MAX_MHR_OVERHEAD (25)
|
|
|
|
static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
|
|
static int _set(netdev_t *dev, netopt_t opt, const void *value, size_t value_len);
|
|
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
|
|
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
|
|
static void _isr(netdev_t *netdev);
|
|
static int _init(netdev_t *dev);
|
|
|
|
const netdev_driver_t cc2538_rf_driver = {
|
|
.get = _get,
|
|
.set = _set,
|
|
.send = _send,
|
|
.recv = _recv,
|
|
.isr = _isr,
|
|
.init = _init,
|
|
};
|
|
|
|
/* Reference pointer for the IRQ handler */
|
|
static netdev_t *_dev;
|
|
|
|
void _irq_handler(void)
|
|
{
|
|
if (_dev->event_callback) {
|
|
_dev->event_callback(_dev, NETDEV_EVENT_ISR);
|
|
}
|
|
}
|
|
|
|
static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
|
|
{
|
|
cc2538_rf_t *dev = (cc2538_rf_t *)netdev;
|
|
|
|
if (dev == NULL) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
switch (opt) {
|
|
case NETOPT_AUTOACK:
|
|
if (RFCORE->XREG_FRMCTRL0bits.AUTOACK) {
|
|
*((netopt_enable_t *)value) = NETOPT_ENABLE;
|
|
}
|
|
else {
|
|
*((netopt_enable_t *)value) = NETOPT_DISABLE;
|
|
}
|
|
return sizeof(netopt_enable_t);
|
|
|
|
case NETOPT_CHANNEL_PAGE:
|
|
if (max_len < sizeof(uint16_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
/* This tranceiver only supports page 0 */
|
|
*((uint16_t *)value) = 0;
|
|
return sizeof(uint16_t);
|
|
|
|
case NETOPT_DEVICE_TYPE:
|
|
if (max_len < sizeof(uint16_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
*((uint16_t *) value) = NETDEV_TYPE_IEEE802154;
|
|
return sizeof(uint16_t);
|
|
|
|
case NETOPT_IS_CHANNEL_CLR:
|
|
if (cc2538_channel_clear()) {
|
|
*((netopt_enable_t *)value) = NETOPT_ENABLE;
|
|
}
|
|
else {
|
|
*((netopt_enable_t *)value) = NETOPT_DISABLE;
|
|
}
|
|
return sizeof(netopt_enable_t);
|
|
|
|
case NETOPT_IS_WIRED:
|
|
return -ENOTSUP;
|
|
|
|
case NETOPT_MAX_PACKET_SIZE:
|
|
if (max_len < sizeof(int16_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
*((uint16_t *)value) = CC2538_RF_MAX_DATA_LEN - _MAX_MHR_OVERHEAD;
|
|
return sizeof(uint16_t);
|
|
|
|
case NETOPT_PROMISCUOUSMODE:
|
|
if (cc2538_get_monitor()) {
|
|
*((netopt_enable_t *)value) = NETOPT_ENABLE;
|
|
}
|
|
else {
|
|
*((netopt_enable_t *)value) = NETOPT_DISABLE;
|
|
}
|
|
return sizeof(netopt_enable_t);
|
|
|
|
case NETOPT_STATE:
|
|
if (max_len < sizeof(netopt_state_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
*((netopt_state_t *)value) = dev->state;
|
|
return sizeof(netopt_state_t);
|
|
|
|
case NETOPT_TX_POWER:
|
|
if (max_len < sizeof(int16_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
*((uint16_t *)value) = cc2538_get_tx_power();
|
|
return sizeof(uint16_t);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
int res;
|
|
|
|
if (((res = netdev_ieee802154_get((netdev_ieee802154_t *)netdev, opt, value,
|
|
max_len)) >= 0) || (res != -ENOTSUP)) {
|
|
return res;
|
|
}
|
|
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t value_len)
|
|
{
|
|
cc2538_rf_t *dev = (cc2538_rf_t *)netdev;
|
|
int res = -ENOTSUP;
|
|
|
|
if (dev == NULL) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
switch (opt) {
|
|
case NETOPT_ADDRESS:
|
|
if (value_len > sizeof(uint16_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
cc2538_set_addr_short(*((const uint16_t*)value));
|
|
}
|
|
break;
|
|
|
|
case NETOPT_ADDRESS_LONG:
|
|
if (value_len > sizeof(uint64_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
cc2538_set_addr_long(*((const uint64_t*)value));
|
|
}
|
|
break;
|
|
|
|
case NETOPT_AUTOACK:
|
|
RFCORE->XREG_FRMCTRL0bits.AUTOACK = ((const bool *)value)[0];
|
|
res = sizeof(netopt_enable_t);
|
|
break;
|
|
|
|
case NETOPT_CHANNEL:
|
|
if (value_len != sizeof(uint16_t)) {
|
|
res = -EINVAL;
|
|
}
|
|
else {
|
|
uint8_t chan = ((const uint8_t *)value)[0];
|
|
if (chan < IEEE802154_CHANNEL_MIN ||
|
|
chan > IEEE802154_CHANNEL_MAX) {
|
|
res = -EINVAL;
|
|
}
|
|
else {
|
|
cc2538_set_chan(chan);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETOPT_CHANNEL_PAGE:
|
|
/* This tranceiver only supports page 0 */
|
|
if (value_len != sizeof(uint16_t) ||
|
|
*((const uint16_t *)value) != 0 ) {
|
|
res = -EINVAL;
|
|
}
|
|
else {
|
|
res = sizeof(uint16_t);
|
|
}
|
|
break;
|
|
|
|
case NETOPT_IS_WIRED:
|
|
return -ENOTSUP;
|
|
|
|
case NETOPT_NID:
|
|
if (value_len > sizeof(uint16_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
cc2538_set_pan(*((const uint16_t *)value));
|
|
}
|
|
break;
|
|
|
|
case NETOPT_PROMISCUOUSMODE:
|
|
cc2538_set_monitor(((const bool *)value)[0]);
|
|
res = sizeof(netopt_enable_t);
|
|
break;
|
|
|
|
case NETOPT_STATE:
|
|
if (value_len > sizeof(netopt_state_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
cc2538_set_state(dev, *((const netopt_state_t *)value));
|
|
res = sizeof(netopt_state_t);
|
|
break;
|
|
|
|
case NETOPT_TX_POWER:
|
|
if (value_len > sizeof(int16_t)) {
|
|
return -EOVERFLOW;
|
|
}
|
|
cc2538_set_tx_power(*((const int16_t *)value));
|
|
res = sizeof(uint16_t);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (res == -ENOTSUP) {
|
|
res = netdev_ieee802154_set((netdev_ieee802154_t *)netdev, opt,
|
|
value, value_len);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
|
|
{
|
|
(void) netdev;
|
|
|
|
int pkt_len = 0;
|
|
|
|
/* Flush TX FIFO once no transmission in progress */
|
|
RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE == 0);
|
|
RFCORE_SFR_RFST = ISFLUSHTX;
|
|
|
|
/* The first byte of the TX FIFO must be the packet length,
|
|
but we don't know what it is yet. Write a null byte to the
|
|
start of the FIFO, so we can come back and update it later */
|
|
rfcore_write_byte(0);
|
|
|
|
for (unsigned i = 0; i < count; i++) {
|
|
pkt_len += vector[i].iov_len;
|
|
|
|
if (pkt_len > CC2538_RF_MAX_DATA_LEN) {
|
|
DEBUG("cc2538_rf: packet too large (%u > %u)\n",
|
|
pkt_len, CC2538_RF_MAX_DATA_LEN);
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
rfcore_write_fifo(vector[i].iov_base, vector[i].iov_len);
|
|
}
|
|
|
|
#ifdef MODULE_NETSTATS_L2
|
|
netdev->stats.tx_bytes += pkt_len;
|
|
#endif
|
|
|
|
/* Set first byte of TX FIFO to the packet length */
|
|
rfcore_poke_tx_fifo(0, pkt_len + CC2538_AUTOCRC_LEN);
|
|
|
|
RFCORE_SFR_RFST = ISTXON;
|
|
|
|
/* Wait for transmission to complete */
|
|
RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE == 0);
|
|
|
|
return pkt_len;
|
|
}
|
|
|
|
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
|
{
|
|
(void) netdev;
|
|
|
|
size_t pkt_len;
|
|
|
|
if (buf == NULL) {
|
|
/* GNRC wants to know how much data we've got for it */
|
|
pkt_len = rfcore_read_byte();
|
|
|
|
/* Make sure pkt_len is sane */
|
|
if (pkt_len > CC2538_RF_MAX_DATA_LEN) {
|
|
RFCORE_SFR_RFST = ISFLUSHRX;
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
/* CRC check */
|
|
if (!(rfcore_peek_rx_fifo(pkt_len) & 0x80)) {
|
|
/* CRC failed; discard packet */
|
|
RFCORE_SFR_RFST = ISFLUSHRX;
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (len > 0) {
|
|
/* GNRC wants us to drop the packet */
|
|
RFCORE_SFR_RFST = ISFLUSHRX;
|
|
}
|
|
|
|
return pkt_len - IEEE802154_FCS_LEN;
|
|
}
|
|
else {
|
|
/* GNRC is expecting len bytes of data */
|
|
pkt_len = len;
|
|
}
|
|
|
|
#ifdef MODULE_NETSTATS_L2
|
|
netdev->stats.rx_count++;
|
|
netdev->stats.rx_bytes += pkt_len;
|
|
#endif
|
|
rfcore_read_fifo(buf, pkt_len);
|
|
|
|
if (info != NULL && RFCORE->XREG_RSSISTATbits.RSSI_VALID) {
|
|
uint8_t corr_val;
|
|
int8_t rssi_val;
|
|
netdev_ieee802154_rx_info_t *radio_info = info;
|
|
rssi_val = rfcore_read_byte() + CC2538_RSSI_OFFSET;
|
|
|
|
RFCORE_ASSERT(rssi_val > CC2538_RF_SENSITIVITY);
|
|
|
|
/* The number of dB above maximum sensitivity detected for the
|
|
* received packet */
|
|
radio_info->rssi = -CC2538_RF_SENSITIVITY + rssi_val;
|
|
|
|
corr_val = rfcore_read_byte() & CC2538_CORR_VAL_MASK;
|
|
|
|
if (corr_val < CC2538_CORR_VAL_MIN) {
|
|
corr_val = CC2538_CORR_VAL_MIN;
|
|
}
|
|
else if (corr_val > CC2538_CORR_VAL_MAX) {
|
|
corr_val = CC2538_CORR_VAL_MAX;
|
|
}
|
|
|
|
/* Interpolate the correlation value between 0 - 255
|
|
* to provide an LQI value */
|
|
radio_info->lqi = 255 * (corr_val - CC2538_CORR_VAL_MIN) /
|
|
(CC2538_CORR_VAL_MAX - CC2538_CORR_VAL_MIN);
|
|
}
|
|
|
|
RFCORE_SFR_RFST = ISFLUSHRX;
|
|
|
|
return pkt_len;
|
|
}
|
|
|
|
static void _isr(netdev_t *netdev)
|
|
{
|
|
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
|
}
|
|
|
|
static int _init(netdev_t *netdev)
|
|
{
|
|
cc2538_rf_t *dev = (cc2538_rf_t *) netdev;
|
|
_dev = netdev;
|
|
|
|
uint16_t pan = cc2538_get_pan();
|
|
uint16_t chan = cc2538_get_chan();
|
|
uint16_t addr_short = cc2538_get_addr_short();
|
|
uint64_t addr_long = cc2538_get_addr_long();
|
|
|
|
/* Initialise netdev_ieee802154_t struct */
|
|
netdev_ieee802154_set((netdev_ieee802154_t *)netdev, NETOPT_NID, &pan,
|
|
sizeof(pan));
|
|
netdev_ieee802154_set((netdev_ieee802154_t *)netdev, NETOPT_CHANNEL, &chan,
|
|
sizeof(chan));
|
|
netdev_ieee802154_set((netdev_ieee802154_t *)netdev, NETOPT_ADDRESS,
|
|
&addr_short, sizeof(addr_short));
|
|
netdev_ieee802154_set((netdev_ieee802154_t *)netdev, NETOPT_ADDRESS_LONG,
|
|
&addr_long, sizeof(addr_long));
|
|
|
|
cc2538_set_state(dev, NETOPT_STATE_IDLE);
|
|
|
|
/* set default protocol */
|
|
#ifdef MODULE_GNRC_SIXLOWPAN
|
|
dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN;
|
|
#elif MODULE_GNRC
|
|
dev->netdev.proto = GNRC_NETTYPE_UNDEF;
|
|
#endif
|
|
#ifdef MODULE_NETSTATS_L2
|
|
memset(&netdev->stats, 0, sizeof(netstats_t));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|