View difference between Paste ID: kxeKZndu and JdLKETqw
SHOW: | | - or go back to the newest paste.
1
#include <freertos/FreeRTOS.h>
2
#include <freertos/queue.h>
3
#include <freertos/event_groups.h>
4
#include <driver/can.h>
5
#include <nvs_flash.h>
6
#include <esp_task_wdt.h>
7
#include <stdio.h>
8
#include <string.h>
9
#include <sys/time.h>
10
#include "can.h"
11
#include "hci.h"
12
13
const int can_tx_pin = GPIO_NUM_0;
14
const int can_rx_pin = GPIO_NUM_2;
15
16
struct
17
{
18
	can_timing_config_t timing;
19
	can_filter_config_t filter;
20
	can_message_t periodic_messages[8];
21
	uint8_t flags; /* initialized, rx */
22
} can_config;
23
24
can_general_config_t config =
25
{
26
	.mode = CAN_MODE_NORMAL,
27
	.tx_io = can_tx_pin,
28
	.rx_io = can_rx_pin,
29
	.clkout_io = -1,
30
	.bus_off_io = -1,
31
	.tx_queue_len = 10,
32
	.rx_queue_len = 10,
33
	.alerts_enabled = CAN_ALERT_NONE,
34
	.clkout_divider = 0
35
};
36
37
const uint8_t CAN_FLAG_INIT = 1 << 0;
38
const uint8_t CAN_FLAG_RX_ON = 1 << 1;
39
static QueueHandle_t can_rx_queue;
40
static EventBits_t can_reinstall_done = 1 << 0;
41
static EventGroupHandle_t can_event_group;
42
struct can_rx_event
43
{
44
	uint8_t event;
45
};
46
47
enum
48
{
49
	EVENT_CAN_RX_OFF = 0,
50
	EVENT_CAN_RX_ON = 1,
51
	EVENT_CAN_REINSTALL = 2
52
};
53
54
55
int can_init()
56
{
57
	esp_err_t err;
58
	/* Setup default timing */
59
	can_config.timing.brp = 8;
60
	can_config.timing.tseg_1 = 5;
61
	can_config.timing.tseg_2 = 4;
62
	can_config.timing.sjw = 1;
63
	/* Setup default filter */
64
	can_config.filter.acceptance_code = 0;
65
	can_config.filter.acceptance_mask = 0xffffffff;
66
	can_config.filter.single_filter = 1;
67
	err = can_driver_install(&config, &can_config.timing, &can_config.filter);
68
69
	if(err != ESP_OK)
70
	{
71
		printf("ERR CAN init failed!\n");
72
		return -1;
73
	}
74
75
	err = can_start();
76
	if(err != ESP_OK)
77
	{
78
		printf("ERR CAN init failed!\n");
79
		return -1;
80
	}
81
82
	can_event_group = xEventGroupCreate();
83
	can_config.flags |= CAN_FLAG_INIT;
84
	return 0;
85
}
86
87
int can_reinstall()
88
{
89
	esp_err_t err;
90
	can_stop();
91
	can_driver_uninstall();
92
	/* Setup default timing */
93
	err = can_driver_install(&config, &can_config.timing, &can_config.filter);
94
	if(err != ESP_OK)
95
		return -1;
96
	err = can_start();
97
	if(err != ESP_OK)
98
		return -1;
99
	return 0;
100
}
101
102
int parse_message_format(can_message_t *msg, const char *fmt)
103
{
104
	uint32_t id;
105
	char remote;
106
	memset(msg, 0, sizeof(*msg));
107
	sscanf(fmt, "%x#%c", &id, &remote);
108
	msg->flags |= CAN_MSG_FLAG_SS;
109
	if(remote == 'R')
110
	{
111
		msg->flags |= CAN_MSG_FLAG_RTR;
112
		msg->identifier = id;
113
		msg->data_length_code = 0;
114
	}
115
	else
116
	{
117
		int data[8];
118
		int ret = sscanf(fmt, "%x#%2x%2x%2x%2x%2x%2x%2x%2x",
119
			&id, &data[0], &data[1], &data[2], &data[3],
120
			&data[4], &data[5], &data[6], &data[7]);
121
		if(ret < 1)
122
			return -1;
123
		int len = ret - 1;
124
		msg->identifier = id;
125
		msg->data_length_code = len;
126
		for(int i = 0; i < len; i++)
127
			msg->data[i] = data[i];
128
	}
129
130
	return 0;
131
}
132
133
void can_command()
134
{
135
	char *cmd = strtok(NULL, " ");
136
	esp_err_t err;
137
	/* Make sure we have a command */
138
	if(!cmd)
139
		goto einval;
140
	/*
141
	 * Compare commande against known commands and handle them, otherwise tell
142
	 * the user it was invalid.
143
	 */
144
	if(strcmp(cmd, "help") == 0)
145
	{
146
		printf("OK\n");
147
		printf(
148
			"Available commands:\n"
149
			"Source clock: 80 MHz\n"
150
			"CAN bitrate = 80 000 000 / brp / (1 + tseg_1 + tseg_2)\n"
151
			"\n"
152
			"can help - write this text\n"
153
			"can rx on/off - enable or disable RX\n"
154
			"can send <id>#<data in hex> - e.g. send 13f#02e8\n"
155
			"can config brp [value] - get or set current can brp (2-128, even)\n"
156
			"can config tseg_1 [value] - get or set current can tseg_1 (1-16)\n"
157
			"can config tseg_2 [value] - get or set current can tseg_2 (1-8)\n"
158
			"can config sjw [value] - get or set current can sjw (1-4)\n"
159
			"\n");
160
	}
161
	else if(strcmp(cmd, "rx") == 0)
162
	{
163
		const char *arg = strtok(NULL, " ");
164
165
		if(strcmp(arg, "on") == 0)
166
			can_rx_on();
167
		else if(strcmp(arg, "off") == 0)
168
			can_rx_off();
169
		else
170
			goto einval;
171
	}
172
	else if(strcmp(cmd, "send") == 0)
173
	{
174
		can_message_t msg;
175
		const char *msg_str = strtok(NULL, " ");
176
177
		memset(&msg, 0, sizeof(msg));
178
		if(parse_message_format(&msg, msg_str) < 0)
179
			goto einval;
180
		struct timeval current_time;
181
		gettimeofday(&current_time, NULL);
182
		/* printf("seconds : %ld\nmicro seconds : %ld", current_time.tv_sec, current_time.tv_usec); */
183
		/* unsigned long currentMillis = xTaskGetTickCount(); */
184
		unsigned long time_in_micros = 1000000 * current_time.tv_sec + current_time.tv_usec;
185
		printf("T: %ld SENT %x#", time_in_micros, msg.identifier);
186
		for(int i = 0; i < msg.data_length_code; i++)
187
			printf("%02x", msg.data[i]);
188
		printf("\n");
189
		err = can_transmit(&msg, 0);
190
		if(err != ESP_OK)
191
		{
192
			printf("ERR Transmit failed!\n");
193
			/*
194
			 * If we get to many transmission errors due to non-acked frames
195
			 * then the bus will go into an error state, restart it by
196
			 * reinstalling it.
197
			 */
198
			can_send_reinstall();
199
			return;
200
		}
201
202
	}
203
		else if(strcmp(cmd, "sendex") == 0)
204
	{
205
		can_message_t msg;
206
		const char *msg_str = strtok(NULL, " ");
207
208
		memset(&msg, 0, sizeof(msg));
209
		if(parse_message_format(&msg, msg_str) < 0)
210
			goto einval;
211
		msg.extd = 1;
212
		struct timeval current_time;
213
		gettimeofday(&current_time, NULL);
214
		/* printf("seconds : %ld\nmicro seconds : %ld", current_time.tv_sec, current_time.tv_usec); */
215
		/* unsigned long currentMillis = xTaskGetTickCount(); */
216
		unsigned long time_in_micros = 1000000 * current_time.tv_sec + current_time.tv_usec;
217
		printf("T: %ld SENT %x#", time_in_micros, msg.identifier);
218
		for(int i = 0; i < msg.data_length_code; i++)
219
			printf("%02x", msg.data[i]);
220
		printf("\n");
221
		err = can_transmit(&msg, 0);
222
		if(err != ESP_OK)
223
		{
224
			printf("ERR Transmit failed!\n");
225
226
			/*
227
			 * If we get to many transmission errors due to non-acked frames
228
			 * then the bus will go into an error state, restart it by
229
			 * reinstalling it.
230
			 */
231
			can_send_reinstall();
232
233
			return;
234
		}
235
236
	}
237
	else if(strcmp(cmd, "config") == 0)
238
	{
239
		/* Read value argument */
240
		const char *arg = strtok(NULL, " ");
241
		if(!arg)
242
			goto einval;
243
		if(strcmp(arg, "brp") == 0)
244
		{
245
			const char *value_str = strtok(NULL, " ");
246
			if(!value_str)
247
				printf("OK %d\n", can_config.timing.brp);
248
249
			else
250
			{
251
				int value = atoi(value_str);
252
253
				if(value < 2 || value > 127 || value % 2)
254
					goto einval;
255
				can_config.timing.brp = value;
256
				can_send_reinstall();
257
			}
258
		}
259
		else if(strcmp(arg, "tseg_1") == 0)
260
		{
261
			const char *value_str = strtok(NULL, " ");
262
			if(!value_str)
263
				printf("OK %d\n", can_config.timing.tseg_1);
264
			else
265
			{
266
				int value = atoi(value_str);
267
				if(value < 1 || value > 16 )
268
					goto einval;
269
				can_config.timing.tseg_1 = value;
270
				can_send_reinstall();
271
			}
272
		}
273
		else if(strcmp(arg, "tseg_2") == 0)
274
		{
275
			const char *value_str = strtok(NULL, " ");
276
			if(!value_str)
277
				printf("OK %d\n", can_config.timing.tseg_2);
278
			else
279
			{
280
				int value = atoi(value_str);
281
				if(value < 1 || value > 8 )
282
					goto einval;
283
				can_config.timing.tseg_2 = value;
284
				can_send_reinstall();
285
			}
286
		}
287
		else if(strcmp(arg, "sjw") == 0)
288
		{
289
			const char *value_str = strtok(NULL, " ");
290
			if(!value_str)
291
				printf("OK %d\n", can_config.timing.sjw);
292
			else
293
			{
294
				int value = atoi(value_str);
295
				if(value < 1 || value > 4 )
296
					goto einval;
297
				can_config.timing.sjw = value;
298
				can_send_reinstall();
299
			}
300
		}
301
		else
302
			goto einval;
303
	}
304
	else if(strcmp(cmd, "status") == 0)
305
	{
306
	}
307
	else
308
		goto einval;
309
	return;
310
311
einval:
312
	printf("INVALID COMMAND");
313
	return;
314
}
315
316
void can_rx_off()
317
{
318
	struct can_rx_event event =
319
	{
320
		.event = EVENT_CAN_RX_OFF
321
	};
322
	xQueueSendToBack(can_rx_queue, &event, 0);
323
}
324
325
void can_rx_on()
326
{
327
	struct can_rx_event event =
328
	{
329
		.event = EVENT_CAN_RX_ON
330
	};
331
	xQueueSendToBack(can_rx_queue, &event, 0);
332
}
333
334
void can_send_reinstall()
335
{
336
	struct can_rx_event event =
337
	{
338
		.event = EVENT_CAN_REINSTALL
339
	};
340
	xQueueSendToBack(can_rx_queue, &event, 0);
341
	/* Wait for reinstallation done */
342
	xEventGroupWaitBits(can_event_group, can_reinstall_done, 1, 1, 1000 * portTICK_PERIOD_MS);
343
}
344
345
void can_rx_thread(void *parameters)
346
{
347
	/* Check that CAN initialized correctly */
348
	while(!(can_config.flags & CAN_FLAG_INIT))
349
		vTaskDelay(100 * portTICK_PERIOD_MS);
350
	esp_task_wdt_delete(xTaskGetCurrentTaskHandle());
351
	can_rx_queue = xQueueCreate(10, sizeof(struct can_rx_event));
352
	int rx_running = 0;
353
354
	while(1)
355
	{
356
		can_message_t msg;
357
		while(can_receive(&msg, 10) == ESP_OK)
358
		{
359
			/* AUTOPING */
360
			/* can_transmit(&msg, 0); */
361
			/* AUTOPING */
362
			if(rx_running)
363
			{
364
				
365
				struct timeval tvr;
366
				gettimeofday(&tvr, NULL);
367
				/* unsigned long currentMillis = xTaskGetTickCount(); */
368
				unsigned long time_in_micros = 1000000 * tvr.tv_sec + tvr.tv_usec;
369
				printf("T: %ld CAN RX: %x#", time_in_micros, msg.identifier);
370
				if(msg.flags & CAN_MSG_FLAG_RTR)
371
					printf("R");
372
				else
373
					for(int i = 0; i < msg.data_length_code; i++)
374
						printf("%02x", msg.data[i]);
375
				/* 
376
				if (msg.extd) 
377
    				printf("Message is in Extended Format\n");
378
				else 
379
   					printf("Message is in Standard Format\n");
380
				*/
381
382
				printf("\n");
383
			}
384
		}
385
386
		struct can_rx_event event;
387
		if(xQueueReceive(can_rx_queue, &event, 0))
388
		{
389
			if(event.event == EVENT_CAN_RX_OFF)
390
			{
391
				rx_running = 0;
392
				printf("OK\n");
393
			}
394
395
			else if(event.event == EVENT_CAN_RX_ON)
396
			{
397
				rx_running = 1;
398
				printf("OK\n");
399
			}
400
401
			else if(event.event == EVENT_CAN_REINSTALL)
402
			{
403
				if(can_reinstall() < 0)
404
					printf("ERR Unknown error\n");
405
				else
406
					printf("OK\n");
407
				/* Also perform a full recovery which helps on bus-off recovery */
408
				can_initiate_recovery();
409
410
				while(1)
411
				{
412
					twai_status_info_t info;
413
					twai_get_status_info(&info);
414
					if(info.state != CAN_STATE_RECOVERING)
415
						break;
416
				}
417
418
				xEventGroupSetBits(can_event_group, can_reinstall_done);
419
			}
420
		}
421
	}
422
}