Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2018 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <logging/log.h>
LOG_MODULE_REGISTER(net_socket_can_sample, LOG_LEVEL_DBG);

#include <zephyr.h>

#include <net/socket.h>
#include <net/socket_can.h>

#define PRIORITY  7
#define STACKSIZE 750
#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;

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.std_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), K_FOREVER);
		if (ret < 0) {
			LOG_ERR("Cannot send CAN message (%d)", -errno);
		}

		k_sleep(SLEEP_PERIOD);
	}
}

static void rx(int fd)
{
	struct sockaddr_can can_addr;
	socklen_t addr_len;
	struct zcan_frame msg;
	struct can_frame frame;
	int ret;

	LOG_DBG("Waiting CAN data...");

	while (1) {
		u8_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("Cannot receive CAN message (%d)", ret);
			continue;
		}

		can_copy_frame_to_zframe(&frame, &msg);

		LOG_INF("CAN msg: type 0x%x RTR 0x%x EID 0x%x DLC 0x%x",
			msg.id_type, msg.rtr, msg.std_id, msg.dlc);

		if (!msg.rtr) {
			if (msg.dlc > 8) {
				data = (u8_t *)msg.data_32;
			} else {
				data = msg.data;
			}

			LOG_HEXDUMP_INF(data, msg.dlc, "Data");
		} else {
			LOG_INF("EXT Remote message received");
		}
	}
}

static int setup_socket(void)
{
	const struct zcan_filter zfilter = {
		.id_type = CAN_STANDARD_IDENTIFIER,
		.rtr = CAN_DATAFRAME,
		.std_id = 0x1,
		.rtr_mask = 1,
		.std_id_mask = CAN_STD_ID_MASK
	};
	struct can_filter filter;
	struct sockaddr_can can_addr;
	struct net_if *iface;
	int fd;
	int ret;

	can_copy_zfilter_to_filter(&zfilter, &filter);

	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS));
	if (!iface) {
		LOG_ERR("No CANBUS network interface found!");
		return -ENOENT;
	}

	fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
	if (fd < 0) {
		ret = -errno;
		LOG_ERR("Cannot create CAN socket (%d)", 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 CAN socket (%d)", 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");

	return fd;

cleanup:
	(void)close(fd);
	return ret;
}

void main(void)
{
	int fd;

	fd = setup_socket();
	if (fd < 0) {
		LOG_ERR("Cannot start CAN application (%d)", fd);
		return;
	}

	rx(fd);
}