Skip to content

Commit 07f14d4

Browse files
authored
First commit
1 parent a474fa3 commit 07f14d4

File tree

2 files changed

+334
-0
lines changed

2 files changed

+334
-0
lines changed

CAN.ino

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
const twai_message_t
2+
ehu_bong_start={ .identifier=0x201, .data_length_code=3, .data={0x01, 0xFF, 0x00}},
3+
ehu_bong_end={ .identifier=0x201, .data_length_code=3, .data={0x01, 0xFF, 0x32}},
4+
opcom_helloEHU={ .identifier=0x241, .data_length_code=8, .data={0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // expect 641 # 01 60 ...
5+
opcom_resetEHU={ .identifier=0x241, .data_length_code=8, .data={0x03, 0x3B, 0x5E, 0x01, 0x55, 0x55, 0x55, 0x55}}, // expect 641 # 03 7F 3B 78 ... and 641 # 02 7B 5E afterwards
6+
opcom_requestPartID={ .identifier=0x241, .data_length_code=8, .data={0x02, 0x1A, 0x9A, 0x55, 0x55, 0x55, 0x55, 0x55}},
7+
opcom_requestCodeIndex={ .identifier=0x241, .data_length_code=8, .data={0x02, 0x1A, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00}},
8+
opcom_requestSwVer={ .identifier=0x241, .data_length_code=8, .data={0x02, 0x1A, 0x7B, 0x55, 0x55, 0x55, 0x55, 0x55}},
9+
ISO_AcceptTransmission={ .identifier=0x241, .data_length_code=8, .data={0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
10+
opcom_requestCodeIndexDump={ .identifier=0x241, .data_length_code=8, .data={0x06, 0x23, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x00}};
11+
12+
13+
const twai_message_t
14+
codeIndex01201[26]={ // entire struct of the 01201 code index
15+
{ .identifier=0x241, .data_length_code=8, .data={0x10, 0xB0, 0x3B, 0x3E, 0x00, 0x00, 0xAB, 0x30}},
16+
{ .identifier=0x241, .data_length_code=8, .data={0x21, 0x31, 0x32, 0x30, 0x31, 0x00, 0x00, 0x02}},
17+
{ .identifier=0x241, .data_length_code=8, .data={0x22, 0x05, 0x0A, 0x00, 0x00, 0xDE, 0x03, 0x00}},
18+
{ .identifier=0x241, .data_length_code=8, .data={0x23, 0xE4, 0x00, 0x04, 0x00, 0x00, 0x0E, 0x00}},
19+
{ .identifier=0x241, .data_length_code=8, .data={0x24, 0x00, 0xE9, 0x00, 0x00, 0x00, 0xE8, 0x28}},
20+
{ .identifier=0x241, .data_length_code=8, .data={0x25, 0x00, 0x01, 0x64, 0xC8, 0xFF, 0x01, 0x64}},
21+
{ .identifier=0x241, .data_length_code=8, .data={0x26, 0xC8, 0xFF, 0xB3, 0x00, 0x00, 0x00, 0x32}},
22+
{ .identifier=0x241, .data_length_code=8, .data={0x27, 0x48, 0x48, 0x4C, 0x1E, 0x46, 0xB4, 0x50}},
23+
{ .identifier=0x241, .data_length_code=8, .data={0x28, 0x96, 0x02, 0x32, 0x48, 0x00, 0x28, 0x4C}},
24+
{ .identifier=0x241, .data_length_code=8, .data={0x29, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
25+
{ .identifier=0x241, .data_length_code=8, .data={0x2A, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x05}},
26+
{ .identifier=0x241, .data_length_code=8, .data={0x2B, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
27+
{ .identifier=0x241, .data_length_code=8, .data={0x2C, 0x00, 0x00, 0x00, 0x15, 0x23, 0x03, 0x01}},
28+
{ .identifier=0x241, .data_length_code=8, .data={0x2D, 0x00, 0x11, 0x1F, 0x03, 0x00, 0x00, 0x27}},
29+
{ .identifier=0x241, .data_length_code=8, .data={0x2E, 0x00, 0x00, 0x00, 0x21, 0x09, 0x03, 0x00}},
30+
{ .identifier=0x241, .data_length_code=8, .data={0x2F, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00}},
31+
{ .identifier=0x241, .data_length_code=8, .data={0x20, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00}},
32+
{ .identifier=0x241, .data_length_code=8, .data={0x21, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00}},
33+
{ .identifier=0x241, .data_length_code=8, .data={0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
34+
{ .identifier=0x241, .data_length_code=8, .data={0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
35+
{ .identifier=0x241, .data_length_code=8, .data={0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
36+
{ .identifier=0x241, .data_length_code=8, .data={0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
37+
{ .identifier=0x241, .data_length_code=8, .data={0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
38+
{ .identifier=0x241, .data_length_code=8, .data={0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
39+
{ .identifier=0x241, .data_length_code=8, .data={0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
40+
{ .identifier=0x241, .data_length_code=8, .data={0x29, 0x00, 0x5A, 0x00, 0x00, 0xAE, 0x00, 0x00}}
41+
};
42+
43+
// below functions are used to simplify interaction with freeRTOS eventGroups
44+
void setFlag(uint32_t bit){
45+
xEventGroupSetBits(eventGroup, bit);
46+
}
47+
48+
// clears an event bit
49+
void clearFlag(uint32_t bit){
50+
xEventGroupClearBits(eventGroup, bit);
51+
}
52+
53+
// waits for an event bit to be set, blocking indefinitely if 2nd argument not provided
54+
void waitForFlag(uint32_t bit, TickType_t ticksToWait=portMAX_DELAY){
55+
xEventGroupWaitBits(eventGroup, bit, pdFALSE, pdTRUE, ticksToWait);
56+
}
57+
58+
// Check if a specific event bit is set (without blocking)
59+
bool checkFlag(uint32_t bit){
60+
EventBits_t bits=xEventGroupGetBits(eventGroup);
61+
return (bits&bit)!=0;
62+
}
63+
// initializing CAN communication
64+
void twai_init(){
65+
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_5, GPIO_NUM_4, TWAI_MODE_NORMAL); // CAN bus set up
66+
g_config.rx_queue_len=40;
67+
g_config.tx_queue_len=5;
68+
g_config.intr_flags=(ESP_INTR_FLAG_NMI & ESP_INTR_FLAG_IRAM); // run the TWAI driver at the highest possible priority
69+
twai_timing_config_t t_config = {.brp = 42, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}; // set CAN prescalers and time quanta for 95kbit
70+
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
71+
DEBUG_PRINT("\nCAN/TWAI SETUP => ");
72+
if(twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
73+
DEBUG_PRINT("DRV_INSTALL: OK ");
74+
} else {
75+
DEBUG_PRINT("DRV_INST: FAIL ");
76+
}
77+
if (twai_start() == ESP_OK) {
78+
DEBUG_PRINT("DRV_START: OK ");
79+
} else {
80+
DEBUG_PRINT("DRV_START: FAIL ");
81+
}
82+
uint32_t alerts_to_enable=TWAI_ALERT_TX_SUCCESS;
83+
if(twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK){
84+
DEBUG_PRINTLN("ALERTS: OK \n");
85+
} else {
86+
DEBUG_PRINTLN("ALERTS: FAIL \n");
87+
}
88+
}
89+
90+
// this task only reads CAN messages, filters them and enqueues them to be decoded ansynchronously
91+
void canReceiveTask(void *pvParameters){
92+
twai_message_t Recvd_CAN_MSG;
93+
while(1){
94+
if(twai_receive(&Recvd_CAN_MSG, portMAX_DELAY)==ESP_OK){
95+
switch(Recvd_CAN_MSG.identifier){
96+
case 0x201:
97+
case 0x641:
98+
xQueueSend(canRxQueue, &Recvd_CAN_MSG, portMAX_DELAY); // queue the message contents to be read at a later time
99+
break;
100+
default: break;
101+
}
102+
}
103+
}
104+
}
105+
106+
// this task processes filtered CAN frames read from canRxQueue
107+
void canProcessTask(void *pvParameters){
108+
static twai_message_t RxMsg;
109+
uint8_t sw_year=0, sw_month[2]={0}, sw_day[2]={0};
110+
while(1){
111+
xQueueReceive(canRxQueue, &RxMsg, portMAX_DELAY); // receives data from the internal queue
112+
switch(RxMsg.identifier){
113+
case 0x201: {
114+
switch(RxMsg.data[1]){
115+
case 0x37:{
116+
if(!checkFlag(CAN_softwareVersionOkay) && RxMsg.data[2]==20){
117+
xQueueSend(canTxQueue, &opcom_requestSwVer, portMAX_DELAY);
118+
setFlag(CAN_softwareVersionRequested);
119+
DEBUG_PRINTF("Checking the software version...\r\n");
120+
} else {
121+
if(checkFlag(CAN_softwareVersionOkay) && RxMsg.data[2]==20){
122+
setFlag(CAN_startDumping);
123+
xQueueSend(canTxQueue, &opcom_requestCodeIndexDump, portMAX_DELAY);
124+
}
125+
}
126+
break;
127+
}
128+
case 0x39:{
129+
if(RxMsg.data[2]==0x0A && checkFlag(CAN_dumpingFinished) && checkFlag(CAN_softwareVersionOkay)) setFlag(CAN_startProgramming);
130+
break;
131+
}
132+
default: break;
133+
}
134+
break;
135+
}
136+
case 0x641:{ // this will dump all the received data from 0x641
137+
if(checkFlag(CAN_waitingForISO) && RxMsg.data[0]==0x10){ // this is a mess, yes. but it does work - if it ain't broken, don't fix it.
138+
xQueueSend(canTxQueue, &ISO_AcceptTransmission, portMAX_DELAY);
139+
clearFlag(CAN_waitingForISO);
140+
}
141+
if(checkFlag(CAN_softwareVersionOkay) && !checkFlag(CAN_softwareVersionWrong) && checkFlag(CAN_softwareVersionReceived) && !checkFlag(CAN_programmingFinished)){
142+
if(checkFlag(CAN_startDumping) && !checkFlag(CAN_startProgramming) && !checkFlag(CAN_dumpingFinished) && RxMsg.data[0]!=0x30){
143+
if(RxMsg.data[0]==0x10) DEBUG_PRINTF("Starting index code dump, make sure to save this data:\r\n");
144+
DEBUG_PRINTF("%03X # %02X %02X %02X %02X %02X %02X %02X %02X\r\n", RxMsg.identifier, RxMsg.data[0], RxMsg.data[1], RxMsg.data[2], RxMsg.data[3], RxMsg.data[4], RxMsg.data[5], RxMsg.data[6], RxMsg.data[7], RxMsg.data[8]);
145+
}
146+
if(checkFlag(CAN_startProgramming) && checkFlag(CAN_dumpingFinished) && RxMsg.data[0]==0x30){
147+
DEBUG_PRINTF("Got a programming accept sequence!\r\n");
148+
}
149+
if(checkFlag(CAN_startDumping) && RxMsg.data[1]==0x5A){
150+
DEBUG_PRINTF("Index code dump finished!\r\n");
151+
xQueueSend(canTxQueue, &ehu_bong_start, portMAX_DELAY);
152+
xQueueSend(canTxQueue, &ehu_bong_end, portMAX_DELAY);
153+
setFlag(CAN_dumpingFinished);
154+
clearFlag(CAN_startDumping);
155+
DEBUG_PRINTF("\r\n======== DUMPING FINISHED! ========\r\n Now press 9 for about 2 seconds to attempt the code index programming.\r\n");
156+
DEBUG_PRINTF("Please note that this is experimental and you're solely responsible for whatever happens.\r\n");
157+
}
158+
if(checkFlag(CAN_dumpingFinished) && RxMsg.identifier==0x641 && RxMsg.data[0]==0x30 && checkFlag(CAN_requestedCodeIndexProgramming)){
159+
setFlag(CAN_receivedProgrammingAllow);
160+
}
161+
if(checkFlag(CAN_receivedProgrammingAllow) && RxMsg.data[0]==0x02 && RxMsg.data[1]==0x7B && RxMsg.data[2]==0x3E){
162+
setFlag(CAN_programmingFinished);
163+
}
164+
} else { // software version not yet checked, do that now
165+
if(checkFlag(CAN_softwareVersionRequested) && !checkFlag(CAN_softwareVersionReceived)){
166+
if(RxMsg.data[0]==0x10 && RxMsg.data[3]==0x7B){
167+
sw_day[0]=RxMsg.data[4];
168+
sw_day[1]=RxMsg.data[5];
169+
sw_month[0]=RxMsg.data[7];
170+
}
171+
if(RxMsg.data[0]==0x21){
172+
sw_month[1]=RxMsg.data[1];
173+
sw_year=RxMsg.data[6];
174+
setFlag(CAN_softwareVersionReceived);
175+
}
176+
}
177+
if(checkFlag(CAN_softwareVersionReceived) && !checkFlag(CAN_programmingFinished)){
178+
if((sw_day[0]==0x31 && sw_day[1]==0x30 && sw_month[0]==0x31 && sw_month[1]==0x30 && sw_year==0x37) || (sw_day[0]==0x32 && sw_day[1]==0x30 && sw_month[0]==0x30 && sw_month[1]==0x36 && sw_year==0x38)){ // either 10.10.2007 or 20.06.2008
179+
DEBUG_PRINTF("Detected valid software version to attempt the code index programming! Now hold 7 for 2 seconds to begin dumping the code index.\r\n");
180+
setFlag(CAN_softwareVersionOkay);
181+
ehu_force_testmode();
182+
} else {
183+
DEBUG_PRINTF("Got version %02X %02X %02X %02X %02X\r\n", sw_day[0], sw_day[1], sw_month[0], sw_month[1], sw_year);
184+
setFlag(CAN_softwareVersionWrong);
185+
}
186+
}
187+
}
188+
break;
189+
}
190+
default: break;
191+
}
192+
}
193+
}
194+
195+
// this task receives CAN messages from canTxQueue and transmits them asynchronously
196+
void canTransmitTask(void *pvParameters){
197+
static twai_message_t TxMessage;
198+
uint32_t alerts_triggered;
199+
int alert_result;
200+
while(1){
201+
xQueueReceive(canTxQueue, &TxMessage, portMAX_DELAY);
202+
TxMessage.extd=0;
203+
TxMessage.rtr=0;
204+
TxMessage.ss=0;
205+
TxMessage.self=0;
206+
//DEBUG_PRINTF("%03X # %02X %02X %02X %02X %02X %02X %02X %02X", TxMessage.identifier, TxMessage.data[0], TxMessage.data[1], TxMessage.data[2], TxMessage.data[3], TxMessage.data[4], TxMessage.data[5], TxMessage.data[6], TxMessage.data[7]);
207+
if(twai_transmit(&TxMessage, pdMS_TO_TICKS(50))==ESP_OK) {
208+
//DEBUG_PRINT(" Q:OK ");
209+
} else {
210+
//DEBUG_PRINT("Q:FAIL ");
211+
//setFlag(CAN_prevTxFail);
212+
}
213+
alert_result=twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(10)); // read stats
214+
if(alert_result==ESP_OK){
215+
//DEBUG_PRINT("AR:OK ");
216+
if(alerts_triggered & TWAI_ALERT_TX_SUCCESS){
217+
//DEBUG_PRINTLN("TX:OK ");
218+
if(TxMessage.identifier==0x241){ // transmitted the request for programming the code index, set the flag.
219+
setFlag(CAN_waitingForISO);
220+
}
221+
222+
} else {
223+
DEBUG_PRINTLN("TX:FAIL ");
224+
//setFlag(CAN_prevTxFail);
225+
}
226+
} else {
227+
DEBUG_PRINT("AR:FAIL:");
228+
if(alert_result==ESP_ERR_INVALID_ARG){
229+
DEBUG_PRINTLN("INV_ARG");
230+
}
231+
if(alert_result==ESP_ERR_INVALID_STATE){
232+
DEBUG_PRINTLN("INV_STATE");
233+
}
234+
if(alert_result==ESP_ERR_TIMEOUT){
235+
DEBUG_PRINTLN("TIMEOUT");
236+
}
237+
}
238+
}
239+
}
240+
241+
void indexProgrammerTask(void *pvParameters){
242+
DEBUG_PRINTF("IndexProgrammer: started.\r\n");
243+
waitForFlag(CAN_dumpingFinished);
244+
waitForFlag(CAN_startProgramming);
245+
vTaskDelay(pdMS_TO_TICKS(1000));
246+
#ifdef DISABLE_PROGRAMMING
247+
while(1){
248+
DEBUG_PRINTLN("PROGRAMMING DISABLED!\r\n");
249+
vTaskDelay(10000);
250+
}
251+
#endif
252+
while(1){
253+
setFlag(CAN_requestedCodeIndexProgramming);
254+
xQueueSend(canTxQueue, &codeIndex01201[0], portMAX_DELAY);
255+
waitForFlag(CAN_receivedProgrammingAllow);
256+
for(int i=1; i<26; i++){
257+
xQueueSend(canTxQueue, &codeIndex01201[i], portMAX_DELAY);
258+
vTaskDelay(pdMS_TO_TICKS(15));
259+
}
260+
waitForFlag(CAN_programmingFinished);
261+
DEBUG_PRINTLN("Programming finished! Now resetting the headunit...");
262+
vTaskDelay(pdMS_TO_TICKS(1000));
263+
xQueueSend(canTxQueue, &opcom_resetEHU, portMAX_DELAY);
264+
DEBUG_PRINTF("Headunit has been reset! Check whether Aux is available in the audio menu.");
265+
while(1){
266+
vTaskDelay(10000);
267+
}
268+
}
269+
}
270+
271+
void ehu_force_testmode(){
272+
xQueueSend(canTxQueue, &ehu_bong_start, portMAX_DELAY);
273+
xQueueSend(canTxQueue, &ehu_bong_end, portMAX_DELAY);
274+
}

CodeIndexProgrammer.ino

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "driver/twai.h"
2+
#define DEBUG
3+
//#define DISABLE_PROGRAMMING
4+
5+
#ifdef DEBUG
6+
#define DEBUG_SERIAL(X) Serial.begin(X)
7+
#define DEBUG_PRINT(X) Serial.print(X)
8+
#define DEBUG_PRINTLN(X) Serial.println(X)
9+
#define DEBUG_PRINTF(...) Serial.printf(__VA_ARGS__)
10+
#else
11+
#define DEBUG_SERIAL(X)
12+
#define DEBUG_PRINT(X)
13+
#define DEBUG_PRINTLN(X)
14+
#define DEBUG_PRINTF(...)
15+
#endif
16+
// defining available flags in the eventGroup
17+
18+
#define CAN_ehuStarted (1 << 6)
19+
#define CAN_startProgramming (1 << 0)
20+
#define CAN_startDumping (1 << 5)
21+
#define CAN_dumpingFinished (1 << 7)
22+
#define CAN_waitingForISO (1 << 1)
23+
#define CAN_receivedCodeIndex (1 << 2)
24+
#define CAN_requestedCodeIndexProgramming (1 << 11)
25+
#define CAN_sentFirstProgrammingFrame (1 << 10)
26+
#define CAN_receivedProgrammingAllow (1 << 3)
27+
#define CAN_ehuDumpStarted (1 << 4)
28+
#define CAN_MessageReady (1 << 8)
29+
#define CAN_softwareVersionOkay (1 << 9)
30+
#define CAN_softwareVersionWrong (1 << 12)
31+
#define CAN_softwareVersionRequested (1<<13)
32+
#define CAN_softwareVersionReceived (1<<14)
33+
#define CAN_programmingFinished (1<<15)
34+
35+
// RTOS stuff
36+
TaskHandle_t canReceiveTaskHandle, canDisplayTaskHandle, canProcessTaskHandle, canTransmitTaskHandle, indexProgrammerTaskHandle;
37+
QueueHandle_t canRxQueue, canTxQueue;
38+
EventGroupHandle_t eventGroup;
39+
40+
void setup() {
41+
DEBUG_SERIAL(921600);
42+
canRxQueue=xQueueCreate(100, sizeof(twai_message_t));
43+
canTxQueue=xQueueCreate(100, sizeof(twai_message_t));
44+
eventGroup=xEventGroupCreate();
45+
xTaskCreatePinnedToCore(canReceiveTask, "CANbusReceiveTask", 4096, NULL, 1, &canReceiveTaskHandle, 1);
46+
xTaskCreatePinnedToCore(canTransmitTask, "CANbusTransmitTask", 4096, NULL, 1, &canTransmitTaskHandle, 0);
47+
xTaskCreatePinnedToCore(canProcessTask, "CANbusMessageProcessor", 8192, NULL, 2, &canProcessTaskHandle, 0);
48+
xTaskCreatePinnedToCore(indexProgrammerTask, "CANbusindexProgrammerTask", 8192, NULL, 3, &indexProgrammerTaskHandle, 0);
49+
twai_init();
50+
vTaskDelay(pdMS_TO_TICKS(3000));
51+
DEBUG_PRINTF("\r\nStarted! Press 7 for about 2 seconds to check the software version, afterwards you can follow the instructions to dump the Code Index.\r\n");
52+
ehu_force_testmode();
53+
}
54+
55+
void loop() {
56+
vTaskDelay(pdMS_TO_TICKS(1000));
57+
if(checkFlag(CAN_softwareVersionWrong)){
58+
DEBUG_PRINTF("Wrong software version! Aborting.\r\n");
59+
}
60+
}

0 commit comments

Comments
 (0)