Skip to content

Commit 091b468

Browse files
authored
EHU32 v0.8
Now blocks "Aux" messages with high accuraccy by abusing ISO 15765-2 flow control Tweaked timings
1 parent 91ca93a commit 091b468

File tree

5 files changed

+74
-74
lines changed

5 files changed

+74
-74
lines changed

src/A2DP.ino

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
BluetoothA2DPSink a2dp_sink;
1+
I2SStream i2s;
2+
BluetoothA2DPSink a2dp_sink(i2s);
23

34
// updates the buffers
45
void avrc_metadata_callback(uint8_t md_type, const uint8_t *data2) { // fills the song title buffer with data, updates text_lenght with the amount of chars
@@ -40,19 +41,11 @@ void a2dp_audio_state_changed(esp_a2d_audio_state_t state, void *ptr){ // callb
4041

4142
// start A2DP audio service
4243
void a2dp_init(){
43-
const i2s_config_t i2s_config = { // ext dac BLCK=26 WS/LRCK=25 DOUT=22
44-
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
45-
.sample_rate = 44100,
46-
.bits_per_sample = (i2s_bits_per_sample_t)16,
47-
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
48-
.communication_format = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S),
49-
.intr_alloc_flags = 0,
50-
.dma_buf_count = 8,
51-
.dma_buf_len = 128,
52-
.use_apll = true,
53-
.tx_desc_auto_clear = true
54-
};
55-
a2dp_sink.set_i2s_config(i2s_config);
44+
auto i2s_conf=i2s.defaultConfig();
45+
i2s_conf.pin_bck=26;
46+
i2s_conf.pin_ws=25;
47+
i2s_conf.pin_data=22;
48+
i2s.begin(i2s_conf);
5649
a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
5750
a2dp_sink.set_avrc_metadata_attribute_mask(ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST | ESP_AVRC_MD_ATTR_ALBUM);
5851
a2dp_sink.set_on_connection_state_changed(a2dp_connection_state_changed);
@@ -64,11 +57,9 @@ void a2dp_init(){
6457
a2dp_sink.set_auto_reconnect(true);
6558
}
6659

67-
a2dp_sink.start("EHU32");
68-
// setting up bluetooth audio sink
60+
a2dp_sink.start("EHU32"); // setting up bluetooth audio sink
6961
a2dp_started=1;
7062
if(DEBUGGING_ON) Serial.println("A2DP: Started!");
71-
7263
processDataBuffer(1, "EHU32 Started!", "Bluetooth on", "Waiting for connection...");
7364
}
7465

@@ -110,8 +101,16 @@ void A2DP_EventHandler(){
110101
void a2dp_shutdown(){
111102
if(a2dp_started && RxMessage.data[3]==0x18){
112103
a2dp_sink.disconnect();
104+
a2dp_sink.stop();
113105
ehu_started=0; // so it is possible to restart and reconnect the source afterwards in the rare case radio is shutdown but ESP32 is still powered up
114106
a2dp_started=0; // while extremely unlikely to happen in the vehicle, this comes handy for debugging on my desk setup
115107
if(DEBUGGING_ON) Serial.println("CAN: EHU went down! Disconnecting A2DP.");
116108
}
109+
}
110+
111+
void a2dp_end(){
112+
a2dp_sink.disconnect();
113+
a2dp_sink.stop();
114+
a2dp_started=0;
115+
if(DEBUGGING_ON) Serial.println("A2DP: Stopped!");
117116
}

src/BusReceive.ino

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ void twai_init(){
55
g_config.tx_queue_len=5;
66
g_config.intr_flags=(ESP_INTR_FLAG_LEVEL1 & ESP_INTR_FLAG_IRAM);
77
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
8-
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); // TODO: set up proper filters
8+
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
99
TxMessage.extd=0; // TxMessage settings - not extended ID CAN packet
1010
TxMessage.rtr=0; // not retransmission packet
1111
TxMessage.ss=0; // don't transmit the packet as a single shot -> less chance of an error this way
@@ -35,24 +35,22 @@ void sendPacket(int id, char can_send_buffer[8], int dlc);
3535
// process incoming CAN messages until there is none left in the buffer; picks appropriate action based on message identifier
3636
void canReceive(){ // logical filter based on the CAN ID
3737
while(twai_receive(&RxMessage, pdMS_TO_TICKS(10)==ESP_OK && !CAN_MessageReady)){
38-
if(!RxMessage.rtr){
39-
switch (RxMessage.identifier){
40-
case 0x201: canDecodeEhuButtons();
41-
break;
42-
case 0x206: canDecodeWheel();
43-
break;
44-
case 0x208: canDecodeAC();
45-
break;
46-
case 0x501: a2dp_shutdown();
47-
break;
48-
case 0x548: if(disp_mode==1) canUpdateBodyData();
49-
break;
50-
case 0x4ec: if(disp_mode==3) canUpdateCoolant(); // temporarily unused, but should work without ECC module
51-
break;
52-
case 0x6c1: canUpdateDisplay();
53-
break;
54-
default: break;
55-
}
38+
switch (RxMessage.identifier){
39+
case 0x201: canDecodeEhuButtons();
40+
break;
41+
case 0x206: canDecodeWheel();
42+
break;
43+
case 0x208: canDecodeAC();
44+
break;
45+
case 0x501: a2dp_shutdown();
46+
break;
47+
case 0x548: if(disp_mode==1) canUpdateBodyData();
48+
break;
49+
case 0x4ec: if(disp_mode==3) canUpdateCoolant(); // temporarily unused, but should work without ECC module
50+
break;
51+
case 0x6c1: canUpdateDisplay();
52+
break;
53+
default: break;
5654
}
5755
}
5856
}
@@ -129,8 +127,8 @@ void canUpdateDisplay(){
129127
}
130128
if(DIS_autoupdate && disp_mode!=-1){ // don't bother checking the data if there's no need to update the display
131129
if(RxMessage.data[0]==0x10 && RxMessage.data[1]<0x40){ // we check if the total payload of radio's message is small, if yes assume it's an Aux message
132-
//Serial.println("Got 6C1 # 10 XX...");
133-
vTaskDelay(pdMS_TO_TICKS(50));
130+
preventDisplayUpdate(); // this hack prevents radio from transmitting the entirety of an Aux message
131+
vTaskDelay(pdMS_TO_TICKS(10));
134132
sendMultiPacket();
135133
}
136134
}
@@ -208,7 +206,6 @@ void canDecodeEhuButtons(){
208206
}
209207

210208
void canActionEhuButton0(){
211-
212209
}
213210

214211
void canActionEhuButton1(){ // regular audio metadata mode
@@ -239,9 +236,6 @@ void canActionEhuButton6(){
239236
}
240237

241238
void canActionEhuButton7(){
242-
a2dp_sink.disconnect();
243-
vTaskDelay(pdMS_TO_TICKS(1000));
244-
ESP.restart();
245239
}
246240

247241
void canActionEhuButton8(){

src/BusSend.ino

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
char flowCtlMessage[8]={0x30,0,0x7F,0,0,0,0,0}; //
2+
13
// transmits a CAN message with specified payload; sets CAN_prevTxFail in case there was a failure at any point
24
void sendPacket(int id, char can_send_buffer[8], int dlc=8){
35
TxMessage.identifier=id;
@@ -88,4 +90,10 @@ void requestMeasurementBlocks(){ // request from 0x248, 0x548 respond
8890
if(DEBUGGING_ON) Serial.println("CAN: Requesting measurement blocks from 0x246");
8991
char measurement_payload[8]={0x06, 0xAA, 0x01, 0x01, 0x07, 0x10, 0x11};
9092
sendPacket(0x248, measurement_payload, 7);
93+
}
94+
95+
// this abuses ISO 15765-2 flow control, if sent fast enough will prevent the radio from writing to the display in time and as such will not blank the display; makes the experience more seamless
96+
void preventDisplayUpdate(){
97+
sendPacket(0x2C1, flowCtlMessage, 8);
98+
if(DEBUGGING_ON) Serial.println("CAN: Flow control - preventing display update...");
9199
}

src/EHU32.ino

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
Arduino runs: on core 1
66
Partition scheme: Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
77
*/
8-
8+
#include "AudioTools.h"
99
#include "BluetoothA2DPSink.h"
1010
#include "driver/twai.h"
1111
#include <WiFi.h>
1212
#include <WiFiAP.h>
13-
#include <WiFiUdp.h>
1413
#include <ArduinoOTA.h>
1514

1615
bool DEBUGGING_ON=0;
1716
// pin definitions
18-
const int PCM_MUTE_CTL=23; // this pin controls PCM5102s soft-mute function
17+
const int PCM_MUTE_CTL=23, SD_CS_PIN=32; // this pin controls PCM5102s soft-mute function
1918
// CAN buffers
2019
uint32_t alerts_triggered;
2120
static twai_message_t RxMessage, TxMessage;
@@ -28,8 +27,8 @@ float CAN_data_coolant=0, CAN_data_voltage=0;
2827
// global bluetooth flags
2928
bool ehu_started=0, a2dp_started=0, bt_connected=0, bt_state_changed=0, bt_audio_playing=0, audio_state_changed=0;
3029
// data buffers
31-
static char utf16buffer[384], utf16_title[128], utf16_artist[128], utf16_album[128], CAN_MsgArray[64][8], title_buffer[64], artist_buffer[64], album_buffer[64], coolant_buffer[32], speed_buffer[32], voltage_buffer[32];
32-
// display mode 0 -> song metadata, 1 -> body data, 2 -> MP3 player -1 -> prevent screen updates
30+
static char utf16buffer[512], utf16_title[128], utf16_artist[128], utf16_album[128], CAN_MsgArray[64][8], title_buffer[64], artist_buffer[64], album_buffer[64], coolant_buffer[32], speed_buffer[32], voltage_buffer[32];
31+
// display mode 0 -> song metadata, 1 -> body data, -1 -> prevent screen updates
3332
int disp_mode=3;
3433
bool disp_mode_changed=0, disp_mode_changed_with_delay=0;
3534
// time to compare against
@@ -95,7 +94,7 @@ void loop() {
9594
}
9695
sendMultiPacketData();
9796
} else { // this could use a rewrite
98-
if(DEBUGGING_ON && status_info.msgs_to_rx!=0){Serial.printf("CAN: Got messages %d messages in RX queue!\n", status_info.msgs_to_rx);}
97+
if(DEBUGGING_ON && status_info.msgs_to_rx!=0){Serial.printf("CAN: Got messages %d messages in RX queue!\r\n\b", status_info.msgs_to_rx);}
9998
canReceive(); // read data from RX buffer
10099
}
101100

src/TextHandler.ino

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,43 +58,43 @@ unsigned int utf8_to_utf16(const char* utf8_buffer, char* utf16_buffer){
5858

5959
// converts UTF-8 strings from arguments to real UTF-16, then compiles a full display message with formatting; returns total bytes written as part of message payload
6060
int utf8_conversion(char* upper_line_buffer, char* middle_line_buffer, char* lower_line_buffer){
61-
int upper_line_buffer_lenght=0, middle_line_buffer_lenght=0, lower_line_buffer_lenght=0;
62-
if(upper_line_buffer!=nullptr){ // calculating string lenghts to keep track of processed data
63-
upper_line_buffer_lenght=utf8_to_utf16(upper_line_buffer, utf16_album);
61+
int upper_line_buffer_length=0, middle_line_buffer_length=0, lower_line_buffer_length=0;
62+
if(upper_line_buffer!=nullptr){ // calculating string lengths to keep track of processed data
63+
upper_line_buffer_length=utf8_to_utf16(upper_line_buffer, utf16_album);
6464
}
6565
if(middle_line_buffer!=nullptr){
66-
middle_line_buffer_lenght=utf8_to_utf16(middle_line_buffer, utf16_title);
66+
middle_line_buffer_length=utf8_to_utf16(middle_line_buffer, utf16_title);
6767
}
6868
if(lower_line_buffer!=nullptr){
69-
lower_line_buffer_lenght=utf8_to_utf16(lower_line_buffer, utf16_artist);
69+
lower_line_buffer_length=utf8_to_utf16(lower_line_buffer, utf16_artist);
7070
}
7171

7272
if(DEBUGGING_ON){ // debug stuff
73-
Serial.printf("\nTitle lenght: %d", middle_line_buffer_lenght);
74-
Serial.printf("\nAlbum lenght: %d", upper_line_buffer_lenght);
75-
Serial.printf("\nArtist lenght: %d", lower_line_buffer_lenght);
73+
Serial.printf("\nTitle length: %d", middle_line_buffer_length);
74+
Serial.printf("\nAlbum length: %d", upper_line_buffer_length);
75+
Serial.printf("\nArtist length: %d", lower_line_buffer_length);
7676
Serial.println("\nTitle buffer in UTF-8:");
77-
for(int i=0;i<middle_line_buffer_lenght;i++){
77+
for(int i=0;i<middle_line_buffer_length;i++){
7878
Serial.printf(" %02X", middle_line_buffer[i]);
7979
}
8080
Serial.println("\nTitle buffer in UTF-16:");
81-
for(int i=0;i<(middle_line_buffer_lenght*2);i++){
81+
for(int i=0;i<(middle_line_buffer_length*2);i++){
8282
Serial.printf(" %02X", utf16_title[i]);
8383
}
8484
Serial.println("\nAlbum buffer in UTF-8:");
85-
for(int i=0;i<upper_line_buffer_lenght;i++){
85+
for(int i=0;i<upper_line_buffer_length;i++){
8686
Serial.printf(" %02X", upper_line_buffer[i]);
8787
}
8888
Serial.println("\nAlbum buffer in UTF-16:");
89-
for(int i=0;i<(upper_line_buffer_lenght*2);i++){
89+
for(int i=0;i<(upper_line_buffer_length*2);i++){
9090
Serial.printf(" %02X", utf16_album[i]);
9191
}
9292
Serial.println("\nArtist buffer in UTF-8:");
93-
for(int i=0;i<lower_line_buffer_lenght;i++){
93+
for(int i=0;i<lower_line_buffer_length;i++){
9494
Serial.printf(" %02X", lower_line_buffer[i]);
9595
}
9696
Serial.println("\nArtist buffer in UTF-16:");
97-
for(int i=0;i<(lower_line_buffer_lenght*2);i++){
97+
for(int i=0;i<(lower_line_buffer_length*2);i++){
9898
Serial.printf(" %02X", utf16_artist[i]);
9999
}
100100
}
@@ -114,56 +114,56 @@ int utf8_conversion(char* upper_line_buffer, char* middle_line_buffer, char* low
114114
last_byte_written++;
115115
utf16buffer[last_byte_written]=0x10;
116116
last_byte_written++; // we skip utf16buffer[6], its filled in the end (char count for id 0x10)
117-
if(middle_line_buffer_lenght>1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
117+
if(middle_line_buffer_length>1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
118118
for(int i=1;i<=sizeof(DIS_leftadjusted);i++){ // write left-justified formatting string
119119
utf16buffer[last_byte_written+i]=DIS_leftadjusted[i-1];
120120
}
121121
last_byte_written+=sizeof(DIS_leftadjusted);
122122
utf16buffer[6]=sizeof(DIS_leftadjusted)/2;
123123
}
124-
for(int i=1;i<=(middle_line_buffer_lenght*2);i++){
124+
for(int i=1;i<=(middle_line_buffer_length*2);i++){
125125
utf16buffer[last_byte_written+i]=utf16_title[i-1];
126126
}
127-
last_byte_written+=(middle_line_buffer_lenght*2);
128-
utf16buffer[6]+=middle_line_buffer_lenght; // this is static, char count = title+(formatting/2)
127+
last_byte_written+=(middle_line_buffer_length*2);
128+
utf16buffer[6]+=middle_line_buffer_length; // this is static, char count = title+(formatting/2)
129129

130130
int album_count_pos=10;
131131
// ALBUM FIELD
132132
last_byte_written++;
133133
utf16buffer[last_byte_written]=0x11;
134134
last_byte_written++;
135135
album_count_pos=last_byte_written;
136-
if(upper_line_buffer_lenght>=1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
136+
if(upper_line_buffer_length>=1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
137137
for(int i=1;i<=sizeof(DIS_smallfont);i++){ // formatting - small text
138138
utf16buffer[last_byte_written+i]=DIS_smallfont[i-1];
139139
}
140140
last_byte_written+=sizeof(DIS_smallfont);
141141
utf16buffer[album_count_pos]=sizeof(DIS_smallfont)/2;
142142
}
143-
for(int i=1;i<=(upper_line_buffer_lenght*2);i++){
143+
for(int i=1;i<=(upper_line_buffer_length*2);i++){
144144
utf16buffer[last_byte_written+i]=utf16_album[i-1];
145145
}
146-
last_byte_written+=(upper_line_buffer_lenght*2);
147-
utf16buffer[album_count_pos]+=upper_line_buffer_lenght;
146+
last_byte_written+=(upper_line_buffer_length*2);
147+
utf16buffer[album_count_pos]+=upper_line_buffer_length;
148148

149149
int artist_count_pos=album_count_pos;
150150
// ARTIST FIELD
151151
last_byte_written++;
152152
utf16buffer[last_byte_written]=0x12;
153153
last_byte_written++;
154154
artist_count_pos=last_byte_written;
155-
if(lower_line_buffer_lenght>=1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
155+
if(lower_line_buffer_length>=1){ // if the upper line data is just a space, don't apply formatting - saves 2 frames of data
156156
for(int i=1;i<=sizeof(DIS_smallfont);i++){ // formatting - small text
157157
utf16buffer[last_byte_written+i]=DIS_smallfont[i-1];
158158
}
159159
last_byte_written+=sizeof(DIS_smallfont);
160160
utf16buffer[artist_count_pos]=sizeof(DIS_smallfont)/2;
161161
}
162-
for(int i=1;i<=(lower_line_buffer_lenght*2);i++){
162+
for(int i=1;i<=(lower_line_buffer_length*2);i++){
163163
utf16buffer[last_byte_written+i]=utf16_artist[i-1];
164164
}
165-
last_byte_written+=(lower_line_buffer_lenght*2);
166-
utf16buffer[artist_count_pos]+=lower_line_buffer_lenght;
165+
last_byte_written+=(lower_line_buffer_length*2);
166+
utf16buffer[artist_count_pos]+=lower_line_buffer_length;
167167

168168
if((last_byte_written+1)%7==0){ // if the amount of bytes were to result in a full packet (ie no unused bytes), add a char to overflow into the next packet
169169
utf16buffer[artist_count_pos]+=1; // workaround because if the packets are full the display would ignore the message

0 commit comments

Comments
 (0)