blob: 4b576efedc3056d5cd4e2e4a7bcfd91b9a44fed1 [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_socket_can_sample, LOG_LEVEL_DBG);
#include <zephyr/zephyr.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/socket_can.h>
#ifdef CONFIG_SAMPLE_SOCKETCAN_LOOPBACK_MODE
#include <zephyr/drivers/can.h>
#endif
#define PRIORITY k_thread_priority_get(k_current_get())
#define STACKSIZE 1024
#define SLEEP_PERIOD K_SECONDS(1)
static k_tid_t tx_tid;
static K_THREAD_STACK_DEFINE(tx_stack, STACKSIZE);
static struct k_thread tx_data;
/* For testing purposes, we create another RX receiver if configured so */
#if CONFIG_NET_SOCKETS_CAN_RECEIVERS == 2
static k_tid_t rx_tid;
static K_THREAD_STACK_DEFINE(rx_stack, STACKSIZE);
static struct k_thread rx_data;
#endif
#define CLOSE_PERIOD 15
static const struct zcan_filter zfilter = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.id = 0x1,
.rtr_mask = 1,
.id_mask = CAN_STD_ID_MASK
};
static struct can_filter filter;
static void tx(int *can_fd)
{
int fd = POINTER_TO_INT(can_fd);
struct zcan_frame msg = {0};
struct can_frame frame = {0};
int ret, i;
msg.dlc = 8U;
msg.id_type = CAN_STANDARD_IDENTIFIER;
msg.id = 0x1;
msg.rtr = CAN_DATAFRAME;
for (i = 0; i < msg.dlc; i++) {
msg.data[i] = 0xF0 | i;
}
can_copy_zframe_to_frame(&msg, &frame);
LOG_DBG("Sending CAN data...");
while (1) {
ret = send(fd, &frame, sizeof(frame), 0);
if (ret < 0) {
LOG_ERR("Cannot send CAN message (%d)", -errno);
}
k_sleep(SLEEP_PERIOD);
}
}
static int create_socket(const struct can_filter *filter)
{
struct sockaddr_can can_addr;
int fd, ret;
fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
if (fd < 0) {
LOG_ERR("Cannot create %s CAN socket (%d)", "2nd", fd);
return fd;
}
can_addr.can_ifindex = net_if_get_by_iface(
net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW)));
can_addr.can_family = PF_CAN;
ret = bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (ret < 0) {
LOG_ERR("Cannot bind %s CAN socket (%d)", "2nd", -errno);
(void)close(fd);
return ret;
}
(void)setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, filter,
sizeof(*filter));
return fd;
}
static void rx(int *can_fd, int *do_close_period,
const struct can_filter *filter)
{
int close_period = POINTER_TO_INT(do_close_period);
int fd = POINTER_TO_INT(can_fd);
struct sockaddr_can can_addr;
socklen_t addr_len;
struct zcan_frame msg;
struct can_frame frame;
int ret;
LOG_DBG("[%d] Waiting CAN data...", fd);
while (1) {
uint8_t *data;
memset(&frame, 0, sizeof(frame));
addr_len = sizeof(can_addr);
ret = recvfrom(fd, &frame, sizeof(struct can_frame),
0, (struct sockaddr *)&can_addr, &addr_len);
if (ret < 0) {
LOG_ERR("[%d] Cannot receive CAN message (%d)", fd,
-errno);
continue;
}
can_copy_frame_to_zframe(&frame, &msg);
LOG_INF("[%d] CAN msg: type 0x%x RTR 0x%x EID 0x%x DLC 0x%x",
fd, msg.id_type, msg.rtr, msg.id, msg.dlc);
if (!msg.rtr) {
if (msg.dlc > 8) {
data = (uint8_t *)msg.data_32;
} else {
data = msg.data;
}
LOG_HEXDUMP_INF(data, msg.dlc, "Data");
} else {
LOG_INF("[%d] EXT Remote message received", fd);
}
if (POINTER_TO_INT(do_close_period) > 0) {
close_period--;
if (close_period <= 0) {
(void)close(fd);
k_sleep(K_SECONDS(1));
fd = create_socket(filter);
if (fd < 0) {
LOG_ERR("Cannot get socket (%d)",
-errno);
return;
}
close_period = POINTER_TO_INT(do_close_period);
}
}
}
}
static int setup_socket(void)
{
struct sockaddr_can can_addr;
struct net_if *iface;
int fd, rx_fd;
int ret;
can_copy_zfilter_to_filter(&zfilter, &filter);
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW));
if (!iface) {
LOG_ERR("No CANBUS network interface found!");
return -ENOENT;
}
#ifdef CONFIG_SAMPLE_SOCKETCAN_LOOPBACK_MODE
can_set_mode(DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)), CAN_MODE_LOOPBACK);
#endif
fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
if (fd < 0) {
ret = -errno;
LOG_ERR("Cannot create %s CAN socket (%d)", "1st", ret);
return ret;
}
can_addr.can_ifindex = net_if_get_by_iface(iface);
can_addr.can_family = PF_CAN;
ret = bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (ret < 0) {
ret = -errno;
LOG_ERR("Cannot bind %s CAN socket (%d)", "1st", ret);
goto cleanup;
}
ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &filter,
sizeof(filter));
if (ret < 0) {
ret = -errno;
LOG_ERR("Cannot set CAN sockopt (%d)", ret);
goto cleanup;
}
/* Delay TX startup so that RX is ready to receive */
tx_tid = k_thread_create(&tx_data, tx_stack,
K_THREAD_STACK_SIZEOF(tx_stack),
(k_thread_entry_t)tx, INT_TO_POINTER(fd),
NULL, NULL, PRIORITY, 0, K_SECONDS(1));
if (!tx_tid) {
ret = -ENOENT;
errno = -ret;
LOG_ERR("Cannot create TX thread!");
goto cleanup;
}
LOG_DBG("Started socket CAN TX thread");
LOG_INF("1st RX fd %d", fd);
rx_fd = fd;
#if CONFIG_NET_SOCKETS_CAN_RECEIVERS == 2
fd = create_socket(&filter);
if (fd >= 0) {
rx_tid = k_thread_create(&rx_data, rx_stack,
K_THREAD_STACK_SIZEOF(rx_stack),
(k_thread_entry_t)rx,
INT_TO_POINTER(fd),
INT_TO_POINTER(CLOSE_PERIOD),
&filter, PRIORITY, 0, K_NO_WAIT);
if (!rx_tid) {
ret = -ENOENT;
errno = -ret;
LOG_ERR("Cannot create 2nd RX thread!");
goto cleanup2;
}
LOG_INF("2nd RX fd %d", fd);
} else {
LOG_ERR("2nd RX not created (%d)", fd);
}
#endif
return rx_fd;
#if CONFIG_NET_SOCKETS_CAN_RECEIVERS == 2
cleanup2:
(void)close(rx_fd);
#endif
cleanup:
(void)close(fd);
return ret;
}
void main(void)
{
int fd;
/* Let the device start before doing anything */
k_sleep(K_SECONDS(2));
fd = setup_socket();
if (fd < 0) {
LOG_ERR("Cannot start CAN application (%d)", fd);
return;
}
rx(INT_TO_POINTER(fd), NULL, NULL);
}