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:
parent
f1e75dea50
commit
e24b087918
8 changed files with 171 additions and 341 deletions
|
@ -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_USERSPACE can_handlers.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.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)
|
add_subdirectory(transceiver)
|
||||||
|
|
|
@ -18,7 +18,7 @@ module-str = CAN
|
||||||
source "subsys/logging/Kconfig.template.log_config"
|
source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
||||||
config CAN_INIT_PRIORITY
|
config CAN_INIT_PRIORITY
|
||||||
int "CAN init priority"
|
int "CAN driver init priority"
|
||||||
default KERNEL_INIT_PRIORITY_DEVICE
|
default KERNEL_INIT_PRIORITY_DEVICE
|
||||||
help
|
help
|
||||||
CAN driver device initialization priority.
|
CAN driver device initialization priority.
|
||||||
|
@ -66,14 +66,17 @@ config CANFD_MAX_DLC
|
||||||
optimize memory consumption.
|
optimize memory consumption.
|
||||||
endif # CAN_FD_MODE
|
endif # CAN_FD_MODE
|
||||||
|
|
||||||
config CAN_INIT_PRIORITY
|
config CAN_SOCKETCAN_INIT_PRIORITY
|
||||||
int "CAN driver init priority"
|
int "socketCAN net device init priority"
|
||||||
default 80
|
default 81
|
||||||
|
depends on NET_SOCKETS_CAN
|
||||||
help
|
help
|
||||||
CAN device driver initialization priority.
|
socketCAN net device initialization priority.
|
||||||
Do not mess with it unless you know what you are doing.
|
Do not mess with it unless you know what you are doing.
|
||||||
Note that the priority needs to be lower than the net stack
|
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
|
config CAN_RX_TIMESTAMP
|
||||||
bool "Receiving timestamps"
|
bool "Receiving timestamps"
|
||||||
|
|
|
@ -332,41 +332,3 @@ static int can_loopback_init(const struct device *dev)
|
||||||
&can_loopback_driver_api);
|
&can_loopback_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT)
|
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 */
|
|
||||||
|
|
|
@ -993,39 +993,4 @@ DEVICE_DT_INST_DEFINE(0, &mcp2515_init, NULL,
|
||||||
&mcp2515_data_1, &mcp2515_config_1, POST_KERNEL,
|
&mcp2515_data_1, &mcp2515_config_1, POST_KERNEL,
|
||||||
CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);
|
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) */
|
#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */
|
||||||
|
|
|
@ -869,34 +869,3 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
||||||
}
|
}
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(FLEXCAN_DEVICE_INIT_MCUX)
|
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
161
drivers/can/can_socketcan.c
Normal 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);
|
|
@ -1239,41 +1239,6 @@ static void config_can_1_irq(CAN_TypeDef *can)
|
||||||
#endif /* CONFIG_CAN_STATS */
|
#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) */
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) */
|
||||||
|
|
||||||
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can2), st_stm32_can, 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 */
|
#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) */
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay) */
|
||||||
|
|
|
@ -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_ */
|
|
Loading…
Add table
Add a link
Reference in a new issue