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

197 lines
5.5 KiB
C

/*
* 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/netdev.h"
#include "net/gnrc.h"
#include "cc110x.h"
#include "cc110x-netdev.h"
#include "net/gnrc/netif.h"
#include "od.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
cc110x_pkt_t cc110x_pkt;
netdev_t *dev = netif->dev;
netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t *) dev;
cc110x_t *cc110x = &netdev_cc110x->cc110x;
assert(pkt != NULL);
assert(dev->driver == &netdev_cc110x_driver);
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *payload;
payload = pkt->next;
if (pkt->type != GNRC_NETTYPE_NETIF) {
DEBUG("gnrc_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_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_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_netif_t *netif)
{
netdev_t *dev = netif->dev;
cc110x_t *cc110x = &((netdev_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("gnrc_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_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_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;
}
static const gnrc_netif_ops_t _cc110x_ops = {
.send = _send,
.recv = _recv,
.get = gnrc_netif_get_from_netdev,
.set = gnrc_netif_set_from_netdev,
};
gnrc_netif_t *gnrc_netif_cc110x_create(char *stack, int stacksize, char priority,
char *name, netdev_t *dev)
{
return gnrc_netif_create(stack, stacksize, priority, name, dev,
&_cc110x_ops);
}