drivers: can: socketCAN: Move socket code to own file

Move the code for socket instanciation from each driver
to a generic driver, that makes an instance of a socketCAN
net device for the chosen node.

Signed-off-by: Alexander Wachter <alexander@wachter.cloud>
This commit is contained in:
Alexander Wachter 2022-01-16 14:35:07 +01:00 committed by Carles Cufí
commit e24b087918
8 changed files with 171 additions and 341 deletions

View file

@ -16,5 +16,6 @@ zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c)
zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_CAN can_socketcan.c)
add_subdirectory(transceiver)

View file

@ -18,7 +18,7 @@ module-str = CAN
source "subsys/logging/Kconfig.template.log_config"
config CAN_INIT_PRIORITY
int "CAN init priority"
int "CAN driver init priority"
default KERNEL_INIT_PRIORITY_DEVICE
help
CAN driver device initialization priority.
@ -66,14 +66,17 @@ config CANFD_MAX_DLC
optimize memory consumption.
endif # CAN_FD_MODE
config CAN_INIT_PRIORITY
int "CAN driver init priority"
default 80
config CAN_SOCKETCAN_INIT_PRIORITY
int "socketCAN net device init priority"
default 81
depends on NET_SOCKETS_CAN
help
CAN device driver initialization priority.
socketCAN net device initialization priority.
Do not mess with it unless you know what you are doing.
Note that the priority needs to be lower than the net stack
so that it can start before the networking sub-system.
so that it can start before the networking sub-system,
and higher than the CAN driver so that it can use the underlaying
driver when starting.
config CAN_RX_TIMESTAMP
bool "Receiving timestamps"

View file

@ -332,41 +332,3 @@ static int can_loopback_init(const struct device *dev)
&can_loopback_driver_api);
DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT)
#if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h"
#define CAN_LOOPBACK_SOCKET_CAN(inst) \
static struct socket_can_context socket_can_context_##inst; \
\
static int socket_can_init_##inst(const struct device *dev) \
{ \
const struct device *can_dev = DEVICE_DT_INST_GET(inst); \
struct socket_can_context *socket_context = dev->data; \
\
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \
dev, dev->name, can_dev, can_dev->name); \
\
socket_context->can_dev = can_dev; \
socket_context->msgq = &socket_can_msgq; \
\
socket_context->rx_tid = \
k_thread_create(&socket_context->rx_thread_data, \
rx_thread_stack, \
K_KERNEL_STACK_SIZEOF(rx_thread_stack), \
rx_thread, socket_context, NULL, NULL, \
RX_THREAD_PRIORITY, 0, K_NO_WAIT); \
\
return 0; \
} \
\
NET_DEVICE_INIT(socket_can_loopback_##inst, SOCKET_CAN_NAME_##inst, \
socket_can_init_##inst, NULL, \
&socket_can_context_##inst, NULL, \
CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \
CAN_MTU);
DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_SOCKET_CAN)
#endif /* CONFIG_NET_SOCKETS_CAN */

View file

@ -993,39 +993,4 @@ DEVICE_DT_INST_DEFINE(0, &mcp2515_init, NULL,
&mcp2515_data_1, &mcp2515_config_1, POST_KERNEL,
CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);
#if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h"
static struct socket_can_context socket_can_context_1;
static int socket_can_init(const struct device *dev)
{
const struct device *can_dev = DEVICE_DT_INST_GET(1);
struct socket_can_context *socket_context = dev->data;
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)",
dev, dev->name, can_dev, can_dev->name);
socket_context->can_dev = can_dev;
socket_context->msgq = &socket_can_msgq;
socket_context->rx_tid =
k_thread_create(&socket_context->rx_thread_data,
rx_thread_stack,
K_KERNEL_STACK_SIZEOF(rx_thread_stack),
rx_thread, socket_context, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
return 0;
}
NET_DEVICE_INIT(socket_can_mcp2515_1, SOCKET_CAN_NAME_1, socket_can_init,
NULL, &socket_can_context_1, NULL,
CONFIG_CAN_INIT_PRIORITY,
&socket_can_api,
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
#endif
#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */

View file

@ -869,34 +869,3 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
}
DT_INST_FOREACH_STATUS_OKAY(FLEXCAN_DEVICE_INIT_MCUX)
#if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h"
#define FLEXCAN_DEVICE_SOCKET_CAN(id) \
static struct socket_can_context socket_can_context_##id; \
static int socket_can_init_##id(const struct device *dev) \
{ \
const struct device *can_dev = DEVICE_DT_INST_GET(id); \
struct socket_can_context *socket_context = dev->data; \
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \
dev, dev->name, can_dev, can_dev->name); \
socket_context->can_dev = can_dev; \
socket_context->msgq = &socket_can_msgq; \
socket_context->rx_tid = \
k_thread_create(&socket_context->rx_thread_data, \
rx_thread_stack, \
K_KERNEL_STACK_SIZEOF(rx_thread_stack), \
rx_thread, socket_context, NULL, NULL, \
RX_THREAD_PRIORITY, 0, K_NO_WAIT); \
return 0; \
} \
\
NET_DEVICE_INIT(socket_can_flexcan_##id, SOCKET_CAN_NAME_##id, \
socket_can_init_##id, NULL, \
&socket_can_context_##id, NULL, \
CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \
CAN_MTU); \
DT_INST_FOREACH_STATUS_OKAY(FLEXCAN_DEVICE_SOCKET_CAN)
#endif

161
drivers/can/can_socketcan.c Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2019 Intel Corporation.
* Copyright (c) 2022 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <net/net_pkt.h>
#include <net/socket_can.h>
#include <drivers/can.h>
#include <devicetree.h>
#include <device.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(can_socketcan, CONFIG_CAN_LOG_LEVEL);
#define SEND_TIMEOUT K_MSEC(100)
struct socketcan_context {
struct net_if *iface;
};
struct socketcan_config {
const struct device *can_dev;
};
static void socketcan_recv(const struct device *dev, struct zcan_frame *frame, void *arg)
{
struct socketcan_context *ctx = (struct socketcan_context *)arg;
struct net_pkt *pkt;
int ret;
ARG_UNUSED(dev);
LOG_DBG("pkt on interface %p", ctx->iface);
pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, sizeof(struct zcan_frame),
AF_CAN, 0, K_NO_WAIT);
if (pkt == NULL) {
LOG_ERR("Failed to obtain net_pkt");
return;
}
if (net_pkt_write(pkt, frame, sizeof(struct zcan_frame))) {
LOG_ERR("Failed to append RX data");
net_pkt_unref(pkt);
return;
}
ret = net_recv_data(ctx->iface, pkt);
if (ret < 0) {
LOG_DBG("net_recv_data failed [%d]", ret);
net_pkt_unref(pkt);
}
}
static int socketcan_setsockopt(const struct device *dev, void *obj, int level,
int optname, const void *optval, socklen_t optlen)
{
const struct socketcan_config *cfg = dev->config;
struct socketcan_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(cfg->can_dev, socketcan_recv, socket_context, optval);
if (ret == -ENOSPC) {
errno = ENOSPC;
return -1;
}
net_context_set_filter_id(ctx, ret);
return 0;
}
static void socketcan_close(const struct device *dev, int filter_id)
{
const struct socketcan_config *cfg = dev->config;
can_remove_rx_filter(cfg->can_dev, filter_id);
}
static void socketcan_send_tx_callback(const struct device *dev, int error, void *arg)
{
ARG_UNUSED(dev);
ARG_UNUSED(arg);
if (error != 0) {
LOG_DBG("socket CAN TX error [%d]", error);
}
}
static int socketcan_send(const struct device *dev, struct net_pkt *pkt)
{
const struct socketcan_config *cfg = dev->config;
int ret;
if (net_pkt_family(pkt) != AF_CAN) {
return -EPFNOSUPPORT;
}
ret = can_send(cfg->can_dev, (struct zcan_frame *)pkt->frags->data,
SEND_TIMEOUT, socketcan_send_tx_callback, NULL);
if (ret == 0) {
net_pkt_unref(pkt);
} else {
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 void socketcan_iface_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
struct socketcan_context *socket_context = dev->data;
socket_context->iface = iface;
LOG_DBG("Init CAN interface %p dev %p", iface, dev);
}
static int socketcan_init(const struct device *dev)
{
const struct socketcan_config *cfg = dev->config;
if (!device_is_ready(cfg->can_dev)) {
LOG_ERR("CAN device not ready");
return -ENODEV;
}
return 0;
}
static struct canbus_api socketcan_api = {
.iface_api.init = socketcan_iface_init,
.send = socketcan_send,
.close = socketcan_close,
.setsockopt = socketcan_setsockopt,
};
static struct socketcan_context socketcan_ctx;
static const struct socketcan_config socketcan_cfg = {
.can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus))
};
NET_DEVICE_INIT(socket_can, "SOCKET_CAN", socketcan_init, NULL, &socketcan_ctx, &socketcan_cfg,
CONFIG_CAN_SOCKETCAN_INIT_PRIORITY, &socketcan_api, CANBUS_RAW_L2,
NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);

View file

@ -1239,41 +1239,6 @@ static void config_can_1_irq(CAN_TypeDef *can)
#endif /* CONFIG_CAN_STATS */
}
#if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h"
static struct socket_can_context socket_can_context_1;
static int socket_can_init_1(const struct device *dev)
{
const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(can1));
struct socket_can_context *socket_context = dev->data;
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)",
dev, dev->name, can_dev, can_dev->name);
socket_context->can_dev = can_dev;
socket_context->msgq = &socket_can_msgq;
socket_context->rx_tid =
k_thread_create(&socket_context->rx_thread_data,
rx_thread_stack,
K_KERNEL_STACK_SIZEOF(rx_thread_stack),
rx_thread, socket_context, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
return 0;
}
NET_DEVICE_INIT(socket_can_stm32_1, SOCKET_CAN_NAME_1, socket_can_init_1,
NULL, &socket_can_context_1, NULL,
CONFIG_CAN_INIT_PRIORITY,
&socket_can_api,
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
#endif /* CONFIG_NET_SOCKETS_CAN */
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) */
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can2), st_stm32_can, okay)
@ -1335,39 +1300,4 @@ static void config_can_2_irq(CAN_TypeDef *can)
#endif /* CONFIG_CAN_STATS */
}
#if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h"
static struct socket_can_context socket_can_context_2;
static int socket_can_init_2(const struct device *dev)
{
const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(can2));
struct socket_can_context *socket_context = dev->data;
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)",
dev, dev->name, can_dev, can_dev->name);
socket_context->can_dev = can_dev;
socket_context->msgq = &socket_can_msgq;
socket_context->rx_tid =
k_thread_create(&socket_context->rx_thread_data,
rx_thread_stack,
K_KERNEL_STACK_SIZEOF(rx_thread_stack),
rx_thread, socket_context, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
return 0;
}
NET_DEVICE_INIT(socket_can_stm32_2, SOCKET_CAN_NAME_2, socket_can_init_2,
NULL, &socket_can_context_2, NULL,
CONFIG_CAN_INIT_PRIORITY,
&socket_can_api,
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
#endif /* CONFIG_NET_SOCKETS_CAN */
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay) */

View file

@ -1,161 +0,0 @@
/*
* 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(const struct device *dev, int error, void *arg)
{
char *caller_str = (char *)arg;
ARG_UNUSED(dev);
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_ */