Skip to content

Commit dd09826

Browse files
committed
Add initial support of ThingSet via CAN ISO-TP
1 parent d5a2299 commit dd09826

File tree

5 files changed

+156
-40
lines changed

5 files changed

+156
-40
lines changed

main/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ set(app_sources
1010
"web_fs.c"
1111
"web_server.c"
1212
"provisioning.c"
13+
"../lib/isotp/isotp.c"
14+
"isotp_user.c"
1315
)
1416

1517
idf_component_register(SRCS ${app_sources} INCLUDE_DIRS ".")

main/can.c

Lines changed: 94 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,28 @@
2121
#include "driver/can.h"
2222
#include "driver/gpio.h"
2323

24+
#include "../lib/isotp/isotp.h"
25+
#include "../lib/isotp/isotp_defines.h"
26+
27+
static const char *TAG = "can";
28+
2429
bool update_bms_received = false;
2530
bool update_mppt_received = false;
2631

2732
#if CONFIG_THINGSET_CAN
2833

34+
#define ISOTP_BUFSIZE 512
35+
36+
/* Alloc IsoTpLink statically in RAM */
37+
static IsoTpLink isotp_link;
38+
39+
/* Alloc send and receive buffer statically in RAM */
40+
static uint8_t isotp_recv_buf[ISOTP_BUFSIZE];
41+
static uint8_t isotp_send_buf[ISOTP_BUFSIZE];
42+
43+
uint32_t can_addr_client = 0xF1; // this device
44+
uint32_t can_addr_server = 0x14; // select MPPT or BMS
45+
2946
// buffer for JSON string generated from received data objects via CAN
3047
static char json_buf[500];
3148

@@ -101,7 +118,8 @@ static int generate_json_string(char *buf, size_t len, DataObject *objs, size_t
101118
switch (objs[i].raw_data[0]) {
102119
case CAN_TS_T_TRUE:
103120
case CAN_TS_T_FALSE:
104-
pos += snprintf(&buf[pos], len - pos, "%d", (objs[i].raw_data[0] == CAN_TS_T_TRUE) ? 1 : 0);
121+
pos += snprintf(&buf[pos], len - pos, "%d",
122+
(objs[i].raw_data[0] == CAN_TS_T_TRUE) ? 1 : 0);
105123
break;
106124
case CAN_TS_T_POS_INT32:
107125
value_abs =
@@ -160,7 +178,6 @@ static int generate_json_string(char *buf, size_t len, DataObject *objs, size_t
160178
return pos;
161179
}
162180

163-
164181
char *get_mppt_json_data()
165182
{
166183
generate_json_string(json_buf, sizeof(json_buf),
@@ -184,69 +201,106 @@ void can_setup()
184201
gpio_set_level(CONFIG_GPIO_CAN_STB, 0);
185202
#endif
186203

187-
if (can_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
188-
printf("CAN driver installed\n");
189-
}
190-
else {
191-
printf("Failed to install CAN driver\n");
204+
if (can_driver_install(&g_config, &t_config, &f_config) != ESP_OK) {
205+
ESP_LOGE(TAG, "Failed to install CAN driver");
192206
return;
193207
}
194208

195-
if (can_start() == ESP_OK) {
196-
printf("CAN driver started\n");
197-
}
198-
else {
199-
printf("Failed to start CAN driver\n");
209+
if (can_start() != ESP_OK) {
210+
ESP_LOGE(TAG, "Failed to start CAN driver");
200211
return;
201212
}
213+
214+
/* Initialize link with the CAN ID we send with */
215+
isotp_init_link(&isotp_link, can_addr_server << 8 | can_addr_client | 0x1ada << 16,
216+
isotp_send_buf, sizeof(isotp_send_buf), isotp_recv_buf, sizeof(isotp_recv_buf));
202217
}
203218

204219
void can_receive_task(void *arg)
205220
{
206221
can_message_t message;
207-
//unsigned int msg_priority; // currently not used
208-
unsigned int node_id;
209-
unsigned int data_object_id;
222+
unsigned int device_addr;
223+
unsigned int data_node_id;
224+
225+
uint8_t payload[500];
210226

211227
while (1) {
212228
if (can_receive(&message, pdMS_TO_TICKS(10000)) == ESP_OK) {
213229

214-
// ThingSet publication message format: https://thingset.github.io/spec/can
215-
//msg_priority = message.identifier >> 26;
216-
node_id = message.identifier & 0x000000FF;
217-
data_object_id = (message.identifier >> 8) & 0x000000FF;
218-
219-
if (node_id == 0) {
220-
for (int i = 0; i < sizeof(data_obj_bms)/sizeof(DataObject); i++) {
221-
if (data_obj_bms[i].id == data_object_id) {
222-
memcpy(data_obj_bms[i].raw_data, message.data, message.data_length_code);
223-
data_obj_bms[i].len = message.data_length_code;
224-
}
230+
/* checking for CAN ID used to receive ISO-TP frames */
231+
if (message.identifier == (can_addr_client << 8 | can_addr_server | 0x1ada << 16)) {
232+
ESP_LOGI(TAG, "ISO TP msg part received");
233+
isotp_on_can_message(&isotp_link, message.data, message.data_length_code);
234+
235+
/* process multiple frame transmissions and timeouts */
236+
isotp_poll(&isotp_link);
237+
238+
/* extract received data */
239+
uint16_t out_size;
240+
int ret = isotp_receive(&isotp_link, payload, sizeof(payload) - 1, &out_size);
241+
if (ret == ISOTP_RET_OK) {
242+
payload[out_size] = '\0';
243+
ESP_LOGI(TAG, "Received %d bytes via ISO-TP: %s", out_size, payload);
244+
/* ToDo: handle received message */
225245
}
226-
update_bms_received = true;
227246
}
228-
else if (node_id == 10) {
229-
for (int i = 0; i < sizeof(data_obj_mppt)/sizeof(DataObject); i++) {
230-
if (data_obj_mppt[i].id == data_object_id) {
231-
memcpy(data_obj_mppt[i].raw_data, message.data, message.data_length_code);
232-
data_obj_mppt[i].len = message.data_length_code;
247+
else {
248+
// ThingSet publication message format: https://thingset.github.io/spec/can
249+
device_addr = message.identifier & 0x000000FF;
250+
data_node_id = (message.identifier >> 8) & 0x0000FFFF;
251+
252+
if (device_addr == 0) {
253+
for (int i = 0; i < sizeof(data_obj_bms) / sizeof(DataObject); i++) {
254+
if (data_obj_bms[i].id == data_node_id) {
255+
memcpy(data_obj_bms[i].raw_data, message.data,
256+
message.data_length_code);
257+
data_obj_bms[i].len = message.data_length_code;
258+
}
233259
}
260+
update_bms_received = true;
261+
}
262+
else if (device_addr == 10) {
263+
for (int i = 0; i < sizeof(data_obj_mppt) / sizeof(DataObject); i++) {
264+
if (data_obj_mppt[i].id == data_node_id) {
265+
memcpy(data_obj_mppt[i].raw_data, message.data,
266+
message.data_length_code);
267+
data_obj_mppt[i].len = message.data_length_code;
268+
}
269+
}
270+
update_mppt_received = true;
234271
}
235-
update_mppt_received = true;
236-
}
237272

238-
printf("CAN msg node %u, data object 0x%.2x = 0x",
239-
node_id, data_object_id);
240-
if (!(message.flags & CAN_MSG_FLAG_RTR)) {
241-
for (int i = 0; i < message.data_length_code; i++) {
242-
printf("%.2x", message.data[i]);
273+
printf("CAN device addr %u, data node 0x%.2x = 0x", device_addr, data_node_id);
274+
if (!(message.flags & CAN_MSG_FLAG_RTR)) {
275+
for (int i = 0; i < message.data_length_code; i++) {
276+
printf("%.2x", message.data[i]);
277+
}
243278
}
279+
printf("\n");
244280
}
245-
printf("\n");
246281
}
247282
}
248283
}
249284

285+
/* dummy task to send regular requests for testing */
286+
void isotp_task(void *arg)
287+
{
288+
//uint8_t ts_request[] = { 0x01, 0x18, 0x70, 0xA0 };
289+
uint8_t ts_request[] = "?output";
290+
291+
while (1) {
292+
293+
int ret = isotp_send(&isotp_link, ts_request, strlen((char *)ts_request));
294+
if (ISOTP_RET_OK == ret) {
295+
printf("ISOTP Send OK\n");
296+
} else {
297+
printf("ISOTP Send ERROR\n");
298+
}
299+
300+
vTaskDelay(3000 / portTICK_PERIOD_MS);
301+
}
302+
}
303+
250304
#else /* not CONFIG_THINGSET_CAN */
251305

252306
char *get_mppt_json_data()

main/can.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ void can_setup();
3434
*/
3535
void can_receive_task(void *arg);
3636

37+
/**
38+
* Thread performing regular requests to other devices using ISO-TP
39+
*/
40+
void isotp_task(void *arg);
41+
3742
/**
3843
* Get data from MPPT connected via CAN bus and convert it to JSON
3944
*

main/isotp_user.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* Copyright (c) 2020 Martin Jäger / Libre Solar
5+
*/
6+
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
#include "esp_system.h"
12+
#include "esp_err.h"
13+
#include "esp_log.h"
14+
15+
#include "driver/can.h"
16+
#include "driver/gpio.h"
17+
18+
#include "../lib/isotp/isotp.h"
19+
20+
/*
21+
* required, this must send a single CAN message with the given arbitration
22+
* ID (i.e. the CAN message ID) and data. The size will never be more than 8
23+
* bytes.
24+
*/
25+
int isotp_user_send_can(const uint32_t arbitration_id,
26+
const uint8_t* data, const uint8_t size)
27+
{
28+
can_message_t msg;
29+
memcpy(msg.data, data, size);
30+
msg.data_length_code = size;
31+
msg.identifier = arbitration_id;
32+
msg.flags = CAN_MSG_FLAG_EXTD;
33+
return can_transmit(&msg, 0);
34+
}
35+
36+
/*
37+
* required, return system tick, unit is millisecond
38+
*/
39+
uint32_t isotp_user_get_ms(void)
40+
{
41+
return esp_timer_get_time() / 1000;
42+
}
43+
44+
/*
45+
* optional, provide to receive debugging log messages
46+
*/
47+
void isotp_user_debug(const char* message, ...)
48+
{
49+
va_list argp;
50+
va_start(argp, message);
51+
printf(message, argp);
52+
va_end(argp);
53+
}

main/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ void app_main(void)
6060
can_setup();
6161
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096,
6262
NULL, RX_TASK_PRIO, NULL, 1);
63+
xTaskCreatePinnedToCore(isotp_task, "CAN_isotp", 1024,
64+
NULL, RX_TASK_PRIO, NULL, 1);
6365
#endif
6466

6567
#if CONFIG_THINGSET_SERIAL

0 commit comments

Comments
 (0)