-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers: add cc110x driver #3716
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ | ||
/** @} */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
DIRS += gnrc_cc110x | ||
|
||
include $(RIOTBASE)/Makefile.base |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you only send the first entry from the ivec list? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the driver currently accepts only that. But gnrc_cc110x converts a full pktsnip into one iovec. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see |
||
|
||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't some pseudo random number make more sense? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably, will change. |
||
} | ||
#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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One board I had to do a port for uses the cc110x as clock source, so SPI&cc1101 get initialized in the board config. IOCONF0 is set to output a clock. If later at driver initialization the cc110x gets reset or ioconf0 overwritten, the board hangs.
I'll add a comment.