1 /*
2  * Copyright (c) 2020 Alexander Wachter
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/canbus/isotp.h>
9 
10 const struct isotp_fc_opts fc_opts_8_0 = {.bs = 8, .stmin = 0};
11 const struct isotp_fc_opts fc_opts_0_5 = {.bs = 0, .stmin = 5};
12 
13 const struct isotp_msg_id rx_addr_8_0 = {
14 	.std_id = 0x80,
15 #ifdef CONFIG_SAMPLE_CAN_FD_MODE
16 	.flags = ISOTP_MSG_FDF | ISOTP_MSG_BRS,
17 #endif
18 };
19 const struct isotp_msg_id tx_addr_8_0 = {
20 	.std_id = 0x180,
21 #ifdef CONFIG_SAMPLE_CAN_FD_MODE
22 	.dl = 64,
23 	.flags = ISOTP_MSG_FDF | ISOTP_MSG_BRS,
24 #endif
25 };
26 const struct isotp_msg_id rx_addr_0_5 = {
27 	.std_id = 0x01,
28 #ifdef CONFIG_SAMPLE_CAN_FD_MODE
29 	.flags = ISOTP_MSG_FDF | ISOTP_MSG_BRS,
30 #endif
31 };
32 const struct isotp_msg_id tx_addr_0_5 = {
33 	.std_id = 0x101,
34 #ifdef CONFIG_SAMPLE_CAN_FD_MODE
35 	.dl = 64,
36 	.flags = ISOTP_MSG_FDF | ISOTP_MSG_BRS,
37 #endif
38 };
39 
40 const struct device *can_dev;
41 struct isotp_recv_ctx recv_ctx_8_0;
42 struct isotp_recv_ctx recv_ctx_0_5;
43 
44 K_THREAD_STACK_DEFINE(rx_8_0_thread_stack, CONFIG_SAMPLE_RX_THREAD_STACK_SIZE);
45 K_THREAD_STACK_DEFINE(rx_0_5_thread_stack, CONFIG_SAMPLE_RX_THREAD_STACK_SIZE);
46 struct k_thread rx_8_0_thread_data;
47 struct k_thread rx_0_5_thread_data;
48 
49 const char tx_data_large[] =
50 "========================================\n"
51 "|   ____  ___  ____       ____  ____   |\n"
52 "|  |_  _|/ __||    | ___ |_  _||  _ \\  |\n"
53 "|   _||_ \\__ \\| || | ___   ||  | ___/  |\n"
54 "|  |____||___/|____|       ||  |_|     |\n"
55 "========================================\n";
56 
57 const char tx_data_small[] = "This is the sample test for the short payload\n";
58 
rx_8_0_thread(void * arg1,void * arg2,void * arg3)59 void rx_8_0_thread(void *arg1, void *arg2, void *arg3)
60 {
61 	ARG_UNUSED(arg1);
62 	ARG_UNUSED(arg2);
63 	ARG_UNUSED(arg3);
64 	int ret, rem_len, received_len;
65 	struct net_buf *buf;
66 
67 	ret = isotp_bind(&recv_ctx_8_0, can_dev,
68 			 &tx_addr_8_0, &rx_addr_8_0,
69 			 &fc_opts_8_0, K_FOREVER);
70 	if (ret != ISOTP_N_OK) {
71 		printk("Failed to bind to rx ID %d [%d]\n",
72 		       rx_addr_8_0.std_id, ret);
73 		return;
74 	}
75 
76 	while (1) {
77 		received_len = 0;
78 		do {
79 			rem_len = isotp_recv_net(&recv_ctx_8_0, &buf,
80 						 K_MSEC(2000));
81 			if (rem_len < 0) {
82 				printk("Receiving error [%d]\n", rem_len);
83 				break;
84 			}
85 
86 			while (buf != NULL) {
87 				received_len += buf->len;
88 				printk("%.*s", buf->len, buf->data);
89 				buf = net_buf_frag_del(NULL, buf);
90 			}
91 		} while (rem_len);
92 		printk("Got %d bytes in total\n", received_len);
93 	}
94 }
95 
rx_0_5_thread(void * arg1,void * arg2,void * arg3)96 void rx_0_5_thread(void *arg1, void *arg2, void *arg3)
97 {
98 	ARG_UNUSED(arg1);
99 	ARG_UNUSED(arg2);
100 	ARG_UNUSED(arg3);
101 	int ret, received_len;
102 	static uint8_t rx_buffer[32];
103 
104 	ret = isotp_bind(&recv_ctx_0_5, can_dev,
105 			 &tx_addr_0_5, &rx_addr_0_5,
106 			 &fc_opts_0_5, K_FOREVER);
107 	if (ret != ISOTP_N_OK) {
108 		printk("Failed to bind to rx ID %d [%d]\n",
109 		       rx_addr_0_5.std_id, ret);
110 		return;
111 	}
112 
113 	while (1) {
114 		received_len = isotp_recv(&recv_ctx_0_5, rx_buffer,
115 					  sizeof(rx_buffer)-1U, K_MSEC(2000));
116 		if (received_len < 0) {
117 			printk("Receiving error [%d]\n", received_len);
118 			continue;
119 		}
120 
121 		rx_buffer[received_len] = '\0';
122 		printk("%s", rx_buffer);
123 	}
124 }
125 
send_complette_cb(int error_nr,void * arg)126 void send_complette_cb(int error_nr, void *arg)
127 {
128 	ARG_UNUSED(arg);
129 	printk("TX complete cb [%d]\n", error_nr);
130 }
131 
132 /**
133  * @brief Main application entry point.
134  *
135  */
main(void)136 int main(void)
137 {
138 	k_tid_t tid;
139 	static struct isotp_send_ctx send_ctx_8_0;
140 	static struct isotp_send_ctx send_ctx_0_5;
141 	int ret = 0;
142 
143 	can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
144 	if (!device_is_ready(can_dev)) {
145 		printk("CAN: Device driver not ready.\n");
146 		return 0;
147 	}
148 
149 	can_mode_t mode = (IS_ENABLED(CONFIG_SAMPLE_LOOPBACK_MODE) ? CAN_MODE_LOOPBACK : 0) |
150 			  (IS_ENABLED(CONFIG_SAMPLE_CAN_FD_MODE) ? CAN_MODE_FD : 0);
151 	ret = can_set_mode(can_dev, mode);
152 	if (ret != 0) {
153 		printk("CAN: Failed to set mode [%d]", ret);
154 		return 0;
155 	}
156 
157 	ret = can_start(can_dev);
158 	if (ret != 0) {
159 		printk("CAN: Failed to start device [%d]\n", ret);
160 		return 0;
161 	}
162 
163 	tid = k_thread_create(&rx_8_0_thread_data, rx_8_0_thread_stack,
164 			      K_THREAD_STACK_SIZEOF(rx_8_0_thread_stack),
165 			      rx_8_0_thread, NULL, NULL, NULL,
166 			      CONFIG_SAMPLE_RX_THREAD_PRIORITY, 0, K_NO_WAIT);
167 	if (!tid) {
168 		printk("ERROR spawning rx thread\n");
169 		return 0;
170 	}
171 	k_thread_name_set(tid, "rx_8_0");
172 
173 	tid = k_thread_create(&rx_0_5_thread_data, rx_0_5_thread_stack,
174 			      K_THREAD_STACK_SIZEOF(rx_0_5_thread_stack),
175 			      rx_0_5_thread, NULL, NULL, NULL,
176 			      CONFIG_SAMPLE_RX_THREAD_PRIORITY, 0, K_NO_WAIT);
177 	if (!tid) {
178 		printk("ERROR spawning rx thread\n");
179 		return 0;
180 	}
181 	k_thread_name_set(tid, "rx_0_5");
182 
183 	printk("Start sending data\n");
184 
185 	while (1) {
186 		k_msleep(1000);
187 		ret = isotp_send(&send_ctx_0_5, can_dev,
188 				 tx_data_small, sizeof(tx_data_small),
189 				 &tx_addr_0_5, &rx_addr_0_5,
190 				 send_complette_cb, NULL);
191 		if (ret != ISOTP_N_OK) {
192 			printk("Error while sending data to ID %d [%d]\n",
193 			       tx_addr_0_5.std_id, ret);
194 		}
195 
196 		ret = isotp_send(&send_ctx_8_0, can_dev,
197 				 tx_data_large, sizeof(tx_data_large),
198 				 &tx_addr_8_0, &rx_addr_8_0, NULL, NULL);
199 		if (ret != ISOTP_N_OK) {
200 			printk("Error while sending data to ID %d [%d]\n",
201 			       tx_addr_8_0.std_id, ret);
202 		}
203 	}
204 }
205