Rename a few CAN API functions for clarity and consistency with other Zephyr RTOS APIs. CAN_DEFINE_MSGQ() becomes CAN_MSGQ_DEFINE() to match K_MSGQ_DEFINE(). can_attach_isr() becomes can_add_rx_filter() since a filter callback function is not an interrupt service routine (although it is called in isr context). The word "attach" is replaced with "add" since filters are added, not attached. This matches the terminology used is other Zephyr APIs better. can_detach() becomes can_remove_rx_filter() to pair with can_add_rx_filter(). can_attach_msgq() becomes can_add_rx_filter_msgq() and documentation is updated to mention its relationship with can_add_rx_filter(). can_register_state_change_isr() becomes can_set_state_change_callback() since a state change callback function is not an interrupt service routine (although it is called in isr context). The word "register" is replaced with "set" since only one state change callback can be in place. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
158 lines
3.8 KiB
C
158 lines
3.8 KiB
C
/*
|
|
* 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_0 "SOCKET_CAN_0"
|
|
#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1"
|
|
#define SOCKET_CAN_NAME_2 "SOCKET_CAN_2"
|
|
#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_MSGQ_DEFINE(socket_can_msgq, 5);
|
|
K_KERNEL_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE);
|
|
|
|
struct socket_can_context {
|
|
const 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)
|
|
{
|
|
const struct device *dev = net_if_get_device(iface);
|
|
struct socket_can_context *socket_context = dev->data;
|
|
|
|
socket_context->iface = iface;
|
|
|
|
LOG_DBG("Init CAN interface %p dev %p", iface, dev);
|
|
}
|
|
|
|
static inline void tx_irq_callback(int error, void *arg)
|
|
{
|
|
char *caller_str = (char *)arg;
|
|
if (error != 0) {
|
|
LOG_DBG("TX error from %s! error-code: %d",
|
|
caller_str, error);
|
|
}
|
|
}
|
|
|
|
/* This is called by net_if.c when packet is about to be sent */
|
|
static inline int socket_can_send(const struct device *dev,
|
|
struct net_pkt *pkt)
|
|
{
|
|
struct socket_can_context *socket_context = dev->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, "socket_can_send");
|
|
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(const struct device *dev, void *obj,
|
|
int level, int optname,
|
|
const void *optval, socklen_t optlen)
|
|
{
|
|
struct socket_can_context *socket_context = dev->data;
|
|
struct net_context *ctx = obj;
|
|
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_add_rx_filter_msgq(socket_context->can_dev, socket_context->msgq,
|
|
optval);
|
|
if (ret == -ENOSPC) {
|
|
errno = ENOSPC;
|
|
return -1;
|
|
}
|
|
|
|
net_context_set_filter_id(ctx, ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void socket_can_close(const struct device *dev, int filter_id)
|
|
{
|
|
struct socket_can_context *socket_context = dev->data;
|
|
|
|
can_remove_rx_filter(socket_context->can_dev, filter_id);
|
|
}
|
|
|
|
static struct canbus_api socket_can_api = {
|
|
.iface_api.init = socket_can_iface_init,
|
|
.send = socket_can_send,
|
|
.close = socket_can_close,
|
|
.setsockopt = socket_can_setsockopt,
|
|
};
|
|
|
|
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 frame;
|
|
int ret;
|
|
|
|
ARG_UNUSED(unused1);
|
|
ARG_UNUSED(unused2);
|
|
|
|
while (1) {
|
|
k_msgq_get((struct k_msgq *)socket_context->msgq, &frame,
|
|
K_FOREVER);
|
|
|
|
pkt = net_pkt_rx_alloc_with_buffer(socket_context->iface,
|
|
sizeof(frame),
|
|
AF_CAN, 0,
|
|
BUF_ALLOC_TIMEOUT);
|
|
if (!pkt) {
|
|
LOG_ERR("Failed to obtain RX buffer");
|
|
continue;
|
|
}
|
|
|
|
if (net_pkt_write(pkt, (void *)&frame, sizeof(frame))) {
|
|
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_ */
|