espd

ESP32_EMU_BT_V.3.06

May 23rd, 2025
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.42 KB | None | 0 0
  1. #include <Arduino.h>
  2. #define LV_COLOR_16_SWAP 0
  3. #include <lvgl.h>
  4. #include <TFT_eSPI.h>
  5. #include "BluetoothSerial.h"
  6. #include <string>
  7. #include <stdexcept>
  8. #include "CST820.h"
  9. using namespace std;
  10.  
  11. //#define USE_NAME
  12. const char *pin = "1234";
  13. String myBtName = "ESP32-BT-Master";
  14.  
  15. #if !defined(CONFIG_BT_SPP_ENABLED)
  16. #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
  17. #endif
  18.  
  19. BluetoothSerial SerialBT;
  20.  
  21. #ifdef USE_NAME
  22. String slaveName = "EMUCANBT_SPP";
  23. #else
  24. uint8_t address[6] = { 0x98, 0xDA, 0x20, 0x02, 0xBE, 0xA4 };
  25. #endif
  26.  
  27. const int backLightPin = 27;
  28. const int buzzerPin = 22;
  29. bool buzzerOn = false;
  30. bool btIconSts = false;
  31. static lv_style_t style_bt;
  32. static bool style_initialized = false;
  33.  
  34. int rpm;
  35. int spd;
  36. float afr;
  37. float mapR;
  38. float boost;
  39. int tps;
  40. int clt;
  41. int ign;
  42. int inj;
  43. float bat;
  44. int cel;
  45.  
  46. #define I2C_SDA 33
  47. #define I2C_SCL 32
  48. #define TP_RST 25
  49. #define TP_INT 21
  50.  
  51. static const uint16_t screenWidth = 320;
  52. static const uint16_t screenHeight = 240;
  53.  
  54. TFT_eSPI tft = TFT_eSPI();
  55. CST820 touch(I2C_SDA, I2C_SCL, TP_RST, TP_INT);
  56.  
  57. unsigned long previousMillis = 0;
  58. const unsigned long reconnectInterval = 5000;
  59.  
  60. LV_FONT_DECLARE(lv_font_montserrat_14);
  61. LV_FONT_DECLARE(lv_font_montserrat_28);
  62.  
  63. lv_obj_t *bt_icon_label;
  64.  
  65. // Display & LVGL setup
  66. static lv_disp_draw_buf_t draw_buf;
  67. static lv_color_t buf[LV_HOR_RES_MAX * 10];
  68. lv_obj_t *table;
  69.  
  70. #define NUM_TABS 3
  71. lv_obj_t *tabview;
  72. lv_obj_t *tabs[NUM_TABS];
  73. const char *tab_titles[NUM_TABS] = {"1", "2", "3"};
  74.  
  75. void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  76.   uint16_t w = area->x2 - area->x1 + 1;
  77.   uint16_t h = area->y2 - area->y1 + 1;
  78.  
  79.   tft.startWrite();
  80.   tft.setAddrWindow(area->x1, area->y1, w, h);
  81.   tft.pushColors((uint16_t *)&color_p->full, w * h, true);
  82.   tft.endWrite();
  83.  
  84.   lv_disp_flush_ready(disp);
  85. }
  86.  
  87. void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) {
  88.   uint16_t rawX, rawY;
  89.   uint8_t gesture;
  90.   bool touched = touch.getTouch(&rawX, &rawY, &gesture);
  91.  
  92.   Serial.printf("Touched: %d | X: %d, Y: %d\n", touched, rawX, rawY);
  93.  
  94.  
  95.   if (!touched) {
  96.     data->state = LV_INDEV_STATE_REL;
  97.   } else {
  98.     data->state = LV_INDEV_STATE_PR;
  99.  
  100.     uint16_t tmp = rawX;
  101.     rawX = rawY;
  102.     rawY = 240 - tmp - 1;
  103.  
  104.     data->point.x = rawX;
  105.     data->point.y = rawY;
  106.   }
  107. }
  108.  
  109. // Initialize LVGL Table
  110. void create_table() {
  111.  
  112.   tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 0);
  113.   lv_obj_t *tab_btns = lv_tabview_get_tab_btns(tabview);
  114.   lv_obj_add_flag(tab_btns, LV_OBJ_FLAG_HIDDEN);
  115.   lv_obj_set_style_text_opa(tabview, LV_OPA_COVER, 0);
  116.   lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
  117.  
  118.   lv_obj_clear_flag(tabview, LV_OBJ_FLAG_SCROLLABLE);
  119.   lv_obj_set_scrollbar_mode(tabview, LV_SCROLLBAR_MODE_OFF);
  120.  
  121.   for(int i = 0; i < NUM_TABS; i++) {
  122.     tabs[i] = lv_tabview_add_tab(tabview, tab_titles[i]);
  123.     table = lv_table_create(tabs[i]);
  124.  
  125.     lv_obj_clear_flag(tabs[i], LV_OBJ_FLAG_SCROLLABLE);
  126.     lv_obj_set_scrollbar_mode(tabs[i], LV_SCROLLBAR_MODE_OFF);
  127.    
  128.     lv_obj_clear_flag(table, LV_OBJ_FLAG_SCROLLABLE);
  129.     lv_obj_set_scrollbar_mode(table, LV_SCROLLBAR_MODE_OFF);
  130.  
  131.  // table = lv_table_create(lv_scr_act());
  132.     lv_obj_align(table, LV_ALIGN_CENTER, -1, 0);
  133.  
  134.     lv_obj_set_style_text_opa(table, LV_OPA_COVER, 0);
  135.  
  136.    // lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
  137.  
  138.     lv_obj_set_style_bg_color(lv_scr_act(), lv_color_make(30, 30, 30), LV_PART_MAIN);
  139.  
  140.     lv_obj_set_style_text_color(table, lv_color_white(), LV_PART_ITEMS);
  141.  
  142.     lv_obj_set_style_bg_color(table, lv_color_make(30, 30, 30), LV_PART_MAIN);
  143.  
  144.     lv_obj_set_style_text_font(table, &lv_font_montserrat_14, LV_PART_ITEMS);
  145.  
  146.     lv_table_set_col_cnt(table, 4);
  147.     lv_table_set_row_cnt(table, 6);
  148.  
  149.     lv_obj_set_style_border_width(table, 1, LV_PART_ITEMS);
  150.     lv_obj_set_style_border_color(table, lv_color_white(), LV_PART_ITEMS);
  151.     lv_obj_set_style_border_side(table, LV_BORDER_SIDE_FULL, LV_PART_ITEMS);
  152.  
  153.     lv_table_set_col_width(table, 0, 60);
  154.     lv_table_set_col_width(table, 1, 100);
  155.     lv_table_set_col_width(table, 2, 60);
  156.     lv_table_set_col_width(table, 3, 100);
  157.  
  158.     lv_table_add_cell_ctrl(table, 5, 1, LV_TABLE_CELL_CTRL_MERGE_RIGHT);
  159.     lv_table_add_cell_ctrl(table, 5, 2, LV_TABLE_CELL_CTRL_MERGE_RIGHT);
  160.     lv_table_add_cell_ctrl(table, 5, 3, LV_TABLE_CELL_CTRL_MERGE_RIGHT);
  161.  
  162.     lv_table_set_cell_value(table, 0, 0, "RPM");
  163.     lv_table_set_cell_value(table, 0, 2, "SPD");
  164.     lv_table_set_cell_value(table, 1, 0, "AFR");
  165.     lv_table_set_cell_value(table, 1, 2, "CLT");
  166.     lv_table_set_cell_value(table, 2, 0, "TPS");
  167.     lv_table_set_cell_value(table, 2, 2, "BAT");
  168.     lv_table_set_cell_value(table, 3, 0, "MAP");
  169.     lv_table_set_cell_value(table, 3, 2, "BST");
  170.     lv_table_set_cell_value(table, 4, 0, "INJ");
  171.     lv_table_set_cell_value(table, 4, 2, "IGN");
  172.     lv_table_set_cell_value(table, 5, 0, "CEL");
  173.  
  174.     lv_obj_add_event_cb(table, my_table_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
  175.     lv_obj_add_event_cb(table, table_event_cb_bg, LV_EVENT_DRAW_PART_BEGIN, NULL);
  176.   }
  177.  // create_bt_icon();
  178.  
  179.   lv_timer_handler();
  180. }
  181.  
  182. void setup() {
  183.   tft.init();
  184.   pinMode(backLightPin, OUTPUT);
  185.   digitalWrite(backLightPin, LOW);
  186.   uint16_t darkGray = ((30 & 0xF8) << 8) | ((30 & 0xFC) << 3) | (30 >> 3);
  187.   tft.fillScreen(darkGray);
  188.   tft.setRotation(1);
  189.   Serial.begin(1000000);
  190.  
  191.   pinMode(buzzerPin, OUTPUT);
  192.  
  193.   // Initialize LVGL
  194.   lv_init();
  195.   lv_refr_now(NULL);
  196.   lv_disp_draw_buf_init(&draw_buf, buf, NULL, LV_HOR_RES_MAX * 10);
  197.  
  198.   static lv_disp_drv_t disp_drv;
  199.   lv_disp_drv_init(&disp_drv);
  200.   disp_drv.hor_res = screenWidth;
  201.   disp_drv.ver_res = screenHeight;
  202.   disp_drv.flush_cb = my_disp_flush;
  203.   disp_drv.draw_buf = &draw_buf;
  204.   lv_disp_drv_register(&disp_drv);
  205.  
  206.   touch.begin();
  207.  
  208.   static lv_indev_drv_t indev_drv;
  209.   lv_indev_drv_init(&indev_drv);
  210.   indev_drv.type = LV_INDEV_TYPE_POINTER;
  211.   indev_drv.read_cb = my_touchpad_read;
  212.   lv_indev_drv_register(&indev_drv);
  213.  
  214.   /*Serial.begin(115200);
  215.  
  216.   tft.init();
  217.   tft.setRotation(1);
  218.   tft.fillScreen(TFT_BLACK);
  219.  
  220.   lv_init();
  221.   lv_disp_draw_buf_init(&draw_buf, buf, NULL, LV_HOR_RES_MAX * 10);
  222.  
  223.   static lv_disp_drv_t disp_drv;
  224.   lv_disp_drv_init(&disp_drv);
  225.   disp_drv.hor_res = screenWidth;
  226.   disp_drv.ver_res = screenHeight;
  227.   disp_drv.flush_cb = my_disp_flush;
  228.   disp_drv.draw_buf = &draw_buf;
  229.   lv_disp_drv_register(&disp_drv);
  230.  
  231.   touch.begin();
  232.  
  233.   static lv_indev_drv_t indev_drv;
  234.   lv_indev_drv_init(&indev_drv);
  235.   indev_drv.type = LV_INDEV_TYPE_POINTER;
  236.   indev_drv.read_cb = my_touchpad_read;
  237.   lv_indev_drv_register(&indev_drv);*/
  238.  
  239.   SerialBT.begin(myBtName, true);
  240.  
  241.   create_table();
  242.   digitalWrite(backLightPin, HIGH);
  243.   connectToBt();
  244. }
  245.  
  246. void connectToBt() {
  247.   bool connected;
  248.   #ifndef USE_NAME
  249.     SerialBT.setPin(pin);
  250.   #endif
  251.  
  252.   #ifdef USE_NAME
  253.     connected = SerialBT.connect(slaveName);
  254.   #else
  255.     connected = SerialBT.connect(address);
  256.   #endif
  257.  
  258.   if (connected) {
  259.     Serial.println("Connected Successfully!");
  260.   } else {
  261.     Serial.println("Initial connect failed. Will retry in loop...");
  262.   }
  263.   update_bt_icon_color(SerialBT.hasClient(), false);
  264.   lv_timer_handler();
  265. }
  266.  
  267. void loop() {
  268.   uint8_t frame[5];
  269.   uint8_t channel;
  270.   uint16_t value;
  271.   int chData;
  272.   unsigned long currentMillis = millis();
  273.  
  274.   if (!SerialBT.connected()) {
  275.     // Attempt reconnection every 5 seconds
  276.     if (currentMillis - previousMillis >= reconnectInterval) {
  277.       previousMillis = currentMillis;
  278.       connectToBt();
  279.     }
  280.   }
  281.  
  282.   update_bt_icon_color(SerialBT.hasClient(), false);
  283.  
  284.   // Wait until at least 5 bytes are available
  285.   while (SerialBT.available() >= 5) {
  286.     SerialBT.readBytes(frame, 5);  // Read exactly 5 bytes
  287.  
  288.     channel = frame[0];
  289.     value = (frame[2] << 8) | frame[3];
  290.     chData = static_cast<int>(channel);
  291.     if (chData == 1) {
  292.       rpm = static_cast<int>(value);
  293.       lv_table_set_cell_value(table, 0, 1, String(rpm).c_str());
  294.     } else if (chData == 28) {
  295.       spd = (static_cast<int>(value) / 2.8);
  296.       lv_table_set_cell_value(table, 0, 3, (String(spd) + " KM/H").c_str());
  297.     } else if (chData == 12) {
  298.       afr = (static_cast<float>(value) / 10);
  299.       lv_table_set_cell_value(table, 1, 1, String(afr).c_str());
  300.     } else if (chData == 2) {
  301.       mapR = (static_cast<float>(value) / 100);
  302.       boost = (mapR - 1.0132f);
  303.       lv_table_set_cell_value(table, 3, 1, (String(mapR) + " BAR").c_str());
  304.       lv_table_set_cell_value(table, 3, 3, (String(boost) + " BAR").c_str());
  305.     } else if (chData == 3) {
  306.       tps = static_cast<int>(value);
  307.       lv_table_set_cell_value(table, 2, 1, (String(tps) + " %").c_str());
  308.     } else if (chData == 24) {
  309.       clt = static_cast<int>(value);
  310.       lv_table_set_cell_value(table, 1, 3, (String(clt) + " °C").c_str());
  311.     } else if (chData == 6) {
  312.       ign = (static_cast<int>(value) / 2);
  313.       lv_table_set_cell_value(table, 4, 3, (String(ign) + " °").c_str());
  314.     } else if (chData == 19) {
  315.       inj = (static_cast<int>(value) / 2);
  316.       lv_table_set_cell_value(table, 4, 1, (String(inj) + " %").c_str());
  317.     } else if (chData == 5) {
  318.       bat = (static_cast<float>(value) / 37);
  319.       lv_table_set_cell_value(table, 2, 3, (String(bat) + " V").c_str());
  320.     } else if (chData == 255) {
  321.       cel = decodeCheckEngine(value);
  322.     }
  323.   }
  324.  
  325.   /*if (cel > 0 || clt > 105 || rpm > 7000 || boost > 1.10 || (bat < 12.00 && bat > 1.00)) {
  326.     digitalWrite(buzzerPin, HIGH);  // Buzzer ON
  327.   } else {
  328.     digitalWrite(buzzerPin, LOW);   // Buzzer OFF
  329.   }*/
  330.  
  331.   buzzerOn = (cel > 0 || clt > 105 || rpm > 7000 || boost > 1.10 || (bat < 12.00 && bat > 1.00));
  332.   digitalWrite(buzzerPin, (millis() % 600 < 300) && buzzerOn);
  333.  
  334.   lv_obj_invalidate(table);
  335.   lv_timer_handler();
  336. }
  337.  
  338. int decodeCheckEngine(uint16_t value) {
  339.   int cel_codes = 0; string cel_names = "";
  340.   if (value == 0) {
  341.     return 0;
  342.   }
  343.   else {
  344.     if (value & (1 << 0)) {
  345.       cel_codes++;  // Bit 0
  346.       cel_names = "CLT ";
  347.     }
  348.     if (value & (1 << 1)) {
  349.       //cel_codes++;  // Bit 1
  350.       //cel_names += "IAT ";
  351.     }
  352.     if (value & (1 << 2)) {
  353.       cel_codes++;  // Bit 2
  354.       cel_names += "MAP ";
  355.     }
  356.     if (value & (1 << 3)) {
  357.       cel_codes++;  // Bit 3
  358.       cel_names += "WBO ";
  359.     }
  360.     if (value & (1 << 8)) {
  361.       cel_codes++;  // Bit 8
  362.       cel_names += "FF SENSOR ";
  363.     }
  364.     if (value & (1 << 9)) {
  365.       cel_codes++;  // Bit 9
  366.       cel_names += "DBW ";
  367.     }
  368.     if (value & (1 << 10)) {
  369.       cel_codes++;  // Bit 10
  370.       cel_names += "FPR ";
  371.     }
  372.  
  373.     lv_table_set_cell_value(table, 5, 1, cel_names.c_str());
  374.     return cel_codes;
  375.   }
  376. }
  377.  
  378. // Cell alignment fix
  379. void my_table_event_cb(lv_event_t * e) {
  380.   lv_obj_t * table = lv_event_get_target(e);
  381.   lv_obj_draw_part_dsc_t * dsc = (lv_obj_draw_part_dsc_t *)lv_event_get_param(e);
  382.  
  383.   if (dsc->part == LV_PART_ITEMS) {
  384.     uint16_t row = dsc->id / lv_table_get_col_cnt(table);
  385.     uint16_t col = dsc->id % lv_table_get_col_cnt(table);
  386.  
  387.     dsc->label_dsc->align = LV_TEXT_ALIGN_LEFT;
  388.     if ((row == 0 && col == 1) || (row == 0 && col == 3) || (row == 1 && col == 1) || (row == 1 && col == 3) || (row == 2 && col == 1) || (row == 2 && col == 3) || (row == 3 && col == 1) || (row == 3 && col == 3) ||
  389.         (row == 4 && col == 1) || (row == 4 && col == 3)) {
  390.       dsc->label_dsc->align = LV_TEXT_ALIGN_RIGHT;
  391.     }
  392.     if (row == 5 && col == 1) {
  393.       dsc->label_dsc->align = LV_TEXT_ALIGN_CENTER;
  394.     }
  395.   }
  396. }
  397.  
  398. static void table_event_cb_bg(lv_event_t *e) {
  399.   lv_obj_t *table = lv_event_get_target(e);
  400.   lv_obj_draw_part_dsc_t *dsc = (lv_obj_draw_part_dsc_t *)lv_event_get_param(e);
  401.  
  402.   // Ensure dsc and rect_dsc are valid
  403.   if (!dsc || !dsc->rect_dsc) return;
  404.  
  405.   // Only modify table cell backgrounds
  406.   if (dsc->part == LV_PART_ITEMS) {
  407.     uint16_t row = dsc->id / lv_table_get_col_cnt(table);
  408.     uint16_t col = dsc->id % lv_table_get_col_cnt(table);
  409.  
  410.     const char *value_str = lv_table_get_cell_value(table, row, col);
  411.  
  412.     // Check if value_str is null or empty before conversion
  413.     float value = 0.0f;  // Default value
  414.     if (value_str != nullptr && value_str[0] != '\0') {
  415.       try {
  416.         value = std::stof(value_str);  // Convert string to float safely
  417.       } catch (...) {
  418.         value = 0.0f;  // Handle invalid conversions
  419.       }
  420.     }
  421.  
  422.     // Default cell color
  423.     lv_color_t bg_color = lv_color_make(30, 30, 30);
  424.     lv_color_t text_color = lv_color_white();
  425.  
  426.     if (row == 0 && col == 1 && value > 7000.00) {
  427.       bg_color = lv_color_make(0, 0, 255);
  428.       text_color = lv_color_white();
  429.     }
  430.     if (row == 1 && col == 3 && value > 100.00) {
  431.       bg_color = lv_color_make(0, 0, 255);
  432.       text_color = lv_color_white();
  433.     }
  434.     if (row == 1 && col == 3 && value < 55.00 && value > 01.00) {
  435.       bg_color = lv_color_make(0, 255, 255);
  436.       text_color = lv_color_black();
  437.     }
  438.     if (row == 2 && col == 3 && value < 12.00 && value > 01.00) {
  439.       bg_color = lv_color_make(0, 0, 255);
  440.       text_color = lv_color_white();
  441.     }
  442.     if (row == 3 && col == 3 && value > 1.10) {
  443.       bg_color = lv_color_make(0, 0, 255);
  444.       text_color = lv_color_white();
  445.     }
  446.     if (row == 5 && col == 1 && value_str != nullptr && value_str[0] != '\0') {
  447.       bg_color = lv_color_make(0, 0, 255);
  448.       text_color = lv_color_white();
  449.     }
  450.  
  451.     // Apply background color to the cell
  452.     dsc->rect_dsc->bg_color = bg_color;
  453.     dsc->rect_dsc->bg_opa = LV_OPA_COVER;
  454.     dsc->label_dsc->color = text_color;
  455.   }
  456. }
  457.  
  458. void update_bt_icon_color(bool is_connected, bool firstTime) {
  459.   if(btIconSts != is_connected || firstTime) {
  460.     if (!style_initialized) {
  461.       lv_style_init(&style_bt);
  462.       style_initialized = true;
  463.     }
  464.     if (is_connected) {
  465.       lv_style_set_text_color(&style_bt, lv_color_make(0, 255, 0)); // Green
  466.     } else {
  467.       lv_style_set_text_color(&style_bt, lv_color_make(0, 0, 255)); // Red
  468.     }
  469.     lv_obj_add_style(bt_icon_label, &style_bt, 0);
  470.     btIconSts = is_connected;
  471.   }
  472. }
  473.  
  474. void create_bt_icon() {
  475.   bt_icon_label = lv_label_create(lv_scr_act());
  476.   lv_label_set_text(bt_icon_label, LV_SYMBOL_BLUETOOTH);
  477.   lv_obj_set_style_text_font(bt_icon_label, &lv_font_montserrat_28, LV_PART_MAIN);
  478.   lv_obj_align(bt_icon_label, LV_ALIGN_BOTTOM_RIGHT, -3, -1);
  479.   update_bt_icon_color(SerialBT.hasClient(), true);
  480. }
Advertisement
Add Comment
Please, Sign In to add comment