With information above I've succesfully finished my first trip yesterday without any errors and in fact without ABS, DPS and with my own LCD in cluster -> no limp mode off course

.
Without nanny this is a drift beast. TBH it's better for drifting than normal riding. For uneven roads it's constantly a bit wobbly with passanger present. For drifting it's pure fun.
So, let's start technical.
After removing motor from DPS to remove any resistance in steering system I've had to pretend there is working DPS by constantly putting message 0x330 with data 0x00, 0x99, 0x99, 0x00, 0xFF, 0xFF, 0x00, 0x00 to can bus and it works. No DPS and no errors
Because ABS was also partly fauly (all can bus data correct but going into error above 10km/h), I've had to remove any traces of errors going from ABS. To do that ABS in on separate CAN bus and messages are forwarded to main bus but with removed errors. This also is succesfull.
Unfortunately after key is turned there is a delay between ABS working and my program which causes errors in ECM. To clear errors I'm sending diagnostic messages after 5s from when key is turned:
msg_error_clear[0].id = 0x713;
msg_error_clear[1].id = 0x71C;
msg_error_clear[2].id = 0x710;
msg_error_clear[3].id = 0x715;
msg_error_clear[4].id = 0x717;
msg_error_clear[5].id = 0x715;
msg_error_clear[6].id = 0x715;
uint8_t tmp_buf_0[8] = { 0x04, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_1[8] = { 0x0D, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_2[8] = { 0x01, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_3[8] = { 0x06, 0x03, 0x14, 0xFF, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_4[8] = { 0x06, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_5[8] = { 0x06, 0x02, 0x10, 0x89, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_6[8] = { 0x06, 0x02, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00 };
There is also a matter of menu button which must be pressed before every ride. I'm sending 0x519 together with 0x402:
0x591: 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x402: { /* three types of data */
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x03, 0x21, 0x13, 0x61, 0x20, 0x11, 0x09, 0x00 },
{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }
}
Below is the code for can bus commmunication which sends, changes and retrieves data to/from can bus:
Code:
#pragma once
#include <FlexCAN_T4.h>
#include <globalVar.h>
extern void can_changer_modify(CAN_message_t &msg);
FlexCAN_T4<CAN1, RX_SIZE_1024, TX_SIZE_32> can1; // internal
FlexCAN_T4<CAN2, RX_SIZE_1024, TX_SIZE_32> can2; // external
CAN_message_t msg1;
bool hasMsg1;
CAN_message_t msg2;
bool hasMsg2;
#define msg_changer_id 0xAA
CAN_message_t msg_changer0; // b0 - 0/1/2 no action/change/new, b1 b2 - message id, b3 len, b4 type - 0/1/2/3 set exactly/set/reset/toggle
CAN_message_t msg_changer1; // b0-b7 - toggle
CAN_message_t msg_changer_new;
uint16_t ready_delay_ms = 5000; // delay for isok message and error cleaning
CAN_message_t msg_dps;
CAN_message_t msg_lcd[3];
uint8_t msg_lcd_cnt;
CAN_message_t msg_isok;
CAN_message_t msg_error_clear[7];
uint8_t msg_error_clear_repeat_cntdn = 2;
uint8_t msg_error_clear_cnt;
uint8_t btn_buf_prev;
void can_setup()
{
can1.begin();
can1.setBaudRate(500000);
can2.begin();
can2.setBaudRate(500000);
}
void can_calcCrc8(CAN_message_t &msg)
{
switch (msg.len)
{
case 8: msg.buf[7] = msg.buf[0] ^ msg.buf[1] ^ msg.buf[2] ^ msg.buf[3] ^ msg.buf[4] ^ msg.buf[5] ^ msg.buf[6]; break;
case 7: msg.buf[6] = msg.buf[0] ^ msg.buf[1] ^ msg.buf[2] ^ msg.buf[3] ^ msg.buf[4] ^ msg.buf[5]; break;
case 6: msg.buf[5] = msg.buf[0] ^ msg.buf[1] ^ msg.buf[2] ^ msg.buf[3] ^ msg.buf[4]; break;
case 5: msg.buf[4] = msg.buf[0] ^ msg.buf[1] ^ msg.buf[2] ^ msg.buf[3]; break;
case 4: msg.buf[3] = msg.buf[0] ^ msg.buf[1] ^ msg.buf[2]; break;
}
}
void can_incCounter0F(CAN_message_t &msg)
{
// assumption that if counter exists, it is before last byte
msg.buf[msg.len - 2]++;
if (msg.buf[msg.len - 2] == 0x10)
msg.buf[msg.len - 2] = 0x00;
}
void can_changer_modify(CAN_message_t &msg)
{
if (msg_changer0.buf[3] > 8)
msg.len = msg_changer0.buf[3] & 0xFF;
else
msg.len = 8; // default to 8
if (msg_changer0.buf[4] == 0)
{
msg.buf[0] = msg_changer1.buf[0];
msg.buf[1] = msg_changer1.buf[1];
msg.buf[2] = msg_changer1.buf[2];
msg.buf[3] = msg_changer1.buf[3];
msg.buf[4] = msg_changer1.buf[4];
msg.buf[5] = msg_changer1.buf[5];
msg.buf[6] = msg_changer1.buf[6];
msg.buf[7] = msg_changer1.buf[7];
}
else if (msg_changer0.buf[4] == 1)
{
msg.buf[0] |= msg_changer1.buf[0];
msg.buf[1] |= msg_changer1.buf[1];
msg.buf[2] |= msg_changer1.buf[2];
msg.buf[3] |= msg_changer1.buf[3];
msg.buf[4] |= msg_changer1.buf[4];
msg.buf[5] |= msg_changer1.buf[5];
msg.buf[6] |= msg_changer1.buf[6];
msg.buf[7] |= msg_changer1.buf[7];
}
else if (msg_changer0.buf[4] == 2)
{
msg.buf[0] &= ~msg_changer1.buf[0];
msg.buf[1] &= ~msg_changer1.buf[1];
msg.buf[2] &= ~msg_changer1.buf[2];
msg.buf[3] &= ~msg_changer1.buf[3];
msg.buf[4] &= ~msg_changer1.buf[4];
msg.buf[5] &= ~msg_changer1.buf[5];
msg.buf[6] &= ~msg_changer1.buf[6];
msg.buf[7] &= ~msg_changer1.buf[7];
}
else if (msg_changer0.buf[4] == 3)
{
msg.buf[0] ^= msg_changer1.buf[0];
msg.buf[1] ^= msg_changer1.buf[1];
msg.buf[2] ^= msg_changer1.buf[2];
msg.buf[3] ^= msg_changer1.buf[3];
msg.buf[4] ^= msg_changer1.buf[4];
msg.buf[5] ^= msg_changer1.buf[5];
msg.buf[6] ^= msg_changer1.buf[6];
msg.buf[7] ^= msg_changer1.buf[7];
}
}
/*void can_testchange_401(CAN_message_t &msg)
{
switch (msg.buf[0])
{
case 1:
msg.buf[1] = 0;
msg.buf[2] = 3;
msg.buf[3] = 0xe7;
msg.buf[4] = 0;
msg.buf[5] = 0;
msg.buf[6] = 0;
msg.buf[7] = 0;
break;
case 3:
msg.buf[1] = 0;
msg.buf[2] = 0;
msg.buf[3] = 6;
msg.buf[4] = 149;
msg.buf[5] = 13;
msg.buf[6] = 107;
msg.buf[7] = 0;
break;
case 4:
msg.buf[1] = 0;
msg.buf[2] = 0;
msg.buf[3] = 6;
msg.buf[4] = 204;
msg.buf[5] = 19;
msg.buf[6] = 170;
msg.buf[7] = 0;
break;
}
}*/
void can_send_changer_new()
{
msg_changer_new.id = msg_changer0.buf[2];
msg_changer_new.id = msg_changer_new.id << 8;
msg_changer_new.id += msg_changer0.buf[1];
can_changer_modify(msg_changer_new);
can1.write(msg_changer_new);
}
void can_save_msg_keys(CAN_message_t &msg)
{
if (btn_buf_prev == msg.buf[1])
return;
// store bits changed to 1
uint8_t tmp = (btn_buf_prev ^ msg.buf[1]) & msg.buf[1];
if (tmp & 0x1)
key_up = true;
if (tmp & 0x2)
key_down = true;
if (tmp & 0x4)
key_left = true;
if (tmp & 0x8)
key_right = true;
if (tmp & 0x10)
key_menu = true;
if (tmp & 0x20)
key_set = true;
if (tmp & 0x40)
key_back = true;
btn_buf_prev = msg.buf[1];
}
void can_save_data_cluster_401(CAN_message_t &msg)
{
/* Serial.println(
String(msg.buf[1]).append( " ")
.append(msg.buf[2]).append(" ")
.append(msg.buf[3]).append(" ")
.append(msg.buf[4]).append(" ")
.append(msg.buf[5]).append(" ")
.append(msg.buf[6]).append(" ")
.append(msg.buf[7]).append(" "));
*/
switch (msg.buf[0])
{
case 0:
break;
case 1:
break;
case 2:
can_triptotal = ((uint32_t)msg.buf[1] << 24) + ((uint32_t)msg.buf[2] << 16) + ((uint32_t)msg.buf[3] << 8) + msg.buf[4];
break;
case 3:
can_tripa = ((uint32_t)msg.buf[1] << 24) + ((uint32_t)msg.buf[2] << 16) + ((uint32_t)msg.buf[3] << 8) + msg.buf[4];
break;
case 4:
can_tripb = ((uint32_t)msg.buf[1] << 24) + ((uint32_t)msg.buf[2] << 16) + ((uint32_t)msg.buf[3] << 8) + msg.buf[4];
break;
case 5:
break;
case 6:
can_acslevel = B1000 - ((msg.buf[2] & B1110) >> 1);
can_acsheight = ((uint16_t)msg.buf[3] << 8) + msg.buf[4];
break;
}
}
void can_save_data(CAN_message_t &msg)
{
switch (msg.id)
{
case 0x102:
can_tempengine = msg.buf[3];
can_tempair = msg.buf[4];
break;
case 0x308:
// B0: bity: low bat, -, -, -, engine hi temp, -, oil switch
can_islowbat = msg.buf[0] & 1;
can_i****emp = msg.buf[0] >> 4 & 1;
can_isoilswitch = msg.buf[0] >> 6 & 1;
break;
case 0x310:
can_gearbyte = msg.buf[0] & 0xF; // b0: bieg 1-6, 7 neutral, 8 reverse
break;
case 0x430:
can_abspressure = msg.buf[4]; // stosunek 1:33 kpa, 0x3E == 0, 0xFF == 6369 kPa
break;
}
}
void can_send_dps()
{
// initialize dps message
if (msg_dps.id == 0)
{
msg_dps.id = 0x330;
uint8_t tmp_buf[8] = { 0x00, 0x99, 0x99, 0x00, 0xFF, 0xFF, 0x00, 0x00 };
memcpy(msg_dps.buf, tmp_buf, 8);
}
// send dps data to both buses
can1.write(msg_dps);
can2.write(msg_dps);
// set new values for counter and crc8 bytes
can_incCounter0F(msg_dps);
msg_dps.buf[7] = msg_dps.buf[6]; // copy counter to crc because crc in this case is the same as counter
}
void can_send_lcd()
{
// initialize lcd message
if (msg_lcd[0].id == 0)
{
msg_lcd[0].id = 0x402;
msg_lcd[1].id = 0x402;
msg_lcd[2].id = 0x402;
uint8_t tmp_buf[3][8] = {
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x03, 0x21, 0x13, 0x61, 0x20, 0x11, 0x09, 0x00 },
{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 } };
memcpy(msg_lcd[0].buf, tmp_buf[0], 8);
memcpy(msg_lcd[1].buf, tmp_buf[1], 8);
memcpy(msg_lcd[2].buf, tmp_buf[2], 8);
}
if (msg_lcd_cnt == 11)
can1.write(msg_lcd[2]);
else if (msg_lcd_cnt == 10)
can1.write(msg_lcd[1]);
else
can1.write(msg_lcd[0]);
msg_lcd_cnt++;
if (msg_lcd_cnt == 12)
msg_lcd_cnt = 0;
}
void can_send_isok()
{
// initialize lcd message
if (msg_isok.id == 0)
{
msg_isok.id = 0x591;
msg_isok.len = 1;
uint8_t tmp_buf[8] = { 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
memcpy(msg_isok.buf, tmp_buf, 8);
}
can1.write(msg_isok);
}
void can_send_error_clear()
{
// initialize lcd message
if (msg_error_clear[0].id == 0)
{
msg_error_clear[0].id = 0x713;
msg_error_clear[1].id = 0x71C;
msg_error_clear[2].id = 0x710;
msg_error_clear[3].id = 0x715;
msg_error_clear[4].id = 0x717;
msg_error_clear[5].id = 0x715;
msg_error_clear[6].id = 0x715;
uint8_t tmp_buf_0[8] = { 0x04, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_1[8] = { 0x0D, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_2[8] = { 0x01, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_3[8] = { 0x06, 0x03, 0x14, 0xFF, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_4[8] = { 0x06, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_5[8] = { 0x06, 0x02, 0x10, 0x89, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmp_buf_6[8] = { 0x06, 0x02, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00 };
memcpy(msg_error_clear[0].buf, tmp_buf_0, 8);
memcpy(msg_error_clear[1].buf, tmp_buf_1, 8);
memcpy(msg_error_clear[2].buf, tmp_buf_2, 8);
memcpy(msg_error_clear[3].buf, tmp_buf_3, 8);
memcpy(msg_error_clear[4].buf, tmp_buf_4, 8);
memcpy(msg_error_clear[5].buf, tmp_buf_5, 8);
memcpy(msg_error_clear[6].buf, tmp_buf_6, 8);
}
can1.write(msg_error_clear[msg_error_clear_cnt]);
can2.write(msg_error_clear[msg_error_clear_cnt]);
msg_error_clear_cnt++;
if (msg_error_clear_cnt == 7)
{
msg_error_clear_repeat_cntdn--;
msg_error_clear_cnt = 0;
}
}
void can_handle_msg_post(CAN_message_t &msg)
{
switch (msg.id)
{
// store message changer data
case (msg_changer_id+0): msg_changer0 = msg; break;
case (msg_changer_id+1): msg_changer1 = msg; break;
//case 0x401: can_testchange_401(msg); break;
case 0x102: can_save_data(msg); break;
case 0x308: can_save_data(msg); break;
case 0x310: can_save_data(msg); break;
case 0x401: can_save_data_cluster_401(msg); break;
case 0x340: can_save_msg_keys(msg); break;
case 0x430: // remove error from vcm message
can_save_data(msg); break;
break;
}
}
void can_handle_msg_pre(CAN_message_t &msg)
{
switch (msg.id)
{
case 0x020: // remove error from vcm message
msg.buf[0] = msg.buf[0] & 0xF0;
msg.buf[1] = 0x00;
can_calcCrc8(msg);
break;
case 0x430: // remove error from vcm message
msg.buf[0] = msg.buf[1] = 0x99;
can_calcCrc8(msg);
break;
}
// change message
if (msg_changer0.buf[0] == 1)
{
// match id
if ((msg.id & 0xFF) == msg_changer0.buf[1] && ((msg.id >> 8) & 0xFF) == msg_changer0.buf[2])
can_changer_modify(msg);
}
}
void can_handle()
{
// send custom messages with minimum 1ms offset
if (event1ms && timer1msCounterStored > 10) // skip first few ms because of -n in checks
{
if (ready_delay_ms > 0)
ready_delay_ms--;
// send dps every 34ms
if (!((timer1msCounterStored -0) & (0x20-1)))
can_send_dps();
// send lcd every 128ms
if (!((timer1msCounterStored -1) & (0x80-1)))
can_send_lcd();
// send isok every 128ms
// start sending after moto is ready
if (ready_delay_ms == 0 && !((timer1msCounterStored -2) & (0x80-1)))
can_send_isok();
// send error clear every 128ms
// start sending after moto is ready
// send only once
if (ready_delay_ms == 0 && msg_error_clear_repeat_cntdn > 0 && !((timer1msCounterStored -2) & (0x80-1)))
can_send_error_clear();
// send test message every 128ms
if (!((timer1msCounterStored -4) & (0x80-1)))
{
// new test message
if (msg_changer0.buf[0] == 2)
can_send_changer_new();
}
}
// read messages
hasMsg1 = can1.read(msg1);
hasMsg2 = can2.read(msg2);
// don't change message going from ecu to external bus
if (hasMsg1)
{
if (msg1.id < 0x700) // skip diagnostic messages
can_handle_msg_pre(msg1);
can2.write(msg1);
if (msg1.id < 0x700) // skip diagnostic messages
can_handle_msg_post(msg1);
}
if (hasMsg2)
{
if (msg2.id < 0x700) // skip diagnostic messages
can_handle_msg_pre(msg2);
can1.write(msg2);
if (msg2.id < 0x700) // skip diagnostic messages
can_handle_msg_post(msg2);
}
}
Below is code responsible for lcd screen with LVGL library:
Code:
#pragma once
#include <lvgl.h>
#include <types.h>
#include <globalVar.h>
#include <gui.h>
class scr_main : public screen_base
{
// styles
lv_style_t box_style_box;
lv_style_t box_style_box_checked;
lv_style_t bar_style_temp;
// controls
lv_obj_t* rol_gearpos;
lv_obj_t* lbl_tempair;
lv_obj_t* lbl_tripa;
lv_obj_t* lbl_triptotal;
lv_obj_t* lbl_tempengine;
lv_obj_t* bar_tempengine;
lv_obj_t* bar_abspressure;
lv_obj_t* lbl_acslevel;
lv_obj_t* bar_acsheight;
lv_obj_t* box_islowbat;
lv_obj_t* box_i****emp;
lv_obj_t* box_isoilswitch;
uint32_t gui_tripa;
uint32_t gui_triptotal;
uint16_t gui_tempair;
uint16_t gui_tempengine;
uint16_t gui_acslevel;
uint16_t gui_abspressure;
uint16_t gui_acsheight;
lv_obj_t* build()
{
lv_obj_t* ret = lv_obj_create(NULL);
//lv_obj_set_style_bg_color(ret, lv_palette_lighten(LV_PALETTE_BLUE, 4), LV_PART_MAIN);
lv_obj_set_style_bg_color(ret, lv_color_black(), LV_PART_MAIN);
lv_obj_set_style_text_color(ret, lv_color_white(), LV_PART_MAIN);
// create styles
lv_style_init(&box_style_box);
lv_style_set_border_color(&box_style_box, lv_palette_main(LV_PALETTE_RED));
lv_style_set_border_width(&box_style_box, 3);
lv_style_init(&box_style_box_checked);
lv_style_set_border_color(&box_style_box_checked, lv_palette_main(LV_PALETTE_RED));
lv_style_set_border_width(&box_style_box_checked, 3);
lv_style_set_bg_color(&box_style_box_checked, lv_palette_main(LV_PALETTE_RED));
lv_style_init(&bar_style_temp);
lv_style_set_bg_opa(&bar_style_temp, LV_OPA_COVER);
lv_style_set_bg_color(&bar_style_temp, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_color(&bar_style_temp, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_bg_grad_dir(&bar_style_temp, LV_GRAD_DIR_VER);
// lv_style_set_bg_grad_color(&style_btn, lv_palette_main(LV_PALETTE_GREY));
// lv_style_set_bg_grad_dir(&style_btn, LV_GRAD_DIR_VER);
lv_obj_t * panel;
lv_obj_t * obj;
// gear pos
rol_gearpos = lv_roller_create(ret);
lv_roller_set_options(rol_gearpos, " \n1\n2\n3\n4\n5\n6\nN\nR", LV_ROLLER_MODE_INFINITE);
lv_roller_set_visible_row_count(rol_gearpos, 5);
lv_obj_set_width(rol_gearpos, 40);
lv_obj_set_pos(rol_gearpos, 0, 0);
// air temp
lbl_tempair = lv_label_create(ret);
lv_label_set_text(lbl_tempair, "AIR T");
lv_obj_set_pos(lbl_tempair, 50, 0);
// Trip A
obj = lv_label_create(ret);
lv_label_set_text(obj, "Trip");
lv_obj_set_style_text_font(obj, &lv_font_montserrat_20, LV_PART_MAIN);
lv_obj_set_pos(obj, 50, 41);
lbl_tripa = lv_label_create(ret);
// lv_obj_set_style_text_align(lbl_triptotal, LV_TEXT_ALIGN_RIGHT, 0); // crashing
lv_obj_set_width(lbl_tripa, 120);
lv_obj_set_pos(lbl_tripa, 110, 40);
// Total
obj = lv_label_create(ret);
lv_label_set_text(obj, "Total");
lv_obj_set_style_text_font(obj, &lv_font_montserrat_20, LV_PART_MAIN);
lv_obj_set_pos(obj, 50, 81);
lbl_triptotal = lv_label_create(ret);
//lv_obj_set_style_text_align(lbl_triptotal, LV_TEXT_ALIGN_RIGHT, 0); // crashing
lv_obj_set_width(lbl_triptotal, 120);
lv_obj_set_pos(lbl_triptotal, 110, 80);
// right side bars
// engine temp
lbl_tempengine = lv_label_create(ret);
lv_label_set_text(lbl_tempengine, "ENG T");
lv_obj_set_pos(lbl_tempengine, 215, 0);
bar_tempengine = lv_bar_create(ret);
lv_obj_add_style(bar_tempengine, &bar_style_temp, LV_PART_INDICATOR);
lv_obj_set_size(bar_tempengine, 30, 180);
lv_bar_set_range(bar_tempengine, 40, 130);
lv_obj_set_pos(bar_tempengine, 235, 30);
// abs pressure
bar_abspressure = lv_bar_create(ret);
lv_obj_set_style_bg_color(bar_abspressure, lv_palette_main(LV_PALETTE_RED), LV_PART_INDICATOR);
lv_obj_set_size(bar_abspressure, 20, 180);
lv_bar_set_range(bar_abspressure, 0x3e, 0xCA); // 140 * 33 = 4620kPa
lv_obj_set_pos(bar_abspressure, 270, 30);
// acs level
lbl_acslevel = lv_label_create(ret);
lv_label_set_text(lbl_acslevel, "-");
lv_obj_set_pos(lbl_acslevel, 295, 0);
// acs height
bar_acsheight = lv_bar_create(ret);
lv_obj_set_size(bar_acsheight, 20, 180);
lv_bar_set_range(bar_acsheight, 250, 650);
lv_obj_set_pos(bar_acsheight, 295, 30);
// checkboxes
panel = lv_obj_create(ret);
lv_obj_set_size(panel, 320, 30);
lv_obj_set_pos(panel, 0, 210);
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(panel, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER);
box_islowbat = lv_checkbox_create(panel);
lv_checkbox_set_text(box_islowbat, "Bat");
lv_obj_add_style(box_islowbat, &box_style_box, LV_PART_INDICATOR);
lv_obj_add_style(box_islowbat, &box_style_box_checked, LV_PART_INDICATOR | LV_STATE_CHECKED);
box_i****emp = lv_checkbox_create(panel);
lv_checkbox_set_text(box_i****emp, "Temp");
lv_obj_add_style(box_i****emp, &box_style_box, LV_PART_INDICATOR);
lv_obj_add_style(box_i****emp, &box_style_box_checked, LV_PART_INDICATOR | LV_STATE_CHECKED);
box_isoilswitch = lv_checkbox_create(panel);
lv_checkbox_set_text(box_isoilswitch, "Oil");
lv_obj_add_style(box_isoilswitch, &box_style_box, LV_PART_INDICATOR);
lv_obj_add_style(box_isoilswitch, &box_style_box_checked, LV_PART_INDICATOR | LV_STATE_CHECKED);
lv_obj_update_layout(box_isoilswitch);
return ret;
}
void open()
{
}
void close()
{
}
// 100us main
void event()
{
// only one at a time for optimization purposes starting from highest priority
if (gui_abspressure != can_abspressure)
{
gui_abspressure = can_abspressure;
lv_bar_set_value(bar_abspressure, gui_abspressure, LV_ANIM_OFF);
}
else if (gui_acsheight != can_acsheight)
{
gui_acsheight = can_acsheight;
lv_bar_set_value(bar_acsheight, gui_acsheight, LV_ANIM_OFF);
}
else if (gui_tempair != can_tempair)
{
gui_tempair = can_tempair;
int temp = gui_tempair-60;
lv_label_set_text(lbl_tempair, String((temp)).append("*C").c_str());
}
else if (gui_tripa != can_tripa)
{
gui_tripa = can_tripa;
String tripastr = String(gui_tripa >= 10 ? gui_tripa : 10); // co najmniej 100m zeby bylo co wyswietlac
String tripadec = tripastr.substring(tripastr.length()-2, tripastr.length());
tripastr.remove(tripastr.length()-2, 2);
tripastr.append(",").append(tripadec);
lv_label_set_text(lbl_tripa, tripastr.c_str());
}
else if (gui_triptotal != can_triptotal)
{
gui_triptotal = can_triptotal;
String triptotalstr = String(gui_triptotal);
String triptotaldecstr = triptotalstr.substring(triptotalstr.length()-2, triptotalstr.length());
triptotalstr.remove(triptotalstr.length()-2, 2);
triptotalstr.append(",").append(triptotaldecstr);
lv_label_set_text(lbl_triptotal, triptotalstr.c_str());
}
else if (gui_tempengine != can_tempengine)
{
gui_tempengine = can_tempengine;
int temp = gui_tempengine-60;
lv_label_set_text(lbl_tempengine, String((temp)).append("*C").c_str());
lv_bar_set_value(bar_tempengine, temp, LV_ANIM_OFF);
}
else if (gui_acslevel != can_acslevel)
{
gui_acslevel = can_acslevel;
lv_label_set_text(lbl_acslevel, String(gui_acslevel).c_str());
}
else
{
lv_roller_set_selected(rol_gearpos, (uint16_t)can_gearbyte, LV_ANIM_OFF);
if (can_islowbat) lv_obj_add_state(box_islowbat, LV_STATE_CHECKED);
else lv_obj_clear_state(box_islowbat, LV_STATE_CHECKED);
if (can_i****emp) lv_obj_add_state(box_i****emp, LV_STATE_CHECKED);
else lv_obj_clear_state(box_i****emp, LV_STATE_CHECKED);
if (can_isoilswitch) lv_obj_add_state(box_isoilswitch, LV_STATE_CHECKED);
else lv_obj_clear_state(box_isoilswitch, LV_STATE_CHECKED);
}
}
};
global variables:
Code:
// can bus data
bool can_islowbat, can_i****emp, can_isoilswitch;
uint16_t can_tempengine, can_tempair;
uint16_t can_gearbyte;
uint16_t can_abspressure;
uint16_t can_acsheight;
uint16_t can_acslevel;
uint32_t can_triptotal;
uint32_t can_tripa;
uint32_t can_tripb;
main loop:
Code:
void loop()
{
// critical code
can_handle();
// catch volatile timer
event1ms = timer1msCounterStored != timer1msCounter;
if (!event1ms)
return;
// 1ms code
timer1msCounterStored = timer1msCounter;
event4ms = !(timer1msCounterStored & 0x3);
// GUI code every 4ms
if (event4ms)
{
gui_update();
}
}
gui_update() basically calls event() on current screen.
I have two screens:
- main for brake pressure, trip, ACS height, gear position, temp and some other stuff
- snake game for playing while my wife goes for shopping