blob: 5dc51aa573ab370038e9f82d8549cf946373ff9d [file] [log] [blame]
/*
* Copyright (c) 2019 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/* CANBUS related functions that are generic in all the drivers. */
#include <net/net_pkt.h>
#include <net/socket_can.h>
#ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_
#define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_
#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1"
#define SEND_TIMEOUT K_MSEC(100)
#define RX_THREAD_STACK_SIZE 512
#define RX_THREAD_PRIORITY 2
#define BUF_ALLOC_TIMEOUT K_MSEC(50)
/* TODO: make msgq size configurable */
CAN_DEFINE_MSGQ(socket_can_msgq, 5);
K_THREAD_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE);
struct socket_can_context {
struct device *can_dev;
struct net_if *iface;
struct k_msgq *msgq;
/* TODO: remove the thread and push data to net directly from rx isr */
k_tid_t rx_tid;
struct k_thread rx_thread_data;
};
static inline void socket_can_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct socket_can_context *socket_context = dev->driver_data;
socket_context->iface = iface;
LOG_DBG("Init CAN interface %p dev %p", iface, dev);
}
static inline void tx_irq_callback(u32_t error_flags)
{
if (error_flags) {
LOG_DBG("Callback! error-code: %d", error_flags);
}
}
/* This is called by net_if.c when packet is about to be sent */
static inline int socket_can_send(struct device *dev, struct net_pkt *pkt)
{
struct socket_can_context *socket_context = dev->driver_data;
int ret;
if (net_pkt_family(pkt) != AF_CAN) {
return -EPFNOSUPPORT;
}
ret = can_send(socket_context->can_dev,
(struct zcan_frame *)pkt->frags->data,
SEND_TIMEOUT, tx_irq_callback);
if (ret) {
LOG_DBG("Cannot send socket CAN msg (%d)", ret);
}
/* If something went wrong, then we need to return negative value to
* net_if.c:net_if_tx() so that the net_pkt will get released.
*/
return -ret;
}
static inline int socket_can_setsockopt(struct device *dev, void *obj,
int level, int optname,
const void *optval, socklen_t optlen)
{
struct socket_can_context *socket_context = dev->driver_data;
int ret;
if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) {
errno = EINVAL;
return -1;
}
__ASSERT_NO_MSG(optlen == sizeof(struct zcan_filter));
ret = can_attach_msgq(socket_context->can_dev, socket_context->msgq,
optval);
if (ret == CAN_NO_FREE_FILTER) {
errno = ENOSPC;
return -1;
}
return 0;
}
static struct canbus_api socket_can_api = {
.iface_api.init = socket_can_iface_init,
.send = socket_can_send,
.setsockopt = socket_can_setsockopt,
};
static struct socket_can_context socket_can_context_1;
static inline void rx_thread(void *ctx, void *unused1, void *unused2)
{
struct socket_can_context *socket_context = ctx;
struct net_pkt *pkt;
struct zcan_frame msg;
int ret;
ARG_UNUSED(unused1);
ARG_UNUSED(unused2);
while (1) {
k_msgq_get((struct k_msgq *)socket_context->msgq, &msg,
K_FOREVER);
pkt = net_pkt_rx_alloc_with_buffer(socket_context->iface,
sizeof(msg),
AF_CAN, 0,
BUF_ALLOC_TIMEOUT);
if (!pkt) {
LOG_ERR("Failed to obtain RX buffer");
continue;
}
if (net_pkt_write(pkt, (void *)&msg, sizeof(msg))) {
LOG_ERR("Failed to append RX data");
net_pkt_unref(pkt);
continue;
}
ret = net_recv_data(socket_context->iface, pkt);
if (ret < 0) {
net_pkt_unref(pkt);
}
}
}
#endif /* ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ */