Skip to content

Commit e93bc66

Browse files
committed
drivers: can: Add support for native_posix board
This initial version supports SocketCAN. The driver passes CANBUS data between Linux vcan virtual CAN driver and Zephyr. You also need to use can-setup.sh script from the net-tools project in order to make communication work with Linux vcan driver. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent c9090ca commit e93bc66

File tree

6 files changed

+558
-1
lines changed

6 files changed

+558
-1
lines changed

drivers/can/CMakeLists.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3-
zephyr_sources_ifdef(CONFIG_CAN_STM32 stm32_can.c)
3+
zephyr_sources_ifdef(CONFIG_CAN_STM32 stm32_can.c)
44
zephyr_sources_ifdef(CONFIG_CAN_MCP2515 mcp2515.c)
55
zephyr_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
6+
7+
if(CONFIG_CAN_NATIVE_POSIX)
8+
zephyr_library()
9+
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2)
10+
zephyr_library_compile_definitions(NO_POSIX_CHEATS)
11+
zephyr_library_compile_definitions(_BSD_SOURCE)
12+
zephyr_library_compile_definitions(_DEFAULT_SOURCE)
13+
zephyr_library_sources(
14+
canbus_native_posix.c
15+
canbus_native_posix_adapt.c
16+
)
17+
endif()

drivers/can/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ config CAN_1
3737

3838
source "drivers/can/Kconfig.stm32"
3939
source "drivers/can/Kconfig.mcp2515"
40+
source "drivers/can/Kconfig.native_posix"
4041

4142
endif # CAN

drivers/can/Kconfig.native_posix

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Kconfig.native_posix - native_posix CAN configuration options
2+
3+
#
4+
# Copyright (c) 2019 Intel Corporation
5+
#
6+
# SPDX-License-Identifier: Apache-2.0
7+
#
8+
9+
config CAN_NATIVE_POSIX
10+
bool "native_posix CAN Driver"
11+
depends on ARCH_POSIX
12+
help
13+
Enable native_posix CAN driver
14+
15+
config CAN_MAX_FILTER
16+
int "Maximum number of concurrent active filters"
17+
depends on CAN_NATIVE_POSIX
18+
default 32
19+
range 1 56
20+
help
21+
Defines the array size of the callback/msgq pointers.
22+
Must be at least the size of concurrent reads.
23+
24+
config CAN_NATIVE_POSIX_INTERFACE_NAME
25+
string "CANBUS interface name in Linux side"
26+
default "zcan"
27+
help
28+
This option sets the CANBUS network interface name in host system.

drivers/can/canbus_native_posix.c

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
/*
2+
* Copyright (c) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
*
10+
* CANBUS driver for native_posix board. This is meant to test CANBUS
11+
* connectivity between host and Zephyr.
12+
*/
13+
14+
#define LOG_MODULE_NAME canbus_posix
15+
#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL
16+
17+
#include <logging/log.h>
18+
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
19+
20+
#include <stdio.h>
21+
22+
#include <kernel.h>
23+
#include <stdbool.h>
24+
#include <errno.h>
25+
#include <stddef.h>
26+
27+
#include <net/net_pkt.h>
28+
#include <net/net_core.h>
29+
#include <net/net_if.h>
30+
31+
#include <can.h>
32+
#include <net/socket_can.h>
33+
34+
#include "canbus_native_posix_priv.h"
35+
36+
#define NET_BUF_TIMEOUT K_MSEC(100)
37+
#define DT_CAN_1_NAME "CAN_1"
38+
39+
struct canbus_np_context {
40+
u8_t recv[CAN_MTU];
41+
42+
struct device *can_dev;
43+
struct k_msgq *msgq;
44+
struct net_if *iface;
45+
const char *if_name;
46+
int dev_fd;
47+
bool init_done;
48+
};
49+
50+
NET_STACK_DEFINE(RX_ZCAN, canbus_rx_stack,
51+
CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE,
52+
CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
53+
static struct k_thread rx_thread_data;
54+
55+
/* TODO: support multiple interfaces */
56+
static struct canbus_np_context canbus_context_data;
57+
58+
static int read_data(struct canbus_np_context *ctx, int fd)
59+
{
60+
struct net_pkt *pkt;
61+
int count;
62+
63+
count = canbus_np_read_data(fd, ctx->recv, sizeof(ctx->recv));
64+
if (count <= 0) {
65+
return 0;
66+
}
67+
68+
pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count,
69+
AF_CAN, 0, NET_BUF_TIMEOUT);
70+
if (!pkt) {
71+
return -ENOMEM;
72+
}
73+
74+
if (net_pkt_write_new(pkt, ctx->recv, count)) {
75+
net_pkt_unref(pkt);
76+
return -ENOBUFS;
77+
}
78+
79+
if (net_recv_data(ctx->iface, pkt) < 0) {
80+
net_pkt_unref(pkt);
81+
}
82+
83+
return 0;
84+
}
85+
86+
static void canbus_np_rx(struct canbus_np_context *ctx)
87+
{
88+
int ret;
89+
90+
LOG_DBG("Starting ZCAN RX thread");
91+
92+
while (1) {
93+
if (ctx->iface && net_if_is_up(ctx->iface)) {
94+
ret = canbus_np_wait_data(ctx->dev_fd);
95+
if (!ret) {
96+
read_data(ctx, ctx->dev_fd);
97+
}
98+
}
99+
100+
k_sleep(K_MSEC(50));
101+
}
102+
}
103+
104+
static void create_rx_handler(struct canbus_np_context *ctx)
105+
{
106+
k_thread_create(&rx_thread_data, canbus_rx_stack,
107+
K_THREAD_STACK_SIZEOF(canbus_rx_stack),
108+
(k_thread_entry_t)canbus_np_rx,
109+
ctx, NULL, NULL, K_PRIO_COOP(14),
110+
0, K_NO_WAIT);
111+
}
112+
113+
static int canbus_np_init(struct device *dev)
114+
{
115+
struct canbus_np_context *ctx = dev->driver_data;
116+
117+
ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_NAME;
118+
119+
ctx->dev_fd = canbus_np_iface_open(ctx->if_name);
120+
if (ctx->dev_fd < 0) {
121+
LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd);
122+
} else {
123+
/* Create a thread that will handle incoming data from host */
124+
create_rx_handler(ctx);
125+
}
126+
127+
return 0;
128+
}
129+
130+
static int canbus_np_runtime_configure(struct device *dev, enum can_mode mode,
131+
u32_t bitrate)
132+
{
133+
ARG_UNUSED(dev);
134+
ARG_UNUSED(mode);
135+
ARG_UNUSED(bitrate);
136+
137+
return 0;
138+
}
139+
140+
static int canbus_np_send(struct device *dev, const struct zcan_frame *msg,
141+
s32_t timeout, can_tx_callback_t callback)
142+
{
143+
struct canbus_np_context *ctx = dev->driver_data;
144+
int ret = -ENODEV;
145+
146+
ARG_UNUSED(timeout);
147+
ARG_UNUSED(callback);
148+
149+
if (ctx->dev_fd > 0) {
150+
struct can_frame frame;
151+
152+
can_copy_zframe_to_frame(msg, &frame);
153+
154+
ret = canbus_np_write_data(ctx->dev_fd, &frame, sizeof(frame));
155+
if (ret < 0) {
156+
LOG_ERR("Cannot send CAN data len %d (%d)",
157+
frame.can_dlc, -errno);
158+
}
159+
}
160+
161+
return ret < 0 ? ret : 0;
162+
}
163+
164+
static int canbus_np_attach_msgq(struct device *dev, struct k_msgq *msgq,
165+
const struct zcan_filter *filter)
166+
{
167+
ARG_UNUSED(dev);
168+
ARG_UNUSED(msgq);
169+
ARG_UNUSED(filter);
170+
171+
return 0;
172+
}
173+
174+
static int canbus_np_attach_isr(struct device *dev, can_rx_callback_t isr,
175+
const struct zcan_filter *filter)
176+
{
177+
ARG_UNUSED(dev);
178+
ARG_UNUSED(isr);
179+
ARG_UNUSED(filter);
180+
181+
return 0;
182+
}
183+
184+
static void canbus_np_detach(struct device *dev, int filter_nr)
185+
{
186+
ARG_UNUSED(dev);
187+
ARG_UNUSED(filter_nr);
188+
}
189+
190+
static const struct can_driver_api can_api_funcs = {
191+
.configure = canbus_np_runtime_configure,
192+
.send = canbus_np_send,
193+
.attach_msgq = canbus_np_attach_msgq,
194+
.attach_isr = canbus_np_attach_isr,
195+
.detach = canbus_np_detach,
196+
};
197+
198+
#ifdef CONFIG_CAN_1
199+
200+
DEVICE_AND_API_INIT(canbus_np_1, DT_CAN_1_NAME,
201+
canbus_np_init, &canbus_context_data, NULL,
202+
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
203+
&can_api_funcs);
204+
205+
#if defined(CONFIG_NET_SOCKETS_CAN)
206+
207+
#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1"
208+
#define SEND_TIMEOUT K_MSEC(100)
209+
#define BUF_ALLOC_TIMEOUT K_MSEC(50)
210+
211+
/* TODO: make msgq size configurable */
212+
CAN_DEFINE_MSGQ(socket_can_msgq, 5);
213+
214+
static void socket_can_iface_init(struct net_if *iface)
215+
{
216+
struct device *dev = net_if_get_device(iface);
217+
struct canbus_np_context *socket_context = dev->driver_data;
218+
219+
socket_context->iface = iface;
220+
221+
LOG_DBG("Init CAN interface %p dev %p", iface, dev);
222+
}
223+
224+
static void tx_irq_callback(u32_t error_flags)
225+
{
226+
if (error_flags) {
227+
LOG_DBG("Callback! error-code: %d", error_flags);
228+
}
229+
}
230+
231+
/* This is called by net_if.c when packet is about to be sent */
232+
static int socket_can_send(struct device *dev, struct net_pkt *pkt)
233+
{
234+
struct canbus_np_context *socket_context = dev->driver_data;
235+
int ret;
236+
237+
if (net_pkt_family(pkt) != AF_CAN) {
238+
return -EPFNOSUPPORT;
239+
}
240+
241+
ret = can_send(socket_context->can_dev,
242+
(struct zcan_frame *)pkt->frags->data,
243+
SEND_TIMEOUT, tx_irq_callback);
244+
if (ret) {
245+
LOG_DBG("Cannot send socket CAN msg (%d)", ret);
246+
}
247+
248+
/* If something went wrong, then we need to return negative value to
249+
* net_if.c:net_if_tx() so that the net_pkt will get released.
250+
*/
251+
return -ret;
252+
}
253+
254+
static int socket_can_setsockopt(struct device *dev, void *obj,
255+
int level, int optname,
256+
const void *optval, socklen_t optlen)
257+
{
258+
struct canbus_np_context *socket_context = dev->driver_data;
259+
struct can_filter filter;
260+
261+
if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) {
262+
errno = EINVAL;
263+
return -1;
264+
}
265+
266+
/* Our userspace can send either zcan_filter or can_filter struct.
267+
* They are different sizes so we need to convert them if needed.
268+
*/
269+
if (optlen != sizeof(struct can_filter) &&
270+
optlen != sizeof(struct zcan_filter)) {
271+
errno = EINVAL;
272+
return -1;
273+
}
274+
275+
if (optlen == sizeof(struct zcan_filter)) {
276+
can_copy_zfilter_to_filter((struct zcan_filter *)optval,
277+
&filter);
278+
} else {
279+
memcpy(&filter, optval, sizeof(filter));
280+
}
281+
282+
return canbus_np_setsockopt(socket_context->dev_fd, level, optname,
283+
&filter, sizeof(filter));
284+
}
285+
286+
static struct canbus_api socket_can_api = {
287+
.iface_api.init = socket_can_iface_init,
288+
.send = socket_can_send,
289+
.setsockopt = socket_can_setsockopt,
290+
};
291+
292+
static int socket_can_init_1(struct device *dev)
293+
{
294+
struct device *can_dev = DEVICE_GET(canbus_np_1);
295+
struct canbus_np_context *socket_context = dev->driver_data;
296+
297+
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)",
298+
dev, dev->config->name, can_dev, can_dev->config->name);
299+
300+
socket_context->can_dev = can_dev;
301+
socket_context->msgq = &socket_can_msgq;
302+
303+
return 0;
304+
}
305+
306+
NET_DEVICE_INIT(socket_can_native_posix_1, SOCKET_CAN_NAME_1,
307+
socket_can_init_1, &canbus_context_data, NULL,
308+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api,
309+
CANBUS_L2, NET_L2_GET_CTX_TYPE(CANBUS_L2), CAN_MTU);
310+
311+
#endif /* CONFIG_NET_SOCKETS_CAN */
312+
313+
#endif /* CONFIG_CAN_1 */

0 commit comments

Comments
 (0)