/*
 * 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/kernel.h>

#include <zephyr/drivers/can.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/socketcan.h>
#include <zephyr/net/socketcan_utils.h>

#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 can_filter zfilter = {
	.flags = 0U,
	.id = 0x1,
	.mask = CAN_STD_ID_MASK
};

static struct socketcan_filter sock_filter;

static void tx(void *p1, void *p2, void *p3)
{
	ARG_UNUSED(p2);
	ARG_UNUSED(p3);

	int *can_fd = p1;
	int fd = POINTER_TO_INT(can_fd);
	struct can_frame zframe = {0};
	struct socketcan_frame sframe = {0};
	int ret, i;

	zframe.id = 0x1;
	zframe.dlc = 8U;

	for (i = 0; i < zframe.dlc; i++) {
		zframe.data[i] = 0xF0 | i;
	}

	socketcan_from_can_frame(&zframe, &sframe);

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

	while (1) {
		ret = send(fd, &sframe, sizeof(sframe), 0);
		if (ret < 0) {
			LOG_ERR("Cannot send CAN frame (%d)", -errno);
		}

		k_sleep(SLEEP_PERIOD);
	}
}

static int create_socket(const struct socketcan_filter *sfilter)
{
	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, sfilter,
			 sizeof(*sfilter));

	return fd;
}

static void rx(void *p1, void *p2, void *p3)
{
	int *can_fd = p1;
	int *do_close_period = p2;
	const struct socketcan_filter *sfilter = p3;
	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 can_frame zframe;
	struct socketcan_frame sframe;
	int ret;

	LOG_DBG("[%d] Waiting CAN data...", fd);

	while (1) {
		uint8_t *data;

		memset(&sframe, 0, sizeof(sframe));
		addr_len = sizeof(can_addr);

		ret = recvfrom(fd, &sframe, sizeof(struct socketcan_frame),
			       0, (struct sockaddr *)&can_addr, &addr_len);
		if (ret < 0) {
			LOG_ERR("[%d] Cannot receive CAN frame (%d)", fd,
				-errno);
			continue;
		}

		socketcan_to_can_frame(&sframe, &zframe);

		LOG_INF("[%d] CAN frame: IDE 0x%x RTR 0x%x ID 0x%x DLC 0x%x",
			fd,
			(zframe.flags & CAN_FRAME_IDE) != 0 ? 1 : 0,
			(zframe.flags & CAN_FRAME_RTR) != 0 ? 1 : 0,
			zframe.id, zframe.dlc);

		if ((zframe.flags & CAN_FRAME_RTR) != 0) {
			LOG_INF("[%d] EXT Remote frame received", fd);
		} else {
			if (zframe.dlc > 8) {
				data = (uint8_t *)zframe.data_32;
			} else {
				data = zframe.data;
			}

			LOG_HEXDUMP_INF(data, zframe.dlc, "Data");
		}

		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(sfilter);
				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;

	socketcan_from_can_filter(&zfilter, &sock_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;
	}

	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, &sock_filter,
			 sizeof(sock_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),
				 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(&sock_filter);
	if (fd >= 0) {
		rx_tid = k_thread_create(&rx_data, rx_stack,
					 K_THREAD_STACK_SIZEOF(rx_stack),
					 rx,
					 INT_TO_POINTER(fd),
					 INT_TO_POINTER(CLOSE_PERIOD),
					 &sock_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;
}

int main(void)
{
	const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
	int ret;
	int fd;

#ifdef CONFIG_SAMPLE_SOCKETCAN_LOOPBACK_MODE
	ret = can_set_mode(dev, CAN_MODE_LOOPBACK);
	if (ret != 0) {
		LOG_ERR("Cannot set CAN loopback mode (%d)", ret);
		return 0;
	}
#endif

	ret = can_start(dev);
	if (ret != 0) {
		LOG_ERR("Cannot start CAN controller (%d)", ret);
		return 0;
	}

	/* 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 0;
	}

	rx(INT_TO_POINTER(fd), NULL, NULL);
	return 0;
}
