Skip to content
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

Merged
merged 2 commits into from
Sep 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions boards/msba2/Makefile.include
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
44 changes: 44 additions & 0 deletions boards/msba2/include/cc110x_params.h
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 */
/** @} */
3 changes: 3 additions & 0 deletions drivers/cc110x/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DIRS += gnrc_cc110x

include $(RIOTBASE)/Makefile.base
100 changes: 100 additions & 0 deletions drivers/cc110x/cc110x-defaultsettings.c
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's that?

Copy link
Contributor Author

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.

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 changes: 218 additions & 0 deletions drivers/cc110x/cc110x-netdev2.c
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you only send the first entry from the ivec list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't some pseudo random number make more sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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);
}
Loading