|
| 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