1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/cc110x/cc110x-netdev.c

254 lines
6.3 KiB
C

/*
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_cc110x
* @{
* @file
* @brief Functionality for netdev base interface
*
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @}
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "cc110x.h"
#include "cc110x-internal.h"
#include "periph/gpio.h"
#include "netdev/base.h"
#ifdef MODULE_NETDEV_BASE
extern netdev_rcv_data_cb_t cc110x_recv_cb;
int _cc110x_send_data(netdev_t *dev, void *dest, size_t dest_len,
netdev_hlist_t *upper_layer_hdrs, void *data, size_t data_len)
{
netdev_hlist_t *ptr = upper_layer_hdrs;
uint8_t tx_buffer[data_len + netdev_get_hlist_len(upper_layer_hdrs)];
size_t tx_ptr = 0;
cc110x_packet_t cc110x_pkt;
if (dev != &cc110x_dev) {
return -ENODEV;
}
if (dest_len > sizeof(uint8_t)) {
return -EAFNOSUPPORT;
}
if ((sizeof(tx_buffer) + CC1100_HEADER_LENGTH + 1) > PACKET_LENGTH) {
return -EMSGSIZE;
}
/* append possible upper layer headers */
if (upper_layer_hdrs) {
do {
memcpy(&(tx_buffer[tx_ptr]), ptr->header, ptr->header_len);
tx_ptr += ptr->header_len;
netdev_hlist_advance(&ptr);
} while (ptr != upper_layer_hdrs);
}
/* append data */
memcpy(&(tx_buffer[tx_ptr]), data, data_len);
cc110x_pkt.length = sizeof(tx_buffer) + CC1100_HEADER_LENGTH;
cc110x_pkt.address = *((uint8_t *)dest);
cc110x_pkt.flags = 0;
memcpy(cc110x_pkt.data, &tx_buffer[0], sizeof(tx_buffer));
return cc110x_send(&cc110x_pkt);
}
int _cc110x_add_rcv_data_cb(netdev_t *dev, netdev_rcv_data_cb_t cb)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
else if (cc110x_recv_cb != NULL) {
return -ENOBUFS;
}
cc110x_recv_cb = cb;
return 0;
}
int _cc110x_rem_rcv_data_cb(netdev_t *dev, netdev_rcv_data_cb_t cb)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
if (cc110x_recv_cb == cb) {
cc110x_recv_cb = NULL;
}
return 0;
}
int _cc110x_get_option(netdev_t *dev, netdev_opt_t opt, void *value, size_t *value_len)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
switch (opt) {
case NETDEV_OPT_CHANNEL:
if (*value_len == 0) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint8_t)) {
*value_len = sizeof(uint8_t);
}
*((uint8_t *)value) = cc110x_get_channel();
break;
case NETDEV_OPT_ADDRESS:
if (*value_len < sizeof(radio_address_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint8_t)) {
*value_len = sizeof(uint8_t);
}
*((uint8_t *)value) = (uint8_t) cc110x_get_address();
break;
case NETDEV_OPT_PROTO:
if (*value_len < sizeof(netdev_proto_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(netdev_proto_t)) {
*value_len = sizeof(netdev_proto_t);
}
*((netdev_proto_t *)value) = NETDEV_PROTO_CC110X;
break;
case NETDEV_OPT_MAX_PACKET_SIZE:
if (*value_len == 0) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint8_t)) {
*value_len = sizeof(uint8_t);
}
*((uint8_t *)value) = PACKET_LENGTH;
break;
default:
return -ENOTSUP;
}
return 0;
}
int _cc110x_set_option(netdev_t *dev, netdev_opt_t opt, void *value, size_t value_len)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
switch (opt) {
case NETDEV_OPT_CHANNEL:
if (value_len != sizeof(uint8_t)) {
return -EOVERFLOW;
}
if (cc110x_set_channel(*((uint8_t *)value)) == -1) {
return -EINVAL;
}
break;
case NETDEV_OPT_ADDRESS:
/* leaves room for optimization */
if (value_len > sizeof(radio_address_t)) {
return -EOVERFLOW;
}
radio_address_t temp_address;
if (value_len == sizeof(uint8_t)) {
temp_address = ((radio_address_t)(*((uint8_t *)value)));
}
else {
temp_address = *((radio_address_t *)value);
}
if (!cc110x_set_address(temp_address)) {
return -EINVAL;
}
break;
default:
return -ENOTSUP;
}
return 0;
}
int _cc110x_get_state(netdev_t *dev, netdev_state_t *state)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
switch(radio_state) {
case RADIO_IDLE:
*state = NETDEV_STATE_POWER_IDLE;
break;
case RADIO_SEND_BURST:
*state = NETDEV_STATE_TX_BURST;
break;
case RADIO_RX:
*state = NETDEV_STATE_RX_MODE;
break;
case RADIO_UNKNOWN:
case RADIO_PWD:
default:
*state = NETDEV_STATE_POWER_OFF;
break;
}
return 0;
}
int _cc110x_set_state(netdev_t *dev, netdev_state_t state)
{
if (dev != &cc110x_dev) {
return -ENODEV;
}
switch (state) {
case NETDEV_STATE_POWER_OFF:
gpio_irq_disable(CC110X_GDO2);
cc110x_switch_to_pwd();
break;
case NETDEV_STATE_RX_MODE:
gpio_irq_enable(CC110X_GDO2);
cc110x_setup_rx_mode();
break;
default:
return -ENOTSUP;
}
return 0;
}
void _cc110x_event(netdev_t *dev, uint32_t event_type)
{
(void)dev;
(void)event_type;
}
const netdev_driver_t cc110x_net_driver = {
cc110x_initialize,
_cc110x_send_data,
_cc110x_add_rcv_data_cb,
_cc110x_rem_rcv_data_cb,
_cc110x_get_option,
_cc110x_set_option,
_cc110x_get_state,
_cc110x_set_state,
_cc110x_event,
};
netdev_t cc110x_dev = {NETDEV_TYPE_BASE, &cc110x_net_driver, 0};
#else
netdev_t cc110x_dev = {NETDEV_TYPE_BASE, 0, 0};
#endif /* MODULE_NETDEV_BASE */