mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-26 23:11:19 +01:00
Merge pull request #3716 from kaspar030/ng_cc110x
drivers: add cc110x driver
This commit is contained in:
commit
7cb3f9bd5e
@ -36,6 +36,10 @@ ifneq (,$(filter at86rf2%,$(USEMODULE)))
|
||||
USEMODULE += netif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter cc110x,$(USEMODULE)))
|
||||
USEMODULE += ieee802154
|
||||
endif
|
||||
|
||||
ifneq (,$(filter kw2xrf,$(USEMODULE)))
|
||||
USEMODULE += ieee802154
|
||||
USEMODULE += netif
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
export INCLUDES += -I$(RIOTBOARD)/msba2/include
|
||||
|
||||
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
|
||||
USEMODULE += cc110x gnrc_netdev2 gnrc_cc110x
|
||||
endif
|
||||
|
||||
include $(RIOTBOARD)/msba2-common/Makefile.include
|
||||
|
||||
44
boards/msba2/include/cc110x_params.h
Normal file
44
boards/msba2/include/cc110x_params.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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 board_msba2
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief cc110x board specific configuration
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_PARAMS_H
|
||||
#define CC110X_PARAMS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name CC110X configuration
|
||||
*/
|
||||
const cc110x_params_t cc110x_params[] = {
|
||||
{
|
||||
.spi = 0,
|
||||
.cs = 53,
|
||||
.gdo0 = 27,
|
||||
.gdo1 = 55,
|
||||
.gdo2 = 28
|
||||
},
|
||||
};
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* CC110X_PARAMS_H */
|
||||
/** @} */
|
||||
3
drivers/cc110x/Makefile
Normal file
3
drivers/cc110x/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
DIRS += gnrc_cc110x
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
100
drivers/cc110x/cc110x-defaultsettings.c
Normal file
100
drivers/cc110x/cc110x-defaultsettings.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2013 INRIA
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TI Chipcon CC110x default settings
|
||||
*
|
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
|
||||
* @author Heiko Will <hwill@inf.fu-berlin.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include "cc110x.h"
|
||||
|
||||
/**
|
||||
* @brief PATABLE with available output powers
|
||||
* @note If changed in size, adjust MAX_OUTPUT_POWER definition
|
||||
* in CC110x interface
|
||||
*/
|
||||
const char cc110x_default_pa_table[8] = {
|
||||
0x00, /*< -52 dBm */
|
||||
0x0D, /*< -20 dBm */
|
||||
0x34, /*< -10 dBm */
|
||||
0x57, /*< - 5 dBm */
|
||||
0x8E, /*< 0 dBm */
|
||||
0x85, /*< + 5 dBm */
|
||||
0xCC, /*< + 7 dBm */
|
||||
0xC3 /*< +10 dBm */
|
||||
};
|
||||
|
||||
const char cc110x_default_base_freq[3] = { 0x21, 0x71, 0x7F };
|
||||
|
||||
/**
|
||||
* @brief cc110x default settings
|
||||
*/
|
||||
const char cc110x_default_conf[] = {
|
||||
0x06, /* IOCFG2 */
|
||||
0x2E, /* IOCFG1 */
|
||||
/* some boards use cc110x' GDO0 as clock source, so for those, we allow
|
||||
* overriding of the corresponding setting, e.g., in board.h */
|
||||
#ifdef CC110X_IOCONF0_VAL
|
||||
CC110X_IOCONF0_VAL,
|
||||
#else
|
||||
0x0E, /* IOCFG0 */
|
||||
#endif
|
||||
0x07, /* FIFOTHR */
|
||||
0x9B, /* SYNC1 */
|
||||
0xAD, /* SYNC0 */
|
||||
0xFF, /* PKTLEN */
|
||||
0x06, /* PKTCTRL1 */
|
||||
0x45, /* PKTCTRL0 (variable packet length) */
|
||||
0xFF, /* ADDR */
|
||||
0x00, /* CHANNR */
|
||||
0x0F, /* FSCTRL1 */
|
||||
0x00, /* FSCTRL0 */
|
||||
0x21, /* FREQ2 */
|
||||
0x71, /* FREQ1 */
|
||||
0x7A, /* FREQ0 */
|
||||
0x7C, /* MDMCFG4 */
|
||||
0x7A, /* MDMCFG3 */
|
||||
0x06, /* MDMCFG2 */
|
||||
0xC0, /* MDMCFG1 */
|
||||
0xF8, /* MDMCFG0 */
|
||||
0x44, /* DEVIATN */
|
||||
0x07, /* MCSM2 */
|
||||
0x03, /* MCSM1 */
|
||||
0x18, /* MCSM0 */
|
||||
0x16, /* FOCCFG */
|
||||
0x6C, /* BSCFG */
|
||||
0x45, /* AGCCTRL2 */
|
||||
0x40, /* AGCCTRL1 */
|
||||
0x91, /* AGCCTRL0 */
|
||||
0x87, /* WOREVT1 */
|
||||
0x6B, /* WOREVT0 */
|
||||
0xF8, /* WORCTRL */
|
||||
0x56, /* FREND1 */
|
||||
0x17, /* FREND0 */
|
||||
0xEA, /* FSCAL3 */
|
||||
0x2A, /* FSCAL2 */
|
||||
0x00, /* FSCAL1 */
|
||||
0x1F, /* FSCAL0 */
|
||||
0x00 /* padding to 4 bytes */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The size of the configuration array for CC110X in bytes
|
||||
* */
|
||||
const uint8_t cc110x_default_conf_size = sizeof(cc110x_default_conf);
|
||||
218
drivers/cc110x/cc110x-netdev2.c
Normal file
218
drivers/cc110x/cc110x-netdev2.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Implementation of netdev2 interface for cc110x
|
||||
*
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "cc110x.h"
|
||||
#include "cc110x/cc110x-netdev2.h"
|
||||
#include "cc110x/cc110x-internal.h"
|
||||
#include "cc110x/cc110x-interface.h"
|
||||
#include "net/eui64.h"
|
||||
|
||||
#include "periph/cpuid.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static int _send(netdev2_t *dev, const struct iovec *vector, int count)
|
||||
{
|
||||
DEBUG("%s:%u\n", __func__, __LINE__);
|
||||
|
||||
netdev2_cc110x_t *netdev2_cc110x = (netdev2_cc110x_t*) dev;
|
||||
cc110x_pkt_t *cc110x_pkt = vector[0].iov_base;
|
||||
|
||||
return cc110x_send(&netdev2_cc110x->cc110x, cc110x_pkt);
|
||||
}
|
||||
|
||||
static int _recv(netdev2_t *dev, char* buf, int len)
|
||||
{
|
||||
DEBUG("%s:%u\n", __func__, __LINE__);
|
||||
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
|
||||
cc110x_pkt_t *cc110x_pkt = &cc110x->pkt_buf.packet;
|
||||
if (cc110x_pkt->length > len) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
memcpy(buf, (void*)cc110x_pkt, cc110x_pkt->length);
|
||||
return cc110x_pkt->length;
|
||||
}
|
||||
|
||||
static inline int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len)
|
||||
{
|
||||
if (max_len < sizeof(eui64_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
uint8_t *eui64 = (uint8_t*) value;
|
||||
#ifdef CPUID_ID_LEN
|
||||
int n = (CPUID_ID_LEN < sizeof(eui64_t))
|
||||
? CPUID_ID_LEN
|
||||
: sizeof(eui64_t);
|
||||
|
||||
char cpuid[CPUID_ID_LEN];
|
||||
cpuid_get(cpuid);
|
||||
|
||||
memcpy(eui64 + 8 - n, cpuid, n);
|
||||
|
||||
#else
|
||||
for (int i = 0; i < 8; i++) {
|
||||
eui64[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* make sure we mark the address as non-multicast and not globally unique */
|
||||
eui64[0] &= ~(0x01);
|
||||
eui64[0] |= 0x02;
|
||||
|
||||
return sizeof(eui64_t);
|
||||
}
|
||||
|
||||
static int _get(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
|
||||
{
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_DEVICE_TYPE:
|
||||
assert(value_len == 2);
|
||||
*((uint16_t *) value) = NETDEV2_TYPE_CC110X;
|
||||
return 2;
|
||||
case NETOPT_PROTO:
|
||||
assert(value_len == sizeof(gnrc_nettype_t));
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
*((gnrc_nettype_t*)value) = GNRC_NETTYPE_SIXLOWPAN;
|
||||
#else
|
||||
*((gnrc_nettype_t*)value) = GNRC_NETTYPE_UNDEF;
|
||||
#endif
|
||||
return sizeof(gnrc_nettype_t);
|
||||
case NETOPT_CHANNEL:
|
||||
assert(value_len > 1);
|
||||
*((uint16_t *)value) = (uint16_t)cc110x->radio_channel;
|
||||
return 2;
|
||||
case NETOPT_ADDRESS:
|
||||
assert(value_len > 0);
|
||||
*((uint8_t *)value) = cc110x->radio_address;
|
||||
return 1;
|
||||
case NETOPT_MAX_PACKET_SIZE:
|
||||
assert(value_len > 0);
|
||||
*((uint8_t *)value) = CC110X_PACKET_LENGTH;
|
||||
return 1;
|
||||
case NETOPT_IPV6_IID:
|
||||
return _get_iid(dev, value, value_len);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
|
||||
{
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_CHANNEL:
|
||||
{
|
||||
uint8_t *arg = (uint8_t*)value;
|
||||
uint8_t channel = arg[value_len-1];
|
||||
if ((channel < CC110X_MIN_CHANNR) || (channel > CC110X_MAX_CHANNR)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cc110x_set_channel(cc110x, channel) == -1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
case NETOPT_ADDRESS:
|
||||
if (value_len < 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!cc110x_set_address(cc110x, *(uint8_t*)value)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _netdev2_cc110x_isr(void *arg)
|
||||
{
|
||||
netdev2_t *netdev2 = (netdev2_t*) arg;
|
||||
netdev2->event_callback(netdev2, NETDEV2_EVENT_ISR, netdev2->isr_arg);
|
||||
}
|
||||
|
||||
static void _netdev2_cc110x_rx_callback(void *arg)
|
||||
{
|
||||
netdev2_t *netdev2 = (netdev2_t*) arg;
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) arg)->cc110x;
|
||||
gpio_irq_disable(cc110x->params.gdo2);
|
||||
netdev2->event_callback(netdev2, NETDEV2_EVENT_RX_COMPLETE, netdev2->isr_arg);
|
||||
}
|
||||
|
||||
static void _isr(netdev2_t *dev)
|
||||
{
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
cc110x_isr_handler(cc110x, _netdev2_cc110x_rx_callback, (void*)dev);
|
||||
}
|
||||
|
||||
static int _init(netdev2_t *dev)
|
||||
{
|
||||
DEBUG("%s:%u\n", __func__, __LINE__);
|
||||
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
|
||||
gpio_init_int(cc110x->params.gdo2, GPIO_NOPULL, GPIO_BOTH,
|
||||
&_netdev2_cc110x_isr, (void*)dev);
|
||||
|
||||
gpio_set(cc110x->params.gdo2);
|
||||
gpio_irq_disable(cc110x->params.gdo2);
|
||||
|
||||
/* Switch to RX mode */
|
||||
cc110x_rd_set_mode(cc110x, RADIO_MODE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const netdev2_driver_t netdev2_cc110x_driver = {
|
||||
.send=_send,
|
||||
.recv=_recv,
|
||||
.init=_init,
|
||||
.get=_get,
|
||||
.set=_set,
|
||||
.isr=_isr
|
||||
};
|
||||
|
||||
int netdev2_cc110x_setup(netdev2_cc110x_t *netdev2_cc110x, const cc110x_params_t *params)
|
||||
{
|
||||
DEBUG("netdev2_cc110x_setup()\n");
|
||||
netdev2_cc110x->netdev.driver = &netdev2_cc110x_driver;
|
||||
|
||||
return cc110x_setup(&netdev2_cc110x->cc110x, params);
|
||||
}
|
||||
298
drivers/cc110x/cc110x-rxtx.c
Normal file
298
drivers/cc110x/cc110x-rxtx.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Functions for packet reception and transmission on cc110x devices
|
||||
*
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cc110x.h"
|
||||
#include "cc110x/cc110x-spi.h"
|
||||
#include "cc110x/cc110x-internal.h"
|
||||
#include "cc110x/cc110x-interface.h"
|
||||
#include "cc110x/cc110x-defines.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "irq.h"
|
||||
|
||||
#include "kernel_types.h"
|
||||
#include "msg.h"
|
||||
|
||||
#include "cpu_conf.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static void _rx_abort(cc110x_t *dev)
|
||||
{
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
|
||||
cc110x_strobe(dev, CC110X_SIDLE); /* Switch to IDLE (should already be)... */
|
||||
cc110x_strobe(dev, CC110X_SFRX); /* ...for flushing the RX FIFO */
|
||||
|
||||
cc110x_switch_to_rx(dev);
|
||||
}
|
||||
|
||||
static void _rx_start(cc110x_t *dev)
|
||||
{
|
||||
dev->radio_state = RADIO_RX_BUSY;
|
||||
|
||||
cc110x_pkt_buf_t *pkt_buf = &dev->pkt_buf;
|
||||
pkt_buf->pos = 0;
|
||||
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
cc110x_write_reg(dev, CC110X_IOCFG2, 0x01);
|
||||
gpio_irq_enable(dev->params.gdo2);
|
||||
}
|
||||
|
||||
static void _rx_read_data(cc110x_t *dev, void(*callback)(void*), void*arg)
|
||||
{
|
||||
int fifo = cc110x_get_reg_robust(dev, 0xfb);
|
||||
|
||||
if (fifo & 0x80) {
|
||||
DEBUG("%s:%s:%u rx overflow\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
_rx_abort(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fifo) {
|
||||
gpio_irq_enable(dev->params.gdo2);
|
||||
return;
|
||||
}
|
||||
|
||||
cc110x_pkt_buf_t *pkt_buf = &dev->pkt_buf;
|
||||
if (!pkt_buf->pos) {
|
||||
pkt_buf->pos = 1;
|
||||
pkt_buf->packet.length = cc110x_read_reg(dev, CC110X_RXFIFO);
|
||||
|
||||
/* Possible packet received, RX -> IDLE (0.1 us) */
|
||||
dev->cc110x_statistic.packets_in++;
|
||||
}
|
||||
|
||||
int left = pkt_buf->packet.length+1 - pkt_buf->pos;
|
||||
|
||||
/* if the fifo doesn't contain the rest of the packet,
|
||||
* leav at least one byte as per spec sheet. */
|
||||
int to_read = (fifo < left) ? (fifo-1) : fifo;
|
||||
if (to_read > left) {
|
||||
to_read = left;
|
||||
}
|
||||
|
||||
if (to_read) {
|
||||
cc110x_readburst_reg(dev, CC110X_RXFIFO,
|
||||
((char *)&pkt_buf->packet)+pkt_buf->pos, to_read);
|
||||
pkt_buf->pos += to_read;
|
||||
}
|
||||
|
||||
if (to_read == left) {
|
||||
uint8_t status[2];
|
||||
/* full packet received. */
|
||||
/* Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) */
|
||||
cc110x_readburst_reg(dev, CC110X_RXFIFO, (char *)status, 2);
|
||||
|
||||
/* Store RSSI value of packet */
|
||||
pkt_buf->rssi = status[I_RSSI];
|
||||
|
||||
/* Bit 0-6 of LQI indicates the link quality (LQI) */
|
||||
pkt_buf->lqi = status[I_LQI] & LQI_EST;
|
||||
|
||||
/* MSB of LQI is the CRC_OK bit */
|
||||
int crc_ok = (status[I_LQI] & CRC_OK) >> 7;
|
||||
|
||||
if (crc_ok) {
|
||||
LOG_DEBUG("cc110x: received packet from=%u to=%u payload "
|
||||
"len=%u\n",
|
||||
(unsigned)pkt_buf->packet.phy_src,
|
||||
(unsigned)pkt_buf->packet.address,
|
||||
pkt_buf->packet.length-3);
|
||||
/* let someone know that we've got a packet */
|
||||
callback(arg);
|
||||
|
||||
cc110x_switch_to_rx(dev);
|
||||
}
|
||||
else {
|
||||
DEBUG("%s:%s:%u crc-error\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
dev->cc110x_statistic.packets_in_crc_fail++;
|
||||
_rx_abort(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _rx_continue(cc110x_t *dev, void(*callback)(void*), void*arg)
|
||||
{
|
||||
|
||||
if (dev->radio_state != RADIO_RX_BUSY) {
|
||||
DEBUG("%s:%s:%u _rx_continue in invalid state\n", RIOT_FILE_RELATIVE,
|
||||
__func__, __LINE__);
|
||||
_rx_abort(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
|
||||
do {
|
||||
_rx_read_data(dev, callback, arg);
|
||||
}
|
||||
while (gpio_read(dev->params.gdo2));
|
||||
}
|
||||
|
||||
static void _tx_abort(cc110x_t *dev)
|
||||
{
|
||||
cc110x_switch_to_rx(dev);
|
||||
}
|
||||
|
||||
static void _tx_continue(cc110x_t *dev)
|
||||
{
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
|
||||
cc110x_pkt_t *pkt = &dev->pkt_buf.packet;
|
||||
int size = pkt->length + 1;
|
||||
int left = size - dev->pkt_buf.pos;
|
||||
|
||||
if (!left) {
|
||||
dev->cc110x_statistic.raw_packets_out++;
|
||||
|
||||
LOG_DEBUG("cc110x: packet successfully sent.\n");
|
||||
|
||||
cc110x_switch_to_rx(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int fifo = 64 - cc110x_get_reg_robust(dev, 0xfa);
|
||||
|
||||
if (fifo & 0x80) {
|
||||
DEBUG("%s:%s:%u tx underflow!\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
_tx_abort(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fifo) {
|
||||
DEBUG("%s:%s:%u fifo full!?\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
_tx_abort(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int to_send = left > fifo ? fifo : left;
|
||||
|
||||
/* Write packet into TX FIFO */
|
||||
cc110x_writeburst_reg(dev, CC110X_TXFIFO, ((char *)pkt)+dev->pkt_buf.pos, to_send);
|
||||
dev->pkt_buf.pos += to_send;
|
||||
|
||||
if (left == size) {
|
||||
/* Switch to TX mode */
|
||||
cc110x_strobe(dev, CC110X_STX);
|
||||
}
|
||||
|
||||
if (to_send < left) {
|
||||
/* set GDO2 to 0x2 -> will deassert at TX FIFO below threshold */
|
||||
gpio_irq_enable(dev->params.gdo2);
|
||||
cc110x_write_reg(dev, CC110X_IOCFG2, 0x02);
|
||||
}
|
||||
else {
|
||||
/* set GDO2 to 0x6 -> will deassert at packet end */
|
||||
cc110x_write_reg(dev, CC110X_IOCFG2, 0x06);
|
||||
gpio_irq_enable(dev->params.gdo2);
|
||||
}
|
||||
}
|
||||
|
||||
void cc110x_isr_handler(cc110x_t *dev, void(*callback)(void*), void*arg)
|
||||
{
|
||||
switch (dev->radio_state) {
|
||||
case RADIO_RX:
|
||||
if (gpio_read(dev->params.gdo2)) {
|
||||
_rx_start(dev);
|
||||
}
|
||||
else {
|
||||
DEBUG("cc110x_isr_handler((): isr handled too slow?\n");
|
||||
_rx_abort(dev);
|
||||
}
|
||||
break;
|
||||
case RADIO_RX_BUSY:
|
||||
_rx_continue(dev, callback, arg);
|
||||
break;
|
||||
case RADIO_TX_BUSY:
|
||||
if (!gpio_read(dev->params.gdo2)) {
|
||||
_tx_continue(dev);
|
||||
}
|
||||
else {
|
||||
DEBUG("cc110x_isr_handler() RADIO_TX_BUSY + GDO2\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG("%s:%s:%u: unhandled mode\n", RIOT_FILE_RELATIVE,
|
||||
__func__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
int cc110x_send(cc110x_t *dev, cc110x_pkt_t *packet)
|
||||
{
|
||||
DEBUG("cc110x: snd pkt to %u payload_length=%u\n",
|
||||
(unsigned)packet->address, (unsigned)packet->length-3);
|
||||
uint8_t size;
|
||||
|
||||
switch (dev->radio_state) {
|
||||
case RADIO_RX_BUSY:
|
||||
case RADIO_TX_BUSY:
|
||||
DEBUG("cc110x: invalid state for sending: %s\n",
|
||||
cc110x_state_to_text(dev->radio_state));
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Number of bytes to send is:
|
||||
* length of phy payload (packet->length)
|
||||
* + size of length field (1 byte)
|
||||
*/
|
||||
size = packet->length + 1;
|
||||
|
||||
if (size > CC110X_PACKET_LENGTH) {
|
||||
DEBUG("%s:%s:%u trying to send oversized packet\n",
|
||||
RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* set source address */
|
||||
packet->phy_src = dev->radio_address;
|
||||
|
||||
/* Disable RX interrupt */
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
dev->radio_state = RADIO_TX_BUSY;
|
||||
|
||||
#ifdef MODULE_CC110X_HOOKS
|
||||
cc110x_hook_tx();
|
||||
#endif
|
||||
|
||||
cc110x_write_reg(dev, CC110X_IOCFG2, 0x02);
|
||||
|
||||
/* Put CC110x in IDLE mode to flush the FIFO */
|
||||
cc110x_strobe(dev, CC110X_SIDLE);
|
||||
/* Flush TX FIFO to be sure it is empty */
|
||||
cc110x_strobe(dev, CC110X_SFTX);
|
||||
|
||||
memcpy((char*)&dev->pkt_buf.packet, packet, size);
|
||||
dev->pkt_buf.pos = 0;
|
||||
|
||||
_tx_continue(dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
179
drivers/cc110x/cc110x-spi.c
Normal file
179
drivers/cc110x/cc110x-spi.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TI Chipcon CC110x spi driver
|
||||
*
|
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
|
||||
* @author Heiko Will <hwill@inf.fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Joakim Gebart <joakim.gebart@eistec.se>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cc110x.h"
|
||||
#include "cc110x/cc110x-spi.h"
|
||||
#include "cc110x/cc110x-internal.h"
|
||||
#include "cc110x/cc110x-defines.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "xtimer.h"
|
||||
#include "irq.h"
|
||||
|
||||
/**********************************************************************
|
||||
* CC110x spi access
|
||||
**********************************************************************/
|
||||
|
||||
void cc110x_cs(cc110x_t *dev)
|
||||
{
|
||||
volatile int retry_count = 0;
|
||||
/* Switch MISO/GDO1 to GPIO input mode */
|
||||
#ifndef GPIO_READS_SPI_PINS
|
||||
gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL);
|
||||
#endif
|
||||
/* CS to low */
|
||||
gpio_clear(dev->params.cs);
|
||||
/* Wait for SO to go low (voltage regulator
|
||||
* has stabilized and the crystal is running) */
|
||||
while (gpio_read(dev->params.gdo1)) {
|
||||
/* Wait ~500us and try again */
|
||||
xtimer_usleep(CS_SO_WAIT_TIME);
|
||||
|
||||
if (gpio_read(dev->params.gdo1)) {
|
||||
retry_count++;
|
||||
|
||||
if (retry_count > CC110X_GDO1_LOW_RETRY) {
|
||||
puts("[CC110X spi] fatal error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
gpio_set(dev->params.cs);
|
||||
gpio_clear(dev->params.cs);
|
||||
}
|
||||
}
|
||||
/* Switch MISO/GDO1 to spi mode */
|
||||
#ifndef GPIO_READS_SPI_PINS
|
||||
spi_conf_pins(dev->params.spi);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count)
|
||||
{
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_regs(dev->params.spi, addr | CC110X_WRITE_BURST, (char *)src, 0, count);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
}
|
||||
|
||||
void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_byte(dev->params.spi, addr | CC110X_READ_BURST, 0);
|
||||
while (i < count) {
|
||||
spi_transfer_byte(dev->params.spi, CC110X_NOBYTE, &buffer[i]);
|
||||
i++;
|
||||
}
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
}
|
||||
|
||||
void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value)
|
||||
{
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_reg(dev->params.spi, addr, value, 0);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
}
|
||||
|
||||
uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr)
|
||||
{
|
||||
char result;
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_reg(dev->params.spi, addr | CC110X_READ_SINGLE, CC110X_NOBYTE, &result);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
return (uint8_t) result;
|
||||
}
|
||||
|
||||
uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr)
|
||||
{
|
||||
char result;
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
return (uint8_t) result;
|
||||
}
|
||||
|
||||
uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr)
|
||||
{
|
||||
char result, result2;
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
do {
|
||||
spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result);
|
||||
spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result2);
|
||||
} while (result != result2);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
return (uint8_t) result;
|
||||
}
|
||||
|
||||
uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c)
|
||||
{
|
||||
#ifdef CC110X_DONT_RESET
|
||||
if (c == CC110X_SRES) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char result;
|
||||
unsigned int cpsr;
|
||||
spi_acquire(dev->params.spi);
|
||||
cpsr = disableIRQ();
|
||||
cc110x_cs(dev);
|
||||
spi_transfer_byte(dev->params.spi, c, &result);
|
||||
gpio_set(dev->params.cs);
|
||||
restoreIRQ(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
return (uint8_t) result;
|
||||
}
|
||||
281
drivers/cc110x/cc110x.c
Normal file
281
drivers/cc110x/cc110x.c
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Basic functionality of cc110x driver
|
||||
*
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include "periph/cpuid.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "xtimer.h"
|
||||
#include "cpu.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "cc110x.h"
|
||||
#include "cc110x/cc110x-defaultsettings.h"
|
||||
#include "cc110x/cc110x-defines.h"
|
||||
#include "cc110x/cc110x-interface.h"
|
||||
#include "cc110x/cc110x-internal.h"
|
||||
#include "cc110x/cc110x-spi.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* Internal function prototypes */
|
||||
#ifndef CC110X_DONT_RESET
|
||||
static void _reset(cc110x_t *dev);
|
||||
static void _power_up_reset(cc110x_t *dev);
|
||||
#endif
|
||||
|
||||
int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
#ifdef MODULE_CC110X_HOOKS
|
||||
cc110x_hooks_init();
|
||||
#endif
|
||||
|
||||
dev->params = *params;
|
||||
|
||||
/* Configure chip-select */
|
||||
gpio_init(dev->params.cs, GPIO_DIR_OUT, GPIO_NOPULL);
|
||||
gpio_set(dev->params.cs);
|
||||
|
||||
/* Configure GDO1 */
|
||||
gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL);
|
||||
|
||||
/* Configure SPI */
|
||||
spi_acquire(dev->params.spi);
|
||||
spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
|
||||
spi_release(dev->params.spi);
|
||||
|
||||
#ifndef CC110X_DONT_RESET
|
||||
/* reset device*/
|
||||
_power_up_reset(dev);
|
||||
#endif
|
||||
|
||||
/* set default state */
|
||||
dev->radio_state = RADIO_IDLE;
|
||||
|
||||
/* Write configuration to configuration registers */
|
||||
cc110x_writeburst_reg(dev, 0x00, cc110x_default_conf, cc110x_default_conf_size);
|
||||
|
||||
/* Write PATABLE (power settings) */
|
||||
cc110x_writeburst_reg(dev, CC110X_PATABLE, CC110X_DEFAULT_PATABLE, 8);
|
||||
|
||||
/* set base frequency */
|
||||
cc110x_set_base_freq_raw(dev, CC110X_DEFAULT_FREQ);
|
||||
|
||||
/* Set default channel number */
|
||||
cc110x_set_channel(dev, CC110X_DEFAULT_CHANNEL);
|
||||
|
||||
/* set default node id */
|
||||
#ifdef CPUID_ID_LEN
|
||||
if (CPUID_ID_LEN>0) {
|
||||
char cpuid[CPUID_ID_LEN];
|
||||
cpuid_get(cpuid);
|
||||
cc110x_set_address(dev, (uint8_t) cpuid[CPUID_ID_LEN-1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_INFO("cc110x: initialized with address=%u and channel=%i\n",
|
||||
(unsigned)dev->radio_address,
|
||||
dev->radio_channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t cc110x_set_address(cc110x_t *dev, uint8_t address)
|
||||
{
|
||||
DEBUG("%s:%s:%u setting address %u\n", RIOT_FILE_RELATIVE, __func__,
|
||||
__LINE__, (unsigned)address);
|
||||
if (!(address < MIN_UID) || (address > MAX_UID)) {
|
||||
if (dev->radio_state != RADIO_UNKNOWN) {
|
||||
cc110x_write_register(dev, CC110X_ADDR, address);
|
||||
dev->radio_address = address;
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cc110x_set_base_freq_raw(cc110x_t *dev, const char* freq_array)
|
||||
{
|
||||
#if ENABLE_DEBUG == 1
|
||||
uint8_t _tmp[] = { freq_array[2], freq_array[1], freq_array[0], 0x00};
|
||||
uint32_t *FREQ = (uint32_t*) _tmp;
|
||||
|
||||
DEBUG("cc110x_set_base_freq_raw(): setting base frequency to %uHz\n",
|
||||
(26000000>>16) * (unsigned)(*FREQ));
|
||||
#endif
|
||||
cc110x_writeburst_reg(dev, CC110X_FREQ2, freq_array, 3);
|
||||
}
|
||||
|
||||
void cc110x_set_monitor(cc110x_t *dev, uint8_t mode)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
cc110x_write_register(dev, CC110X_PKTCTRL1, mode ? 0x04 : 0x06);
|
||||
}
|
||||
|
||||
void cc110x_setup_rx_mode(cc110x_t *dev)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
/* Stay in RX mode until end of packet */
|
||||
cc110x_write_reg(dev, CC110X_MCSM2, 0x07);
|
||||
cc110x_switch_to_rx(dev);
|
||||
}
|
||||
|
||||
void cc110x_switch_to_rx(cc110x_t *dev)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
#ifdef MODULE_CC110X_HOOKS
|
||||
cc110x_hook_rx();
|
||||
#endif
|
||||
|
||||
gpio_irq_disable(dev->params.gdo2);
|
||||
|
||||
/* flush RX fifo */
|
||||
cc110x_strobe(dev, CC110X_SIDLE);
|
||||
cc110x_strobe(dev, CC110X_SFRX);
|
||||
|
||||
dev->radio_state = RADIO_RX;
|
||||
|
||||
cc110x_write_reg(dev, CC110X_IOCFG2, 0x6);
|
||||
cc110x_strobe(dev, CC110X_SRX);
|
||||
|
||||
gpio_irq_enable(dev->params.gdo2);
|
||||
}
|
||||
|
||||
void cc110x_wakeup_from_rx(cc110x_t *dev)
|
||||
{
|
||||
if (dev->radio_state != RADIO_RX) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("cc110x: switching to idle mode\n");
|
||||
|
||||
cc110x_strobe(dev, CC110X_SIDLE);
|
||||
dev->radio_state = RADIO_IDLE;
|
||||
}
|
||||
|
||||
void cc110x_switch_to_pwd(cc110x_t *dev)
|
||||
{
|
||||
LOG_DEBUG("cc110x: switching to powerdown mode\n");
|
||||
cc110x_wakeup_from_rx(dev);
|
||||
cc110x_strobe(dev, CC110X_SPWD);
|
||||
dev->radio_state = RADIO_PWD;
|
||||
|
||||
#ifdef MODULE_CC110X_HOOKS
|
||||
cc110x_hook_off();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef MODULE_CC110X_HOOKS
|
||||
int16_t cc110x_set_channel(cc110x_t *dev, uint8_t channr)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
if (channr > MAX_CHANNR) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc110x_write_register(dev, CC110X_CHANNR, channr * 10);
|
||||
dev->radio_channel = channr;
|
||||
|
||||
return channr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CC110X_DONT_RESET
|
||||
static void _reset(cc110x_t *dev)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
cc110x_wakeup_from_rx(dev);
|
||||
cc110x_cs(dev);
|
||||
cc110x_strobe(dev, CC110X_SRES);
|
||||
xtimer_usleep(100);
|
||||
}
|
||||
|
||||
static void _power_up_reset(cc110x_t *dev)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
gpio_set(dev->params.cs);
|
||||
gpio_clear(dev->params.cs);
|
||||
gpio_set(dev->params.cs);
|
||||
xtimer_usleep(RESET_WAIT_TIME);
|
||||
_reset(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cc110x_write_register(cc110x_t *dev, uint8_t r, uint8_t value)
|
||||
{
|
||||
/* Save old radio state */
|
||||
uint8_t old_state = dev->radio_state;
|
||||
|
||||
/* Wake up from RX (no effect if in other mode) */
|
||||
cc110x_wakeup_from_rx(dev);
|
||||
cc110x_write_reg(dev, r, value);
|
||||
|
||||
/* Have to put radio back to RX if old radio state
|
||||
* was RX, otherwise no action is necessary */
|
||||
if (old_state == RADIO_RX) {
|
||||
cc110x_switch_to_rx(dev);
|
||||
}
|
||||
}
|
||||
|
||||
int cc110x_rd_set_mode(cc110x_t *dev, int mode)
|
||||
{
|
||||
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
||||
|
||||
int result;
|
||||
|
||||
/* Get current radio mode */
|
||||
if ((dev->radio_state == RADIO_UNKNOWN) || (dev->radio_state == RADIO_PWD)) {
|
||||
result = RADIO_MODE_OFF;
|
||||
}
|
||||
else {
|
||||
result = RADIO_MODE_ON;
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case RADIO_MODE_ON:
|
||||
LOG_DEBUG("cc110x: switching to RX mode\n");
|
||||
cc110x_setup_rx_mode(dev); /* Set chip to desired mode */
|
||||
break;
|
||||
|
||||
case RADIO_MODE_OFF:
|
||||
gpio_irq_disable(dev->params.gdo2); /* Disable interrupts */
|
||||
cc110x_switch_to_pwd(dev); /* Set chip to power down mode */
|
||||
break;
|
||||
|
||||
case RADIO_MODE_GET:
|
||||
/* do nothing, just return current mode */
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return previous mode */
|
||||
return result;
|
||||
}
|
||||
1
drivers/cc110x/gnrc_cc110x/Makefile
Normal file
1
drivers/cc110x/gnrc_cc110x/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
192
drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c
Normal file
192
drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "net/netdev2.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "cc110x.h"
|
||||
#include "cc110x/cc110x-netdev2.h"
|
||||
#include "net/gnrc/gnrc_netdev2.h"
|
||||
#include "od.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static int _send(gnrc_netdev2_t *gnrc_netdev2, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
cc110x_pkt_t cc110x_pkt;
|
||||
netdev2_t *dev = gnrc_netdev2->dev;
|
||||
netdev2_cc110x_t *netdev_cc110x = (netdev2_cc110x_t *) dev;
|
||||
cc110x_t *cc110x = &netdev_cc110x->cc110x;
|
||||
|
||||
assert(pkt != NULL);
|
||||
assert(dev->driver == &netdev2_cc110x_driver);
|
||||
|
||||
gnrc_netif_hdr_t *netif_hdr;
|
||||
gnrc_pktsnip_t *payload;
|
||||
|
||||
payload = pkt->next;
|
||||
|
||||
if (pkt->type != GNRC_NETTYPE_NETIF) {
|
||||
DEBUG("gnrc_netdev2_cc110x: First header was not generic netif header\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
netif_hdr = (gnrc_netif_hdr_t *) pkt->data;
|
||||
|
||||
/* set up header */
|
||||
if (netif_hdr->src_l2addr_len == 1) {
|
||||
uint8_t *_src_addr = gnrc_netif_hdr_get_src_addr(netif_hdr);
|
||||
cc110x_pkt.phy_src = *_src_addr;
|
||||
}
|
||||
else {
|
||||
cc110x_pkt.phy_src = cc110x->radio_address;
|
||||
}
|
||||
|
||||
if (netif_hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST |
|
||||
GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
|
||||
cc110x_pkt.address = 0;
|
||||
}
|
||||
else {
|
||||
uint8_t *_dst_addr = gnrc_netif_hdr_get_dst_addr(netif_hdr);
|
||||
cc110x_pkt.address = _dst_addr[netif_hdr->dst_l2addr_len-1];
|
||||
}
|
||||
|
||||
switch (payload->type) {
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
case GNRC_NETTYPE_SIXLOWPAN:
|
||||
cc110x_pkt.flags = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
cc110x_pkt.flags = 0;
|
||||
}
|
||||
|
||||
struct iovec vector;
|
||||
vector.iov_base = (char*)&cc110x_pkt;
|
||||
vector.iov_len = sizeof(cc110x_pkt_t);
|
||||
|
||||
unsigned payload_len = 0;
|
||||
uint8_t *pos = cc110x_pkt.data;
|
||||
|
||||
while (payload) {
|
||||
payload_len += payload->size;
|
||||
|
||||
if (payload_len > CC110X_MAX_DATA_LENGTH) {
|
||||
DEBUG("gnrc_netdev2_cc110x: payload length exceeds maximum"
|
||||
"(%u>%u)\n", payload_len, CC110X_MAX_DATA_LENGTH);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
memcpy(pos, payload->data, payload->size);
|
||||
pos += payload->size;
|
||||
payload = payload->next;
|
||||
}
|
||||
|
||||
/* pkt has been copied into iovec, we're done with it. */
|
||||
gnrc_pktbuf_release(pkt);
|
||||
|
||||
cc110x_pkt.length = (uint8_t) payload_len + CC110X_HEADER_LENGTH;
|
||||
|
||||
DEBUG("gnrc_netdev2_cc110x: sending packet from %u to %u with payload "
|
||||
"length %u\n",
|
||||
(unsigned)cc110x_pkt.phy_src,
|
||||
(unsigned)cc110x_pkt.address,
|
||||
(unsigned)cc110x_pkt.length);
|
||||
|
||||
return dev->driver->send(dev, &vector, 1);
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2)
|
||||
{
|
||||
netdev2_t *dev = gnrc_netdev2->dev;
|
||||
cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x;
|
||||
|
||||
cc110x_pkt_t *cc110x_pkt = &cc110x->pkt_buf.packet;
|
||||
|
||||
int payload_length = cc110x_pkt->length - CC110X_HEADER_LENGTH;
|
||||
|
||||
int nettype;
|
||||
|
||||
int addr_len;
|
||||
switch (cc110x_pkt->flags) {
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
case 1:
|
||||
addr_len = 8;
|
||||
nettype = GNRC_NETTYPE_SIXLOWPAN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
addr_len = 1;
|
||||
nettype = GNRC_NETTYPE_UNDEF;
|
||||
}
|
||||
|
||||
/* copy packet payload into pktbuf */
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, cc110x_pkt->data,
|
||||
payload_length, nettype);
|
||||
|
||||
if(!pkt) {
|
||||
DEBUG("cc110x: _recv: cannot allocate pktsnip.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
gnrc_pktsnip_t *netif_hdr;
|
||||
netif_hdr = gnrc_pktbuf_add(NULL, NULL,
|
||||
sizeof(gnrc_netif_hdr_t) + 2*addr_len,
|
||||
GNRC_NETTYPE_NETIF);
|
||||
|
||||
if (netif_hdr == NULL) {
|
||||
DEBUG("gnrc_netdev2_cc110x: no space left in packet buffer\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gnrc_netif_hdr_init(netif_hdr->data, addr_len, addr_len);
|
||||
if (addr_len == 8) {
|
||||
uint64_t src_addr = cc110x_pkt->phy_src;
|
||||
uint64_t dst_addr = cc110x_pkt->address;
|
||||
gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&src_addr, addr_len);
|
||||
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&dst_addr, addr_len);
|
||||
}
|
||||
else {
|
||||
gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->phy_src, addr_len);
|
||||
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->address, addr_len);
|
||||
}
|
||||
|
||||
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = thread_getpid();
|
||||
((gnrc_netif_hdr_t *)netif_hdr->data)->lqi = cc110x->pkt_buf.lqi;
|
||||
((gnrc_netif_hdr_t *)netif_hdr->data)->rssi = cc110x->pkt_buf.rssi;
|
||||
|
||||
DEBUG("gnrc_netdev2_cc110x: received packet from %02x"
|
||||
" of length %u\n",
|
||||
(unsigned)cc110x_pkt->phy_src,
|
||||
(unsigned)cc110x_pkt->length-CC110X_HEADER_LENGTH);
|
||||
#if defined(MODULE_OD) && ENABLE_DEBUG
|
||||
od_hex_dump(cc110x_pkt->data, payload_length, OD_WIDTH_DEFAULT);
|
||||
#endif
|
||||
|
||||
|
||||
pkt->next = netif_hdr;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
int gnrc_netdev2_cc110x_init(gnrc_netdev2_t *gnrc_netdev2, netdev2_t *dev)
|
||||
{
|
||||
gnrc_netdev2->send = _send;
|
||||
gnrc_netdev2->recv = _recv;
|
||||
gnrc_netdev2->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
132
drivers/include/cc110x.h
Normal file
132
drivers/include/cc110x.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x CC110x
|
||||
* @ingroup drivers
|
||||
* @brief TI CC110x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Public interface for cc110x driver
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_H
|
||||
#define CC110X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "periph/spi.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "cc110x/cc110x-internal.h"
|
||||
|
||||
/**
|
||||
* @brief Struct for holding cc110x IO parameters
|
||||
*/
|
||||
typedef struct cc110x_params {
|
||||
spi_t spi; /**< what */
|
||||
gpio_t cs; /**< does */
|
||||
gpio_t gdo0; /**< this */
|
||||
gpio_t gdo1; /**< look */
|
||||
gpio_t gdo2; /**< like */
|
||||
} cc110x_params_t;
|
||||
|
||||
/**
|
||||
* @brief forward declaration
|
||||
*/
|
||||
typedef struct cc110x cc110x_t;
|
||||
|
||||
/**
|
||||
* @brief Struct for holding cc110x device state
|
||||
*/
|
||||
struct cc110x {
|
||||
cc110x_params_t params; /**< cc110x IO configuration */
|
||||
|
||||
cc110x_statistic_t cc110x_statistic; /**< Statistic values for
|
||||
debugging */
|
||||
|
||||
uint8_t radio_state; /**< Radio state */
|
||||
uint8_t radio_channel; /**< current Radio channel */
|
||||
uint8_t radio_address; /**< current Radio address */
|
||||
|
||||
cc110x_pkt_buf_t pkt_buf; /**< RX/TX buffer */
|
||||
void (*isr_cb)(cc110x_t *dev, void* arg); /**< isr callback */
|
||||
void *isr_cb_arg; /**< isr callback argument */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Setup cc110x device parameters
|
||||
*
|
||||
* @param[in] dev device struct to set up
|
||||
* @param[in] params struct holding parameters
|
||||
*
|
||||
* @return always succeeds
|
||||
*/
|
||||
int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Set cc110x channel number
|
||||
*
|
||||
* @param[in] dev device to work on
|
||||
* @param[in] channr guess what
|
||||
*
|
||||
* @return nr of set channel on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int16_t cc110x_set_channel(cc110x_t *dev, uint8_t channr);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send raw cc110x packet
|
||||
*
|
||||
* @param[in] dev Device to send on
|
||||
* @param[in] packet ptr to packet to be sent
|
||||
*
|
||||
* @return size of packet on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int cc110x_send(cc110x_t *dev, cc110x_pkt_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Set cc110x radio address
|
||||
*
|
||||
* @param[in] dev device to query
|
||||
*
|
||||
* @return nr of currently set address
|
||||
*/
|
||||
uint8_t cc110x_get_address(cc110x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set cc110x radio address
|
||||
*
|
||||
* @param[in] dev device to work on
|
||||
* @param[in] address new address
|
||||
*
|
||||
* @return address set on success
|
||||
* @return 0 on error
|
||||
*/
|
||||
uint8_t cc110x_set_address(cc110x_t *dev, uint8_t address);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set cc110x monitor mode setting
|
||||
*
|
||||
* @param[in] dev device to work on
|
||||
* @param[in] mode mode to set (0 or 1)
|
||||
*/
|
||||
void cc110x_set_monitor(cc110x_t *dev, uint8_t mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CC110X_H */
|
||||
/** @} */
|
||||
46
drivers/include/cc110x/cc110x-defaultsettings.h
Normal file
46
drivers/include/cc110x/cc110x-defaultsettings.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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 driver_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief cc110x default settings override
|
||||
*
|
||||
* By setting either CC110X_DEFAULT_PATABLE or CC110X_DEFAULT_FREQ in board.h,
|
||||
* it is possible to override the default pa table or base frequency registers
|
||||
* on a per-device basis.
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
#ifndef CC110X_DEFAULTSETTINGS_H
|
||||
#define CC110X_DEFAULTSETTINGS_H
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef CC110X_DEFAULT_PATABLE
|
||||
#define CC110X_DEFAULT_PATABLE cc110x_default_pa_table
|
||||
extern const char cc110x_default_pa_table[8];
|
||||
#endif
|
||||
|
||||
#ifndef CC110X_DEFAULT_FREQ
|
||||
#define CC110X_DEFAULT_FREQ cc110x_default_base_freq
|
||||
extern const char cc110x_default_base_freq[3];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CC110X_DEFAULTSETTINGS_H */
|
||||
/** @} */
|
||||
207
drivers/include/cc110x/cc110x-defines.h
Normal file
207
drivers/include/cc110x/cc110x-defines.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Driver internal constants for CC110x chip configuration
|
||||
*
|
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
|
||||
* @author Heiko Will <hwill@inf.fu-berlin.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_DEFINES_H
|
||||
#define CC110X_DEFINES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Variable packet length PKTCTRL0 bit configuration
|
||||
*
|
||||
* If variable packet length is configured in PKTCTRL0 the
|
||||
* first byte after the synch word determines the packet length.
|
||||
*/
|
||||
#define VARIABLE_PKTLEN (0x01)
|
||||
|
||||
/**
|
||||
* @name Bitmasks for reading out status register values
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Bitmask (=10000000) for reading CRC_OK.
|
||||
*
|
||||
* If CRC_OK == 1: CRC for received data OK (or CRC disabled).
|
||||
* If CRC_OK == 0: CRC error in received data.
|
||||
*/
|
||||
#define CRC_OK (0x80)
|
||||
/**
|
||||
* @brief Bitmask (=01111111) for reading LQI_EST.
|
||||
*
|
||||
* The Link Quality Indicator estimates how easily a received signal can be demodulated.
|
||||
*/
|
||||
#define LQI_EST (0x7F)
|
||||
#define I_RSSI (0x00) /**< Index 0 contains RSSI information (from optionally appended packet status bytes). */
|
||||
#define I_LQI (0x01) /**< Index 1 contains LQI & CRC_OK information (from optionally appended packet status bytes). */
|
||||
#define MARC_STATE (0x1F) /**< Bitmask (=00011111) for reading MARC_STATE in MARCSTATE status register. */
|
||||
#define PKTSTATUS_CS (0x40) /**< Bitmask (=01000000) for reading CS (Carrier Sense) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_PQT_REACHED (0x20) /**< Bitmask (=00100000) for reading PQT_REACHED (Preamble Quality reached) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_CCA (0x10) /**< Bitmask (=00010000) for reading CCA (clear channel assessment) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_SFD (0x08) /**< Bitmask (=00001000) for reading SFD (Sync word found) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_GDO2 (0x04) /**< Bitmask (=00000100) for reading GDO2 (current value on GDO2 pin) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_GDO1 (0x02) /**< Bitmask (=00000010) for reading GDO1 (current value on GDO1 pin) in PKTSTATUS status register. */
|
||||
#define PKTSTATUS_GDO0 (0x01) /**< Bitmask (=00000001) for reading GDO0 (current value on GDO0 pin) in PKTSTATUS status register. */
|
||||
#define TXFIFO_UNDERFLOW (0x80) /**< Bitmask (=10000000) for reading TXFIFO_UNDERFLOW in TXBYTES status register. */
|
||||
#define BYTES_IN_TXFIFO (0x7F) /**< Bitmask (=01111111) for reading NUM_TXBYTES in TXBYTES status register. */
|
||||
#define RXFIFO_OVERFLOW (0x80) /**< Bitmask (=10000000) for reading RXFIFO_OVERFLOW in RXBYTES status register. */
|
||||
#define BYTES_IN_RXFIFO (0x7F) /**< Bitmask (=01111111) for reading NUM_RXBYTES in RXBYTES status register. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Bitmasks for reading out configuration register values
|
||||
* @{
|
||||
*/
|
||||
#define PKT_LENGTH_CONFIG (0x03) /**< Bitmask (=00000011) for reading LENGTH_CONFIG in PKTCTRL0 configuration register. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Definitions to support burst/single access
|
||||
* @{
|
||||
*/
|
||||
#define CC110X_WRITE_BURST (0x40) /**< Offset for burst write. */
|
||||
#define CC110X_READ_SINGLE (0x80) /**< Offset for read single byte. */
|
||||
#define CC110X_READ_BURST (0xC0) /**< Offset for read burst. */
|
||||
#define CC110X_NOBYTE (0xFF) /**< No command (for reading). */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Configuration Registers (47x)
|
||||
* @{
|
||||
*/
|
||||
#define CC110X_IOCFG2 (0x00) /**< GDO2 output pin configuration */
|
||||
#define CC110X_IOCFG1 (0x01) /**< GDO1 output pin configuration */
|
||||
#define CC110X_IOCFG0 (0x02) /**< GDO0 output pin configuration */
|
||||
#define CC110X_FIFOTHR (0x03) /**< RX FIFO and TX FIFO thresholds */
|
||||
#define CC110X_SYNC1 (0x04) /**< Sync word, high byte */
|
||||
#define CC110X_SYNC0 (0x05) /**< Sync word, low byte */
|
||||
#define CC110X_PKTLEN (0x06) /**< Packet length */
|
||||
#define CC110X_PKTCTRL1 (0x07) /**< Packet automation control */
|
||||
#define CC110X_PKTCTRL0 (0x08) /**< Packet automation control */
|
||||
#define CC110X_ADDR (0x09) /**< Device address */
|
||||
#define CC110X_CHANNR (0x0A) /**< Channel number */
|
||||
#define CC110X_FSCTRL1 (0x0B) /**< Frequency synthesizer control */
|
||||
#define CC110X_FSCTRL0 (0x0C) /**< Frequency synthesizer control */
|
||||
#define CC110X_FREQ2 (0x0D) /**< Frequency control word, high byte */
|
||||
#define CC110X_FREQ1 (0x0E) /**< Frequency control word, middle byte */
|
||||
#define CC110X_FREQ0 (0x0F) /**< Frequency control word, low byte */
|
||||
#define CC110X_MDMCFG4 (0x10) /**< Modem configuration */
|
||||
#define CC110X_MDMCFG3 (0x11) /**< Modem configuration */
|
||||
#define CC110X_MDMCFG2 (0x12) /**< Modem configuration */
|
||||
#define CC110X_MDMCFG1 (0x13) /**< Modem configuration */
|
||||
#define CC110X_MDMCFG0 (0x14) /**< Modem configuration */
|
||||
#define CC110X_DEVIATN (0x15) /**< Modem deviation setting */
|
||||
#define CC110X_MCSM2 (0x16) /**< Main Radio Control State Machine configuration */
|
||||
#define CC110X_MCSM1 (0x17) /**< Main Radio Control State Machine configuration */
|
||||
#define CC110X_MCSM0 (0x18) /**< Main Radio Control State Machine configuration */
|
||||
#define CC110X_FOCCFG (0x19) /**< Frequency Offset Compensation configuration */
|
||||
#define CC110X_BSCFG (0x1A) /**< Bit Synchronization configuration */
|
||||
#define CC110X_AGCCTRL2 (0x1B) /**< AGC control */
|
||||
#define CC110X_AGCCTRL1 (0x1C) /**< AGC control */
|
||||
#define CC110X_AGCCTRL0 (0x1D) /**< AGC control */
|
||||
#define CC110X_WOREVT1 (0x1E) /**< High byte Event 0 timeout */
|
||||
#define CC110X_WOREVT0 (0x1F) /**< Low byte Event 0 timeout */
|
||||
#define CC110X_WORCTRL (0x20) /**< Wake On Radio control */
|
||||
#define CC110X_FREND1 (0x21) /**< Front end RX configuration */
|
||||
#define CC110X_FREND0 (0x22) /**< Front end TX configuration */
|
||||
#define CC110X_FSCAL3 (0x23) /**< Frequency synthesizer calibration */
|
||||
#define CC110X_FSCAL2 (0x24) /**< Frequency synthesizer calibration */
|
||||
#define CC110X_FSCAL1 (0x25) /**< Frequency synthesizer calibration */
|
||||
#define CC110X_FSCAL0 (0x26) /**< Frequency synthesizer calibration */
|
||||
#define CC110X_RCCTRL1 (0x27) /**< RC oscillator configuration */
|
||||
#define CC110X_RCCTRL0 (0x28) /**< RC oscillator configuration */
|
||||
#define CC110X_FSTEST (0x29) /**< Frequency synthesizer calibration control */
|
||||
#define CC110X_PTEST (0x2A) /**< Production test */
|
||||
#define CC110X_AGCTEST (0x2B) /**< AGC test */
|
||||
#define CC110X_TEST2 (0x2C) /**< Various test settings */
|
||||
#define CC110X_TEST1 (0x2D) /**< Various test settings */
|
||||
#define CC110X_TEST0 (0x2E) /**< Various test settings */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Strobe commands (14x)
|
||||
* @{
|
||||
*/
|
||||
#define CC110X_SRES (0x30) /**< Reset chip. */
|
||||
/**
|
||||
* @brief Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
|
||||
*
|
||||
* If in RX/TX: Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
|
||||
*/
|
||||
#define CC110X_SFSTXON (0x31)
|
||||
#define CC110X_SXOFF (0x32) /**< Turn off crystal oscillator. */
|
||||
#define CC110X_SCAL (0x33) /**< Calibrate frequency synthesizer and turn it off (enables quick start). */
|
||||
#define CC110X_SRX (0x34) /**< Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1. */
|
||||
/**
|
||||
* In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1.
|
||||
* If in RX state and CCA is enabled: Only go to TX if channel is clear.
|
||||
*/
|
||||
#define CC110X_STX (0x35)
|
||||
#define CC110X_SIDLE (0x36) /**< Exit RX / TX, turn off frequency synthesizer and exit WOR mode if applicable. */
|
||||
#define CC110X_SAFC (0x37) /**< Perform AFC adjustment of the frequency synthesizer */
|
||||
#define CC110X_SWOR (0x38) /**< Start automatic RX polling sequence (Wake-on-Radio) */
|
||||
#define CC110X_SPWD (0x39) /**< Enter power down mode when CSn goes high. */
|
||||
#define CC110X_SFRX (0x3A) /**< Flush the RX FIFO buffer (CC110X should be in IDLE state). */
|
||||
#define CC110X_SFTX (0x3B) /**< Flush the TX FIFO buffer (CC110X should be in IDLE state). */
|
||||
#define CC110X_SWORRST (0x3C) /**< Reset real time clock. */
|
||||
#define CC110X_SNOP (0x3D) /**< No operation. May be used to pad strobe commands to two bytes for simpler software. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Status registers (12x)
|
||||
* @{
|
||||
*/
|
||||
#define CC110X_PARTNUM (0x30) /**< Part number of CC110X. */
|
||||
#define CC110X_VERSION (0x31) /**< Current version number. */
|
||||
#define CC110X_FREQEST (0x32) /**< Frequency Offset Estimate. */
|
||||
#define CC110X_LQI (0x33) /**< Demodulator estimate for Link Quality. */
|
||||
#define CC110X_RSSI (0x34) /**< Received signal strength indication. */
|
||||
#define CC110X_MARCSTATE (0x35) /**< Control state machine state. */
|
||||
#define CC110X_WORTIME1 (0x36) /**< High byte of WOR timer. */
|
||||
#define CC110X_WORTIME0 (0x37) /**< Low byte of WOR timer. */
|
||||
#define CC110X_PKTSTATUS (0x38) /**< Current GDOx status and packet status. */
|
||||
#define CC110X_VCO_VC_DAC (0x39) /**< Current setting from PLL calibration module. */
|
||||
#define CC110X_TXBYTES (0x3A) /**< Underflow and number of bytes in the TX FIFO. */
|
||||
#define CC110X_RXBYTES (0x3B) /**< Overflow and number of bytes in the RX FIFO. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Multi byte registers
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Register for eight user selected output power settings.
|
||||
*
|
||||
* 3-bit FREND0.PA_POWER value selects the PATABLE entry to use.
|
||||
*/
|
||||
#define CC110X_PATABLE (0x3E)
|
||||
#define CC110X_TXFIFO (0x3F) /**< TX FIFO: Write operations write to the TX FIFO (SB: +0x00; BURST: +0x40) */
|
||||
#define CC110X_RXFIFO (0x3F) /**< RX FIFO: Read operations read from the RX FIFO (SB: +0x80; BURST: +0xC0) */
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif
|
||||
66
drivers/include/cc110x/cc110x-interface.h
Normal file
66
drivers/include/cc110x/cc110x-interface.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief internal declarations for cc110x driver
|
||||
*
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_INTERFACE_H
|
||||
#define CC110X_INTERFACE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "cc110x.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name cc110x raw low-level interface
|
||||
* @internal
|
||||
* @{
|
||||
*/
|
||||
char *cc110x_get_marc_state(cc110x_t *dev);
|
||||
char *cc110x_state_to_text(uint8_t state);
|
||||
int cc110x_rd_set_mode(cc110x_t *dev, int mode);
|
||||
uint8_t cc110x_get_buffer_pos(cc110x_t *dev);
|
||||
void cc110x_isr_handler(cc110x_t *dev, void(*callback)(void*), void*arg);
|
||||
void cc110x_set_base_freq_raw(cc110x_t *dev, const char* freq_array);
|
||||
void cc110x_setup_rx_mode(cc110x_t *dev);
|
||||
void cc110x_switch_to_pwd(cc110x_t *dev);
|
||||
void cc110x_switch_to_rx(cc110x_t *dev);
|
||||
void cc110x_wakeup_from_rx(cc110x_t *dev);
|
||||
void cc110x_write_register(cc110x_t *dev, uint8_t r, uint8_t value);
|
||||
|
||||
extern const char cc110x_default_conf[];
|
||||
extern const uint8_t cc110x_default_conf_size;
|
||||
extern const uint8_t cc110x_pa_table[];
|
||||
|
||||
#ifdef MODULE_CC110X_HOOKS
|
||||
void cc110x_hooks_init(void);
|
||||
void cc110x_hook_rx(void);
|
||||
void cc110x_hook_tx(void);
|
||||
void cc110x_hook_off(void);
|
||||
#endif
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif /* CC110X_INTERFACE_H */
|
||||
208
drivers/include/cc110x/cc110x-internal.h
Normal file
208
drivers/include/cc110x/cc110x-internal.h
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Data structures and variables for the cc110x driver interface
|
||||
*
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_INTERNAL_H
|
||||
#define CC110X_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CC110X_RXBUF_SIZE (2)
|
||||
#define CC110X_MAX_DATA_LENGTH (58+64)
|
||||
|
||||
#define CC110X_HEADER_LENGTH (3) /**< Header covers SRC, DST and
|
||||
FLAGS */
|
||||
#define CC110X_BROADCAST_ADDRESS (0x00) /**< CC110X broadcast address */
|
||||
|
||||
#define MIN_UID (0x01) /**< Minimum UID of a node is
|
||||
1 */
|
||||
#define MAX_UID (0xFF) /**< Maximum UID of a node is
|
||||
255 */
|
||||
|
||||
#define MIN_CHANNR (0) /**< Minimum channel number */
|
||||
#define MAX_CHANNR (24) /**< Maximum channel number */
|
||||
|
||||
#define CC110X_PACKET_LENGTH (0xFF) /**< max packet length = 255b */
|
||||
#define CC110X_SYNC_WORD_TX_TIME (90000) /**< loop count (max. timeout ~15ms)
|
||||
to wait for sync word to be
|
||||
transmitted (GDO2 from low to
|
||||
high) */
|
||||
|
||||
#define RESET_WAIT_TIME (610) /**< Reset wait time (in reset
|
||||
procedure) */
|
||||
#define IDLE_TO_RX_TIME (122) /**< Time chip needs to go to RX */
|
||||
#define CS_SO_WAIT_TIME (488) /**< Time to wait for SO to go low
|
||||
after CS */
|
||||
#define CC110X_GDO1_LOW_RETRY (100) /**< Max. retries for SO to go low
|
||||
after CS */
|
||||
#define CC110X_DEFAULT_CHANNEL (0) /**< The default channel number */
|
||||
#define CC110X_MIN_CHANNR (0) /**< lowest possible channel number */
|
||||
#define CC110X_MAX_CHANNR (0) /**< highest possible channel number */
|
||||
|
||||
/**
|
||||
* @name State values for state machine
|
||||
* @{
|
||||
*/
|
||||
enum {
|
||||
RADIO_UNKNOWN,
|
||||
RADIO_IDLE,
|
||||
RADIO_TX_BUSY,
|
||||
RADIO_RX,
|
||||
RADIO_RX_BUSY,
|
||||
RADIO_PWD,
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief array holding cc110x register values
|
||||
*/
|
||||
extern char cc110x_conf[];
|
||||
|
||||
/**
|
||||
* @brief CC110X layer 0 protocol
|
||||
*
|
||||
* <pre>
|
||||
---------------------------------------------------
|
||||
| | | | | |
|
||||
| Length | Address | PhySrc | Flags | Data |
|
||||
| | | | | |
|
||||
---------------------------------------------------
|
||||
1 byte 1 byte 1 byte 1 byte <= 251 bytes
|
||||
|
||||
Flags:
|
||||
Bit | Meaning
|
||||
--------------------
|
||||
7:4 | -
|
||||
3:1 | Protocol
|
||||
0 | Identification
|
||||
</pre>
|
||||
Notes:
|
||||
\li length & address are given by CC110X
|
||||
\li Identification is increased is used to scan duplicates. It must be increased
|
||||
for each new packet and kept for packet retransmissions.
|
||||
*/
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint8_t length; /**< Length of the packet (without length byte) */
|
||||
uint8_t address; /**< Destination address */
|
||||
uint8_t phy_src; /**< Source address (physical source) */
|
||||
uint8_t flags; /**< Flags */
|
||||
uint8_t data[CC110X_MAX_DATA_LENGTH]; /**< Data (high layer protocol) */
|
||||
} cc110x_pkt_t;
|
||||
|
||||
/**
|
||||
* @brief struct holding cc110x packet + metadata
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t rssi; /**< RSSI value */
|
||||
uint8_t lqi; /**< link quality indicator */
|
||||
uint8_t pos; /**< I have no clue. */
|
||||
cc110x_pkt_t packet; /**< whole packet */
|
||||
} cc110x_pkt_buf_t;
|
||||
|
||||
/**
|
||||
* @brief enum for holding cc110x radio on/off state */
|
||||
enum cc110x_radio_mode {
|
||||
RADIO_MODE_GET = -1, /**< leave mode unchanged */
|
||||
RADIO_MODE_OFF = 0, /**< turn radio off */
|
||||
RADIO_MODE_ON = 1 /**< turn radio on */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief CC110x register configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t _IOCFG2; /**< GDO2 output pin configuration */
|
||||
uint8_t _IOCFG1; /**< GDO1 output pin configuration */
|
||||
uint8_t _IOCFG0; /**< GDO0 output pin configuration */
|
||||
uint8_t _FIFOTHR; /**< RX FIFO and TX FIFO thresholds */
|
||||
uint8_t _SYNC1; /**< Sync word, high byte */
|
||||
uint8_t _SYNC0; /**< Sync word, low byte */
|
||||
uint8_t _PKTLEN; /**< Packet length */
|
||||
uint8_t _PKTCTRL1; /**< Packet automation control */
|
||||
uint8_t _PKTCTRL0; /**< Packet automation control */
|
||||
uint8_t _ADDR; /**< Device address */
|
||||
uint8_t _CHANNR; /**< Channel number */
|
||||
uint8_t _FSCTRL1; /**< Frequency synthesizer control */
|
||||
uint8_t _FSCTRL0; /**< Frequency synthesizer control */
|
||||
uint8_t _FREQ2; /**< Frequency control word, high byte */
|
||||
uint8_t _FREQ1; /**< Frequency control word, middle byte */
|
||||
uint8_t _FREQ0; /**< Frequency control word, low byte */
|
||||
uint8_t _MDMCFG4; /**< Modem configuration */
|
||||
uint8_t _MDMCFG3; /**< Modem configuration */
|
||||
uint8_t _MDMCFG2; /**< Modem configuration */
|
||||
uint8_t _MDMCFG1; /**< Modem configuration */
|
||||
uint8_t _MDMCFG0; /**< Modem configuration */
|
||||
uint8_t _DEVIATN; /**< Modem deviation setting */
|
||||
uint8_t _MCSM2; /**< Main Radio Control State Machine configuration */
|
||||
uint8_t _MCSM1; /**< Main Radio Control State Machine configuration */
|
||||
uint8_t _MCSM0; /**< Main Radio Control State Machine configuration */
|
||||
uint8_t _FOCCFG; /**< Frequency Offset Compensation configuration */
|
||||
uint8_t _BSCFG; /**< Bit Synchronization configuration */
|
||||
uint8_t _AGCCTRL2; /**< AGC control */
|
||||
uint8_t _AGCCTRL1; /**< AGC control */
|
||||
uint8_t _AGCCTRL0; /**< AGC control */
|
||||
uint8_t _WOREVT1; /**< High byte Event 0 timeout */
|
||||
uint8_t _WOREVT0; /**< Low byte Event 0 timeout */
|
||||
uint8_t _WORCTRL; /**< Wake On Radio control */
|
||||
uint8_t _FREND1; /**< Front end RX configuration */
|
||||
uint8_t _FREND0; /**< Front end TX configuration */
|
||||
uint8_t _FSCAL3; /**< Frequency synthesizer calibration */
|
||||
uint8_t _FSCAL2; /**< Frequency synthesizer calibration */
|
||||
uint8_t _FSCAL1; /**< Frequency synthesizer calibration */
|
||||
uint8_t _FSCAL0; /**< Frequency synthesizer calibration */
|
||||
} cc110x_reg_t;
|
||||
|
||||
/**
|
||||
* @brief CC110x radio configuration
|
||||
*/
|
||||
typedef struct {
|
||||
cc110x_reg_t reg_cfg; /**< CC110X register configuration */
|
||||
uint8_t pa_power; /**< Output power setting */
|
||||
} cc110x_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Radio Control Flags
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t _RSSI; /**< The RSSI value of last received packet */
|
||||
uint8_t _LQI; /**< The LQI value of the last received packet */
|
||||
} cc110x_flags_t;
|
||||
|
||||
/**
|
||||
* @brief Statistic interface for debugging
|
||||
*/
|
||||
typedef struct cc110x_statistic {
|
||||
uint32_t packets_in; /**< total nr of packets received */
|
||||
uint32_t packets_in_crc_fail; /**< dropped because of invalid crc */
|
||||
uint32_t packets_in_while_tx; /**< receive while tx */
|
||||
uint32_t raw_packets_out; /**< packets sent */
|
||||
} cc110x_statistic_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif /* CC110X_INTERNAL_H */
|
||||
62
drivers/include/cc110x/cc110x-netdev2.h
Normal file
62
drivers/include/cc110x/cc110x-netdev2.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Variables for the cc110x ng_netdev base interface
|
||||
*
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_NETDEV_H
|
||||
#define CC110X_NETDEV_H
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "cc110x.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Implementation of netdev2_driver_t for CC110X device
|
||||
*/
|
||||
extern const netdev2_driver_t netdev2_cc110x_driver;
|
||||
|
||||
/**
|
||||
* @brief cc110x netdev2 struct
|
||||
*/
|
||||
typedef struct netdev2_cc110x {
|
||||
netdev2_t netdev; /**< writing obious */
|
||||
cc110x_t cc110x; /**< documentation here */
|
||||
} netdev2_cc110x_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief netdev2 <-> cc110x glue code initialization function
|
||||
*
|
||||
* @param[out] netdev2_cc110x ptr to netdev2_cc110x struct ti initialize
|
||||
* @param[in] params cc110x IO parameter struct to use
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int netdev2_cc110x_setup(netdev2_cc110x_t *netdev2_cc110x, const cc110x_params_t *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CC110X_NETDEV_H */
|
||||
116
drivers/include/cc110x/cc110x-spi.h
Normal file
116
drivers/include/cc110x/cc110x-spi.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2013 INRIA
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief CC110X SPI functions
|
||||
*
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef CC110X_SPI_H
|
||||
#define CC110X_SPI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Write a set of bytes using burst mode (if available)
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Destination register
|
||||
* @param buffer Data to be written
|
||||
* @param count Size of data
|
||||
*/
|
||||
void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *buffer, uint8_t count);
|
||||
|
||||
/**
|
||||
* @brief Read a set of bytes using burst mode (if available)
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Source register
|
||||
* @param buffer Buffer to store read data
|
||||
* @param count Size of data to be read
|
||||
*/
|
||||
void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count);
|
||||
|
||||
/**
|
||||
* @brief Write one byte to a register
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Destinatoin register
|
||||
* @param value New value
|
||||
*/
|
||||
void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Read a byte from register
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Source register
|
||||
*
|
||||
* @return Read state and value of register
|
||||
*/
|
||||
uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Read a byte from register, robust version
|
||||
*
|
||||
* Datasheet states some registered should be read twice until
|
||||
* it returns the same value.
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Source register
|
||||
*
|
||||
* @return Read state and value of register
|
||||
*/
|
||||
uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Read state of a register
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param addr Source register
|
||||
*
|
||||
* @return State of register
|
||||
*/
|
||||
uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Sends a command strobe
|
||||
*
|
||||
* @param dev Device to work on
|
||||
* @param c Command code
|
||||
*
|
||||
* @return Command response
|
||||
*/
|
||||
uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c);
|
||||
|
||||
/**
|
||||
* @brief Pull CS to low and wait for CC110x stabilization
|
||||
*
|
||||
* @param dev Device to work on
|
||||
*/
|
||||
void cc110x_cs(cc110x_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif /* CC110X_SPI_H */
|
||||
45
drivers/include/cc110x/gnrc_netdev2_cc110x.h
Normal file
45
drivers/include/cc110x/gnrc_netdev2_cc110x.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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 driver_cc110x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief cc110x gnrc glue code interface
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#include "net/gnrc/gnrc_netdev2.h"
|
||||
#include "cc110x/cc110x-netdev2.h"
|
||||
|
||||
#ifndef GNRC_CC110X_H
|
||||
#define GNRC_CC110X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief initialize cc110x gnrc glue code
|
||||
*
|
||||
* @param[in] gnrc_netdev2 gnrc_netdev2 state structure to initialize
|
||||
* @param[in] dev cc110x device structure to setup
|
||||
*
|
||||
* @return 1 on sucess
|
||||
* @return <=0 on error
|
||||
*/
|
||||
int gnrc_netdev2_cc110x_init(gnrc_netdev2_t *gnrc_netdev2, netdev2_cc110x_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_CC110X_H */
|
||||
/** @} */
|
||||
@ -158,6 +158,11 @@ void auto_init(void)
|
||||
auto_init_slip();
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_CC110X
|
||||
extern void auto_init_cc110x(void);
|
||||
auto_init_cc110x();
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_XBEE
|
||||
extern void auto_init_xbee(void);
|
||||
auto_init_xbee();
|
||||
|
||||
70
sys/auto_init/netif/auto_init_cc110x.c
Normal file
70
sys/auto_init/netif/auto_init_cc110x.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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 auto_init_ng_netif
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Auto initialization for cc110x network interfaces
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifdef MODULE_CC110X
|
||||
|
||||
#include "board.h"
|
||||
#include "net/gnrc/gnrc_netdev2.h"
|
||||
#include "cc110x/gnrc_netdev2_cc110x.h"
|
||||
#include "net/gnrc.h"
|
||||
|
||||
#include "cc110x.h"
|
||||
#include "cc110x_params.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Define stack parameters for the MAC layer thread
|
||||
* @{
|
||||
*/
|
||||
#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)
|
||||
#define CC110X_MAC_PRIO (THREAD_PRIORITY_MAIN - 3)
|
||||
|
||||
#define CC110X_NUM (sizeof(cc110x_params)/sizeof(cc110x_params[0]))
|
||||
|
||||
static netdev2_cc110x_t cc110x_devs[CC110X_NUM];
|
||||
static char _stacks[CC110X_MAC_STACKSIZE][CC110X_NUM];
|
||||
|
||||
static gnrc_netdev2_t _gnrc_netdev2_devs[CC110X_NUM];
|
||||
|
||||
void auto_init_cc110x(void)
|
||||
{
|
||||
for (int i = 0; i < CC110X_NUM; i++) {
|
||||
const cc110x_params_t *p = &cc110x_params[i];
|
||||
DEBUG("Initializing CC110X radio at SPI_%i\n", p->spi);
|
||||
int res = netdev2_cc110x_setup(&cc110x_devs[i], p);
|
||||
if (res < 0) {
|
||||
DEBUG("Error initializing CC110X radio device!");
|
||||
}
|
||||
else {
|
||||
gnrc_netdev2_cc110x_init(&_gnrc_netdev2_devs[i], &cc110x_devs[i]);
|
||||
res = gnrc_netdev2_init(_stacks[i], CC110X_MAC_STACKSIZE,
|
||||
CC110X_MAC_PRIO, "cc110x", &_gnrc_netdev2_devs[i]);
|
||||
if (res < 0) {
|
||||
DEBUG("Error starting gnrc_cc110x thread for CC110X!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
typedef int dont_be_pedantic;
|
||||
#endif /* MODULE_CC110X */
|
||||
|
||||
/** @} */
|
||||
Loading…
x
Reference in New Issue
Block a user