zephyr/drivers/ieee802154/ieee802154_uart_pipe.c
Tomasz Bursztyka 11a1d9ef32 drivers: ieee802154: Make uart pipe driver tx one fragment only
Let's not count the whole buffer length but only the very first frag's.
Up to L2 radio strategy to loop on every fragments and call tx for each.
(once sent, it deletes the fragment, so next fragment is always
buf->frags).

Change-Id: I94130fedfbecffdf62286bcb7f10563c776a255e
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-12-02 12:40:55 +02:00

298 lines
5.8 KiB
C

/*
* Copyright (c) 2016 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_UPIPE_15_4_LEVEL
#define SYS_LOG_DOMAIN "net/ieee802154/upipe/"
#include <misc/sys_log.h>
#include <errno.h>
#include <nanokernel.h>
#include <arch/cpu.h>
#include <board.h>
#include <device.h>
#include <init.h>
#include <net/net_if.h>
#include <net/nbuf.h>
#include <console/uart_pipe.h>
#include <net/ieee802154_radio.h>
#include "ieee802154_uart_pipe.h"
/** Singleton device used in uart pipe callback */
static struct device *upipe_dev;
static uint8_t *upipe_rx(uint8_t *buf, size_t *off)
{
struct upipe_context *upipe = upipe_dev->driver_data;
struct net_buf *pkt_buf = NULL;
struct net_buf *nbuf = NULL;
if (!upipe_dev) {
goto done;
}
if (!upipe->rx && *buf == UART_PIPE_RADIO_15_4_FRAME_TYPE) {
upipe->rx = true;
goto done;
}
if (!upipe->rx_len) {
if (*buf > 127) {
goto flush;
}
upipe->rx_len = *buf;
goto done;
}
upipe->rx_buf[upipe->rx_off++] = *buf;
if (upipe->rx_len == upipe->rx_off) {
nbuf = net_nbuf_get_reserve_rx(0);
if (!nbuf) {
SYS_LOG_DBG("No buf available");
goto flush;
}
pkt_buf = net_nbuf_get_reserve_data(0);
if (!pkt_buf) {
SYS_LOG_DBG("No fragment available");
goto out;
}
net_buf_frag_insert(nbuf, pkt_buf);
memcpy(pkt_buf->data, upipe->rx_buf, upipe->rx_len);
net_buf_add(pkt_buf, upipe->rx_len);
if (ieee802154_radio_handle_ack(upipe->iface, nbuf) == NET_OK) {
SYS_LOG_DBG("ACK packet handled");
goto out;
}
SYS_LOG_DBG("Caught a packet (%u)", upipe->rx_len - 2);
if (net_recv_data(upipe->iface, nbuf) < 0) {
SYS_LOG_DBG("Packet dropped by NET stack");
goto out;
}
goto flush;
out:
net_buf_unref(nbuf);
flush:
upipe->rx = false;
upipe->rx_len = 0;
upipe->rx_off = 0;
}
done:
*off = 0;
return buf;
}
static int upipe_cca(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_channel(struct device *dev, uint16_t channel)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_pan_id(struct device *dev, uint16_t pan_id)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_short_addr(struct device *dev, uint16_t short_addr)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_ieee_addr(struct device *dev, const uint8_t *ieee_addr)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_txpower(struct device *dev, int16_t dbm)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_tx(struct device *dev, struct net_buf *buf)
{
uint8_t len = net_nbuf_ll_reserve(buf) + buf->frags->len;
struct upipe_context *upipe = dev->driver_data;
uint8_t *pkt_buf = net_nbuf_ll(buf);
uint8_t i, data;
SYS_LOG_DBG("%p (%u)", buf, len);
if (upipe->stopped) {
return -EIO;
}
data = UART_PIPE_RADIO_15_4_FRAME_TYPE;
uart_pipe_send(&data, 1);
data = len + 2;
uart_pipe_send(&data, 1);
for (i = 0; i < len; i++) {
uart_pipe_send(pkt_buf+i, 1);
}
/* The 2 dummy bytes representing FCS */
data = 0xFF;
uart_pipe_send(&data, 1);
uart_pipe_send(&data, 1);
return 0;
}
static int upipe_start(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (!upipe->stopped) {
return -EALREADY;
}
upipe->stopped = false;
return 0;
}
static int upipe_stop(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EALREADY;
}
upipe->stopped = true;
return 0;
}
static int upipe_init(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
memset(upipe, 0, sizeof(struct upipe_context));
uart_pipe_register(upipe->uart_pipe_buf, 1, upipe_rx);
upipe_stop(dev);
return 0;
}
static inline uint8_t *get_mac(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
upipe->mac_addr[0] = 0x00;
upipe->mac_addr[1] = 0x10;
upipe->mac_addr[2] = 0x20;
upipe->mac_addr[3] = 0x30;
UNALIGNED_PUT(sys_cpu_to_be32(sys_rand32_get()),
(uint32_t *) ((void *)upipe->mac_addr+4));
return upipe->mac_addr;
}
static void upipe_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct upipe_context *upipe = dev->driver_data;
uint8_t *mac = get_mac(dev);
SYS_LOG_DBG("");
net_if_set_link_addr(iface, mac, 8);
upipe_dev = dev;
upipe->iface = iface;
ieee802154_init(iface);
}
static struct upipe_context upipe_context_data;
static struct ieee802154_radio_api upipe_radio_api = {
.iface_api.init = upipe_iface_init,
.iface_api.send = ieee802154_radio_send,
.cca = upipe_cca,
.set_channel = upipe_set_channel,
.set_pan_id = upipe_set_pan_id,
.set_short_addr = upipe_set_short_addr,
.set_ieee_addr = upipe_set_ieee_addr,
.set_txpower = upipe_set_txpower,
.tx = upipe_tx,
.start = upipe_start,
.stop = upipe_stop,
};
NET_DEVICE_INIT(upipe_15_4, CONFIG_UPIPE_15_4_DRV_NAME,
upipe_init, &upipe_context_data, NULL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&upipe_radio_api, IEEE802154_L2,
NET_L2_GET_CTX_TYPE(IEEE802154_L2), 127);