Mejoras graficas
This commit is contained in:
parent
ddc4a109af
commit
037c782d11
6 changed files with 238 additions and 156 deletions
|
|
@ -100,7 +100,7 @@ inline void drawClusterBaseCards(int x_offset = 0) {
|
|||
// 1. TACHOMETER CARD (x: 8, y: 8, w: 304, h: 58)
|
||||
tft.fillRoundRect(8 + x_offset, 8, 304, 58, 5, cardBg);
|
||||
tft.drawRoundRect(8 + x_offset, 8, 304, 58, 5, border);
|
||||
tft.fillRoundRect(14 + x_offset, 14, 4, 46, 2, cRpm);
|
||||
tft.drawRect(14 + x_offset, 14, 4, 46, cRpm);
|
||||
// Tachometer triangle VU-meter inactive background slots (14 steps, ramp h: 5..31 px, x: 24..106)
|
||||
for (int s = 0; s < 14; s++) {
|
||||
int barX = 24 + s * 6 + x_offset;
|
||||
|
|
@ -114,20 +114,20 @@ inline void drawClusterBaseCards(int x_offset = 0) {
|
|||
// 2. SPEEDOMETER CARD (x: 8, y: 70, w: 304, h: 100)
|
||||
tft.fillRoundRect(8 + x_offset, 70, 304, 100, 5, cardBg);
|
||||
tft.drawRoundRect(8 + x_offset, 70, 304, 100, 5, border);
|
||||
tft.fillRoundRect(14 + x_offset, 78, 4, 84, 2, cSpd);
|
||||
tft.drawRect(14 + x_offset, 78, 4, 84, cSpd);
|
||||
// Large anti-aliased "KM/H" (Chakra Petch Bold Italic) at far right (baseline at y = 160)
|
||||
drawKmH_AA(tft, 198 + x_offset, 132, cSpd, cardBg, 240, isRainbowTheme());
|
||||
|
||||
// 3. COOLANT TEMP CARD (x: 8, y: 174, w: 148, h: 62)
|
||||
tft.fillRoundRect(8 + x_offset, 174, 148, 62, 5, cardBg);
|
||||
tft.drawRoundRect(8 + x_offset, 174, 148, 62, 5, border);
|
||||
tft.fillRoundRect(14 + x_offset, 182, 4, 46, 2, cCool);
|
||||
tft.drawRect(14 + x_offset, 182, 4, 46, cCool);
|
||||
draw7SegDegreeC(tft, 118 + x_offset, 201, cCool, cardBg, isRainbowTheme());
|
||||
|
||||
// 4. BATTERY VOLTAGE CARD (x: 164, y: 174, w: 148, h: 62)
|
||||
tft.fillRoundRect(164 + x_offset, 174, 148, 62, 5, cardBg);
|
||||
tft.drawRoundRect(164 + x_offset, 174, 148, 62, 5, border);
|
||||
tft.fillRoundRect(170 + x_offset, 182, 4, 46, 2, cVolt);
|
||||
tft.drawRect(170 + x_offset, 182, 4, 46, cVolt);
|
||||
drawVolt_AA(tft, 286 + x_offset, 202, cVolt, cardBg, 240, isRainbowTheme());
|
||||
}
|
||||
|
||||
|
|
@ -277,14 +277,14 @@ inline void updateClusterScreen(bool forceRedraw) {
|
|||
|
||||
if (coolCol != oldClusterCoolCol || forceRedraw) {
|
||||
oldClusterCoolCol = coolCol;
|
||||
tft.fillRoundRect(14, 182, 4, 46, 2, coolCol);
|
||||
tft.drawRect(14, 182, 4, 46, coolCol);
|
||||
draw7SegDegreeC(tft, 118, 201, coolCol, cardBg, rainbowTxt && (coolCol != TFT_RED));
|
||||
}
|
||||
} else {
|
||||
drawDseg7RightFast44(tft, "---", 114, 183, cCool, cardBg, 90, isRainbowTheme());
|
||||
if (cCool != oldClusterCoolCol || forceRedraw) {
|
||||
oldClusterCoolCol = cCool;
|
||||
tft.fillRoundRect(14, 182, 4, 46, 2, cCool);
|
||||
tft.drawRect(14, 182, 4, 46, cCool);
|
||||
draw7SegDegreeC(tft, 118, 201, cCool, cardBg, isRainbowTheme());
|
||||
}
|
||||
}
|
||||
|
|
@ -305,14 +305,14 @@ inline void updateClusterScreen(bool forceRedraw) {
|
|||
|
||||
if (voltCol != oldClusterVoltCol || forceRedraw) {
|
||||
oldClusterVoltCol = voltCol;
|
||||
tft.fillRoundRect(170, 182, 4, 46, 2, voltCol);
|
||||
tft.drawRect(170, 182, 4, 46, voltCol);
|
||||
drawVolt_AA(tft, 286, 202, voltCol, cardBg, 240, rainbowTxt);
|
||||
}
|
||||
} else {
|
||||
drawDseg7RightFast44(tft, "---", 282, 183, cVolt, cardBg, 106, isRainbowTheme());
|
||||
if (cVolt != oldClusterVoltCol || forceRedraw) {
|
||||
oldClusterVoltCol = cVolt;
|
||||
tft.fillRoundRect(170, 182, 4, 46, 2, cVolt);
|
||||
tft.drawRect(170, 182, 4, 46, cVolt);
|
||||
drawVolt_AA(tft, 286, 202, cVolt, cardBg, 240, isRainbowTheme());
|
||||
}
|
||||
}
|
||||
|
|
@ -345,7 +345,7 @@ inline void renderClusterScreenToSprite(TFT_eSprite &s, int x_offset, int y_slic
|
|||
if (c0Y < slice_h && c0Y + 58 > 0) {
|
||||
s.fillRoundRect(8, c0Y, 304, 58, 5, cardBg);
|
||||
s.drawRoundRect(8, c0Y, 304, 58, 5, border);
|
||||
s.fillRoundRect(14, c0Y + 6, 4, 46, 2, cRpm);
|
||||
s.drawRect(14, c0Y + 6, 4, 46, cRpm);
|
||||
float curRpmF = getClusterRpmVal();
|
||||
int curRpm = (int)round(curRpmF);
|
||||
bool rainbowTxt = isRainbowTheme();
|
||||
|
|
@ -400,7 +400,7 @@ inline void renderClusterScreenToSprite(TFT_eSprite &s, int x_offset, int y_slic
|
|||
if (c1Y < slice_h && c1Y + 100 > 0) {
|
||||
s.fillRoundRect(8, c1Y, 304, 100, 5, cardBg);
|
||||
s.drawRoundRect(8, c1Y, 304, 100, 5, border);
|
||||
s.fillRoundRect(14, c1Y + 8, 4, 84, 2, cSpd);
|
||||
s.drawRect(14, c1Y + 8, 4, 84, cSpd);
|
||||
|
||||
bool isGps = isClusterSpeedFromGps();
|
||||
if (isGps) {
|
||||
|
|
@ -429,7 +429,7 @@ inline void renderClusterScreenToSprite(TFT_eSprite &s, int x_offset, int y_slic
|
|||
float curCoolF = getClusterCoolantVal();
|
||||
int curCool = (curCoolF > -900.0f) ? (int)round(curCoolF) : -999;
|
||||
uint16_t coolCol = (curCool > -900) ? ((curCool >= 105) ? TFT_RED : ((curCool < 70) ? 0x05BF : cCool)) : cCool;
|
||||
s.fillRoundRect(14, c2Y + 8, 4, 46, 2, coolCol);
|
||||
s.drawRect(14, c2Y + 8, 4, 46, coolCol);
|
||||
if (curCool > -900) {
|
||||
String valStr = String(curCool);
|
||||
bool rainbowTxt = isRainbowTheme();
|
||||
|
|
@ -448,7 +448,7 @@ inline void renderClusterScreenToSprite(TFT_eSprite &s, int x_offset, int y_slic
|
|||
s.drawRoundRect(164, c3Y, 148, 62, 5, border);
|
||||
float curVolt = getClusterVoltVal();
|
||||
uint16_t voltCol = (curVolt > 0.0f) ? ((curVolt < 11.8f || curVolt > 15.0f) ? TFT_RED : ((curVolt >= 13.5f) ? 0x07E0 : cVolt)) : cVolt;
|
||||
s.fillRoundRect(170, c3Y + 8, 4, 46, 2, voltCol);
|
||||
s.drawRect(170, c3Y + 8, 4, 46, voltCol);
|
||||
if (curVolt > 0.0f) {
|
||||
String voltStr = String(curVolt, 1);
|
||||
bool rainbowTxt = isRainbowTheme();
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ inline void drawDateCardContent(int cardX, int cardY, int cardW, int cardH,
|
|||
String dayStr = (gpsDay < 10) ? "0" + String(gpsDay) : String(gpsDay);
|
||||
|
||||
// Left vertical accent bar
|
||||
tft.fillRoundRect(cardX + 6, cardY + 8, 4, cardH - 16, 2, accCol);
|
||||
tft.drawRect(cardX + 6, cardY + 8, 4, cardH - 16, accCol);
|
||||
|
||||
// --- CALENDAR BADGE (Left side: 80x82 px) ---
|
||||
int bx = cardX + 20;
|
||||
|
|
@ -364,7 +364,7 @@ inline void drawGpsClockScreen(int x_offset = 0) {
|
|||
tft.drawRoundRect(clkX, clkY, clkW, clkH, 6, cardBorder);
|
||||
|
||||
// Left vertical accent bar
|
||||
tft.fillRoundRect(clkX + 6, clkY + 8, 4, clkH - 16, 2, clkAccCol);
|
||||
tft.drawRect(clkX + 6, clkY + 8, 4, clkH - 16, clkAccCol);
|
||||
|
||||
// Digits: Hours HH & Minutes MM with smooth rainbow gradient
|
||||
uint8_t h10 = (gpsHour / 10) % 10;
|
||||
|
|
@ -480,7 +480,7 @@ inline void renderPage2ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
|||
if (clkX + clkW > 0 && clkX < 320 && clkY + clkH > 0 && clkY < slice_h) {
|
||||
s.fillRoundRect(clkX, clkY, clkW, clkH, 6, cardBg);
|
||||
s.drawRoundRect(clkX, clkY, clkW, clkH, 6, cardBorder);
|
||||
s.fillRoundRect(clkX + 6, clkY + 8, 4, clkH - 16, 2, clkAccCol);
|
||||
s.drawRect(clkX + 6, clkY + 8, 4, clkH - 16, clkAccCol);
|
||||
|
||||
// Colon dots during transition (italic 7-segment style with anti-aliasing)
|
||||
draw7SegColon(s, clkX, clkY, clkAccCol, cardBg, slice_h, isRainbowTheme());
|
||||
|
|
@ -518,7 +518,7 @@ inline void renderPage2ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
|||
uint16_t yearCol = isRainbowTheme() ? (uint16_t)0xFFE0 : accCol;
|
||||
s.fillRoundRect(dateX, dateY, dateW, dateH, 6, cardBg);
|
||||
s.drawRoundRect(dateX, dateY, dateW, dateH, 6, cardBorder);
|
||||
s.fillRoundRect(dateX + 6, dateY + 8, 4, dateH - 16, 2, dateAccCol);
|
||||
s.drawRect(dateX + 6, dateY + 8, 4, dateH - 16, dateAccCol);
|
||||
|
||||
// Badge container
|
||||
int bx = dateX + 20;
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
|||
int cH1 = 102;
|
||||
tft.fillRoundRect(c0X, c0Y, cW, cH1, 6, cardBg);
|
||||
tft.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
||||
tft.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
||||
tft.drawRect(c0X + 6, c0Y + 8, 4, cH1 - 16, c0Col);
|
||||
|
||||
drawGpsNavTitle(tft, "ALTITUD", c0X + 16, c0Y + 8, 0x8410, cardBg, 240);
|
||||
drawGpsNavSubword(tft, "MSNM", c0X + 96, c0Y + 9, 0x9CD3, cardBg, 240);
|
||||
|
|
@ -169,7 +169,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
|||
int c1Y = 19;
|
||||
tft.fillRoundRect(c1X, c1Y, cW, cH1, 6, cardBg);
|
||||
tft.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
||||
tft.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
||||
tft.drawRect(c1X + 6, c1Y + 8, 4, cH1 - 16, c1Col);
|
||||
|
||||
drawGpsNavTitle(tft, "RUMBO / BRUJULA", c1X + 16, c1Y + 8, 0x8410, cardBg, 240);
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
|||
int cH2 = 110;
|
||||
tft.fillRoundRect(c2X, c2Y, cW, cH2, 6, cardBg);
|
||||
tft.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
||||
tft.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
||||
tft.drawRect(c2X + 6, c2Y + 8, 4, cH2 - 16, c2Col);
|
||||
|
||||
drawGpsNavTitle(tft, "SATELITES GPS", c2X + 16, c2Y + 8, 0x8410, cardBg, 240);
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
|||
int c3Y = 125;
|
||||
tft.fillRoundRect(c3X, c3Y, cW, cH2, 6, cardBg);
|
||||
tft.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
||||
tft.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
||||
tft.drawRect(c3X + 6, c3Y + 8, 4, cH2 - 16, c3Col);
|
||||
|
||||
drawGpsNavTitle(tft, "COORDENADAS", c3X + 16, c3Y + 8, 0x8410, cardBg, 240);
|
||||
|
||||
|
|
@ -390,7 +390,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
|||
if (c0X + cW > 0 && c0X < 320 && c0Y + cH1 > 0 && c0Y < slice_h) {
|
||||
s.fillRoundRect(c0X, c0Y, cW, cH1, 6, cardBg);
|
||||
s.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
||||
s.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
||||
s.drawRect(c0X + 6, c0Y + 8, 4, cH1 - 16, c0Col);
|
||||
|
||||
drawGpsNavTitle(s, "ALTITUD", c0X + 16, c0Y + 8, 0x8410, cardBg, slice_h);
|
||||
drawGpsNavSubword(s, "MSNM", c0X + 96, c0Y + 9, 0x9CD3, cardBg, slice_h);
|
||||
|
|
@ -408,7 +408,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
|||
if (c1X + cW > 0 && c1X < 320 && c1Y + cH1 > 0 && c1Y < slice_h) {
|
||||
s.fillRoundRect(c1X, c1Y, cW, cH1, 6, cardBg);
|
||||
s.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
||||
s.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
||||
s.drawRect(c1X + 6, c1Y + 8, 4, cH1 - 16, c1Col);
|
||||
|
||||
drawGpsNavTitle(s, "RUMBO / BRUJULA", c1X + 16, c1Y + 8, 0x8410, cardBg, slice_h);
|
||||
bool hasCourse = synced && isGpsCourseValid();
|
||||
|
|
@ -435,7 +435,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
|||
if (c2X + cW > 0 && c2X < 320 && c2Y + cH2 > 0 && c2Y < slice_h) {
|
||||
s.fillRoundRect(c2X, c2Y, cW, cH2, 6, cardBg);
|
||||
s.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
||||
s.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
||||
s.drawRect(c2X + 6, c2Y + 8, 4, cH2 - 16, c2Col);
|
||||
|
||||
drawGpsNavTitle(s, "SATELITES GPS", c2X + 16, c2Y + 8, 0x8410, cardBg, slice_h);
|
||||
uint8_t waveState = getGpsWaveAnimState();
|
||||
|
|
@ -460,7 +460,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
|||
if (c3X + cW > 0 && c3X < 320 && c3Y + cH2 > 0 && c3Y < slice_h) {
|
||||
s.fillRoundRect(c3X, c3Y, cW, cH2, 6, cardBg);
|
||||
s.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
||||
s.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
||||
s.drawRect(c3X + 6, c3Y + 8, 4, cH2 - 16, c3Col);
|
||||
|
||||
drawGpsNavTitle(s, "COORDENADAS", c3X + 16, c3Y + 8, 0x8410, cardBg, slice_h);
|
||||
|
||||
|
|
|
|||
|
|
@ -1583,7 +1583,7 @@ inline void renderPage1ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
|||
accentCol = isRainbowTheme() ? (uint16_t)0xFD20 : getThemePrimaryColor();
|
||||
}
|
||||
|
||||
s.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
||||
s.drawRect(cardX + 6, cardY + 6, 4, cardH - 12, accentCol);
|
||||
// Smooth anti-aliased title in transition sprite (zero mallocs, 100%
|
||||
// smooth)
|
||||
if (!sprTriTitleReady)
|
||||
|
|
|
|||
|
|
@ -70,16 +70,16 @@ warn = default warning value
|
|||
*/
|
||||
const String pidConfig[5][9] = {
|
||||
//[pid][data]
|
||||
{"Temperatura", "`C", "0105", "1", "60", "120", "2", "0",
|
||||
"110"}, // 0 = Temperatura (0105)
|
||||
{"Temperatura", "`C", "0105", "1", "60", "120", "14", "0",
|
||||
"110"}, // 0 = Temperatura (0105): skip 14 (~1.5s)
|
||||
{"RPM", "rpm", "010C", "3", "0", "6000", "0", "0",
|
||||
"5000"}, // 1 = RPM (010C)
|
||||
{"Voltaje", "V", "ATRV", "8", "10", "16", "1", "1",
|
||||
"15"}, // 2 = Voltaje Bateria (ATRV)
|
||||
{"Velocidad", "km/h", "010D", "7", "0", "160", "0", "0",
|
||||
"130"}, // 3 = Velocidad (010D)
|
||||
{"Carga", "%", "0104", "2", "0", "100", "0", "0",
|
||||
"85"} // 4 = Carga Motor (0104)
|
||||
"5000"}, // 1 = RPM (010C): skip 0 (queries EVERY cycle)
|
||||
{"Voltaje", "V", "ATRV", "8", "10", "16", "10", "1",
|
||||
"15"}, // 2 = Voltaje Bateria (ATRV): skip 10 (~1s)
|
||||
{"Velocidad", "km/h", "010D", "7", "0", "160", "2", "0",
|
||||
"130"}, // 3 = Velocidad (010D): skip 2 (or skipped if GPS speed valid)
|
||||
{"Carga", "%", "0104", "2", "0", "100", "12", "0",
|
||||
"85"} // 4 = Carga Motor (0104): skip 12 (~1.5s)
|
||||
};
|
||||
|
||||
// hold warning value
|
||||
|
|
@ -344,7 +344,7 @@ uint8_t btDeviceCount = 0; // discovered bluetooth devices counter
|
|||
esp_bd_addr_t client_addr = {0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00}; // obdII mac addr
|
||||
esp_bd_addr_t recent_client_addr = {
|
||||
0x6C, 0x62, 0x6D, 0x14, 0x08, 0xFD}; // Default to PC emulator MAC
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // Real OBD2 MAC address stored in NVS
|
||||
const String client_name = "OBDII"; // adaptor name to search
|
||||
esp_spp_sec_t sec_mask =
|
||||
ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to
|
||||
|
|
@ -546,89 +546,141 @@ void initializeELM327() {
|
|||
TaskHandle_t btTaskHandle = NULL;
|
||||
volatile bool btConnectedTrigger = false;
|
||||
volatile bool systemSleeping = false;
|
||||
bool gpsClockAutoSwitched = false;
|
||||
|
||||
// SPP Event Callback: Automatically captures and stores the remote OBD2 MAC address to NVS
|
||||
void sppCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
|
||||
if (event == ESP_SPP_OPEN_EVT) {
|
||||
if (param->open.status == ESP_SPP_SUCCESS) {
|
||||
bool isZero = true;
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (param->open.rem_bda[i] != 0) {
|
||||
isZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isZero) {
|
||||
memcpy(recent_client_addr, param->open.rem_bda, 6);
|
||||
pref.begin("setting", false);
|
||||
pref.putBytes("recent_client", recent_client_addr, 6);
|
||||
pref.end();
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.printf("[BT] SPP Connected! Stored OBD MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
recent_client_addr[0], recent_client_addr[1], recent_client_addr[2],
|
||||
recent_client_addr[3], recent_client_addr[4], recent_client_addr[5]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void btBackgroundTask(void *pvParameters) {
|
||||
const esp_bd_addr_t EMU_ADDR = {0x6C, 0x62, 0x6D, 0x14, 0x08, 0xFD};
|
||||
while (true) {
|
||||
if (!systemSleeping && !foundOBD2) {
|
||||
// Only attempt connection if not sleeping, not declared found, and not already connected!
|
||||
if (!systemSleeping && !foundOBD2 && !BTSerial.connected()) {
|
||||
bool connected = false;
|
||||
|
||||
// 1. Intentar conectar a la direccion reciente guardada si es valida
|
||||
// Check if recent_client_addr is valid (non-zero and not old default emulator)
|
||||
bool hasRecentAddr = false;
|
||||
const esp_bd_addr_t OLD_EMU = {0x6C, 0x62, 0x6D, 0x14, 0x08, 0xFD};
|
||||
bool isOldEmu = true;
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (recent_client_addr[i] != 0) {
|
||||
hasRecentAddr = true;
|
||||
break;
|
||||
if (recent_client_addr[i] != 0) hasRecentAddr = true;
|
||||
if (recent_client_addr[i] != OLD_EMU[i]) isOldEmu = false;
|
||||
}
|
||||
}
|
||||
if (hasRecentAddr) {
|
||||
setRearLedColor(0, 0, 200);
|
||||
BTSerial.disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (BTSerial.connect(recent_client_addr, 0, sec_mask, role)) {
|
||||
if (BTSerial.connected() && !systemSleeping) {
|
||||
if (isOldEmu) hasRecentAddr = false;
|
||||
|
||||
// 1. Direct connection to saved MAC address (Ultra fast: < 1s, reliable even if OBD2 was already ON)
|
||||
if (hasRecentAddr && !systemSleeping) {
|
||||
setRearLedColor(0, 0, 200); // Blue LED
|
||||
if (BTSerial.connect(recent_client_addr, 0, ESP_SPP_SEC_NONE, ESP_SPP_ROLE_MASTER)) {
|
||||
if (BTSerial.connected(1000) && !systemSleeping) {
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Si fallo o no habia direccion, intentar conectar a la MAC del emulador PC
|
||||
if (!connected && !systemSleeping) {
|
||||
bool isRecentSameAsEmu = true;
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (recent_client_addr[i] != EMU_ADDR[i]) {
|
||||
isRecentSameAsEmu = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isRecentSameAsEmu) {
|
||||
setRearLedColor(0, 0, 200);
|
||||
BTSerial.disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (BTSerial.connect(const_cast<uint8_t*>(EMU_ADDR), 0, sec_mask, role)) {
|
||||
if (BTSerial.connected() && !systemSleeping) {
|
||||
connected = true;
|
||||
memcpy(recent_client_addr, EMU_ADDR, 6);
|
||||
pref.putBytes("recent_client", recent_client_addr, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Si aun no conecto, buscar y conectar por nombre "OBDII" (inquiry scan)
|
||||
// 2. If direct connection failed or no address saved, connect by name "OBDII"
|
||||
if (!connected && !systemSleeping) {
|
||||
setRearLedColor(0, 0, 200);
|
||||
BTSerial.disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
if (BTSerial.connect("OBDII")) {
|
||||
if (BTSerial.connected() && !systemSleeping) {
|
||||
if (BTSerial.connected(1000) && !systemSleeping) {
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback: Escaneo y descubrimiento de dispositivos OBD (OBDII, ELM, etc.)
|
||||
if (!connected && !systemSleeping) {
|
||||
setRearLedColor(0, 0, 200);
|
||||
BTSerial.disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
static esp_bd_addr_t discoveredAddr;
|
||||
static volatile bool discFound = false;
|
||||
discFound = false;
|
||||
|
||||
BTSerial.discoverAsync([](BTAdvertisedDevice *pDevice) {
|
||||
String dName = pDevice->getName().c_str();
|
||||
dName.toUpperCase();
|
||||
if (dName.indexOf("OBD") != -1 || dName.indexOf("ELM") != -1 ||
|
||||
dName.indexOf("VGATE") != -1 || dName.indexOf("VIECAR") != -1) {
|
||||
esp_bd_addr_t *nativeAddr = pDevice->getAddress().getNative();
|
||||
if (nativeAddr != nullptr) {
|
||||
memcpy(discoveredAddr, *nativeAddr, 6);
|
||||
discFound = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
uint32_t startDisc = millis();
|
||||
while (millis() - startDisc < 4000 && !discFound && !systemSleeping) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
BTSerial.discoverAsyncStop();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
if (discFound && !systemSleeping) {
|
||||
if (BTSerial.connect(discoveredAddr, 0, ESP_SPP_SEC_NONE, ESP_SPP_ROLE_MASTER)) {
|
||||
if (BTSerial.connected(1000) && !systemSleeping) {
|
||||
connected = true;
|
||||
memcpy(recent_client_addr, discoveredAddr, 6);
|
||||
pref.begin("setting", false);
|
||||
pref.putBytes("recent_client", recent_client_addr, 6);
|
||||
pref.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si logro conectar con cualquiera de los metodos:
|
||||
if (connected && !systemSleeping) {
|
||||
sendATCommand("ATE0", 800);
|
||||
sendATCommand("ATL0", 800);
|
||||
sendATCommand("ATH0", 800);
|
||||
sendATCommand("ATAT1", 800);
|
||||
sendATCommand("ATSP1", 800);
|
||||
// Enviar ATZ para limpiar buffers y reiniciar chip ELM327 (clave cuando el OBD2 ya estaba enchufado antes)
|
||||
sendATCommand("ATZ", 1500);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
sendATCommand("ATE0", 500); // Echo OFF
|
||||
sendATCommand("ATL0", 500); // Linefeed OFF
|
||||
sendATCommand("ATS0", 500); // Spaces OFF (mucho mas veloz)
|
||||
sendATCommand("ATH0", 500); // Headers OFF
|
||||
sendATCommand("ATAT1", 500); // Adaptive timing
|
||||
sendATCommand("ATSP1", 500); // Ford J1850 PWM
|
||||
|
||||
String r0100 = sendATCommand("0100", 2500);
|
||||
ignitionOn = (r0100.indexOf("41 00") != -1);
|
||||
ignitionOn = (r0100.indexOf("4100") != -1 || r0100.indexOf("41 00") != -1);
|
||||
foundOBD2 = true;
|
||||
prompt = true;
|
||||
bt_message = "";
|
||||
updateRearLedTheme();
|
||||
btConnectedTrigger =
|
||||
true; // Signal Core 1 (UI thread) to switch screen!
|
||||
btConnectedTrigger = true;
|
||||
} else {
|
||||
BTSerial.disconnect();
|
||||
if (!BTSerial.connected()) {
|
||||
setRearLedOff();
|
||||
}
|
||||
foundOBD2 = false;
|
||||
}
|
||||
}
|
||||
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(3500));
|
||||
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -759,9 +811,23 @@ recent_client_addr : {0x00,0x00,0x00,0x00,0x00,0x00} array of bytes[6]
|
|||
currentBacklight = (float)targetBacklight;
|
||||
ledcWrite(backlightChannel, targetBacklight);
|
||||
}
|
||||
lastActivityTime = millis();
|
||||
pref.getBytes("recent_client", recent_client_addr,
|
||||
pref.getBytesLength("recent_client")); // read last bt address
|
||||
if (pref.isKey("recent_client")) {
|
||||
pref.getBytes("recent_client", recent_client_addr, 6);
|
||||
const esp_bd_addr_t OLD_EMU_MAC = {0x6C, 0x62, 0x6D, 0x14, 0x08, 0xFD};
|
||||
bool isOldEmu = true;
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (recent_client_addr[i] != OLD_EMU_MAC[i]) {
|
||||
isOldEmu = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isOldEmu) {
|
||||
memset(recent_client_addr, 0, 6);
|
||||
pref.remove("recent_client");
|
||||
}
|
||||
} else {
|
||||
memset(recent_client_addr, 0, 6);
|
||||
}
|
||||
|
||||
updateRearLedTheme(); // Sync rear RGB LED with loaded theme
|
||||
Terminal("[ OK ] Settings: Theme " + String(GAUGE_THEMES[themeIndex].name) +
|
||||
|
|
@ -822,6 +888,11 @@ recent_client_addr : {0x00,0x00,0x00,0x00,0x00,0x00} array of bytes[6]
|
|||
Terminal("[ OK ] Bluetooth SPP Master stack online");
|
||||
}
|
||||
|
||||
// Automatically capture and persist remote OBD2 MAC address upon connection
|
||||
BTSerial.register_callback(sppCallback);
|
||||
BTSerial.setPin("1234");
|
||||
BTSerial.enableSSP();
|
||||
|
||||
#ifdef SKIP_CONNECTION
|
||||
foundOBD2 = true;
|
||||
#else
|
||||
|
|
@ -853,24 +924,45 @@ void loop() {
|
|||
|
||||
|
||||
|
||||
// Trigger automatico: Cuando el Bluetooth conecta en segundo plano (Core 0),
|
||||
// pasar a pantalla OBD!
|
||||
// 1. Trigger automatico Bluetooth:
|
||||
// Solo en arranque en frio inicial si el usuario NO navego manualmente
|
||||
static bool userNavigatedManually = false;
|
||||
static bool initialBtAutoSwitched = false;
|
||||
if (btConnectedTrigger) {
|
||||
btConnectedTrigger = false;
|
||||
setScreenPage(0); // Cambiar a tablero de 4 cuadrantes OBD!
|
||||
if (!userNavigatedManually && !initialBtAutoSwitched && currentScreenPage == 2 && fullScreenCell == -1) {
|
||||
initialBtAutoSwitched = true;
|
||||
setScreenPage(0); // Cambiar a tablero de 4 cuadrantes OBD solo en el primer arranque
|
||||
fullScreenCell = -1;
|
||||
initScreen(true);
|
||||
touchBeep();
|
||||
lastActivityTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluacion inicial: Si tras el arranque no encuentra ni Bluetooth ni GPS,
|
||||
// pasar a la pantalla de las Temperaturas (Pagina 1)
|
||||
// 2. Trigger automatico GPS:
|
||||
// Solo si el usuario no ha navegado manualmente
|
||||
bool isBt = BTSerial.connected() && foundOBD2;
|
||||
if (!isBt && !userNavigatedManually) {
|
||||
if (isGpsSynced() && !gpsClockAutoSwitched) {
|
||||
gpsClockAutoSwitched = true;
|
||||
if (currentScreenPage != 2 && fullScreenCell == -1) {
|
||||
setScreenPage(2);
|
||||
fullScreenCell = -1;
|
||||
initScreen(true);
|
||||
touchBeep();
|
||||
lastActivityTime = millis();
|
||||
}
|
||||
}
|
||||
} else if (isBt) {
|
||||
gpsClockAutoSwitched = false;
|
||||
}
|
||||
|
||||
// Evaluacion inicial: Si tras el arranque no encuentra ni Bluetooth ni GPS y sin navegacion manual:
|
||||
static bool bootSearchEvaluated = false;
|
||||
if (!bootSearchEvaluated && millis() >= 7000) {
|
||||
bootSearchEvaluated = true;
|
||||
bool isBt = BTSerial.connected() && foundOBD2;
|
||||
if (!isBt && !isGpsSynced()) {
|
||||
if (!isBt && !isGpsSynced() && !userNavigatedManually) {
|
||||
if (currentScreenPage == 2 && fullScreenCell == -1) {
|
||||
setScreenPage(1); // Ir a la pantalla de las Temperaturas (Pagina 1)
|
||||
fullScreenCell = -1;
|
||||
|
|
@ -927,6 +1019,7 @@ void loop() {
|
|||
|
||||
if (isTouched || btnPressed) {
|
||||
lastActivityTime = millis();
|
||||
userNavigatedManually = true;
|
||||
}
|
||||
|
||||
static bool isTouching = false;
|
||||
|
|
@ -1094,36 +1187,20 @@ void loop() {
|
|||
}
|
||||
|
||||
#ifndef SKIP_CONNECTION
|
||||
// Check Bluetooth connection state: if adapter disconnected or lost power,
|
||||
// switch immediately to GPS Clock Screen (Page 2) and show "---" on OBD
|
||||
// parameters
|
||||
static bool wasBtConnected = false;
|
||||
bool isBtConnected = BTSerial.connected() && foundOBD2;
|
||||
// Monitor de enlace Bluetooth con debounce sólido de 4 segundos
|
||||
static uint32_t btDisconnectDebounce = 0;
|
||||
bool isPhysConnected = BTSerial.connected();
|
||||
|
||||
// Si se pierde el enlace Bluetooth: si hay GPS pasa al Reloj (Pag 2), si no
|
||||
// hay GPS pasa a Temperaturas (Pag 1)
|
||||
if (!isBtConnected && wasBtConnected) {
|
||||
wasBtConnected = false;
|
||||
currentRpm = 0.0f;
|
||||
tempEngineCoolant = -999.0f;
|
||||
for (uint8_t c = 0; c < 4; c++) {
|
||||
if (c != 1 || !isGpsSpeedValid()) {
|
||||
last_valid_data[c] = -999.0f;
|
||||
if (isPhysConnected && foundOBD2) {
|
||||
btDisconnectDebounce = 0; // Enlace sano y activo
|
||||
} else if (foundOBD2) {
|
||||
if (btDisconnectDebounce == 0) {
|
||||
btDisconnectDebounce = millis();
|
||||
}
|
||||
}
|
||||
ignitionOn = false;
|
||||
// Solo si el corte físico persiste por más de 4000ms seguidos declarar pérdida de enlace:
|
||||
if (millis() - btDisconnectDebounce >= 4000) {
|
||||
foundOBD2 = false;
|
||||
uint8_t fallbackPage = isGpsSynced() ? 2 : 1;
|
||||
setScreenPage(fallbackPage);
|
||||
fullScreenCell = -1;
|
||||
initScreen(true);
|
||||
setRearLedOff();
|
||||
lastActivityTime = millis();
|
||||
return;
|
||||
}
|
||||
wasBtConnected = isBtConnected;
|
||||
|
||||
if (!isBtConnected) {
|
||||
ignitionOn = false;
|
||||
currentRpm = 0.0f;
|
||||
tempEngineCoolant = -999.0f;
|
||||
for (uint8_t c = 0; c < 4; c++) {
|
||||
|
|
@ -1131,12 +1208,20 @@ void loop() {
|
|||
last_valid_data[c] = -999.0f;
|
||||
}
|
||||
}
|
||||
ignitionOn = false;
|
||||
setRearLedOff();
|
||||
if (currentScreenPage == 0) {
|
||||
updateClusterScreen(false);
|
||||
} else if (currentScreenPage == 1) {
|
||||
updateTriTempCoolant(-999.0f);
|
||||
}
|
||||
foundOBD2 =
|
||||
false; // Core 0 background task will handle reconnection smoothly!
|
||||
// Despertar la tarea de reconexión automática en segundo plano
|
||||
if (btTaskHandle != NULL) {
|
||||
xTaskNotifyGive(btTaskHandle);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Si aún no está conectado, retornar sin tocar ni cambiar la pantalla del usuario
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1161,16 +1246,7 @@ void loop() {
|
|||
while (BTSerial.available() > 0) {
|
||||
char incomingChar = BTSerial.read();
|
||||
if (incomingChar == '>') { // check prompt
|
||||
BTSerial.flush(); // clear tx
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println(bt_message);
|
||||
#endif
|
||||
#ifdef TERMINAL // for degbugging
|
||||
getAB(bt_message, pidList[pidIndex]);
|
||||
Terminal(bt_message + "->" + String(A) + "," + String(B), 0, 48, 320,
|
||||
191);
|
||||
#endif
|
||||
prompt = true; // pid response ready to calculate & display
|
||||
prompt = true; // pid response ready to calculate & display (sin delay de flush!)
|
||||
} else {
|
||||
bt_message.concat(incomingChar); // keep elm327 respond
|
||||
}
|
||||
|
|
@ -1220,11 +1296,17 @@ void loop() {
|
|||
autoDim(); // auto backlight handle
|
||||
}
|
||||
if (pidCurrentSkip[pidIndex] <= 0) { // end of skip loop , go next index
|
||||
// Si este PID es Velocidad (010D) y el GPS ya está entregando velocidad válida, saltearlo sin enviar a OBD:
|
||||
if (pidIndex == 1 && isGpsSpeedValid()) {
|
||||
prompt = true;
|
||||
skip = true;
|
||||
} else {
|
||||
pidCurrentSkip[pidIndex] =
|
||||
pidReadSkip[pidIndex]; // read max delay loop to current
|
||||
skip = false;
|
||||
BTSerial.print(pidList[pidIndex] + "\r"); // send PID request
|
||||
lastPidSendTime = millis();
|
||||
}
|
||||
} else { // skip sending request
|
||||
pidCurrentSkip[pidIndex] =
|
||||
pidCurrentSkip[pidIndex] - 1; // decrese loop count
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ inline void drawTriTempCard(uint8_t cardIdx, float val, int x_offset = 0) {
|
|||
}
|
||||
|
||||
// Left vertical accent bar
|
||||
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
||||
tft.drawRect(cardX + 6, cardY + 6, 4, cardH - 12, accentCol);
|
||||
|
||||
if (isYapaTheme()) {
|
||||
tft.loadFont(Latin_Sans_Bold_26);
|
||||
|
|
@ -418,7 +418,7 @@ inline void updateTriTempCardValue(uint8_t cardIdx, float val, float oldVal) {
|
|||
|
||||
// 1. Accent color changed: update vertical accent bar and unit "°C"
|
||||
if (accentCol != oldAccentCol) {
|
||||
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
||||
tft.drawRect(cardX + 6, cardY + 6, 4, cardH - 12, accentCol);
|
||||
bool rainbowUnit = isRainbowTheme() && (accentCol != TFT_RED);
|
||||
uint16_t unitCol = rainbowUnit ? getRainbowScreenColor(cardX + 268, cardY + 22) : (isYapaTheme() && accentCol != TFT_RED ? getYapaColor(3) : (accentCol == TFT_RED ? TFT_RED : 0xC618));
|
||||
tft.fillRect(cardX + 268, cardY + 22, 34, 26, cardBg);
|
||||
|
|
|
|||
Loading…
Reference in a new issue