561
Board320_240.cpp
561
Board320_240.cpp
@@ -1,7 +1,4 @@
|
|||||||
#ifndef BOARD320_240_CPP
|
//#include <SD.h>
|
||||||
#define BOARD320_240_CPP
|
|
||||||
|
|
||||||
#include <SD.h>
|
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <analogWrite.h>
|
#include <analogWrite.h>
|
||||||
#include <TFT_eSPI.h>
|
#include <TFT_eSPI.h>
|
||||||
@@ -11,6 +8,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "BoardInterface.h"
|
#include "BoardInterface.h"
|
||||||
#include "Board320_240.h"
|
#include "Board320_240.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "SIM800L.h"
|
||||||
|
|
||||||
|
RTC_DATA_ATTR unsigned int bootCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Init board
|
Init board
|
||||||
@@ -22,8 +23,42 @@ void Board320_240::initBoard() {
|
|||||||
pinMode(pinButtonLeft, INPUT);
|
pinMode(pinButtonLeft, INPUT);
|
||||||
pinMode(pinButtonRight, INPUT);
|
pinMode(pinButtonRight, INPUT);
|
||||||
|
|
||||||
|
// Init time library
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 1589011873;
|
||||||
|
settimeofday(&tv, NULL);
|
||||||
|
struct tm now;
|
||||||
|
getLocalTime(&now, 0);
|
||||||
|
liveData->params.chargingStartTime = liveData->params.currentTime = mktime(&now);
|
||||||
|
|
||||||
|
++bootCount;
|
||||||
|
|
||||||
|
syslog->print("Boot count: ");
|
||||||
|
syslog->println(bootCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
After setup device
|
||||||
|
*/
|
||||||
|
void Board320_240::afterSetup() {
|
||||||
|
|
||||||
|
if (digitalRead(pinButtonRight) == LOW) {
|
||||||
|
loadTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afterSetup = false;
|
||||||
|
|
||||||
|
// Check if bard was sleeping
|
||||||
|
if (bootCount > 1) {
|
||||||
|
// Init comm device
|
||||||
|
afterSetup = true;
|
||||||
|
BoardInterface::afterSetup();
|
||||||
|
// Wake or continue with sleeping
|
||||||
|
afterSleep();
|
||||||
|
}
|
||||||
|
|
||||||
// Init display
|
// Init display
|
||||||
Serial.println("Init tft display");
|
syslog->println("Init tft display");
|
||||||
tft.begin();
|
tft.begin();
|
||||||
tft.invertDisplay(invertDisplay);
|
tft.invertDisplay(invertDisplay);
|
||||||
tft.setRotation(liveData->settings.displayRotation);
|
tft.setRotation(liveData->settings.displayRotation);
|
||||||
@@ -37,12 +72,6 @@ void Board320_240::initBoard() {
|
|||||||
#endif
|
#endif
|
||||||
spr.setColorDepth((psramUsed) ? 16 : 8);
|
spr.setColorDepth((psramUsed) ? 16 : 8);
|
||||||
spr.createSprite(320, 240);
|
spr.createSprite(320, 240);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
After setup device
|
|
||||||
*/
|
|
||||||
void Board320_240::afterSetup() {
|
|
||||||
|
|
||||||
// Show test data on right button during boot device
|
// Show test data on right button during boot device
|
||||||
displayScreen = liveData->settings.defaultScreen;
|
displayScreen = liveData->settings.defaultScreen;
|
||||||
@@ -54,18 +83,24 @@ void Board320_240::afterSetup() {
|
|||||||
// Starting Wifi after BLE prevents reboot loop
|
// Starting Wifi after BLE prevents reboot loop
|
||||||
if (liveData->settings.wifiEnabled == 1) {
|
if (liveData->settings.wifiEnabled == 1) {
|
||||||
|
|
||||||
/*Serial.print("memReport(): MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM bytes free. ");
|
/*syslog->print("memReport(): MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM bytes free. ");
|
||||||
Serial.println(heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM));
|
syslog->println(heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM));
|
||||||
|
syslog->println("WiFi init...");
|
||||||
Serial.println("WiFi init...");
|
|
||||||
WiFi.enableSTA(true);
|
WiFi.enableSTA(true);
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(liveData->settings.wifiSsid, liveData->settings.wifiPassword);
|
WiFi.begin(liveData->settings.wifiSsid, liveData->settings.wifiPassword);
|
||||||
Serial.println("WiFi init completed...");*/
|
syslog->println("WiFi init completed...");*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init GPS
|
// Init GPS
|
||||||
if (liveData->settings.gpsHwSerialPort <= 2) {
|
if (liveData->settings.gpsHwSerialPort <= 2) {
|
||||||
|
syslog->print("GPS initialization on hwUart: ");
|
||||||
|
syslog->println(liveData->settings.gpsHwSerialPort);
|
||||||
|
if (liveData->settings.gpsHwSerialPort == 0) {
|
||||||
|
syslog->println("hwUart0 collision with serial console! Disabling serial console");
|
||||||
|
syslog->flush();
|
||||||
|
syslog->end();
|
||||||
|
}
|
||||||
gpsHwUart = new HardwareSerial(liveData->settings.gpsHwSerialPort);
|
gpsHwUart = new HardwareSerial(liveData->settings.gpsHwSerialPort);
|
||||||
gpsHwUart->begin(9600);
|
gpsHwUart->begin(9600);
|
||||||
}
|
}
|
||||||
@@ -73,11 +108,101 @@ void Board320_240::afterSetup() {
|
|||||||
// SD card
|
// SD card
|
||||||
if (liveData->settings.sdcardEnabled == 1) {
|
if (liveData->settings.sdcardEnabled == 1) {
|
||||||
if (sdcardMount() && liveData->settings.sdcardAutstartLog == 1) {
|
if (sdcardMount() && liveData->settings.sdcardAutstartLog == 1) {
|
||||||
|
syslog->println("Toggle recording on SD card");
|
||||||
sdcardToggleRecording();
|
sdcardToggleRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoardInterface::afterSetup();
|
// Init SIM800L
|
||||||
|
if (liveData->settings.gprsHwSerialPort <= 2) {
|
||||||
|
sim800lSetup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init comm device
|
||||||
|
if (!afterSetup) {
|
||||||
|
BoardInterface::afterSetup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Go to Sleep for TIME_TO_SLEEP seconds
|
||||||
|
*/
|
||||||
|
void Board320_240::goToSleep() {
|
||||||
|
|
||||||
|
//Sleep MCP2515
|
||||||
|
commInterface->disconnectDevice();
|
||||||
|
|
||||||
|
//Sleep SIM800L
|
||||||
|
if (liveData->params.sim800l_enabled) {
|
||||||
|
if (sim800l->isConnectedGPRS()) {
|
||||||
|
bool disconnected = sim800l->disconnectGPRS();
|
||||||
|
for (uint8_t i = 0; i < 5 && !disconnected; i++) {
|
||||||
|
delay(1000);
|
||||||
|
disconnected = sim800l->disconnectGPRS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sim800l->getPowerMode() == NORMAL) {
|
||||||
|
sim800l->setPowerMode(SLEEP);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
sim800l->enterSleepMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->println("Going to sleep for " + String(TIME_TO_SLEEP) + " seconds!");
|
||||||
|
syslog->flush();
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
//Sleep ESP32
|
||||||
|
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000ULL);
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Wake up board from sleep
|
||||||
|
Iterate thru commands and determine if car is charging or ignition is on
|
||||||
|
*/
|
||||||
|
void Board320_240::afterSleep() {
|
||||||
|
|
||||||
|
syslog->println("Waking up from sleep mode!");
|
||||||
|
|
||||||
|
// Wakeup reason
|
||||||
|
esp_sleep_wakeup_cause_t wakeup_reason;
|
||||||
|
wakeup_reason = esp_sleep_get_wakeup_cause();
|
||||||
|
switch (wakeup_reason) {
|
||||||
|
case ESP_SLEEP_WAKEUP_EXT0 : syslog->println("Wakeup caused by external signal using RTC_IO"); break;
|
||||||
|
case ESP_SLEEP_WAKEUP_EXT1 : syslog->println("Wakeup caused by external signal using RTC_CNTL"); break;
|
||||||
|
case ESP_SLEEP_WAKEUP_TIMER : syslog->println("Wakeup caused by timer"); break;
|
||||||
|
case ESP_SLEEP_WAKEUP_TOUCHPAD : syslog->println("Wakeup caused by touchpad"); break;
|
||||||
|
case ESP_SLEEP_WAKEUP_ULP : syslog->println("Wakeup caused by ULP program"); break;
|
||||||
|
default: syslog->printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool firstRun = true;
|
||||||
|
while (liveData->commandQueueIndex - 1 > liveData->commandQueueLoopFrom || firstRun) {
|
||||||
|
if (liveData->commandQueueIndex - 1 == liveData->commandQueueLoopFrom) {
|
||||||
|
firstRun = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis() > 5000) {
|
||||||
|
syslog->println("Time's up (5s timeout)...");
|
||||||
|
goToSleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
commInterface->mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (liveData->params.auxVoltage > 5 && liveData->params.auxVoltage < 12) {
|
||||||
|
syslog->println("AuxBATT too low!");
|
||||||
|
goToSleep();
|
||||||
|
} else if (!liveData->params.ignitionOn && !liveData->params.chargingOn) {
|
||||||
|
syslog->println("Not started & Not charging.");
|
||||||
|
goToSleep();
|
||||||
|
} else {
|
||||||
|
syslog->println("Wake up conditions satisfied... Good morning!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,9 +398,14 @@ void Board320_240::drawSceneMain() {
|
|||||||
sprintf(tmpStr1, ((liveData->settings.temperatureUnit == 'c') ? "%01.00f" : "%01.01f"), liveData->celsius2temperature(liveData->params.batHeaterC));
|
sprintf(tmpStr1, ((liveData->settings.temperatureUnit == 'c') ? "%01.00f" : "%01.01f"), liveData->celsius2temperature(liveData->params.batHeaterC));
|
||||||
drawBigCell(2, 3, 1, 1, tmpStr1, "BAT.HEAT", TFT_TEMP, TFT_WHITE);
|
drawBigCell(2, 3, 1, 1, tmpStr1, "BAT.HEAT", TFT_TEMP, TFT_WHITE);
|
||||||
|
|
||||||
// Aux perc
|
// Aux perc / temp
|
||||||
sprintf(tmpStr1, "%01.00f%%", liveData->params.auxPerc);
|
if (liveData->settings.carType == CAR_BMW_I3_2014) { // TODO: use invalid auxPerc value as decision point here?
|
||||||
drawBigCell(3, 0, 1, 1, tmpStr1, "AUX BAT.", (liveData->params.auxPerc < 60 ? TFT_RED : TFT_DEFAULT_BK), TFT_WHITE);
|
sprintf(tmpStr1, "%01.00f", liveData->params.auxTemperature);
|
||||||
|
drawBigCell(3, 0, 1, 1, tmpStr1, "AUX TEMP.", (liveData->params.auxTemperature < 5 ? TFT_RED : TFT_DEFAULT_BK), TFT_WHITE);
|
||||||
|
} else {
|
||||||
|
sprintf(tmpStr1, "%01.00f%%", liveData->params.auxPerc);
|
||||||
|
drawBigCell(3, 0, 1, 1, tmpStr1, "AUX BAT.", (liveData->params.auxPerc < 60 ? TFT_RED : TFT_DEFAULT_BK), TFT_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
// Aux amp
|
// Aux amp
|
||||||
sprintf(tmpStr1, (abs(liveData->params.auxCurrentAmp) > 9.9 ? "%01.00f" : "%01.01f"), liveData->params.auxCurrentAmp);
|
sprintf(tmpStr1, (abs(liveData->params.auxCurrentAmp) > 9.9 ? "%01.00f" : "%01.01f"), liveData->params.auxCurrentAmp);
|
||||||
@@ -814,41 +944,6 @@ void Board320_240::drawSceneSoc10Table() {
|
|||||||
spr.drawString(tmpStr1, 310, zeroY + (14 * 15), 2);
|
spr.drawString(tmpStr1, 310, zeroY + (14 * 15), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
DEBUG screen
|
|
||||||
*/
|
|
||||||
void Board320_240::drawSceneDebug() {
|
|
||||||
|
|
||||||
int32_t posx, posy;
|
|
||||||
String chHex, chHex2;
|
|
||||||
uint8_t chByte;
|
|
||||||
|
|
||||||
spr.setTextSize(1); // Size for small 5x7 font
|
|
||||||
spr.setTextColor(TFT_SILVER, TFT_TEMP);
|
|
||||||
spr.setTextDatum(TL_DATUM);
|
|
||||||
spr.drawString(debugAtshRequest, 0, 0, 2);
|
|
||||||
spr.drawString(debugCommandRequest, 128, 0, 2);
|
|
||||||
spr.drawString(liveData->commandRequest, 256, 0, 2);
|
|
||||||
spr.setTextDatum(TR_DATUM);
|
|
||||||
|
|
||||||
for (int i = 0; i < debugLastString.length() / 2; i++) {
|
|
||||||
chHex = debugLastString.substring(i * 2, (i * 2) + 2);
|
|
||||||
chHex2 = debugPreviousString.substring(i * 2, (i * 2) + 2);
|
|
||||||
spr.setTextColor(((chHex.equals(chHex2)) ? TFT_SILVER : TFT_GREEN), TFT_TEMP);
|
|
||||||
chByte = liveData->hexToDec(chHex.c_str(), 1, false);
|
|
||||||
posx = (((i) % 10) * 32) + 24;
|
|
||||||
posy = ((floor((i) / 10)) * 32) + 24;
|
|
||||||
sprintf(tmpStr1, "%03d", chByte);
|
|
||||||
spr.drawString(tmpStr1, posx + 4, posy, 2);
|
|
||||||
|
|
||||||
spr.setTextColor(TFT_YELLOW, TFT_TEMP);
|
|
||||||
sprintf(tmpStr1, "%c", (char)chByte);
|
|
||||||
spr.drawString(tmpStr1, posx + 4, posy + 13, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPreviousString = debugLastString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Modify caption
|
Modify caption
|
||||||
*/
|
*/
|
||||||
@@ -869,8 +964,12 @@ String Board320_240::menuItemCaption(int16_t menuItemId, String title) {
|
|||||||
case 105: prefix = (liveData->settings.carType == CAR_HYUNDAI_KONA_2020_39) ? ">" : ""; break;
|
case 105: prefix = (liveData->settings.carType == CAR_HYUNDAI_KONA_2020_39) ? ">" : ""; break;
|
||||||
case 106: prefix = (liveData->settings.carType == CAR_RENAULT_ZOE) ? ">" : ""; break;
|
case 106: prefix = (liveData->settings.carType == CAR_RENAULT_ZOE) ? ">" : ""; break;
|
||||||
case 107: prefix = (liveData->settings.carType == CAR_KIA_NIRO_PHEV) ? ">" : ""; break;
|
case 107: prefix = (liveData->settings.carType == CAR_KIA_NIRO_PHEV) ? ">" : ""; break;
|
||||||
|
case 108: prefix = (liveData->settings.carType == CAR_BMW_I3_2014) ? ">" : ""; break;
|
||||||
case 120: prefix = (liveData->settings.carType == CAR_DEBUG_OBD2_KIA) ? ">" : ""; break;
|
case 120: prefix = (liveData->settings.carType == CAR_DEBUG_OBD2_KIA) ? ">" : ""; break;
|
||||||
//
|
//
|
||||||
|
case MENU_ADAPTER_BLE4: prefix = (liveData->settings.commType == COMM_TYPE_OBD2BLE4) ? ">" : ""; break;
|
||||||
|
case MENU_ADAPTER_CAN: prefix = (liveData->settings.commType == COMM_TYPE_OBD2CAN) ? ">" : ""; break;
|
||||||
|
case MENU_ADAPTER_BT3: prefix = (liveData->settings.commType == COMM_TYPE_OBD2BT3) ? ">" : ""; break;
|
||||||
/*case MENU_WIFI:
|
/*case MENU_WIFI:
|
||||||
suffix = "n/a";
|
suffix = "n/a";
|
||||||
switch (WiFi.status()) {
|
switch (WiFi.status()) {
|
||||||
@@ -883,14 +982,23 @@ String Board320_240::menuItemCaption(int16_t menuItemId, String title) {
|
|||||||
WL_DISCONNECTED: suffix = "DISCONNECTED"; break;
|
WL_DISCONNECTED: suffix = "DISCONNECTED"; break;
|
||||||
}
|
}
|
||||||
break;*/
|
break;*/
|
||||||
case MENU_GPRS: sprintf(tmpStr1, "[%s] %s", (liveData->settings.gprsEnabled == 1) ? "on" : "off", liveData->settings.gprsApn); suffix = tmpStr1; break;
|
case MENU_GPRS: sprintf(tmpStr1, "[HW UART=%d]", liveData->settings.gprsHwSerialPort); suffix = (liveData->settings.gprsHwSerialPort == 255) ? "[off]" : tmpStr1; break;
|
||||||
case MENU_SDCARD: sprintf(tmpStr1, "[%d] %lluMB", SD.cardType(), SD.cardSize() / (1024 * 1024)); suffix = tmpStr1; break;
|
case MENU_SDCARD: sprintf(tmpStr1, "[%d] %lluMB", SD.cardType(), SD.cardSize() / (1024 * 1024)); suffix = tmpStr1; break;
|
||||||
|
case MENU_SERIAL_CONSOLE: suffix = (liveData->settings.serialConsolePort == 255) ? "[off]" : "[on]"; break;
|
||||||
|
case MENU_DEBUG_LEVEL: switch (liveData->settings.debugLevel) {
|
||||||
|
case 0: suffix = "[all]" ; break;
|
||||||
|
case 1: suffix = "[comm]" ; break;
|
||||||
|
case 2: suffix = "[gsm]" ; break;
|
||||||
|
case 3: suffix = "[sdcard]" ; break;
|
||||||
|
default: suffix = "[unknown]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
case MENU_SCREEN_ROTATION: suffix = (liveData->settings.displayRotation == 1) ? "[vertical]" : "[normal]"; break;
|
case MENU_SCREEN_ROTATION: suffix = (liveData->settings.displayRotation == 1) ? "[vertical]" : "[normal]"; break;
|
||||||
case MENU_DEFAULT_SCREEN: sprintf(tmpStr1, "[%d]", liveData->settings.defaultScreen); suffix = tmpStr1; break;
|
case MENU_DEFAULT_SCREEN: sprintf(tmpStr1, "[%d]", liveData->settings.defaultScreen); suffix = tmpStr1; break;
|
||||||
case MENU_SCREEN_BRIGHTNESS: sprintf(tmpStr1, "[%d%%]", liveData->settings.lcdBrightness); suffix = (liveData->settings.lcdBrightness == 0) ? "[auto]" : tmpStr1; break;
|
case MENU_SCREEN_BRIGHTNESS: sprintf(tmpStr1, "[%d%%]", liveData->settings.lcdBrightness); suffix = (liveData->settings.lcdBrightness == 0) ? "[auto]" : tmpStr1; break;
|
||||||
case MENU_PREDRAWN_GRAPHS: suffix = (liveData->settings.predrawnChargingGraphs == 1) ? "[on]" : "[off]"; break;
|
case MENU_PREDRAWN_GRAPHS: suffix = (liveData->settings.predrawnChargingGraphs == 1) ? "[on]" : "[off]"; break;
|
||||||
case MENU_HEADLIGHTS_REMINDER: suffix = (liveData->settings.headlightsReminder == 1) ? "[on]" : "[off]"; break;
|
case MENU_HEADLIGHTS_REMINDER: suffix = (liveData->settings.headlightsReminder == 1) ? "[on]" : "[off]"; break;
|
||||||
case MENU_DEBUG_SCREEN: suffix = (liveData->settings.debugScreen == 1) ? "[on]" : "[off]"; break;
|
case MENU_SLEEP_MODE: suffix = (liveData->settings.sleepModeEnabled == 1) ? "[on]" : "[off]"; break;
|
||||||
case MENU_GPS: sprintf(tmpStr1, "[HW UART=%d]", liveData->settings.gpsHwSerialPort); suffix = (liveData->settings.gpsHwSerialPort == 255) ? "[off]" : tmpStr1; break;
|
case MENU_GPS: sprintf(tmpStr1, "[HW UART=%d]", liveData->settings.gpsHwSerialPort); suffix = (liveData->settings.gpsHwSerialPort == 255) ? "[off]" : tmpStr1; break;
|
||||||
//
|
//
|
||||||
case MENU_SDCARD_ENABLED: sprintf(tmpStr1, "[%s]", (liveData->settings.sdcardEnabled == 1) ? "on" : "off"); suffix = tmpStr1; break;
|
case MENU_SDCARD_ENABLED: sprintf(tmpStr1, "[%s]", (liveData->settings.sdcardEnabled == 1) ? "on" : "off"); suffix = tmpStr1; break;
|
||||||
@@ -899,6 +1007,7 @@ String Board320_240::menuItemCaption(int16_t menuItemId, String title) {
|
|||||||
(strlen(liveData->params.sdcardFilename) != 0) ? liveData->params.sdcardFilename :
|
(strlen(liveData->params.sdcardFilename) != 0) ? liveData->params.sdcardFilename :
|
||||||
(liveData->params.sdcardInit) ? "READY" : "MOUNT"); suffix = tmpStr1; break;
|
(liveData->params.sdcardInit) ? "READY" : "MOUNT"); suffix = tmpStr1; break;
|
||||||
case MENU_SDCARD_REC: sprintf(tmpStr1, "[%s]", (liveData->settings.sdcardEnabled == 0) ? "n/a" : (liveData->params.sdcardRecording) ? "STOP" : "START"); suffix = tmpStr1; break;
|
case MENU_SDCARD_REC: sprintf(tmpStr1, "[%s]", (liveData->settings.sdcardEnabled == 0) ? "n/a" : (liveData->params.sdcardRecording) ? "STOP" : "START"); suffix = tmpStr1; break;
|
||||||
|
case MENU_SDCARD_INTERVAL: sprintf(tmpStr1, "[%d]", liveData->settings.sdcardLogIntervalSec); suffix = tmpStr1; break;
|
||||||
//
|
//
|
||||||
case MENU_WIFI_ENABLED: suffix = (liveData->settings.wifiEnabled == 1) ? "[on]" : "[off]"; break;
|
case MENU_WIFI_ENABLED: suffix = (liveData->settings.wifiEnabled == 1) ? "[on]" : "[off]"; break;
|
||||||
case MENU_WIFI_SSID: sprintf(tmpStr1, "%s", liveData->settings.wifiSsid); suffix = tmpStr1; break;
|
case MENU_WIFI_SSID: sprintf(tmpStr1, "%s", liveData->settings.wifiSsid); suffix = tmpStr1; break;
|
||||||
@@ -1005,12 +1114,12 @@ void Board320_240::menuItemClick() {
|
|||||||
// Exit menu, parent level menu, open item
|
// Exit menu, parent level menu, open item
|
||||||
bool showParentMenu = false;
|
bool showParentMenu = false;
|
||||||
if (liveData->menuItemSelected > 0) {
|
if (liveData->menuItemSelected > 0) {
|
||||||
Serial.println(tmpMenuItem->id);
|
syslog->println(tmpMenuItem->id);
|
||||||
// Device list
|
// Device list
|
||||||
if (tmpMenuItem->id > 10000 && tmpMenuItem->id < 10100) {
|
if (tmpMenuItem->id > 10000 && tmpMenuItem->id < 10100) {
|
||||||
strlcpy((char*)liveData->settings.obdMacAddress, (char*)tmpMenuItem->obdMacAddress, 20);
|
strlcpy((char*)liveData->settings.obdMacAddress, (char*)tmpMenuItem->obdMacAddress, 20);
|
||||||
Serial.print("Selected adapter MAC address ");
|
syslog->print("Selected adapter MAC address ");
|
||||||
Serial.println(liveData->settings.obdMacAddress);
|
syslog->println(liveData->settings.obdMacAddress);
|
||||||
saveSettings();
|
saveSettings();
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
@@ -1024,7 +1133,12 @@ void Board320_240::menuItemClick() {
|
|||||||
case 105: liveData->settings.carType = CAR_HYUNDAI_KONA_2020_39; showMenu(); return; break;
|
case 105: liveData->settings.carType = CAR_HYUNDAI_KONA_2020_39; showMenu(); return; break;
|
||||||
case 106: liveData->settings.carType = CAR_RENAULT_ZOE; showMenu(); return; break;
|
case 106: liveData->settings.carType = CAR_RENAULT_ZOE; showMenu(); return; break;
|
||||||
case 107: liveData->settings.carType = CAR_KIA_NIRO_PHEV; showMenu(); return; break;
|
case 107: liveData->settings.carType = CAR_KIA_NIRO_PHEV; showMenu(); return; break;
|
||||||
|
case 108: liveData->settings.carType = CAR_BMW_I3_2014; showMenu(); return; break;
|
||||||
case 120: liveData->settings.carType = CAR_DEBUG_OBD2_KIA; showMenu(); return; break;
|
case 120: liveData->settings.carType = CAR_DEBUG_OBD2_KIA; showMenu(); return; break;
|
||||||
|
// Comm type
|
||||||
|
case MENU_ADAPTER_BLE4: liveData->settings.commType = COMM_TYPE_OBD2BLE4; showMenu(); return; break;
|
||||||
|
case MENU_ADAPTER_CAN: liveData->settings.commType = COMM_TYPE_OBD2CAN; showMenu(); return; break;
|
||||||
|
case MENU_ADAPTER_BT3: liveData->settings.commType = COMM_TYPE_OBD2BT3; showMenu(); return; break;
|
||||||
// Screen orientation
|
// Screen orientation
|
||||||
case MENU_SCREEN_ROTATION: liveData->settings.displayRotation = (liveData->settings.displayRotation == 1) ? 3 : 1; tft.setRotation(liveData->settings.displayRotation); showMenu(); return; break;
|
case MENU_SCREEN_ROTATION: liveData->settings.displayRotation = (liveData->settings.displayRotation == 1) ? 3 : 1; tft.setRotation(liveData->settings.displayRotation); showMenu(); return; break;
|
||||||
// Default screen
|
// Default screen
|
||||||
@@ -1033,23 +1147,26 @@ void Board320_240::menuItemClick() {
|
|||||||
case 3063: liveData->settings.defaultScreen = 3; showParentMenu = true; break;
|
case 3063: liveData->settings.defaultScreen = 3; showParentMenu = true; break;
|
||||||
case 3064: liveData->settings.defaultScreen = 4; showParentMenu = true; break;
|
case 3064: liveData->settings.defaultScreen = 4; showParentMenu = true; break;
|
||||||
case 3065: liveData->settings.defaultScreen = 5; showParentMenu = true; break;
|
case 3065: liveData->settings.defaultScreen = 5; showParentMenu = true; break;
|
||||||
// Debug screen off/on
|
// SleepMode off/on
|
||||||
case MENU_DEBUG_SCREEN: liveData->settings.debugScreen = (liveData->settings.debugScreen == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_SLEEP_MODE: liveData->settings.sleepModeEnabled = (liveData->settings.sleepModeEnabled == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_SCREEN_BRIGHTNESS: liveData->settings.lcdBrightness += 20; if (liveData->settings.lcdBrightness > 100) liveData->settings.lcdBrightness = 0;
|
case MENU_SCREEN_BRIGHTNESS: liveData->settings.lcdBrightness += 20; if (liveData->settings.lcdBrightness > 100) liveData->settings.lcdBrightness = 0;
|
||||||
setBrightness((liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness); showMenu(); return; break;
|
setBrightness((liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness); showMenu(); return; break;
|
||||||
// Pre-drawn charg.graphs off/on
|
// Pre-drawn charg.graphs off/on
|
||||||
case MENU_PREDRAWN_GRAPHS: liveData->settings.predrawnChargingGraphs = (liveData->settings.predrawnChargingGraphs == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_PREDRAWN_GRAPHS: liveData->settings.predrawnChargingGraphs = (liveData->settings.predrawnChargingGraphs == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_HEADLIGHTS_REMINDER: liveData->settings.headlightsReminder = (liveData->settings.headlightsReminder == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_HEADLIGHTS_REMINDER: liveData->settings.headlightsReminder = (liveData->settings.headlightsReminder == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_GPS: liveData->settings.gpsHwSerialPort = (liveData->settings.gpsHwSerialPort == 2) ? 255 : liveData->settings.gpsHwSerialPort + 1; showMenu(); return; break;
|
case MENU_GPRS: liveData->settings.gprsHwSerialPort = (liveData->settings.gprsHwSerialPort == 2) ? 255 : liveData->settings.gprsHwSerialPort + 1; showMenu(); return; break;
|
||||||
|
case MENU_GPS: liveData->settings.gpsHwSerialPort = (liveData->settings.gpsHwSerialPort == 2) ? 255 : liveData->settings.gpsHwSerialPort + 1; showMenu(); return; break;
|
||||||
|
case MENU_SERIAL_CONSOLE: liveData->settings.serialConsolePort = (liveData->settings.serialConsolePort == 0) ? 255 : liveData->settings.serialConsolePort + 1; showMenu(); return; break;
|
||||||
|
case MENU_DEBUG_LEVEL: liveData->settings.debugLevel = (liveData->settings.debugLevel == 3) ? 0 : liveData->settings.debugLevel + 1; syslog->setDebugLevel(liveData->settings.debugLevel); showMenu(); return; break;
|
||||||
// Wifi menu
|
// Wifi menu
|
||||||
case MENU_WIFI_ENABLED: liveData->settings.wifiEnabled = (liveData->settings.wifiEnabled == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_WIFI_ENABLED: liveData->settings.wifiEnabled = (liveData->settings.wifiEnabled == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_WIFI_SSID: return; break;
|
case MENU_WIFI_SSID: return; break;
|
||||||
case MENU_WIFI_PASSWORD: return; break;
|
case MENU_WIFI_PASSWORD: return; break;
|
||||||
// Sdcard
|
// Sdcard
|
||||||
case MENU_SDCARD_ENABLED: liveData->settings.sdcardEnabled = (liveData->settings.sdcardEnabled == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_SDCARD_ENABLED: liveData->settings.sdcardEnabled = (liveData->settings.sdcardEnabled == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_SDCARD_AUTOSTARTLOG: liveData->settings.sdcardAutstartLog = (liveData->settings.sdcardAutstartLog == 1) ? 0 : 1; showMenu(); return; break;
|
case MENU_SDCARD_AUTOSTARTLOG: liveData->settings.sdcardAutstartLog = (liveData->settings.sdcardAutstartLog == 1) ? 0 : 1; showMenu(); return; break;
|
||||||
case MENU_SDCARD_MOUNT_STATUS: sdcardMount(); break;
|
case MENU_SDCARD_MOUNT_STATUS: sdcardMount(); break;
|
||||||
case MENU_SDCARD_REC: sdcardToggleRecording(); showMenu(); return; break;
|
case MENU_SDCARD_REC: sdcardToggleRecording(); showMenu(); return; break;
|
||||||
// Distance
|
// Distance
|
||||||
case 4011: liveData->settings.distanceUnit = 'k'; showParentMenu = true; break;
|
case 4011: liveData->settings.distanceUnit = 'k'; showParentMenu = true; break;
|
||||||
case 4012: liveData->settings.distanceUnit = 'm'; showParentMenu = true; break;
|
case 4012: liveData->settings.distanceUnit = 'm'; showParentMenu = true; break;
|
||||||
@@ -1060,13 +1177,40 @@ void Board320_240::menuItemClick() {
|
|||||||
case 4031: liveData->settings.pressureUnit = 'b'; showParentMenu = true; break;
|
case 4031: liveData->settings.pressureUnit = 'b'; showParentMenu = true; break;
|
||||||
case 4032: liveData->settings.pressureUnit = 'p'; showParentMenu = true; break;
|
case 4032: liveData->settings.pressureUnit = 'p'; showParentMenu = true; break;
|
||||||
// Pair ble device
|
// Pair ble device
|
||||||
case 2: scanDevices = true; /*startBleScan(); */return;
|
case 2:
|
||||||
|
if (liveData->settings.commType == COMM_TYPE_OBD2CAN) {
|
||||||
|
displayMessage("Not supported", "in CAN mode");
|
||||||
|
delay(3000);
|
||||||
|
hideMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scanDevices = true;
|
||||||
|
liveData->menuCurrent = 9999;
|
||||||
|
commInterface->scanDevices();
|
||||||
|
return;
|
||||||
// Reset settings
|
// Reset settings
|
||||||
case 8: resetSettings(); hideMenu(); return;
|
case 8: resetSettings(); hideMenu(); return;
|
||||||
// Save settings
|
// Save settings
|
||||||
case 9: saveSettings(); break;
|
case 9: saveSettings(); break;
|
||||||
// Version
|
// Version
|
||||||
case 10: hideMenu(); return;
|
case 10:
|
||||||
|
/* commInterface->executeCommand("ATSH770");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("3E");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("1003");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("2FBC1003");
|
||||||
|
delay(5000);
|
||||||
|
commInterface->executeCommand("ATSH770");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("3E");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("1003");
|
||||||
|
delay(50);
|
||||||
|
commInterface->executeCommand("2FBC1103");
|
||||||
|
delay(5000);*/
|
||||||
|
hideMenu(); return;
|
||||||
// Shutdown
|
// Shutdown
|
||||||
case 11: shutdownDevice(); return;
|
case 11: shutdownDevice(); return;
|
||||||
default:
|
default:
|
||||||
@@ -1094,7 +1238,7 @@ void Board320_240::menuItemClick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
liveData->menuCurrent = parentMenu;
|
liveData->menuCurrent = parentMenu;
|
||||||
Serial.println(liveData->menuCurrent);
|
syslog->println(liveData->menuCurrent);
|
||||||
showMenu();
|
showMenu();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1146,7 +1290,7 @@ void Board320_240::redrawScreen() {
|
|||||||
drawSceneMain();
|
drawSceneMain();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
displayScreenAutoMode = SCREEN_DASH;
|
displayScreenAutoMode = SCREEN_DASH;
|
||||||
}
|
}
|
||||||
// 2. Main screen
|
// 2. Main screen
|
||||||
if (displayScreen == SCREEN_DASH) {
|
if (displayScreen == SCREEN_DASH) {
|
||||||
@@ -1168,18 +1312,14 @@ void Board320_240::redrawScreen() {
|
|||||||
if (displayScreen == SCREEN_SOC10) {
|
if (displayScreen == SCREEN_SOC10) {
|
||||||
drawSceneSoc10Table();
|
drawSceneSoc10Table();
|
||||||
}
|
}
|
||||||
// 7. DEBUG SCREEN
|
|
||||||
if (displayScreen == SCREEN_DEBUG) {
|
|
||||||
drawSceneDebug();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!displayScreenSpeedHud) {
|
if (!displayScreenSpeedHud) {
|
||||||
|
|
||||||
// SDCARD recording
|
// SDCARD recording
|
||||||
/*liveData->params.sdcardRecording*/
|
/*liveData->params.sdcardRecording*/
|
||||||
if (liveData->settings.sdcardEnabled == 1) {
|
if (liveData->settings.sdcardEnabled == 1 && (liveData->params.mainLoopCounter & 1) == 1) {
|
||||||
spr.fillCircle((displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED) ? 160 : 310, 10, 4, TFT_BLACK);
|
spr.fillCircle((displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED) ? 140 : 310, 10, 4, TFT_BLACK);
|
||||||
spr.fillCircle((displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED) ? 160 : 310, 10, 3,
|
spr.fillCircle((displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED) ? 140 : 310, 10, 3,
|
||||||
(liveData->params.sdcardInit == 1) ?
|
(liveData->params.sdcardInit == 1) ?
|
||||||
(liveData->params.sdcardRecording) ?
|
(liveData->params.sdcardRecording) ?
|
||||||
(strlen(liveData->params.sdcardFilename) != 0) ?
|
(strlen(liveData->params.sdcardFilename) != 0) ?
|
||||||
@@ -1189,18 +1329,32 @@ void Board320_240::redrawScreen() {
|
|||||||
TFT_YELLOW /* failed to initialize sdcard */
|
TFT_YELLOW /* failed to initialize sdcard */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// GPS state
|
||||||
if (gpsHwUart != NULL && (displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED)) {
|
if (gpsHwUart != NULL && (displayScreen == SCREEN_SPEED || displayScreenAutoMode == SCREEN_SPEED)) {
|
||||||
spr.drawCircle(180, 10, 5, (gps.location.isValid()) ? TFT_GREEN : TFT_RED);
|
spr.drawCircle(160, 10, 5, (gps.location.isValid()) ? TFT_GREEN : TFT_RED);
|
||||||
spr.setTextSize(1);
|
spr.setTextSize(1);
|
||||||
spr.setTextColor((gps.location.isValid()) ? TFT_GREEN : TFT_WHITE, TFT_BLACK);
|
spr.setTextColor((gps.location.isValid()) ? TFT_GREEN : TFT_WHITE, TFT_BLACK);
|
||||||
spr.setTextDatum(TL_DATUM);
|
spr.setTextDatum(TL_DATUM);
|
||||||
sprintf(tmpStr1, "%d", liveData->params.gpsSat);
|
sprintf(tmpStr1, "%d", liveData->params.gpsSat);
|
||||||
spr.drawString(tmpStr1, 194, 2, 2);
|
spr.drawString(tmpStr1, 174, 2, 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Door status
|
||||||
|
if (liveData->params.trunkDoorOpen)
|
||||||
|
spr.fillRect(20, 0, 320 - 40, 20, TFT_YELLOW);
|
||||||
|
if (liveData->params.leftFrontDoorOpen)
|
||||||
|
spr.fillRect(0, 20, 20, 98, TFT_YELLOW);
|
||||||
|
if (liveData->params.rightFrontDoorOpen)
|
||||||
|
spr.fillRect(0, 122, 20, 98, TFT_YELLOW);
|
||||||
|
if (liveData->params.leftRearDoorOpen)
|
||||||
|
spr.fillRect(320 - 20, 20, 20, 98, TFT_YELLOW);
|
||||||
|
if (liveData->params.rightRearDoorOpen)
|
||||||
|
spr.fillRect(320 - 20, 122, 20, 98, TFT_YELLOW);
|
||||||
|
if (liveData->params.hoodDoorOpen)
|
||||||
|
spr.fillRect(20, 240 - 20, 320 - 40, 20, TFT_YELLOW);
|
||||||
|
|
||||||
// BLE not connected
|
// BLE not connected
|
||||||
if (!liveData->bleConnected && liveData->bleConnect) {
|
if (!liveData->commConnected && liveData->bleConnect && liveData->tmpSettings.commType == COMM_TYPE_OBD2BLE4) {
|
||||||
// Print message
|
// Print message
|
||||||
spr.setTextSize(1);
|
spr.setTextSize(1);
|
||||||
spr.setTextColor(TFT_WHITE, TFT_BLACK);
|
spr.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
@@ -1219,6 +1373,8 @@ void Board320_240::redrawScreen() {
|
|||||||
*/
|
*/
|
||||||
void Board320_240::loadTestData() {
|
void Board320_240::loadTestData() {
|
||||||
|
|
||||||
|
syslog->println("Loading test data");
|
||||||
|
|
||||||
testDataMode = true; // skip lights off message
|
testDataMode = true; // skip lights off message
|
||||||
carInterface->loadTestData();
|
carInterface->loadTestData();
|
||||||
redrawScreen();
|
redrawScreen();
|
||||||
@@ -1229,6 +1385,8 @@ void Board320_240::loadTestData() {
|
|||||||
*/
|
*/
|
||||||
void Board320_240::mainLoop() {
|
void Board320_240::mainLoop() {
|
||||||
|
|
||||||
|
liveData->params.mainLoopCounter++;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Handle buttons
|
// Handle buttons
|
||||||
// MIDDLE - menu select
|
// MIDDLE - menu select
|
||||||
@@ -1257,7 +1415,7 @@ void Board320_240::mainLoop() {
|
|||||||
menuMove(false);
|
menuMove(false);
|
||||||
} else {
|
} else {
|
||||||
displayScreen++;
|
displayScreen++;
|
||||||
if (displayScreen > displayScreenCount - (liveData->settings.debugScreen == 0) ? 1 : 0)
|
if (displayScreen > displayScreenCount - 1)
|
||||||
displayScreen = 0; // rotate screens
|
displayScreen = 0; // rotate screens
|
||||||
// Turn off display on screen 0
|
// Turn off display on screen 0
|
||||||
setBrightness((displayScreen == SCREEN_BLANK) ? 0 : (liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness);
|
setBrightness((displayScreen == SCREEN_BLANK) ? 0 : (liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness);
|
||||||
@@ -1281,11 +1439,6 @@ void Board320_240::mainLoop() {
|
|||||||
displayScreenSpeedHud = !displayScreenSpeedHud;
|
displayScreenSpeedHud = !displayScreenSpeedHud;
|
||||||
redrawScreen();
|
redrawScreen();
|
||||||
}
|
}
|
||||||
if (liveData->settings.debugScreen == 1 && displayScreen == SCREEN_DEBUG) {
|
|
||||||
debugCommandIndex = (debugCommandIndex >= liveData->commandQueueCount) ? liveData->commandQueueLoopFrom : debugCommandIndex + 1;
|
|
||||||
redrawScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1305,6 +1458,12 @@ void Board320_240::mainLoop() {
|
|||||||
syncGPS();
|
syncGPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SIM800L
|
||||||
|
if (liveData->params.lastDataSent + SIM800L_TIMER < liveData->params.currentTime && liveData->params.sim800l_enabled) {
|
||||||
|
sendDataViaGPRS();
|
||||||
|
liveData->params.lastDataSent = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
// currentTime
|
// currentTime
|
||||||
struct tm now;
|
struct tm now;
|
||||||
getLocalTime(&now, 0);
|
getLocalTime(&now, 0);
|
||||||
@@ -1312,20 +1471,20 @@ void Board320_240::mainLoop() {
|
|||||||
|
|
||||||
// SD card recording
|
// SD card recording
|
||||||
if (liveData->params.sdcardInit && liveData->params.sdcardRecording && liveData->params.sdcardCanNotify &&
|
if (liveData->params.sdcardInit && liveData->params.sdcardRecording && liveData->params.sdcardCanNotify &&
|
||||||
(liveData->params.odoKm != -1 && liveData->params.socPerc != -1)) {
|
(liveData->params.odoKm != -1 && liveData->params.socPerc != -1)) {
|
||||||
|
|
||||||
//Serial.println(&now, "%y%m%d%H%M");
|
//syslog->println(&now, "%y%m%d%H%M");
|
||||||
|
|
||||||
// create filename
|
// create filename
|
||||||
if (liveData->params.operationTimeSec > 0 && strlen(liveData->params.sdcardFilename) == 0) {
|
if (liveData->params.operationTimeSec > 0 && strlen(liveData->params.sdcardFilename) == 0) {
|
||||||
sprintf(liveData->params.sdcardFilename, "/%llu.json", uint64_t(liveData->params.operationTimeSec / 60));
|
sprintf(liveData->params.sdcardFilename, "/%llu.json", uint64_t(liveData->params.operationTimeSec / 60));
|
||||||
Serial.print("Log filename by opTimeSec: ");
|
syslog->print("Log filename by opTimeSec: ");
|
||||||
Serial.println(liveData->params.sdcardFilename);
|
syslog->println(liveData->params.sdcardFilename);
|
||||||
}
|
}
|
||||||
if (liveData->params.currTimeSyncWithGps && strlen(liveData->params.sdcardFilename) < 15) {
|
if (liveData->params.currTimeSyncWithGps && strlen(liveData->params.sdcardFilename) < 15) {
|
||||||
strftime(liveData->params.sdcardFilename, sizeof(liveData->params.sdcardFilename), "/%y%m%d%H%M.json", &now);
|
strftime(liveData->params.sdcardFilename, sizeof(liveData->params.sdcardFilename), "/%y%m%d%H%M.json", &now);
|
||||||
Serial.print("Log filename by GPS: ");
|
syslog->print("Log filename by GPS: ");
|
||||||
Serial.println(liveData->params.sdcardFilename);
|
syslog->println(liveData->params.sdcardFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// append buffer, clear buffer & notify state
|
// append buffer, clear buffer & notify state
|
||||||
@@ -1333,14 +1492,14 @@ void Board320_240::mainLoop() {
|
|||||||
liveData->params.sdcardCanNotify = false;
|
liveData->params.sdcardCanNotify = false;
|
||||||
File file = SD.open(liveData->params.sdcardFilename, FILE_APPEND);
|
File file = SD.open(liveData->params.sdcardFilename, FILE_APPEND);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
Serial.println("Failed to open file for appending");
|
syslog->println("Failed to open file for appending");
|
||||||
File file = SD.open(liveData->params.sdcardFilename, FILE_WRITE);
|
File file = SD.open(liveData->params.sdcardFilename, FILE_WRITE);
|
||||||
}
|
}
|
||||||
if (!file) {
|
if (!file) {
|
||||||
Serial.println("Failed to create file");
|
syslog->println("Failed to create file");
|
||||||
}
|
}
|
||||||
if (file) {
|
if (file) {
|
||||||
Serial.println("Save buffer to SD card");
|
syslog->println("Save buffer to SD card");
|
||||||
serializeParamsToJson(file);
|
serializeParamsToJson(file);
|
||||||
file.print(",\n");
|
file.print(",\n");
|
||||||
file.close();
|
file.close();
|
||||||
@@ -1348,9 +1507,24 @@ void Board320_240::mainLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown when car is off
|
// Turn off display if Ignition is off for more than 10s, less than month (prevent sleep when gps time is synchronized)
|
||||||
if (liveData->params.automaticShutdownTimer != 0 && liveData->params.currentTime - liveData->params.automaticShutdownTimer > 5)
|
if (liveData->params.currentTime - liveData->params.lastIgnitionOnTime > 10 && liveData->params.currentTime - liveData->params.lastIgnitionOnTime < MONTH_SEC
|
||||||
shutdownDevice();
|
&& liveData->params.lastIgnitionOnTime != 0
|
||||||
|
&& liveData->settings.sleepModeEnabled) {
|
||||||
|
setBrightness(0);
|
||||||
|
} else {
|
||||||
|
setBrightness((liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to sleep when car is off for more than 30s and not charging (AC charger is disabled for few seconds when ignition is turned off)
|
||||||
|
if (liveData->params.currentTime - liveData->params.lastIgnitionOnTime > 30 && liveData->params.currentTime - liveData->params.lastIgnitionOnTime < MONTH_SEC
|
||||||
|
&& !liveData->params.chargingOn
|
||||||
|
&& liveData->params.lastIgnitionOnTime != 0
|
||||||
|
&& liveData->settings.sleepModeEnabled)
|
||||||
|
goToSleep();
|
||||||
|
|
||||||
|
// Read data from BLE/CAN
|
||||||
|
commInterface->mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1366,43 +1540,53 @@ bool Board320_240::skipAdapterScan() {
|
|||||||
bool Board320_240::sdcardMount() {
|
bool Board320_240::sdcardMount() {
|
||||||
|
|
||||||
if (liveData->params.sdcardInit) {
|
if (liveData->params.sdcardInit) {
|
||||||
Serial.print("SD card already mounted...");
|
syslog->print("SD card already mounted...");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t countdown = 3;
|
int8_t countdown = 3;
|
||||||
while (1) {
|
bool SdState = false;
|
||||||
Serial.print("Initializing SD card...");
|
|
||||||
|
|
||||||
if (SD.begin(pinSdcardCs)) {
|
while (1) {
|
||||||
|
syslog->print("Initializing SD card...");
|
||||||
|
|
||||||
|
/* syslog->print(" TTGO-T4 ");
|
||||||
|
SPIClass * hspi = new SPIClass(HSPI);
|
||||||
|
spiSD.begin(pinSdcardSclk, pinSdcardMiso, pinSdcardMosi, pinSdcardCs); //SCK,MISO,MOSI,ss
|
||||||
|
SdState = SD.begin(pinSdcardCs, *hspi, SPI_FREQUENCY);*/
|
||||||
|
|
||||||
|
syslog->print(" M5STACK ");
|
||||||
|
SdState = SD.begin(pinSdcardCs);
|
||||||
|
|
||||||
|
if (SdState) {
|
||||||
|
|
||||||
uint8_t cardType = SD.cardType();
|
uint8_t cardType = SD.cardType();
|
||||||
if (cardType == CARD_NONE) {
|
if (cardType == CARD_NONE) {
|
||||||
Serial.println("No SD card attached");
|
syslog->println("No SD card attached");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("SD card found.");
|
syslog->println("SD card found.");
|
||||||
liveData->params.sdcardInit = true;
|
liveData->params.sdcardInit = true;
|
||||||
|
|
||||||
Serial.print("SD Card Type: ");
|
syslog->print("SD Card Type: ");
|
||||||
if (cardType == CARD_MMC) {
|
if (cardType == CARD_MMC) {
|
||||||
Serial.println("MMC");
|
syslog->println("MMC");
|
||||||
} else if (cardType == CARD_SD) {
|
} else if (cardType == CARD_SD) {
|
||||||
Serial.println("SDSC");
|
syslog->println("SDSC");
|
||||||
} else if (cardType == CARD_SDHC) {
|
} else if (cardType == CARD_SDHC) {
|
||||||
Serial.println("SDHC");
|
syslog->println("SDHC");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("UNKNOWN");
|
syslog->println("UNKNOWN");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||||
Serial.printf("SD Card Size: %lluMB\n", cardSize);
|
syslog->printf("SD Card Size: %lluMB\n", cardSize);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("Initialization failed!");
|
syslog->println("Initialization failed!");
|
||||||
countdown--;
|
countdown--;
|
||||||
if (countdown <= 0) {
|
if (countdown <= 0) {
|
||||||
break;
|
break;
|
||||||
@@ -1421,7 +1605,7 @@ void Board320_240::sdcardToggleRecording() {
|
|||||||
if (!liveData->params.sdcardInit)
|
if (!liveData->params.sdcardInit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Serial.println("Toggle SD card recording...");
|
syslog->println("Toggle SD card recording...");
|
||||||
liveData->params.sdcardRecording = !liveData->params.sdcardRecording;
|
liveData->params.sdcardRecording = !liveData->params.sdcardRecording;
|
||||||
if (liveData->params.sdcardRecording) {
|
if (liveData->params.sdcardRecording) {
|
||||||
liveData->params.sdcardCanNotify = true;
|
liveData->params.sdcardCanNotify = true;
|
||||||
@@ -1444,8 +1628,8 @@ void Board320_240::syncGPS() {
|
|||||||
}
|
}
|
||||||
if (gps.satellites.isValid()) {
|
if (gps.satellites.isValid()) {
|
||||||
liveData->params.gpsSat = gps.satellites.value();
|
liveData->params.gpsSat = gps.satellites.value();
|
||||||
//Serial.print("GPS satellites: ");
|
//syslog->print("GPS satellites: ");
|
||||||
//Serial.println(liveData->params.gpsSat);
|
//syslog->println(liveData->params.gpsSat);
|
||||||
}
|
}
|
||||||
if (!liveData->params.currTimeSyncWithGps && gps.date.isValid() && gps.time.isValid()) {
|
if (!liveData->params.currTimeSyncWithGps && gps.date.isValid() && gps.time.isValid()) {
|
||||||
liveData->params.currTimeSyncWithGps = true;
|
liveData->params.currTimeSyncWithGps = true;
|
||||||
@@ -1464,4 +1648,139 @@ void Board320_240::syncGPS() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOARD320_240_CPP
|
|
||||||
|
/**
|
||||||
|
SIM800L
|
||||||
|
*/
|
||||||
|
bool Board320_240::sim800lSetup() {
|
||||||
|
syslog->print("Setting SIM800L module. HW port: ");
|
||||||
|
syslog->println(liveData->settings.gprsHwSerialPort);
|
||||||
|
|
||||||
|
gprsHwUart = new HardwareSerial(liveData->settings.gprsHwSerialPort);
|
||||||
|
gprsHwUart->begin(9600);
|
||||||
|
|
||||||
|
sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 768 , 128);
|
||||||
|
// SIM800L DebugMode:
|
||||||
|
//sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 768 , 128, (Stream *)&Serial);
|
||||||
|
|
||||||
|
bool sim800l_ready = sim800l->isReady();
|
||||||
|
for (uint8_t i = 0; i < 5 && !sim800l_ready; i++) {
|
||||||
|
syslog->println("Problem to initialize SIM800L module, retry in 1 sec");
|
||||||
|
delay(1000);
|
||||||
|
sim800l_ready = sim800l->isReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sim800l_ready) {
|
||||||
|
syslog->println("Problem to initialize SIM800L module");
|
||||||
|
} else {
|
||||||
|
syslog->println("SIM800L module initialized");
|
||||||
|
|
||||||
|
sim800l->exitSleepMode();
|
||||||
|
|
||||||
|
if (sim800l->getPowerMode() != NORMAL) {
|
||||||
|
syslog->println("SIM800L module in sleep mode - Waking up");
|
||||||
|
if (sim800l->setPowerMode(NORMAL)) {
|
||||||
|
syslog->println("SIM800L in normal power mode");
|
||||||
|
} else {
|
||||||
|
syslog->println("Failed to switch SIM800L to normal power mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->print("Setting GPRS APN to: ");
|
||||||
|
syslog->println(liveData->settings.gprsApn);
|
||||||
|
|
||||||
|
bool sim800l_gprs = sim800l->setupGPRS(liveData->settings.gprsApn);
|
||||||
|
for (uint8_t i = 0; i < 5 && !sim800l_gprs; i++) {
|
||||||
|
syslog->println("Problem to set GPRS APN, retry in 1 sec");
|
||||||
|
delay(1000);
|
||||||
|
sim800l_gprs = sim800l->setupGPRS(liveData->settings.gprsApn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sim800l_gprs) {
|
||||||
|
liveData->params.sim800l_enabled = true;
|
||||||
|
syslog->println("GPRS APN set OK");
|
||||||
|
} else {
|
||||||
|
syslog->println("Problem to set GPRS APN");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Board320_240::sendDataViaGPRS() {
|
||||||
|
syslog->println("Sending data via GPRS");
|
||||||
|
|
||||||
|
if (liveData->params.socPerc < 0) {
|
||||||
|
syslog->println("No valid data, skipping data send");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkRegistration network = sim800l->getRegistrationStatus();
|
||||||
|
if (network != REGISTERED_HOME && network != REGISTERED_ROAMING) {
|
||||||
|
syslog->println("SIM800L module not connected to network, skipping data send");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sim800l->isConnectedGPRS()) {
|
||||||
|
syslog->println("GPRS not connected... Connecting");
|
||||||
|
bool connected = sim800l->connectGPRS();
|
||||||
|
for (uint8_t i = 0; i < 5 && !connected; i++) {
|
||||||
|
syslog->println("Problem to connect GPRS, retry in 1 sec");
|
||||||
|
delay(1000);
|
||||||
|
connected = sim800l->connectGPRS();
|
||||||
|
}
|
||||||
|
if (connected) {
|
||||||
|
syslog->println("GPRS connected!");
|
||||||
|
} else {
|
||||||
|
syslog->println("GPRS not connected! Reseting SIM800L module!");
|
||||||
|
sim800l->reset();
|
||||||
|
sim800lSetup();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->println("Start HTTP POST...");
|
||||||
|
|
||||||
|
StaticJsonDocument<768> jsonData;
|
||||||
|
|
||||||
|
jsonData["apikey"] = liveData->settings.remoteApiKey;
|
||||||
|
jsonData["carType"] = liveData->settings.carType;
|
||||||
|
jsonData["ignitionOn"] = liveData->params.ignitionOn;
|
||||||
|
jsonData["chargingOn"] = liveData->params.chargingOn;
|
||||||
|
jsonData["socPerc"] = liveData->params.socPerc;
|
||||||
|
jsonData["sohPerc"] = liveData->params.sohPerc;
|
||||||
|
jsonData["batPowerKw"] = liveData->params.batPowerKw;
|
||||||
|
jsonData["batPowerAmp"] = liveData->params.batPowerAmp;
|
||||||
|
jsonData["batVoltage"] = liveData->params.batVoltage;
|
||||||
|
jsonData["auxVoltage"] = liveData->params.auxVoltage;
|
||||||
|
jsonData["auxAmp"] = liveData->params.auxCurrentAmp;
|
||||||
|
jsonData["batMinC"] = liveData->params.batMinC;
|
||||||
|
jsonData["batMaxC"] = liveData->params.batMaxC;
|
||||||
|
jsonData["batInletC"] = liveData->params.batInletC;
|
||||||
|
jsonData["batFanStatus"] = liveData->params.batFanStatus;
|
||||||
|
jsonData["speedKmh"] = liveData->params.speedKmh;
|
||||||
|
jsonData["odoKm"] = liveData->params.odoKm;
|
||||||
|
jsonData["cumulativeEnergyChargedKWh"] = liveData->params.cumulativeEnergyChargedKWh;
|
||||||
|
jsonData["cumulativeEnergyDischargedKWh"] = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
|
|
||||||
|
char payload[768];
|
||||||
|
serializeJson(jsonData, payload);
|
||||||
|
|
||||||
|
syslog->print("Sending payload: ");
|
||||||
|
syslog->println(payload);
|
||||||
|
|
||||||
|
syslog->print("Remote API server: ");
|
||||||
|
syslog->println(liveData->settings.remoteApiUrl);
|
||||||
|
|
||||||
|
uint16_t rc = sim800l->doPost(liveData->settings.remoteApiUrl, "application/json", payload, 10000, 10000);
|
||||||
|
if (rc == 200) {
|
||||||
|
syslog->println("HTTP POST successful");
|
||||||
|
} else {
|
||||||
|
// Failed...
|
||||||
|
syslog->print("HTTP POST error: ");
|
||||||
|
syslog->println(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef BOARD320_240_H
|
#pragma once
|
||||||
#define BOARD320_240_H
|
|
||||||
|
|
||||||
// TFT COMMON
|
// TFT COMMON
|
||||||
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||||
@@ -12,10 +11,16 @@
|
|||||||
#define SMOOTH_FONT
|
#define SMOOTH_FONT
|
||||||
#define GFXFF 1 // TFT FOnts
|
#define GFXFF 1 // TFT FOnts
|
||||||
|
|
||||||
|
// DEEP SLEEP
|
||||||
|
#define TIME_TO_SLEEP 60 // Sleep time in secs
|
||||||
|
|
||||||
//
|
//
|
||||||
#include <TFT_eSPI.h>
|
#include <TFT_eSPI.h>
|
||||||
#include <TinyGPS++.h>
|
#include <TinyGPS++.h>
|
||||||
#include "BoardInterface.h"
|
#include "BoardInterface.h"
|
||||||
|
#include <SD.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include "SIM800L.h"
|
||||||
|
|
||||||
class Board320_240 : public BoardInterface {
|
class Board320_240 : public BoardInterface {
|
||||||
|
|
||||||
@@ -23,8 +28,9 @@ class Board320_240 : public BoardInterface {
|
|||||||
// TFT, SD SPI
|
// TFT, SD SPI
|
||||||
TFT_eSPI tft = TFT_eSPI();
|
TFT_eSPI tft = TFT_eSPI();
|
||||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||||
//SPIClass spiSD(HSPI);
|
|
||||||
HardwareSerial* gpsHwUart = NULL;
|
HardwareSerial* gpsHwUart = NULL;
|
||||||
|
HardwareSerial* gprsHwUart = NULL;
|
||||||
|
SIM800L* sim800l;
|
||||||
TinyGPSPlus gps;
|
TinyGPSPlus gps;
|
||||||
char tmpStr1[20];
|
char tmpStr1[20];
|
||||||
char tmpStr2[20];
|
char tmpStr2[20];
|
||||||
@@ -46,11 +52,16 @@ class Board320_240 : public BoardInterface {
|
|||||||
void afterSetup() override;
|
void afterSetup() override;
|
||||||
void mainLoop() override;
|
void mainLoop() override;
|
||||||
bool skipAdapterScan() override;
|
bool skipAdapterScan() override;
|
||||||
|
void goToSleep();
|
||||||
|
void afterSleep();
|
||||||
// SD card
|
// SD card
|
||||||
bool sdcardMount() override;
|
bool sdcardMount() override;
|
||||||
void sdcardToggleRecording() override;
|
void sdcardToggleRecording() override;
|
||||||
// GPS
|
// GPS
|
||||||
void syncGPS();
|
void syncGPS();
|
||||||
|
// SIM800L
|
||||||
|
bool sim800lSetup();
|
||||||
|
bool sendDataViaGPRS();
|
||||||
// Basic GUI
|
// Basic GUI
|
||||||
void setBrightness(byte lcdBrightnessPerc) override;
|
void setBrightness(byte lcdBrightnessPerc) override;
|
||||||
void displayMessage(const char* row1, const char* row2) override;
|
void displayMessage(const char* row1, const char* row2) override;
|
||||||
@@ -76,5 +87,3 @@ class Board320_240 : public BoardInterface {
|
|||||||
void loadTestData();
|
void loadTestData();
|
||||||
//
|
//
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOARD320_240_H
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#ifndef BOARDINTERFACE_CPP
|
|
||||||
#define BOARDINTERFACE_CPP
|
|
||||||
|
|
||||||
#define ARDUINOJSON_USE_LONG_LONG 1
|
#define ARDUINOJSON_USE_LONG_LONG 1
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
@@ -31,7 +28,7 @@ void BoardInterface::attachCar(CarInterface* pCarInterface) {
|
|||||||
*/
|
*/
|
||||||
void BoardInterface::shutdownDevice() {
|
void BoardInterface::shutdownDevice() {
|
||||||
|
|
||||||
Serial.println("Shutdown.");
|
syslog->println("Shutdown.");
|
||||||
|
|
||||||
char msg[20];
|
char msg[20];
|
||||||
for (int i = 3; i >= 1; i--) {
|
for (int i = 3; i >= 1; i--) {
|
||||||
@@ -41,7 +38,7 @@ void BoardInterface::shutdownDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIM800L_ENABLED
|
#ifdef SIM800L_ENABLED
|
||||||
if(sim800l->isConnectedGPRS()) {
|
if (sim800l->isConnectedGPRS()) {
|
||||||
sim800l->disconnectGPRS();
|
sim800l->disconnectGPRS();
|
||||||
}
|
}
|
||||||
sim800l->setPowerMode(MINIMUM);
|
sim800l->setPowerMode(MINIMUM);
|
||||||
@@ -51,7 +48,8 @@ void BoardInterface::shutdownDevice() {
|
|||||||
setBrightness(0);
|
setBrightness(0);
|
||||||
//WiFi.disconnect(true);
|
//WiFi.disconnect(true);
|
||||||
//WiFi.mode(WIFI_OFF);
|
//WiFi.mode(WIFI_OFF);
|
||||||
btStop();
|
|
||||||
|
commInterface->disconnectDevice();
|
||||||
//adc_power_off();
|
//adc_power_off();
|
||||||
//esp_wifi_stop();
|
//esp_wifi_stop();
|
||||||
esp_bt_controller_disable();
|
esp_bt_controller_disable();
|
||||||
@@ -67,7 +65,7 @@ void BoardInterface::shutdownDevice() {
|
|||||||
void BoardInterface::saveSettings() {
|
void BoardInterface::saveSettings() {
|
||||||
|
|
||||||
// Flash to memory
|
// Flash to memory
|
||||||
Serial.println("Settings saved to eeprom.");
|
syslog->println("Settings saved to eeprom.");
|
||||||
EEPROM.put(0, liveData->settings);
|
EEPROM.put(0, liveData->settings);
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
}
|
}
|
||||||
@@ -78,7 +76,7 @@ void BoardInterface::saveSettings() {
|
|||||||
void BoardInterface::resetSettings() {
|
void BoardInterface::resetSettings() {
|
||||||
|
|
||||||
// Flash to memory
|
// Flash to memory
|
||||||
Serial.println("Factory reset.");
|
syslog->println("Factory reset.");
|
||||||
liveData->settings.initFlag = 1;
|
liveData->settings.initFlag = 1;
|
||||||
EEPROM.put(0, liveData->settings);
|
EEPROM.put(0, liveData->settings);
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
@@ -98,7 +96,7 @@ void BoardInterface::loadSettings() {
|
|||||||
|
|
||||||
// Default settings
|
// Default settings
|
||||||
liveData->settings.initFlag = 183;
|
liveData->settings.initFlag = 183;
|
||||||
liveData->settings.settingsVersion = 5;
|
liveData->settings.settingsVersion = 6;
|
||||||
liveData->settings.carType = CAR_KIA_ENIRO_2020_64;
|
liveData->settings.carType = CAR_KIA_ENIRO_2020_64;
|
||||||
tmpStr = "00:00:00:00:00:00"; // Pair via menu (middle button)
|
tmpStr = "00:00:00:00:00:00"; // Pair via menu (middle button)
|
||||||
tmpStr.toCharArray(liveData->settings.obdMacAddress, tmpStr.length() + 1);
|
tmpStr.toCharArray(liveData->settings.obdMacAddress, tmpStr.length() + 1);
|
||||||
@@ -114,9 +112,9 @@ void BoardInterface::loadSettings() {
|
|||||||
liveData->settings.pressureUnit = 'b';
|
liveData->settings.pressureUnit = 'b';
|
||||||
liveData->settings.defaultScreen = 1;
|
liveData->settings.defaultScreen = 1;
|
||||||
liveData->settings.lcdBrightness = 0;
|
liveData->settings.lcdBrightness = 0;
|
||||||
liveData->settings.debugScreen = 0;
|
liveData->settings.sleepModeEnabled = 0;
|
||||||
liveData->settings.predrawnChargingGraphs = 1;
|
liveData->settings.predrawnChargingGraphs = 1;
|
||||||
liveData->settings.commType = 0; // BLE4
|
liveData->settings.commType = COMM_TYPE_OBD2BLE4; // BLE4
|
||||||
liveData->settings.wifiEnabled = 0;
|
liveData->settings.wifiEnabled = 0;
|
||||||
tmpStr = "empty";
|
tmpStr = "empty";
|
||||||
tmpStr.toCharArray(liveData->settings.wifiSsid, tmpStr.length() + 1);
|
tmpStr.toCharArray(liveData->settings.wifiSsid, tmpStr.length() + 1);
|
||||||
@@ -138,19 +136,24 @@ void BoardInterface::loadSettings() {
|
|||||||
tmpStr.toCharArray(liveData->settings.remoteApiKey, tmpStr.length() + 1);
|
tmpStr.toCharArray(liveData->settings.remoteApiKey, tmpStr.length() + 1);
|
||||||
liveData->settings.headlightsReminder = 0;
|
liveData->settings.headlightsReminder = 0;
|
||||||
liveData->settings.gpsHwSerialPort = 255; // off
|
liveData->settings.gpsHwSerialPort = 255; // off
|
||||||
|
liveData->settings.gprsHwSerialPort = 255; // off
|
||||||
|
liveData->settings.serialConsolePort = 0; // hwuart0
|
||||||
|
liveData->settings.debugLevel = 1; // 0 - info only, 1 - debug communication (BLE/CAN), 2 - debug GSM, 3 - debug SDcard
|
||||||
|
liveData->settings.sdcardLogIntervalSec = 2;
|
||||||
|
liveData->settings.gprsLogIntervalSec = 60;
|
||||||
|
|
||||||
// Load settings and replace default values
|
// Load settings and replace default values
|
||||||
Serial.println("Reading settings from eeprom.");
|
syslog->println("Reading settings from eeprom.");
|
||||||
EEPROM.begin(sizeof(SETTINGS_STRUC));
|
EEPROM.begin(sizeof(SETTINGS_STRUC));
|
||||||
EEPROM.get(0, liveData->tmpSettings);
|
EEPROM.get(0, liveData->tmpSettings);
|
||||||
|
|
||||||
// Init flash with default settings
|
// Init flash with default settings
|
||||||
if (liveData->tmpSettings.initFlag != 183) {
|
if (liveData->tmpSettings.initFlag != 183) {
|
||||||
Serial.println("Settings not found. Initialization.");
|
syslog->println("Settings not found. Initialization.");
|
||||||
saveSettings();
|
saveSettings();
|
||||||
} else {
|
} else {
|
||||||
Serial.print("Loaded settings ver.: ");
|
syslog->print("Loaded settings ver.: ");
|
||||||
Serial.println(liveData->tmpSettings.settingsVersion);
|
syslog->println(liveData->tmpSettings.settingsVersion);
|
||||||
|
|
||||||
// Upgrade structure
|
// Upgrade structure
|
||||||
if (liveData->settings.settingsVersion != liveData->tmpSettings.settingsVersion) {
|
if (liveData->settings.settingsVersion != liveData->tmpSettings.settingsVersion) {
|
||||||
@@ -158,7 +161,7 @@ void BoardInterface::loadSettings() {
|
|||||||
liveData->tmpSettings.settingsVersion = 2;
|
liveData->tmpSettings.settingsVersion = 2;
|
||||||
liveData->tmpSettings.defaultScreen = liveData->settings.defaultScreen;
|
liveData->tmpSettings.defaultScreen = liveData->settings.defaultScreen;
|
||||||
liveData->tmpSettings.lcdBrightness = liveData->settings.lcdBrightness;
|
liveData->tmpSettings.lcdBrightness = liveData->settings.lcdBrightness;
|
||||||
liveData->tmpSettings.debugScreen = liveData->settings.debugScreen;
|
liveData->tmpSettings.sleepModeEnabled = liveData->settings.sleepModeEnabled;
|
||||||
}
|
}
|
||||||
if (liveData->tmpSettings.settingsVersion == 2) {
|
if (liveData->tmpSettings.settingsVersion == 2) {
|
||||||
liveData->tmpSettings.settingsVersion = 3;
|
liveData->tmpSettings.settingsVersion = 3;
|
||||||
@@ -166,7 +169,7 @@ void BoardInterface::loadSettings() {
|
|||||||
}
|
}
|
||||||
if (liveData->tmpSettings.settingsVersion == 3) {
|
if (liveData->tmpSettings.settingsVersion == 3) {
|
||||||
liveData->tmpSettings.settingsVersion = 4;
|
liveData->tmpSettings.settingsVersion = 4;
|
||||||
liveData->tmpSettings.commType = 0; // BLE4
|
liveData->tmpSettings.commType = COMM_TYPE_OBD2BLE4; // BLE4
|
||||||
liveData->tmpSettings.wifiEnabled = 0;
|
liveData->tmpSettings.wifiEnabled = 0;
|
||||||
tmpStr = "empty";
|
tmpStr = "empty";
|
||||||
tmpStr.toCharArray(liveData->tmpSettings.wifiSsid, tmpStr.length() + 1);
|
tmpStr.toCharArray(liveData->tmpSettings.wifiSsid, tmpStr.length() + 1);
|
||||||
@@ -192,6 +195,13 @@ void BoardInterface::loadSettings() {
|
|||||||
liveData->tmpSettings.settingsVersion = 5;
|
liveData->tmpSettings.settingsVersion = 5;
|
||||||
liveData->tmpSettings.gpsHwSerialPort = 255; // off
|
liveData->tmpSettings.gpsHwSerialPort = 255; // off
|
||||||
}
|
}
|
||||||
|
if (liveData->tmpSettings.settingsVersion == 5) {
|
||||||
|
liveData->tmpSettings.settingsVersion = 6;
|
||||||
|
liveData->tmpSettings.serialConsolePort = 0; // hwuart0
|
||||||
|
liveData->tmpSettings.debugLevel = 0; // show all
|
||||||
|
liveData->tmpSettings.sdcardLogIntervalSec = 2;
|
||||||
|
liveData->tmpSettings.gprsLogIntervalSec = 60;
|
||||||
|
}
|
||||||
|
|
||||||
// Save upgraded structure
|
// Save upgraded structure
|
||||||
liveData->settings = liveData->tmpSettings;
|
liveData->settings = liveData->tmpSettings;
|
||||||
@@ -201,6 +211,8 @@ void BoardInterface::loadSettings() {
|
|||||||
// Apply settings from flash if needed
|
// Apply settings from flash if needed
|
||||||
liveData->settings = liveData->tmpSettings;
|
liveData->settings = liveData->tmpSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syslog->setDebugLevel(liveData->settings.debugLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,14 +220,22 @@ void BoardInterface::loadSettings() {
|
|||||||
*/
|
*/
|
||||||
void BoardInterface::afterSetup() {
|
void BoardInterface::afterSetup() {
|
||||||
|
|
||||||
|
syslog->println("BoardInterface::afterSetup");
|
||||||
|
|
||||||
// Init Comm iterface
|
// Init Comm iterface
|
||||||
|
syslog->print("Init communication device: ");
|
||||||
|
syslog->println(liveData->settings.commType);
|
||||||
|
|
||||||
if (liveData->settings.commType == COMM_TYPE_OBD2BLE4) {
|
if (liveData->settings.commType == COMM_TYPE_OBD2BLE4) {
|
||||||
commInterface = new CommObd2Ble4();
|
commInterface = new CommObd2Ble4();
|
||||||
} else if (liveData->settings.commType == COMM_TYPE_OBD2CAN) {
|
} else if (liveData->settings.commType == COMM_TYPE_OBD2CAN) {
|
||||||
commInterface = new CommObd2Ble4();
|
commInterface = new CommObd2Can();
|
||||||
//commInterface = new CommObd2Can();
|
} else if (liveData->settings.commType == COMM_TYPE_OBD2BT3) {
|
||||||
|
//commInterface = new CommObd2Bt3();
|
||||||
|
syslog->println("BT3 not implemented");
|
||||||
}
|
}
|
||||||
//commInterface->initComm(liveData, NULL);
|
|
||||||
|
commInterface->initComm(liveData, this);
|
||||||
commInterface->connectDevice();
|
commInterface->connectDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +261,15 @@ void BoardInterface::customConsoleCommand(String cmd) {
|
|||||||
if (key == "remoteApiKey") value.toCharArray(liveData->settings.remoteApiKey, value.length() + 1);
|
if (key == "remoteApiKey") value.toCharArray(liveData->settings.remoteApiKey, value.length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Parser response from obd2/can
|
||||||
|
*/
|
||||||
|
void BoardInterface::parseRowMerged() {
|
||||||
|
|
||||||
|
carInterface->parseRowMerged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Serialize parameters
|
Serialize parameters
|
||||||
*/
|
*/
|
||||||
@@ -313,5 +342,3 @@ bool BoardInterface::serializeParamsToJson(File file, bool inclApiKey) {
|
|||||||
serializeJson(jsonData, Serial);
|
serializeJson(jsonData, Serial);
|
||||||
serializeJson(jsonData, file);
|
serializeJson(jsonData, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOARDINTERFACE_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef BOARDINTERFACE_H
|
#pragma once
|
||||||
#define BOARDINTERFACE_H
|
|
||||||
|
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
@@ -24,12 +23,6 @@ class BoardInterface {
|
|||||||
bool testDataMode = false;
|
bool testDataMode = false;
|
||||||
bool scanDevices = false;
|
bool scanDevices = false;
|
||||||
String sdcardRecordBuffer = "";
|
String sdcardRecordBuffer = "";
|
||||||
// Debug screen - next command with right button
|
|
||||||
uint16_t debugCommandIndex = 0;
|
|
||||||
String debugAtshRequest = "ATSH7E4";
|
|
||||||
String debugCommandRequest = "220101";
|
|
||||||
String debugLastString = "620101FFF7E7FF99000000000300B10EFE120F11100F12000018C438C30B00008400003864000035850000153A00001374000647010D017F0BDA0BDA03E8";
|
|
||||||
String debugPreviousString = "620101FFF7E7FFB3000000000300120F9B111011101011000014CC38CB3B00009100003A510000367C000015FB000013D3000690250D018E0000000003E8";
|
|
||||||
//
|
//
|
||||||
void setLiveData(LiveData* pLiveData);
|
void setLiveData(LiveData* pLiveData);
|
||||||
void attachCar(CarInterface* pCarInterface);
|
void attachCar(CarInterface* pCarInterface);
|
||||||
@@ -41,6 +34,7 @@ class BoardInterface {
|
|||||||
virtual void displayMessage(const char* row1, const char* row2)=0;
|
virtual void displayMessage(const char* row1, const char* row2)=0;
|
||||||
virtual void setBrightness(byte lcdBrightnessPerc)=0;
|
virtual void setBrightness(byte lcdBrightnessPerc)=0;
|
||||||
virtual void redrawScreen()=0;
|
virtual void redrawScreen()=0;
|
||||||
|
void parseRowMerged();
|
||||||
// Menu
|
// Menu
|
||||||
virtual void showMenu()=0;
|
virtual void showMenu()=0;
|
||||||
virtual void hideMenu()=0;
|
virtual void hideMenu()=0;
|
||||||
@@ -55,5 +49,3 @@ class BoardInterface {
|
|||||||
virtual void sdcardToggleRecording()=0;
|
virtual void sdcardToggleRecording()=0;
|
||||||
bool serializeParamsToJson(File file, bool inclApiKey = false);
|
bool serializeParamsToJson(File file, bool inclApiKey = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOARDINTERFACE_H
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#ifndef BOARDM5STACKCORE_CPP
|
|
||||||
#define BOARDM5STACKCORE_CPP
|
|
||||||
|
|
||||||
#include "BoardInterface.h"
|
#include "BoardInterface.h"
|
||||||
#include "Board320_240.h"
|
#include "Board320_240.h"
|
||||||
#include "BoardM5stackCore.h"
|
#include "BoardM5stackCore.h"
|
||||||
@@ -24,7 +21,7 @@ void BoardM5stackCore::initBoard() {
|
|||||||
|
|
||||||
// Mute speaker
|
// Mute speaker
|
||||||
//ledcWriteTone(TONE_PIN_CHANNEL, 0);
|
//ledcWriteTone(TONE_PIN_CHANNEL, 0);
|
||||||
digitalWrite(SPEAKER_PIN, 0);
|
dacWrite(SPEAKER_PIN, 0);
|
||||||
|
|
||||||
//
|
//
|
||||||
Board320_240::initBoard();
|
Board320_240::initBoard();
|
||||||
@@ -34,5 +31,3 @@ void BoardM5stackCore::mainLoop() {
|
|||||||
|
|
||||||
Board320_240::mainLoop();
|
Board320_240::mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOARDM5STACKCORE_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef BOARDM5STACKCORE_H
|
#pragma once
|
||||||
#define BOARDM5STACKCORE_H
|
|
||||||
|
|
||||||
// Setup for m5stack core
|
// Setup for m5stack core
|
||||||
#define USER_SETUP_LOADED 1
|
#define USER_SETUP_LOADED 1
|
||||||
@@ -42,5 +41,3 @@ class BoardM5stackCore : public Board320_240 {
|
|||||||
void initBoard() override;
|
void initBoard() override;
|
||||||
void mainLoop() override;
|
void mainLoop() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOARDM5STACKCORE_H
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#ifndef BOARDTTGOT4V13_CPP
|
|
||||||
#define BOARDTTGOT4V13_CPP
|
|
||||||
|
|
||||||
#include "BoardInterface.h"
|
#include "BoardInterface.h"
|
||||||
#include "Board320_240.h"
|
#include "Board320_240.h"
|
||||||
#include "BoardTtgoT4v13.h"
|
#include "BoardTtgoT4v13.h"
|
||||||
@@ -22,5 +19,3 @@ void BoardTtgoT4v13::initBoard() {
|
|||||||
|
|
||||||
Board320_240::initBoard();
|
Board320_240::initBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOARDTTGOT4V13_CPP
|
|
||||||
|
|||||||
412
CarBmwI3.cpp
Normal file
412
CarBmwI3.cpp
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
#include "CarBmwI3.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/**
|
||||||
|
activateliveData->commandQueue
|
||||||
|
*/
|
||||||
|
void CarBmwI3::activateCommandQueue() {
|
||||||
|
const uint16_t commandQueueLoopFrom = 18;
|
||||||
|
|
||||||
|
// const std::vector<String> commandQueue = {
|
||||||
|
const std::vector<LiveData::Command_t> commandQueue = {
|
||||||
|
{0, "ATZ"}, // Reset all
|
||||||
|
{0, "ATD"}, // All to defaults
|
||||||
|
{0, "ATI"}, // Print the version ID
|
||||||
|
{0, "ATE0"}, // Echo off
|
||||||
|
{0, "ATPP2COFF"}, // Disable prog parameter 2C
|
||||||
|
//{0, "ATSH6F1"}, // Set header to 6F1
|
||||||
|
{0, "ATCF600"}, // Set the ID filter to 600
|
||||||
|
{0, "ATCM700"}, // Set the ID mask to 700
|
||||||
|
{0, "ATPBC001"}, // Protocol B options and baudrate (div 1 = 500k)
|
||||||
|
{0, "ATSPB"}, // Set protocol to B and save it (USER1 11bit, 125kbaud)
|
||||||
|
{0, "ATAT0"}, // Adaptive timing off
|
||||||
|
{0, "ATSTFF"}, // Set timeout to ff x 4ms
|
||||||
|
{0, "ATAL"}, // Allow long messages ( > 7 Bytes)
|
||||||
|
{0, "ATH1"}, // Additional headers on
|
||||||
|
{0, "ATS0"}, // Printing of spaces off
|
||||||
|
{0, "ATL0"}, // Linefeeds off
|
||||||
|
{0, "ATCSM0"}, // Silent monitoring off
|
||||||
|
{0, "ATCTM5"}, // Set timer multiplier to 5
|
||||||
|
{0, "ATJE"}, // Use J1939 SAE data format
|
||||||
|
|
||||||
|
// Loop from (BMW i3)
|
||||||
|
// BMS
|
||||||
|
{0, "ATSH6F1"},
|
||||||
|
|
||||||
|
{0x12, "22402B"}, // STATUS_MESSWERTE_IBS - 12V Bat
|
||||||
|
//////{0x12, "22F101"}, // STATUS_A_T_ELUE ???
|
||||||
|
{0x60, "22D107"}, // Speed km/h (ELM CAN send: '600322D107000000')
|
||||||
|
{0x60, "22D10D"}, // Total km without offset (ELM CAN send: '600322D10D000000')
|
||||||
|
{0x60, "22D114"}, // Total km - offset (ELM CAN send: '600322D114000000')
|
||||||
|
{0x78, "22D85C"}, // Calculated indoor temperature (ELM CAN send: '780322D85C000000')
|
||||||
|
{0x78, "22D96B"}, // Outdoor temperature
|
||||||
|
//{0, "22DC61"}, // BREMSLICHT_SCHALTER
|
||||||
|
{0x07, "22DD7B"}, // ALTERUNG_KAPAZITAET Aging of kapacity
|
||||||
|
{0x07, "22DD7C"}, // GW_INFO - should contain kWh but in some strange form
|
||||||
|
{0x07, "22DDBF"}, // Min and Max cell voltage
|
||||||
|
{0x07, "22DDC0"}, // TEMPERATUREN
|
||||||
|
{0x07, "22DD69"}, // HV_STORM
|
||||||
|
{0x07, "22DD6C"}, // KUEHLKREISLAUF_TEMP
|
||||||
|
{0x07, "22DDB4"}, // HV_SPANNUNG
|
||||||
|
{0x07, "22DDBC"} // SOC
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 60Ah / 22kWh version
|
||||||
|
liveData->params.batteryTotalAvailableKWh = 18.8;
|
||||||
|
liveData->params.batModuleTempCount = 4; //?
|
||||||
|
|
||||||
|
// init params which are currently not filled from parsed data
|
||||||
|
liveData->params.tireFrontLeftPressureBar = 0;
|
||||||
|
liveData->params.tireFrontLeftTempC = 0;
|
||||||
|
liveData->params.tireRearLeftPressureBar = 0;
|
||||||
|
liveData->params.tireRearLeftTempC = 0;
|
||||||
|
liveData->params.tireFrontRightPressureBar = 0;
|
||||||
|
liveData->params.tireFrontRightTempC = 0;
|
||||||
|
liveData->params.tireRearRightPressureBar = 0;
|
||||||
|
liveData->params.tireRearRightTempC = 0;
|
||||||
|
|
||||||
|
// Empty and fill command queue
|
||||||
|
liveData->commandQueue.clear(); // probably not needed before assign
|
||||||
|
liveData->commandQueue.assign(commandQueue.begin(), commandQueue.end());
|
||||||
|
|
||||||
|
liveData->commandQueueLoopFrom = commandQueueLoopFrom;
|
||||||
|
liveData->commandQueueCount = commandQueue.size();
|
||||||
|
liveData->bAdditionalStartingChar = true; // there is one additional byte in received packets compared to other cars
|
||||||
|
liveData->expectedMinimalPacketLength = 6; // to filter occasional 5-bytes long packets
|
||||||
|
liveData->rxTimeoutMs = 500; // timeout for receiving of CAN response
|
||||||
|
liveData->delayBetweenCommandsMs = 100; // delay between commands, set to 0 if no delay is needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
parseRowMerged
|
||||||
|
*/
|
||||||
|
void CarBmwI3::parseRowMerged()
|
||||||
|
{
|
||||||
|
syslog->print("--mergedVectorLength: "); syslog->println(liveData->vResponseRowMerged.size());
|
||||||
|
|
||||||
|
struct Header_t
|
||||||
|
{
|
||||||
|
uint8_t startChar;
|
||||||
|
uint8_t pid[2];
|
||||||
|
uint8_t pData[];
|
||||||
|
|
||||||
|
uint16_t getPid() { return 256 * pid[0] + pid[1]; };
|
||||||
|
};
|
||||||
|
|
||||||
|
Header_t* pHeader = (Header_t*)liveData->vResponseRowMerged.data();
|
||||||
|
|
||||||
|
|
||||||
|
const uint16_t payloadLength = liveData->vResponseRowMerged.size() - sizeof(Header_t);
|
||||||
|
|
||||||
|
// create reversed payload to get little endian order of data
|
||||||
|
std::vector<uint8_t> payloadReversed(pHeader->pData, pHeader->pData + payloadLength);
|
||||||
|
std::reverse(payloadReversed.begin(), payloadReversed.end());
|
||||||
|
|
||||||
|
//syslog->print("--extracted PID: "); syslog->println(pHeader->getPid());
|
||||||
|
//syslog->print("--payload length: "); syslog->println(payloadLength);
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
// BMS
|
||||||
|
if (liveData->currentAtshRequest.equals("ATSH6F1")) {
|
||||||
|
|
||||||
|
switch (pHeader->getPid()) {
|
||||||
|
case 0x402B:
|
||||||
|
{
|
||||||
|
struct s402B_t {
|
||||||
|
int16_t unknown[13];
|
||||||
|
uint16_t auxRawCurrent;
|
||||||
|
uint16_t auxRawVoltage;
|
||||||
|
int16_t auxTemp;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(s402B_t)) {
|
||||||
|
s402B_t* ptr = (s402B_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.auxTemperature = ptr->auxTemp / 10.0;
|
||||||
|
liveData->params.auxVoltage = ptr->auxRawVoltage / 4000.0 + 6;
|
||||||
|
liveData->params.auxCurrentAmp = - (ptr->auxRawCurrent / 12.5 - 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD107: // Speed km/h
|
||||||
|
{
|
||||||
|
struct D107_t {
|
||||||
|
uint16_t speedKmh;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(D107_t)) {
|
||||||
|
D107_t* ptr = (D107_t*)payloadReversed.data();
|
||||||
|
liveData->params.speedKmh = ptr->speedKmh / 10.0;
|
||||||
|
|
||||||
|
syslog->print("----speed km/h: "); syslog->println(liveData->params.speedKmh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD10D: // Total km wihtout offset
|
||||||
|
{
|
||||||
|
struct D10D_t {
|
||||||
|
uint32_t totalKm1; // one of those two is RAM and other is EEPROM value
|
||||||
|
uint32_t totalKm2;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(D10D_t)) {
|
||||||
|
D10D_t* ptr = (D10D_t*)payloadReversed.data();
|
||||||
|
liveData->params.odoKm = ptr->totalKm1 - totalDistanceKmOffset;
|
||||||
|
|
||||||
|
syslog->print("----total km1: "); syslog->println(ptr->totalKm1);
|
||||||
|
syslog->print("----total km2: "); syslog->println(ptr->totalKm2);
|
||||||
|
syslog->print("----total km: "); syslog->println(liveData->params.odoKm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD114: // Offset of total km
|
||||||
|
{
|
||||||
|
struct D114_t {
|
||||||
|
uint8_t offsetKm;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(D114_t)) {
|
||||||
|
D114_t* ptr = (D114_t*)payloadReversed.data();
|
||||||
|
totalDistanceKmOffset = ptr->offsetKm;
|
||||||
|
|
||||||
|
syslog->print("----total off: "); syslog->println(totalDistanceKmOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD85C:
|
||||||
|
{
|
||||||
|
struct D85C_t {
|
||||||
|
int8_t indoorTemp;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(D85C_t)) {
|
||||||
|
D85C_t* ptr = (D85C_t*)payloadReversed.data();
|
||||||
|
liveData->params.indoorTemperature = ptr->indoorTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD96B:
|
||||||
|
{
|
||||||
|
struct D96B_t {
|
||||||
|
uint16_t outdoorTempRaw;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(D96B_t)) {
|
||||||
|
D96B_t* ptr = (D96B_t*)payloadReversed.data();
|
||||||
|
liveData->params.outdoorTemperature = (ptr->outdoorTempRaw / 2.0) - 40.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDD69:
|
||||||
|
{
|
||||||
|
struct DD69_t {
|
||||||
|
uint8_t unknown[4];
|
||||||
|
int32_t batAmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DD69_t)) {
|
||||||
|
DD69_t* ptr = (DD69_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.batPowerAmp = ptr->batAmp / 100.0; //liveData->hexToDecFromResponse(6, 14, 4, true) / 100.0;
|
||||||
|
|
||||||
|
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
||||||
|
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
||||||
|
liveData->params.chargingStartTime = liveData->params.currentTime;
|
||||||
|
|
||||||
|
// calculate kWh/100
|
||||||
|
liveData->params.batPowerKwh100 = liveData->params.batPowerKw / liveData->params.speedKmh * 100;
|
||||||
|
|
||||||
|
// update charging graph data if car is charging
|
||||||
|
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
||||||
|
if ( liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw < liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)])
|
||||||
|
liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
||||||
|
if ( liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw > liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)])
|
||||||
|
liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDD6C:
|
||||||
|
{
|
||||||
|
struct DD6C_t {
|
||||||
|
int16_t tempCoolant;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DD6C_t)) {
|
||||||
|
DD6C_t* ptr = (DD6C_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.coolingWaterTempC = ptr->tempCoolant / 10.0;
|
||||||
|
liveData->params.coolantTemp1C = ptr->tempCoolant / 10.0;
|
||||||
|
liveData->params.coolantTemp2C = ptr->tempCoolant / 10.0;
|
||||||
|
|
||||||
|
// update charging graph data if car is charging
|
||||||
|
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
||||||
|
liveData->params.chargingGraphWaterCoolantTempC[int(liveData->params.socPerc)] = liveData->params.coolingWaterTempC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDD7B:
|
||||||
|
{
|
||||||
|
struct DD7B_t {
|
||||||
|
uint8_t agingOfCapacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DD7B_t)) {
|
||||||
|
DD7B_t* ptr = (DD7B_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.sohPerc = ptr->agingOfCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDD7C:
|
||||||
|
{
|
||||||
|
struct DD7C_t {
|
||||||
|
//uint8_t unused1;
|
||||||
|
uint32_t discharged;
|
||||||
|
uint32_t charged;
|
||||||
|
uint8_t unknown[];
|
||||||
|
};
|
||||||
|
|
||||||
|
Serial.print("DD7C received, struct sizeof is "); Serial.println(sizeof(DD7C_t));
|
||||||
|
if (payloadLength >= sizeof(DD7C_t)) {
|
||||||
|
|
||||||
|
DD7C_t* ptr = (DD7C_t*)(payloadReversed.data() + 1); // skip one charcter on beginning (TODO: fix when pragma push/pack is done)
|
||||||
|
liveData->params.cumulativeEnergyDischargedKWh = ptr->discharged / 100000.0;
|
||||||
|
if (liveData->params.cumulativeEnergyDischargedKWhStart == -1)
|
||||||
|
liveData->params.cumulativeEnergyDischargedKWhStart = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
|
|
||||||
|
liveData->params.cumulativeEnergyChargedKWh = ptr->charged / 100000.0;
|
||||||
|
if (liveData->params.cumulativeEnergyChargedKWhStart == -1)
|
||||||
|
liveData->params.cumulativeEnergyChargedKWhStart = liveData->params.cumulativeEnergyChargedKWh;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDDB4:
|
||||||
|
{
|
||||||
|
struct DDB4_t {
|
||||||
|
uint16_t batVoltage;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DDB4_t)) { // HV_SPANNUNG_BATTERIE
|
||||||
|
DDB4_t* ptr = (DDB4_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.batVoltage = ptr->batVoltage / 100.0;
|
||||||
|
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
||||||
|
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
||||||
|
liveData->params.chargingStartTime = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDDBF:
|
||||||
|
{
|
||||||
|
struct DDBF_t {
|
||||||
|
uint16_t unused[2];
|
||||||
|
uint16_t ucellMax;
|
||||||
|
uint16_t ucellMin;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DDBF_t)) { // HV_SPANNUNG_BATTERIE
|
||||||
|
DDBF_t* ptr = (DDBF_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.batCellMaxV = ptr->ucellMax / 1000.0;
|
||||||
|
liveData->params.batCellMinV = ptr->ucellMin / 1000.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDDC0:
|
||||||
|
{
|
||||||
|
struct DDC0_t {
|
||||||
|
uint8_t unknown[2];
|
||||||
|
int16_t tempAvg;
|
||||||
|
int16_t tempMax;
|
||||||
|
int16_t tempMin;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DDC0_t)) {
|
||||||
|
DDC0_t* ptr = (DDC0_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.batMinC = ptr->tempMin / 100.0;
|
||||||
|
liveData->params.batTempC = ptr->tempAvg / 100.0;
|
||||||
|
liveData->params.batMaxC = ptr->tempMax / 100.0;
|
||||||
|
|
||||||
|
liveData->params.batModuleTempC[0] = liveData->params.batTempC;
|
||||||
|
liveData->params.batModuleTempC[1] = liveData->params.batTempC;
|
||||||
|
liveData->params.batModuleTempC[2] = liveData->params.batTempC;
|
||||||
|
liveData->params.batModuleTempC[3] = liveData->params.batTempC;
|
||||||
|
|
||||||
|
// update charging graph data if car is charging
|
||||||
|
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
||||||
|
liveData->params.chargingGraphBatMinTempC[int(liveData->params.socPerc)] = liveData->params.batMinC;
|
||||||
|
liveData->params.chargingGraphBatMaxTempC[int(liveData->params.socPerc)] = liveData->params.batMaxC;
|
||||||
|
//liveData->params.chargingGraphHeaterTempC[int(liveData->params.socPerc)] = liveData->params.batHeaterC;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDDBC:
|
||||||
|
{
|
||||||
|
struct DDBC_t {
|
||||||
|
uint8_t unknown[2];
|
||||||
|
uint16_t socMin;
|
||||||
|
uint16_t socMax;
|
||||||
|
uint16_t soc;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payloadLength == sizeof(DDBC_t)) {
|
||||||
|
DDBC_t* ptr = (DDBC_t*)payloadReversed.data();
|
||||||
|
|
||||||
|
liveData->params.socPercPrevious = liveData->params.socPerc;
|
||||||
|
liveData->params.socPerc = ptr->soc / 10.0;
|
||||||
|
|
||||||
|
// Soc10ced table, record x0% CEC/CED table (ex. 90%->89%, 80%->79%)
|
||||||
|
if(liveData->params.socPercPrevious - liveData->params.socPerc > 0) {
|
||||||
|
byte index = (int(liveData->params.socPerc) == 4) ? 0 : (int)(liveData->params.socPerc / 10) + 1;
|
||||||
|
if ((int(liveData->params.socPerc) % 10 == 9 || int(liveData->params.socPerc) == 4) && liveData->params.soc10ced[index] == -1) {
|
||||||
|
liveData->params.soc10ced[index] = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
|
liveData->params.soc10cec[index] = liveData->params.cumulativeEnergyChargedKWh;
|
||||||
|
liveData->params.soc10odo[index] = liveData->params.odoKm;
|
||||||
|
liveData->params.soc10time[index] = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
} // switch
|
||||||
|
|
||||||
|
} // ATSH6F1
|
||||||
|
#pragma pack(pop)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
loadTestData
|
||||||
|
*/
|
||||||
|
void CarBmwI3::loadTestData()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
16
CarBmwI3.h
Normal file
16
CarBmwI3.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CarInterface.h"
|
||||||
|
|
||||||
|
class CarBmwI3 : public CarInterface {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
public:
|
||||||
|
void activateCommandQueue() override;
|
||||||
|
void parseRowMerged() override;
|
||||||
|
void loadTestData() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t totalDistanceKmOffset = 0;
|
||||||
|
};
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
#ifndef CARHYUNDAIIONIQ_CPP
|
|
||||||
#define CARHYUNDAIIONIQ_CPP
|
|
||||||
|
|
||||||
#include "CarHyundaiIoniq.h"
|
#include "CarHyundaiIoniq.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define commandQueueCountHyundaiIoniq 25
|
|
||||||
#define commandQueueLoopFromHyundaiIoniq 8
|
#define commandQueueLoopFromHyundaiIoniq 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
void CarHyundaiIoniq::activateCommandQueue() {
|
void CarHyundaiIoniq::activateCommandQueue() {
|
||||||
|
|
||||||
String commandQueueHyundaiIoniq[commandQueueCountHyundaiIoniq] = {
|
std::vector<String> commandQueueHyundaiIoniq = {
|
||||||
"AT Z", // Reset all
|
"AT Z", // Reset all
|
||||||
"AT I", // Print the version ID
|
"AT I", // Print the version ID
|
||||||
"AT E0", // Echo off
|
"AT E0", // Echo off
|
||||||
@@ -34,13 +31,17 @@ void CarHyundaiIoniq::activateCommandQueue() {
|
|||||||
"2103", // cell voltages, screen 3 only
|
"2103", // cell voltages, screen 3 only
|
||||||
"2104", // cell voltages, screen 3 only
|
"2104", // cell voltages, screen 3 only
|
||||||
"2105", // soh, soc, ..
|
"2105", // soh, soc, ..
|
||||||
"2106", // cooling water temp
|
|
||||||
|
|
||||||
// VMCU
|
// VMCU
|
||||||
"ATSH7E2",
|
"ATSH7E2",
|
||||||
"2101", // speed, ...
|
"2101", // speed, ...
|
||||||
"2102", // aux, ...
|
"2102", // aux, ...
|
||||||
|
|
||||||
|
// IGPM
|
||||||
|
"ATSH770",
|
||||||
|
"22BC03", // low beam
|
||||||
|
"22BC06", // brake light
|
||||||
|
|
||||||
//"ATSH7Df",
|
//"ATSH7Df",
|
||||||
//"2106",
|
//"2106",
|
||||||
//"220106",
|
//"220106",
|
||||||
@@ -67,15 +68,13 @@ void CarHyundaiIoniq::activateCommandQueue() {
|
|||||||
liveData->params.batModuleTempCount = 12;
|
liveData->params.batModuleTempCount = 12;
|
||||||
|
|
||||||
// Empty and fill command queue
|
// Empty and fill command queue
|
||||||
for (int i = 0; i < 300; i++) {
|
liveData->commandQueue.clear();
|
||||||
liveData->commandQueue[i] = "";
|
for (auto cmd : commandQueueHyundaiIoniq) {
|
||||||
}
|
liveData->commandQueue.push_back({ 0, cmd });
|
||||||
for (int i = 0; i < commandQueueCountHyundaiIoniq; i++) {
|
|
||||||
liveData->commandQueue[i] = commandQueueHyundaiIoniq[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
liveData->commandQueueLoopFrom = commandQueueLoopFromHyundaiIoniq;
|
liveData->commandQueueLoopFrom = commandQueueLoopFromHyundaiIoniq;
|
||||||
liveData->commandQueueCount = commandQueueCountHyundaiIoniq;
|
liveData->commandQueueCount = commandQueueHyundaiIoniq.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +82,10 @@ void CarHyundaiIoniq::activateCommandQueue() {
|
|||||||
*/
|
*/
|
||||||
void CarHyundaiIoniq::parseRowMerged() {
|
void CarHyundaiIoniq::parseRowMerged() {
|
||||||
|
|
||||||
|
uint8_t tempByte;
|
||||||
|
float tempFloat;
|
||||||
|
String tmpStr;
|
||||||
|
|
||||||
// VMCU 7E2
|
// VMCU 7E2
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7E2")) {
|
if (liveData->currentAtshRequest.equals("ATSH7E2")) {
|
||||||
if (liveData->commandRequest.equals("2101")) {
|
if (liveData->commandRequest.equals("2101")) {
|
||||||
@@ -91,11 +94,29 @@ void CarHyundaiIoniq::parseRowMerged() {
|
|||||||
liveData->params.speedKmh = 0;
|
liveData->params.speedKmh = 0;
|
||||||
}
|
}
|
||||||
if (liveData->commandRequest.equals("2102")) {
|
if (liveData->commandRequest.equals("2102")) {
|
||||||
liveData->params.auxPerc = liveData->hexToDecFromResponse(50, 52, 1, false);
|
|
||||||
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IGPM
|
||||||
|
if (liveData->currentAtshRequest.equals("ATSH770")) {
|
||||||
|
if (liveData->commandRequest.equals("22BC03")) {
|
||||||
|
tempByte = liveData->hexToDecFromResponse(16, 18, 1, false);
|
||||||
|
liveData->params.ignitionOn = (bitRead(tempByte, 5) == 1);
|
||||||
|
if (liveData->params.ignitionOn) {
|
||||||
|
liveData->params.lastIgnitionOnTime = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempByte = liveData->hexToDecFromResponse(18, 20, 1, false);
|
||||||
|
liveData->params.headLights = (bitRead(tempByte, 5) == 1);
|
||||||
|
liveData->params.dayLights = (bitRead(tempByte, 3) == 1);
|
||||||
|
}
|
||||||
|
if (liveData->commandRequest.equals("22BC06")) {
|
||||||
|
tempByte = liveData->hexToDecFromResponse(14, 16, 1, false);
|
||||||
|
liveData->params.brakeLights = (bitRead(tempByte, 5) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cluster module 7c6
|
// Cluster module 7c6
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7C6")) {
|
if (liveData->currentAtshRequest.equals("ATSH7C6")) {
|
||||||
if (liveData->commandRequest.equals("22B002")) {
|
if (liveData->commandRequest.equals("22B002")) {
|
||||||
@@ -126,10 +147,25 @@ void CarHyundaiIoniq::parseRowMerged() {
|
|||||||
liveData->params.cumulativeEnergyDischargedKWhStart = liveData->params.cumulativeEnergyDischargedKWh;
|
liveData->params.cumulativeEnergyDischargedKWhStart = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
liveData->params.availableChargePower = liveData->decFromResponse(16, 20) / 100.0;
|
liveData->params.availableChargePower = liveData->decFromResponse(16, 20) / 100.0;
|
||||||
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
||||||
liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, true);
|
liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, false);
|
||||||
liveData->params.batFanStatus = liveData->hexToDecFromResponse(58, 60, 2, true);
|
liveData->params.batFanStatus = liveData->hexToDecFromResponse(58, 60, 1, false);
|
||||||
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(60, 62, 2, true);
|
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(60, 62, 1, false);
|
||||||
liveData->params.auxVoltage = liveData->hexToDecFromResponse(62, 64, 2, true) / 10.0;
|
liveData->params.auxVoltage = liveData->hexToDecFromResponse(62, 64, 1, false) / 10.0;
|
||||||
|
|
||||||
|
float tmpAuxPerc;
|
||||||
|
if(liveData->params.ignitionOn) {
|
||||||
|
tmpAuxPerc = (float)(liveData->params.auxVoltage - 12.8) * 100 / (float)(14.8 - 12.8); //min: 12.8V; max: 14.8V
|
||||||
|
} else {
|
||||||
|
tmpAuxPerc = (float)(liveData->params.auxVoltage - 11.6) * 100 / (float)(12.8 - 11.6); //min 11.6V; max: 12.8V
|
||||||
|
}
|
||||||
|
if(tmpAuxPerc > 100) {
|
||||||
|
liveData->params.auxPerc = 100;
|
||||||
|
} else if(tmpAuxPerc < 0) {
|
||||||
|
liveData->params.auxPerc = 0;
|
||||||
|
} else {
|
||||||
|
liveData->params.auxPerc = tmpAuxPerc;
|
||||||
|
}
|
||||||
|
|
||||||
liveData->params.batPowerAmp = - liveData->hexToDecFromResponse(24, 28, 2, true) / 10.0;
|
liveData->params.batPowerAmp = - liveData->hexToDecFromResponse(24, 28, 2, true) / 10.0;
|
||||||
liveData->params.batVoltage = liveData->hexToDecFromResponse(28, 32, 2, false) / 10.0;
|
liveData->params.batVoltage = liveData->hexToDecFromResponse(28, 32, 2, false) / 10.0;
|
||||||
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
||||||
@@ -147,6 +183,12 @@ void CarHyundaiIoniq::parseRowMerged() {
|
|||||||
//liveData->params.batMaxC = liveData->hexToDecFromResponse(32, 34, 1, true);
|
//liveData->params.batMaxC = liveData->hexToDecFromResponse(32, 34, 1, true);
|
||||||
//liveData->params.batMinC = liveData->hexToDecFromResponse(34, 36, 1, true);
|
//liveData->params.batMinC = liveData->hexToDecFromResponse(34, 36, 1, true);
|
||||||
|
|
||||||
|
tempByte = liveData->hexToDecFromResponse(22, 24, 1, false);
|
||||||
|
liveData->params.chargingOn = (bitRead(tempByte, 5) == 1 || bitRead(tempByte, 6) == 1); // bit 5 = AC; bit 6 = DC
|
||||||
|
if(liveData->params.chargingOn) {
|
||||||
|
liveData->params.lastChargingOnTime = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
||||||
liveData->params.batInletC = liveData->hexToDecFromResponse(48, 50, 1, true);
|
liveData->params.batInletC = liveData->hexToDecFromResponse(48, 50, 1, true);
|
||||||
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
||||||
@@ -249,11 +291,11 @@ void CarHyundaiIoniq::loadTestData() {
|
|||||||
liveData->currentAtshRequest = "ATSH7E2";
|
liveData->currentAtshRequest = "ATSH7E2";
|
||||||
// 2101
|
// 2101
|
||||||
liveData->commandRequest = "2101";
|
liveData->commandRequest = "2101";
|
||||||
liveData->responseRowMerged = "6101FFE0000009211222062F03000000001D7734";
|
liveData->responseRowMerged = "6101FFE0000009215A09061803000000000E773404200000000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 2102
|
// 2102
|
||||||
liveData->commandRequest = "2102";
|
liveData->commandRequest = "2102";
|
||||||
liveData->responseRowMerged = "6102FF80000001010000009315B2888D390B08618B683900000000";
|
liveData->responseRowMerged = "6102FF80000001010000009522C570273A0F0D9199953900000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
// "ATSH7DF",
|
// "ATSH7DF",
|
||||||
@@ -263,52 +305,57 @@ void CarHyundaiIoniq::loadTestData() {
|
|||||||
liveData->currentAtshRequest = "ATSH7B3";
|
liveData->currentAtshRequest = "ATSH7B3";
|
||||||
// 220100
|
// 220100
|
||||||
liveData->commandRequest = "220100";
|
liveData->commandRequest = "220100";
|
||||||
liveData->responseRowMerged = "6201007E5007C8FF8A876A011010FFFF10FF10FFFFFFFFFFFFFFFFFF2EEF767D00FFFF00FFFF000000";
|
liveData->responseRowMerged = "6201007E5007C8FF7A665D00A981FFFF81FF10FFFFFFFFFFFFFFFFFF44CAA7AD00FFFF01FFFF000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 220102
|
// 220102
|
||||||
liveData->commandRequest = "220102";
|
liveData->commandRequest = "220102";
|
||||||
liveData->responseRowMerged = "620102FF800000A3950000000000002600000000";
|
liveData->responseRowMerged = "620102FF800000CA5E0101000101005100000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
// BMS ATSH7E4
|
// BMS ATSH7E4
|
||||||
liveData->currentAtshRequest = "ATSH7E4";
|
liveData->currentAtshRequest = "ATSH7E4";
|
||||||
// 220101
|
// 220101
|
||||||
liveData->commandRequest = "2101";
|
liveData->commandRequest = "2101";
|
||||||
liveData->responseRowMerged = "6101FFFFFFFF5026482648A3FFC30D9E181717171718170019B50FB501000090000142230001425F0000771B00007486007815D809015C0000000003E800";
|
liveData->responseRowMerged = "6101FFFFFFFFBD136826480300220F600B0B0B0B0B0B0B000CCD05CC0A00009100012C4A00012A1800006F37000069F700346CC30D01890000000003E800";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 220102
|
// 220102
|
||||||
liveData->commandRequest = "2102";
|
liveData->commandRequest = "2102";
|
||||||
liveData->responseRowMerged = "6102FFFFFFFFB5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5000000";
|
liveData->responseRowMerged = "6102FFFFFFFFCDCDCDCDCDCDCDCDCDCCCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCCCDCDCD000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 220103
|
// 220103
|
||||||
liveData->commandRequest = "2103";
|
liveData->commandRequest = "2103";
|
||||||
liveData->responseRowMerged = "6103FFFFFFFFB5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5000000";
|
liveData->responseRowMerged = "6103FFFFFFFFCDCDCDCDCDCDCCCDCDCDCDCDCDCDCDCDCCCDCDCCCDCDCDCDCDCDCDCCCDCDCDCC000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 220104
|
// 220104
|
||||||
liveData->commandRequest = "2104";
|
liveData->commandRequest = "2104";
|
||||||
liveData->responseRowMerged = "6104FFFFFFFFB5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5000000";
|
liveData->responseRowMerged = "6104FFFFFFFFCDCDCDCDCDCDCDCDCDCDCCCCCDCDCCCDCDCDCDCDCDCDCDCDCDCDCDCCCCCCCDCD000000";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
// 220105
|
// 220105
|
||||||
liveData->commandRequest = "2105";
|
liveData->commandRequest = "2105";
|
||||||
liveData->responseRowMerged = "6105FFFFFFFF00000000001717171817171726482648000150181703E81A03E801520029000000000000000000000000";
|
liveData->responseRowMerged = "6105FFFFFFFF00000000000B0B0B0B0B0B0B136826480001500B0B03E80203E831C60031000000000000000000000000";
|
||||||
parseRowMerged();
|
|
||||||
// 220106
|
|
||||||
liveData->commandRequest = "2106";
|
|
||||||
liveData->responseRowMerged = "7F2112"; // n/a on ioniq
|
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
// BCM / TPMS ATSH7A0
|
// BCM / TPMS ATSH7A0
|
||||||
liveData->currentAtshRequest = "ATSH7A0";
|
liveData->currentAtshRequest = "ATSH7A0";
|
||||||
// 22c00b
|
// 22c00b
|
||||||
liveData->commandRequest = "22c00b";
|
liveData->commandRequest = "22c00b";
|
||||||
liveData->responseRowMerged = "62C00BFFFF0000B9510100B9510100B84F0100B54F0100AAAAAAAA";
|
liveData->responseRowMerged = "62C00BFFFF0000B73D0100B63D0100B43D0100B53C0100AAAAAAAA";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
// ATSH7C6
|
// ATSH7C6
|
||||||
liveData->currentAtshRequest = "ATSH7C6";
|
liveData->currentAtshRequest = "ATSH7C6";
|
||||||
// 22b002
|
// 22b002
|
||||||
liveData->commandRequest = "22b002";
|
liveData->commandRequest = "22b002";
|
||||||
liveData->responseRowMerged = "62B002E000000000AD003D2D0000000000000000";
|
liveData->responseRowMerged = "62B002E000000000AA003B0B0000000000000000";
|
||||||
|
parseRowMerged();
|
||||||
|
|
||||||
|
//ATSH770
|
||||||
|
liveData->currentAtshRequest = "ATSH770";
|
||||||
|
liveData->commandRequest = "22BC03";
|
||||||
|
liveData->responseRowMerged = "62BC03FDEE3C7300600000AAAA";
|
||||||
|
parseRowMerged();
|
||||||
|
liveData->commandRequest = "22BC06";
|
||||||
|
liveData->responseRowMerged = "62BC06B480000000000000AAAA";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
/* liveData->params.batModule01TempC = 28;
|
/* liveData->params.batModule01TempC = 28;
|
||||||
@@ -377,5 +424,3 @@ void CarHyundaiIoniq::loadTestData() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //CARHYUNDAIIONIQ_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef CARHYUNDAIIONIQ_H
|
#pragma once
|
||||||
#define CARHYUNDAIIONIQ_H
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
|
|
||||||
@@ -12,5 +11,3 @@ class CarHyundaiIoniq : public CarInterface {
|
|||||||
void parseRowMerged() override;
|
void parseRowMerged() override;
|
||||||
void loadTestData() override;
|
void loadTestData() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#ifndef CARINTERFACE_CPP
|
|
||||||
#define CARINTERFACE_CPP
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
|
|
||||||
@@ -19,5 +16,3 @@ void CarInterface::parseRowMerged() {
|
|||||||
void CarInterface::loadTestData() {
|
void CarInterface::loadTestData() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CARINTERFACE_CPP
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#ifndef CARKIADEBUGOBD2_CPP
|
|
||||||
#define CARKIADEBUGOBD2_CPP
|
|
||||||
|
|
||||||
#include "CarKiaDebugObd2.h"
|
#include "CarKiaDebugObd2.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define commandQueueCountDebugObd2Kia 256
|
//#define commandQueueCountDebugObd2Kia 256
|
||||||
#define commandQueueLoopFromDebugObd2Kia 8
|
#define commandQueueLoopFromDebugObd2Kia 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
void CarKiaDebugObd2::activateCommandQueue() {
|
void CarKiaDebugObd2::activateCommandQueue() {
|
||||||
|
|
||||||
String commandQueueDebugObd2Kia[commandQueueCountDebugObd2Kia] = {
|
std::vector<String> commandQueueDebugObd2Kia = {
|
||||||
"AT Z", // Reset all
|
"AT Z", // Reset all
|
||||||
"AT I", // Print the version ID
|
"AT I", // Print the version ID
|
||||||
"AT E0", // Echo off
|
"AT E0", // Echo off
|
||||||
@@ -222,15 +220,13 @@ void CarKiaDebugObd2::activateCommandQueue() {
|
|||||||
liveData->params.batteryTotalAvailableKWh = 64;
|
liveData->params.batteryTotalAvailableKWh = 64;
|
||||||
|
|
||||||
// Empty and fill command queue
|
// Empty and fill command queue
|
||||||
for (uint16_t i = 0; i < 300; i++) {
|
liveData->commandQueue.clear();
|
||||||
liveData->commandQueue[i] = "";
|
for (auto cmd : commandQueueDebugObd2Kia) {
|
||||||
}
|
liveData->commandQueue.push_back({ 0, cmd });
|
||||||
for (uint16_t i = 0; i < commandQueueCountDebugObd2Kia; i++) {
|
|
||||||
liveData->commandQueue[i] = commandQueueDebugObd2Kia[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
liveData->commandQueueLoopFrom = commandQueueLoopFromDebugObd2Kia;
|
liveData->commandQueueLoopFrom = commandQueueLoopFromDebugObd2Kia;
|
||||||
liveData->commandQueueCount = commandQueueCountDebugObd2Kia;
|
liveData->commandQueueCount = commandQueueDebugObd2Kia.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -516,5 +512,3 @@ void CarKiaDebugObd2::loadTestData() {
|
|||||||
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CARKIADEBUGOBD2_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef CARKIADEBUGOBD2_H
|
#pragma once
|
||||||
#define CARKIADEBUGOBD2_H
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
|
|
||||||
@@ -12,5 +11,3 @@ class CarKiaDebugObd2 : public CarInterface {
|
|||||||
void parseRowMerged() override;
|
void parseRowMerged() override;
|
||||||
void loadTestData() override;
|
void loadTestData() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARKIADEBUGOBD2_H
|
|
||||||
|
|||||||
213
CarKiaEniro.cpp
213
CarKiaEniro.cpp
@@ -1,15 +1,12 @@
|
|||||||
#ifndef CARKIAENIRO_CPP
|
|
||||||
#define CARKIAENIRO_CPP
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* eNiro/Kona chargings limits depending on battery temperature (min.value of 01-04 battery module)
|
eNiro/Kona chargings limits depending on battery temperature (min.value of 01-04 battery module)
|
||||||
>= 35°C BMS allows max 180A
|
>= 35°C BMS allows max 180A
|
||||||
>= 25°C without limit (200A)
|
>= 25°C without limit (200A)
|
||||||
>= 15°C BMS allows max 120A
|
>= 15°C BMS allows max 120A
|
||||||
>= 5°C BMS allows max 90A
|
>= 5°C BMS allows max 90A
|
||||||
>= 1°C BMS allows max 60A
|
>= 1°C BMS allows max 60A
|
||||||
<= 0°C BMS allows max 40A
|
<= 0°C BMS allows max 40A
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -18,16 +15,16 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
#include "CarKiaEniro.h"
|
#include "CarKiaEniro.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define commandQueueCountKiaENiro 30
|
#define commandQueueLoopFromKiaENiro 8
|
||||||
#define commandQueueLoopFromKiaENiro 10
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* activateCommandQueue
|
activateCommandQueue
|
||||||
*/
|
*/
|
||||||
void CarKiaEniro::activateCommandQueue() {
|
void CarKiaEniro::activateCommandQueue() {
|
||||||
|
|
||||||
String commandQueueKiaENiro[commandQueueCountKiaENiro] = {
|
std::vector<String> commandQueueKiaENiro = {
|
||||||
"AT Z", // Reset all
|
"AT Z", // Reset all
|
||||||
"AT I", // Print the version ID
|
"AT I", // Print the version ID
|
||||||
"AT S0", // Printing of spaces on
|
"AT S0", // Printing of spaces on
|
||||||
@@ -45,18 +42,31 @@ void CarKiaEniro::activateCommandQueue() {
|
|||||||
|
|
||||||
// Loop from (KIA ENIRO)
|
// Loop from (KIA ENIRO)
|
||||||
|
|
||||||
// ABS / ESP + AHB
|
|
||||||
"ATSH7D1",
|
|
||||||
"22C101", // brake, park/drive mode
|
|
||||||
|
|
||||||
// IGPM
|
// IGPM
|
||||||
"ATSH770",
|
"ATSH770",
|
||||||
"22BC03", // low beam
|
"22BC03", // low beam
|
||||||
"22BC06", // brake light
|
"22BC06", // brake light
|
||||||
|
|
||||||
|
// ABS / ESP + AHB
|
||||||
|
"ATSH7D1",
|
||||||
|
"22C101", // brake, park/drive mode
|
||||||
|
|
||||||
|
// BCM / TPMS
|
||||||
|
"ATSH7A0",
|
||||||
|
"22c00b", // tire pressure/temp
|
||||||
|
|
||||||
|
// Aircondition
|
||||||
|
"ATSH7B3",
|
||||||
|
"220100", // in/out temp
|
||||||
|
"220102", // coolant temp1, 2
|
||||||
|
|
||||||
|
// CLUSTER MODULE
|
||||||
|
"ATSH7C6",
|
||||||
|
"22B002", // odo
|
||||||
|
|
||||||
// VMCU
|
// VMCU
|
||||||
"ATSH7E2",
|
"ATSH7E2",
|
||||||
"2101", // speed, ...
|
// "2101", // speed, ...
|
||||||
"2102", // aux, ...
|
"2102", // aux, ...
|
||||||
|
|
||||||
// BMS
|
// BMS
|
||||||
@@ -68,102 +78,94 @@ void CarKiaEniro::activateCommandQueue() {
|
|||||||
"220105", // soh, soc, ..
|
"220105", // soh, soc, ..
|
||||||
"220106", // cooling water temp
|
"220106", // cooling water temp
|
||||||
|
|
||||||
// Aircondition
|
|
||||||
"ATSH7B3",
|
|
||||||
"220100", // in/out temp
|
|
||||||
"220102", // coolant temp1, 2
|
|
||||||
|
|
||||||
// BCM / TPMS
|
|
||||||
"ATSH7A0",
|
|
||||||
"22c00b", // tire pressure/temp
|
|
||||||
|
|
||||||
// CLUSTER MODULE
|
|
||||||
"ATSH7C6",
|
|
||||||
"22B002", // odo
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 39 or 64 kWh model?
|
// 39 or 64 kWh model?
|
||||||
liveData->params.batModuleTempCount = 4;
|
liveData->params.batModuleTempCount = 4;
|
||||||
liveData->params.batteryTotalAvailableKWh = 64;
|
liveData->params.batteryTotalAvailableKWh = 64;
|
||||||
// =(I18*0,615)*(1+(I18*0,0008)) soc to kwh niro ev 2020
|
// =(I18*0,615)*(1+(I18*0,0008)) soc to kwh niro ev 2020
|
||||||
|
// Calculates based on nick.n17 dashboard data
|
||||||
if (liveData->settings.carType == CAR_KIA_ENIRO_2020_39 || liveData->settings.carType == CAR_HYUNDAI_KONA_2020_39) {
|
if (liveData->settings.carType == CAR_KIA_ENIRO_2020_39 || liveData->settings.carType == CAR_HYUNDAI_KONA_2020_39) {
|
||||||
liveData->params.batteryTotalAvailableKWh = 39.2;
|
liveData->params.batteryTotalAvailableKWh = 39.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty and fill command queue
|
// Empty and fill command queue
|
||||||
for (int i = 0; i < 300; i++) {
|
liveData->commandQueue.clear();
|
||||||
liveData->commandQueue[i] = "";
|
//for (int i = 0; i < commandQueueCountKiaENiro; i++) {
|
||||||
}
|
for (auto cmd : commandQueueKiaENiro) {
|
||||||
for (int i = 0; i < commandQueueCountKiaENiro; i++) {
|
liveData->commandQueue.push_back({ 0, cmd }); // stxChar not used, keep it 0
|
||||||
liveData->commandQueue[i] = commandQueueKiaENiro[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
liveData->commandQueueLoopFrom = commandQueueLoopFromKiaENiro;
|
liveData->commandQueueLoopFrom = commandQueueLoopFromKiaENiro;
|
||||||
liveData->commandQueueCount = commandQueueCountKiaENiro;
|
liveData->commandQueueCount = commandQueueKiaENiro.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parseRowMerged
|
parseRowMerged
|
||||||
*/
|
*/
|
||||||
void CarKiaEniro::parseRowMerged() {
|
void CarKiaEniro::parseRowMerged() {
|
||||||
|
|
||||||
bool tempByte;
|
uint8_t tempByte;
|
||||||
float tempFloat;
|
float tempFloat;
|
||||||
String tmpStr;
|
String tmpStr;
|
||||||
|
|
||||||
|
// IGPM
|
||||||
|
// RESPONDING WHEN CAR IS OFF
|
||||||
|
if (liveData->currentAtshRequest.equals("ATSH770")) {
|
||||||
|
if (liveData->commandRequest.equals("22BC03")) {
|
||||||
|
//
|
||||||
|
tempByte = liveData->hexToDecFromResponse(14, 16, 1, false);
|
||||||
|
liveData->params.hoodDoorOpen = (bitRead(tempByte, 7) == 1);
|
||||||
|
liveData->params.leftFrontDoorOpen = (bitRead(tempByte, 5) == 1);
|
||||||
|
liveData->params.rightFrontDoorOpen = (bitRead(tempByte, 0) == 1);
|
||||||
|
liveData->params.leftRearDoorOpen = (bitRead(tempByte, 4) == 1);
|
||||||
|
liveData->params.rightRearDoorOpen = (bitRead(tempByte, 2) == 1);
|
||||||
|
//
|
||||||
|
tempByte = liveData->hexToDecFromResponse(16, 18, 1, false);
|
||||||
|
liveData->params.ignitionOn = (bitRead(tempByte, 5) == 1);
|
||||||
|
liveData->params.trunkDoorOpen = (bitRead(tempByte, 0) == 1);
|
||||||
|
if (liveData->params.ignitionOn) {
|
||||||
|
liveData->params.lastIgnitionOnTime = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempByte = liveData->hexToDecFromResponse(18, 20, 1, false);
|
||||||
|
liveData->params.headLights = (bitRead(tempByte, 5) == 1);
|
||||||
|
liveData->params.dayLights = (bitRead(tempByte, 3) == 1);
|
||||||
|
}
|
||||||
|
if (liveData->commandRequest.equals("22BC06")) {
|
||||||
|
tempByte = liveData->hexToDecFromResponse(14, 16, 1, false);
|
||||||
|
liveData->params.brakeLights = (bitRead(tempByte, 5) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ABS / ESP + AHB 7D1
|
// ABS / ESP + AHB 7D1
|
||||||
|
// RESPONDING WHEN CAR IS OFF
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7D1")) {
|
if (liveData->currentAtshRequest.equals("ATSH7D1")) {
|
||||||
if (liveData->commandRequest.equals("22C101")) {
|
if (liveData->commandRequest.equals("22C101")) {
|
||||||
uint8_t driveMode = liveData->hexToDecFromResponse(22, 24, 1, false);
|
uint8_t driveMode = liveData->hexToDecFromResponse(22, 24, 1, false);
|
||||||
liveData->params.forwardDriveMode = (driveMode == 4);
|
liveData->params.forwardDriveMode = (driveMode == 4);
|
||||||
liveData->params.reverseDriveMode = (driveMode == 2);
|
liveData->params.reverseDriveMode = (driveMode == 2);
|
||||||
liveData->params.parkModeOrNeutral = (driveMode == 1);
|
liveData->params.parkModeOrNeutral = (driveMode == 1);
|
||||||
|
// Speed
|
||||||
|
liveData->params.speedKmh = liveData->hexToDecFromResponse(18, 20, 2, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IGPM
|
// TPMS 7A0
|
||||||
if (liveData->currentAtshRequest.equals("ATSH770")) {
|
if (liveData->currentAtshRequest.equals("ATSH7A0")) {
|
||||||
if (liveData->commandRequest.equals("22BC03")) {
|
if (liveData->commandRequest.equals("22c00b")) {
|
||||||
tempByte = liveData->hexToDecFromResponse(16, 18, 1, false);
|
liveData->params.tireFrontLeftPressureBar = liveData->hexToDecFromResponse(14, 16, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
liveData->params.ignitionOnPrevious = liveData->params.ignitionOn;
|
liveData->params.tireFrontRightPressureBar = liveData->hexToDecFromResponse(22, 24, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
liveData->params.ignitionOn = (bitRead(tempByte, 5) == 1);
|
liveData->params.tireRearRightPressureBar = liveData->hexToDecFromResponse(30, 32, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
if (liveData->params.ignitionOnPrevious && !liveData->params.ignitionOn)
|
liveData->params.tireRearLeftPressureBar = liveData->hexToDecFromResponse(38, 40, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
liveData->params.automaticShutdownTimer = liveData->params.currentTime;
|
liveData->params.tireFrontLeftTempC = liveData->hexToDecFromResponse(16, 18, 2, false) - 50; // === OK Valid
|
||||||
|
liveData->params.tireFrontRightTempC = liveData->hexToDecFromResponse(24, 26, 2, false) - 50; // === OK Valid
|
||||||
liveData->params.lightInfo = liveData->hexToDecFromResponse(18, 20, 1, false);
|
liveData->params.tireRearRightTempC = liveData->hexToDecFromResponse(32, 34, 2, false) - 50; // === OK Valid
|
||||||
liveData->params.headLights = (bitRead(liveData->params.lightInfo, 5) == 1);
|
liveData->params.tireRearLeftTempC = liveData->hexToDecFromResponse(40, 42, 2, false) - 50; // === OK Valid
|
||||||
liveData->params.dayLights = (bitRead(liveData->params.lightInfo, 3) == 1);
|
|
||||||
}
|
|
||||||
if (liveData->commandRequest.equals("22BC06")) {
|
|
||||||
liveData->params.brakeLightInfo = liveData->hexToDecFromResponse(14, 16, 1, false);
|
|
||||||
liveData->params.brakeLights = (bitRead(liveData->params.brakeLightInfo, 5) == 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VMCU 7E2
|
// Aircon 7B3
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7E2")) {
|
|
||||||
if (liveData->commandRequest.equals("2101")) {
|
|
||||||
liveData->params.speedKmh = liveData->hexToDecFromResponse(32, 36, 2, false) * 0.0155; // / 100.0 *1.609 = real to gps is 1.750
|
|
||||||
if (liveData->params.speedKmh < -99 || liveData->params.speedKmh > 200)
|
|
||||||
liveData->params.speedKmh = 0;
|
|
||||||
}
|
|
||||||
if (liveData->commandRequest.equals("2102")) {
|
|
||||||
liveData->params.auxPerc = liveData->hexToDecFromResponse(50, 52, 1, false);
|
|
||||||
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cluster module 7c6
|
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7C6")) {
|
|
||||||
if (liveData->commandRequest.equals("22B002")) {
|
|
||||||
tempFloat = liveData->params.odoKm;
|
|
||||||
liveData->params.odoKm = liveData->decFromResponse(18, 24);
|
|
||||||
//if (tempFloat != liveData->params.odoKm) liveData->params.sdcardCanNotify = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aircon 7b3
|
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7B3")) {
|
if (liveData->currentAtshRequest.equals("ATSH7B3")) {
|
||||||
if (liveData->commandRequest.equals("220100")) {
|
if (liveData->commandRequest.equals("220100")) {
|
||||||
liveData->params.indoorTemperature = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
liveData->params.indoorTemperature = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
||||||
@@ -175,6 +177,28 @@ void CarKiaEniro::parseRowMerged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cluster module 7C6
|
||||||
|
if (liveData->currentAtshRequest.equals("ATSH7C6")) {
|
||||||
|
if (liveData->commandRequest.equals("22B002")) {
|
||||||
|
tempFloat = liveData->params.odoKm;
|
||||||
|
liveData->params.odoKm = liveData->decFromResponse(18, 24);
|
||||||
|
//if (tempFloat != liveData->params.odoKm) liveData->params.sdcardCanNotify = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VMCU 7E2
|
||||||
|
if (liveData->currentAtshRequest.equals("ATSH7E2")) {
|
||||||
|
/*if (liveData->commandRequest.equals("2101")) {
|
||||||
|
liveData->params.speedKmh = liveData->hexToDecFromResponse(32, 36, 2, false) * 0.0155; // / 100.0 *1.609 = real to gps is 1.750
|
||||||
|
if (liveData->params.speedKmh < -99 || liveData->params.speedKmh > 200)
|
||||||
|
liveData->params.speedKmh = 0;
|
||||||
|
}*/
|
||||||
|
if (liveData->commandRequest.equals("2102")) {
|
||||||
|
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
||||||
|
liveData->params.auxPerc = liveData->hexToDecFromResponse(50, 52, 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BMS 7e4
|
// BMS 7e4
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7E4")) {
|
if (liveData->currentAtshRequest.equals("ATSH7E4")) {
|
||||||
if (liveData->commandRequest.equals("220101")) {
|
if (liveData->commandRequest.equals("220101")) {
|
||||||
@@ -188,15 +212,15 @@ void CarKiaEniro::parseRowMerged() {
|
|||||||
liveData->params.availableChargePower = liveData->decFromResponse(16, 20) / 100.0;
|
liveData->params.availableChargePower = liveData->decFromResponse(16, 20) / 100.0;
|
||||||
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
||||||
//liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, true);
|
//liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, true);
|
||||||
liveData->params.batFanStatus = liveData->hexToDecFromResponse(60, 62, 2, true);
|
liveData->params.batFanStatus = liveData->hexToDecFromResponse(60, 62, 1, false);
|
||||||
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(62, 64, 2, true);
|
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(62, 64, 1, false);
|
||||||
liveData->params.auxVoltage = liveData->hexToDecFromResponse(64, 66, 2, true) / 10.0;
|
|
||||||
liveData->params.batPowerAmp = - liveData->hexToDecFromResponse(26, 30, 2, true) / 10.0;
|
liveData->params.batPowerAmp = - liveData->hexToDecFromResponse(26, 30, 2, true) / 10.0;
|
||||||
liveData->params.batVoltage = liveData->hexToDecFromResponse(30, 34, 2, false) / 10.0;
|
liveData->params.batVoltage = liveData->hexToDecFromResponse(30, 34, 2, false) / 10.0;
|
||||||
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
||||||
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
||||||
liveData->params.chargingStartTime = liveData->params.currentTime;
|
liveData->params.chargingStartTime = liveData->params.currentTime;
|
||||||
liveData->params.batPowerKwh100 = liveData->params.batPowerKw / liveData->params.speedKmh * 100;
|
liveData->params.batPowerKwh100 = liveData->params.batPowerKw / liveData->params.speedKmh * 100;
|
||||||
|
liveData->params.auxVoltage = liveData->hexToDecFromResponse(64, 66, 1, false) / 10.0;
|
||||||
liveData->params.batCellMaxV = liveData->hexToDecFromResponse(52, 54, 1, false) / 50.0;
|
liveData->params.batCellMaxV = liveData->hexToDecFromResponse(52, 54, 1, false) / 50.0;
|
||||||
liveData->params.batCellMinV = liveData->hexToDecFromResponse(56, 58, 1, false) / 50.0;
|
liveData->params.batCellMinV = liveData->hexToDecFromResponse(56, 58, 1, false) / 50.0;
|
||||||
liveData->params.batModuleTempC[0] = liveData->hexToDecFromResponse(38, 40, 1, true);
|
liveData->params.batModuleTempC[0] = liveData->hexToDecFromResponse(38, 40, 1, true);
|
||||||
@@ -208,6 +232,15 @@ void CarKiaEniro::parseRowMerged() {
|
|||||||
//liveData->params.batMaxC = liveData->hexToDecFromResponse(34, 36, 1, true);
|
//liveData->params.batMaxC = liveData->hexToDecFromResponse(34, 36, 1, true);
|
||||||
//liveData->params.batMinC = liveData->hexToDecFromResponse(36, 38, 1, true);
|
//liveData->params.batMinC = liveData->hexToDecFromResponse(36, 38, 1, true);
|
||||||
|
|
||||||
|
// Ignition Off/on
|
||||||
|
// tempByte = liveData->hexToDecFromResponse(106, 108, 1, false);
|
||||||
|
// liveData->params.chargingOn = (bitRead(tempByte, 2) == 1);
|
||||||
|
tempByte = liveData->hexToDecFromResponse(24, 26, 1, false);
|
||||||
|
liveData->params.chargingOn = (bitRead(tempByte, 5) == 1 || bitRead(tempByte, 6) == 1); // bit 5 = AC; bit 6 = DC
|
||||||
|
if(liveData->params.chargingOn) {
|
||||||
|
liveData->params.lastChargingOnTime = liveData->params.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
||||||
liveData->params.batMinC = liveData->params.batMaxC = liveData->params.batModuleTempC[0];
|
liveData->params.batMinC = liveData->params.batMaxC = liveData->params.batModuleTempC[0];
|
||||||
for (uint16_t i = 1; i < liveData->params.batModuleTempCount; i++) {
|
for (uint16_t i = 1; i < liveData->params.batModuleTempCount; i++) {
|
||||||
@@ -278,7 +311,7 @@ void CarKiaEniro::parseRowMerged() {
|
|||||||
}
|
}
|
||||||
// BMS 7e4
|
// BMS 7e4
|
||||||
if (liveData->commandRequest.equals("220106")) {
|
if (liveData->commandRequest.equals("220106")) {
|
||||||
liveData->params.coolingWaterTempC = liveData->hexToDecFromResponse(14, 16, 1, false);
|
liveData->params.coolingWaterTempC = liveData->hexToDecFromResponse(14, 16, 1, true);
|
||||||
liveData->params.bmsUnknownTempC = liveData->hexToDecFromResponse(18, 20, 1, true);
|
liveData->params.bmsUnknownTempC = liveData->hexToDecFromResponse(18, 20, 1, true);
|
||||||
liveData->params.bmsUnknownTempD = liveData->hexToDecFromResponse(46, 48, 1, true);
|
liveData->params.bmsUnknownTempD = liveData->hexToDecFromResponse(46, 48, 1, true);
|
||||||
// log 220106 to sdcard
|
// log 220106 to sdcard
|
||||||
@@ -286,25 +319,11 @@ void CarKiaEniro::parseRowMerged() {
|
|||||||
tmpStr.toCharArray(liveData->params.debugData2, tmpStr.length() + 1);
|
tmpStr.toCharArray(liveData->params.debugData2, tmpStr.length() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TPMS 7a0
|
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7A0")) {
|
|
||||||
if (liveData->commandRequest.equals("22c00b")) {
|
|
||||||
liveData->params.tireFrontLeftPressureBar = liveData->hexToDecFromResponse(14, 16, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireFrontRightPressureBar = liveData->hexToDecFromResponse(22, 24, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireRearRightPressureBar = liveData->hexToDecFromResponse(30, 32, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireRearLeftPressureBar = liveData->hexToDecFromResponse(38, 40, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireFrontLeftTempC = liveData->hexToDecFromResponse(16, 18, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireFrontRightTempC = liveData->hexToDecFromResponse(24, 26, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireRearRightTempC = liveData->hexToDecFromResponse(32, 34, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireRearLeftTempC = liveData->hexToDecFromResponse(40, 42, 2, false) - 50; // === OK Valid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loadTestData
|
loadTestData
|
||||||
*/
|
*/
|
||||||
void CarKiaEniro::loadTestData() {
|
void CarKiaEniro::loadTestData() {
|
||||||
|
|
||||||
// IGPM
|
// IGPM
|
||||||
@@ -454,5 +473,3 @@ void CarKiaEniro::loadTestData() {
|
|||||||
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CARKIAENIRO_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef CARKIAENIRO_H
|
#pragma once
|
||||||
#define CARKIAENIRO_H
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
|
|
||||||
@@ -12,5 +11,3 @@ class CarKiaEniro : public CarInterface {
|
|||||||
void parseRowMerged() override;
|
void parseRowMerged() override;
|
||||||
void loadTestData() override;
|
void loadTestData() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARKIAENIRO_H
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#ifndef CARKIANIROPHEV_CPP
|
|
||||||
#define CARKIANIROPHEV_CPP
|
|
||||||
|
|
||||||
#include "CarKiaNiroPhev.h"
|
#include "CarKiaNiroPhev.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define commandQueueCountKiaNiroPhev 25
|
|
||||||
#define commandQueueLoopFromKiaNiroPhev 8
|
#define commandQueueLoopFromKiaNiroPhev 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
void CarKiaNiroPhev::activateCommandQueue() {
|
void CarKiaNiroPhev::activateCommandQueue() {
|
||||||
|
|
||||||
String commandQueueKiaNiroPhev[commandQueueCountKiaNiroPhev] = {
|
std::vector<String> commandQueueKiaNiroPhev = {
|
||||||
"AT Z", // Reset all
|
"AT Z", // Reset all
|
||||||
"AT I", // Print the version ID
|
"AT I", // Print the version ID
|
||||||
"AT E0", // Echo off
|
"AT E0", // Echo off
|
||||||
@@ -67,15 +64,13 @@ void CarKiaNiroPhev::activateCommandQueue() {
|
|||||||
liveData->params.batModuleTempCount = 5;
|
liveData->params.batModuleTempCount = 5;
|
||||||
|
|
||||||
// Empty and fill command queue
|
// Empty and fill command queue
|
||||||
for (int i = 0; i < 300; i++) {
|
liveData->commandQueue.clear();
|
||||||
liveData->commandQueue[i] = "";
|
for (auto cmd : commandQueueKiaNiroPhev) {
|
||||||
}
|
liveData->commandQueue.push_back({ 0, cmd });
|
||||||
for (int i = 0; i < commandQueueCountKiaNiroPhev; i++) {
|
|
||||||
liveData->commandQueue[i] = commandQueueKiaNiroPhev[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
liveData->commandQueueLoopFrom = commandQueueLoopFromKiaNiroPhev;
|
liveData->commandQueueLoopFrom = commandQueueLoopFromKiaNiroPhev;
|
||||||
liveData->commandQueueCount = commandQueueCountKiaNiroPhev;
|
liveData->commandQueueCount = commandQueueKiaNiroPhev.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -376,5 +371,3 @@ void CarKiaNiroPhev::loadTestData() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //CARKIANIROPHEV_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef CARKIANIROPHEV_H
|
#pragma once
|
||||||
#define CARKIANIROPHEV_H
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
|
|
||||||
@@ -12,5 +11,3 @@ class CarKiaNiroPhev: public CarInterface {
|
|||||||
void parseRowMerged() override;
|
void parseRowMerged() override;
|
||||||
void loadTestData() override;
|
void loadTestData() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#ifndef CARRENAULTZOE_CPP
|
|
||||||
#define CARRENAULTZOE_CPP
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <WString.h>
|
#include <WString.h>
|
||||||
@@ -8,16 +5,16 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
#include "CarRenaultZoe.h"
|
#include "CarRenaultZoe.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define commandQueueCountRenaultZoe 18
|
#define commandQueueLoopFromRenaultZoe 8
|
||||||
#define commandQueueLoopFromRenaultZoe 11
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
activateCommandQueue
|
activateCommandQueue
|
||||||
*/
|
*/
|
||||||
void CarRenaultZoe::activateCommandQueue() {
|
void CarRenaultZoe::activateCommandQueue() {
|
||||||
|
|
||||||
String commandQueueRenaultZoe[commandQueueCountRenaultZoe] = {
|
std::vector<String> commandQueueRenaultZoe = {
|
||||||
"AT Z", // Reset all
|
"AT Z", // Reset all
|
||||||
"AT I", // Print the version ID
|
"AT I", // Print the version ID
|
||||||
"AT S0", // Printing of spaces on
|
"AT S0", // Printing of spaces on
|
||||||
@@ -32,36 +29,97 @@ void CarRenaultZoe::activateCommandQueue() {
|
|||||||
////"AT AT0", // disabled adaptive timing
|
////"AT AT0", // disabled adaptive timing
|
||||||
"AT DP",
|
"AT DP",
|
||||||
"AT ST16", // reduced timeout to 1, orig.16
|
"AT ST16", // reduced timeout to 1, orig.16
|
||||||
"atfcsd300010",
|
|
||||||
"atfcsm1", // Allow long messages
|
|
||||||
|
|
||||||
// Loop from (RENAULT ZOE)
|
// Loop from (RENAULT ZOE)
|
||||||
|
|
||||||
// LBC Lithium battery controller
|
// LBC Lithium battery controller
|
||||||
"ATSH79B",
|
"ATSH79B",
|
||||||
"ATFCSH79B",
|
"ATFCSH79B",
|
||||||
"2101",
|
"atfcsd300010",
|
||||||
"2103",
|
"atfcsm1",
|
||||||
"2104",
|
"221415",
|
||||||
"2141",
|
"2101", // 034 61011383138600000000000000000000000009970D620FC920D0000005420000000000000008D80500000B202927100000000000000000
|
||||||
"2142",
|
"2103", // 01D 6103018516A717240000000001850185000000FFFF07D00516E60000030000000000
|
||||||
"2161",
|
"2104", // 04D 6104099A37098D37098F3709903709AC3609BB3609A136098B37099737098A37098437099437FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF363637000000000000
|
||||||
|
"2141", // 07e 61410F360F380F380F360F380F380F380F380F390F390F3A0F390F3A0F390F390F380F380F390F380F380F380F390F390F380F380F3A0F390F380F380F380F390F390F350F380F360F380F380F380F380F360F380F360F350F380F360F380F360F360F350F360F360F380F380F380F3A0F380F3A0F3A0F390F390F380F36000000000000
|
||||||
|
"2142", // 04a 61420F3A0F390F390F390F380F380F390F390F390F390F360F360F380F380F360F380F360F380F390F390F3A0F390F390F3A0F3A0F3A0F380F390F390F3A0F390F390F380F38922091F20000
|
||||||
|
"2161", // 014 6161000AA820C8C8C8C2C20001545800004696FF
|
||||||
|
|
||||||
|
// CLUSTER Instrument panel
|
||||||
|
"ATSH743",
|
||||||
|
"ATFCSH743",
|
||||||
|
"atfcsd300010",
|
||||||
|
"atfcsm1",
|
||||||
|
// "220201", // 62020175300168
|
||||||
|
// "220202", // 62020274710123
|
||||||
|
// "220203"- "220205", // 7F2212
|
||||||
|
"220206", // 62020600015459
|
||||||
|
//"222204", // temp ext.
|
||||||
|
|
||||||
|
// BCB 793 Battery Connection Box
|
||||||
|
// "ATSH792",
|
||||||
|
// "ATFCSH792",
|
||||||
|
// "atfcsd300010",
|
||||||
|
// "atfcsm1",
|
||||||
|
// "223101", to "223114", // all with negative 7F2212*/
|
||||||
|
|
||||||
|
// CLIM 764 CLIMATE CONTROL
|
||||||
|
"ATSH744",
|
||||||
|
"ATFCSH744",
|
||||||
|
"atfcsd300010",
|
||||||
|
"atfcsm1",
|
||||||
|
"2143",
|
||||||
|
// "2180", // NO DATA
|
||||||
|
// "2181", // NO DATA
|
||||||
|
//"2182", // 618038303139520430343239353031520602051523080201008815
|
||||||
|
// "2125", // 6125000000000000000000000000000000000000
|
||||||
|
// "2126", // NO DATA
|
||||||
|
// "2128", // NO DATA
|
||||||
|
|
||||||
|
// EVC 7ec El vehicle controler
|
||||||
|
"ATSH7E4",
|
||||||
|
"ATFCSH7E4",
|
||||||
|
"atfcsd300010",
|
||||||
|
"atfcsm1",
|
||||||
|
// "222001", // 62200136
|
||||||
|
// "222002", // 6220020B3D
|
||||||
|
"222003", // 6220030000
|
||||||
|
// "222004", // 62200402ED
|
||||||
|
// "222005", // 6220050532
|
||||||
|
// "222006", // 622006015459
|
||||||
|
|
||||||
|
// PEB 77e Power Electronics Bloc
|
||||||
|
// "ATSH75A",
|
||||||
|
// "ATFCSH75A",
|
||||||
|
// "atfcsd300010",
|
||||||
|
// "atfcsm1",
|
||||||
|
// "223009", // 6230093640
|
||||||
|
|
||||||
|
// UBP 7bc Uncoupled Braking Pedal
|
||||||
|
// "ATSH79C",
|
||||||
|
// "ATFCSH79C",
|
||||||
|
// "atfcsd300010",
|
||||||
|
// "atfcsm1",
|
||||||
|
// "21F0", // 61F0303235315204303337333733325215160C0400000101008800
|
||||||
|
// "21F1", // 61F10000000000F000000000F0000000000012061400005C91F600
|
||||||
|
// "21FE", // 61FE333731325204303337333733325215160C0400010201008800
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
liveData->params.batModuleTempCount = 12; // 24, 12 is display limit
|
liveData->params.batModuleTempCount = 12; // 24, 12 is display limit
|
||||||
liveData->params.batteryTotalAvailableKWh = 28;
|
liveData->params.batteryTotalAvailableKWh = 22;
|
||||||
|
// usable 22, total 26
|
||||||
|
|
||||||
|
|
||||||
// Empty and fill command queue
|
// Empty and fill command queue
|
||||||
for (int i = 0; i < 300; i++) {
|
liveData->commandQueue.clear();
|
||||||
liveData->commandQueue[i] = "";
|
for (auto cmd : commandQueueRenaultZoe) {
|
||||||
}
|
liveData->commandQueue.push_back({ 0, cmd });
|
||||||
for (int i = 0; i < commandQueueCountRenaultZoe; i++) {
|
|
||||||
liveData->commandQueue[i] = commandQueueRenaultZoe[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
liveData->commandQueueLoopFrom = commandQueueLoopFromRenaultZoe;
|
liveData->commandQueueLoopFrom = commandQueueLoopFromRenaultZoe;
|
||||||
liveData->commandQueueCount = commandQueueCountRenaultZoe;
|
liveData->commandQueueCount = commandQueueRenaultZoe.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,13 +127,19 @@ void CarRenaultZoe::activateCommandQueue() {
|
|||||||
*/
|
*/
|
||||||
void CarRenaultZoe::parseRowMerged() {
|
void CarRenaultZoe::parseRowMerged() {
|
||||||
|
|
||||||
bool tempByte;
|
uint8_t tempByte;
|
||||||
|
|
||||||
// LBC 79B
|
// LBC 79B
|
||||||
if (liveData->currentAtshRequest.equals("ATSH79B")) {
|
if (liveData->currentAtshRequest.equals("ATSH79B")) {
|
||||||
|
if (liveData->commandRequest.equals("221415")) {
|
||||||
|
liveData->params.batVoltage = liveData->hexToDecFromResponse(6, 8, 2, false);
|
||||||
|
}
|
||||||
if (liveData->commandRequest.equals("2101")) {
|
if (liveData->commandRequest.equals("2101")) {
|
||||||
liveData->params.batPowerAmp = liveData->hexToDecFromResponse(4, 8, 2, false) - 5000;
|
liveData->params.batPowerAmp = liveData->hexToDecFromResponse(4, 8, 2, false) - 5000;
|
||||||
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
liveData->params.batPowerKw = (liveData->params.batPowerAmp * liveData->params.batVoltage) / 1000.0;
|
||||||
|
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
||||||
|
liveData->params.chargingStartTime = liveData->params.currentTime;
|
||||||
|
liveData->params.batPowerKwh100 = liveData->params.batPowerKw / liveData->params.speedKmh * 100;
|
||||||
liveData->params.auxVoltage = liveData->hexToDecFromResponse(56, 60, 2, false) / 100.0;
|
liveData->params.auxVoltage = liveData->hexToDecFromResponse(56, 60, 2, false) / 100.0;
|
||||||
liveData->params.availableChargePower = liveData->hexToDecFromResponse(84, 88, 2, false) / 100.0;
|
liveData->params.availableChargePower = liveData->hexToDecFromResponse(84, 88, 2, false) / 100.0;
|
||||||
liveData->params.batCellMinV = liveData->hexToDecFromResponse(24, 28, 2, false) / 100.0;
|
liveData->params.batCellMinV = liveData->hexToDecFromResponse(24, 28, 2, false) / 100.0;
|
||||||
@@ -92,6 +156,14 @@ void CarRenaultZoe::parseRowMerged() {
|
|||||||
for (uint16_t i = 12; i < 24; i++) {
|
for (uint16_t i = 12; i < 24; i++) {
|
||||||
liveData->params.batModuleTempC[i] = liveData->hexToDecFromResponse(80 + ((i - 12) * 6), 82 + ((i - 12) * 6), 1, false) - 40;
|
liveData->params.batModuleTempC[i] = liveData->hexToDecFromResponse(80 + ((i - 12) * 6), 82 + ((i - 12) * 6), 1, false) - 40;
|
||||||
}
|
}
|
||||||
|
liveData->params.batMinC = liveData->params.batMaxC = liveData->params.batModuleTempC[0];
|
||||||
|
for (uint16_t i = 1; i < 24; i++) {
|
||||||
|
if (liveData->params.batModuleTempC[i] < liveData->params.batMinC)
|
||||||
|
liveData->params.batMinC = liveData->params.batModuleTempC[i];
|
||||||
|
if (liveData->params.batModuleTempC[i] > liveData->params.batMaxC)
|
||||||
|
liveData->params.batMaxC = liveData->params.batModuleTempC[i];
|
||||||
|
}
|
||||||
|
liveData->params.batTempC = liveData->params.batMinC;
|
||||||
}
|
}
|
||||||
if (liveData->commandRequest.equals("2141")) {
|
if (liveData->commandRequest.equals("2141")) {
|
||||||
for (int i = 0; i < 62; i++) {
|
for (int i = 0; i < 62; i++) {
|
||||||
@@ -108,178 +180,99 @@ void CarRenaultZoe::parseRowMerged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CLUSTER 743
|
||||||
/* niro
|
if (liveData->currentAtshRequest.equals("ATSH743")) {
|
||||||
// ABS / ESP + AHB 7D1
|
if (liveData->commandRequest.equals("220206")) {
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7D1")) {
|
liveData->params.odoKm = liveData->hexToDecFromResponse(6, 14, 4, false);
|
||||||
if (liveData->commandRequest.equals("22C101")) {
|
|
||||||
uint8_t driveMode = liveData->hexToDecFromResponse(22, 24, 1, false);
|
|
||||||
liveData->params.forwardDriveMode = (driveMode == 4);
|
|
||||||
liveData->params.reverseDriveMode = (driveMode == 2);
|
|
||||||
liveData->params.parkModeOrNeutral = (driveMode == 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IGPM
|
// CLUSTER ATSH7E4
|
||||||
if (liveData->currentAtshRequest.equals("ATSH770")) {
|
if (liveData->currentAtshRequest.equals("ATSH7E4")) {
|
||||||
if (liveData->commandRequest.equals("22BC03")) {
|
if (liveData->commandRequest.equals("222003")) {
|
||||||
tempByte = liveData->hexToDecFromResponse(16, 18, 1, false);
|
liveData->params.speedKmh = liveData->hexToDecFromResponse(6, 8, 2, false) / 100;
|
||||||
liveData->params.ignitionOnPrevious = liveData->params.ignitionOn;
|
if (liveData->params.speedKmh < -99 || liveData->params.speedKmh > 200)
|
||||||
liveData->params.ignitionOn = (bitRead(tempByte, 5) == 1);
|
liveData->params.speedKmh = 0;
|
||||||
if (liveData->params.ignitionOnPrevious && !liveData->params.ignitionOn)
|
|
||||||
liveData->params.automaticShutdownTimer = liveData->params.currentTime;
|
|
||||||
|
|
||||||
liveData->params.lightInfo = liveData->hexToDecFromResponse(18, 20, 1, false);
|
|
||||||
liveData->params.headLights = (bitRead(liveData->params.lightInfo, 5) == 1);
|
|
||||||
liveData->params.dayLights = (bitRead(liveData->params.lightInfo, 3) == 1);
|
|
||||||
}
|
|
||||||
if (liveData->commandRequest.equals("22BC06")) {
|
|
||||||
liveData->params.brakeLightInfo = liveData->hexToDecFromResponse(14, 16, 1, false);
|
|
||||||
liveData->params.brakeLights = (bitRead(liveData->params.brakeLightInfo, 5) == 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VMCU 7E2
|
// CLIM 744 CLIMATE CONTROL
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7E2")) {
|
if (liveData->currentAtshRequest.equals("ATSH744")) {
|
||||||
if (liveData->commandRequest.equals("2101")) {
|
if (liveData->commandRequest.equals("2143")) {
|
||||||
liveData->params.speedKmh = liveData->hexToDecFromResponse(32, 36, 2, false) * 0.0155; // / 100.0 *1.609 = real to gps is 1.750
|
liveData->params.outdoorTemperature = (liveData->hexToDecFromResponse(26, 28, 1, false)) - 40;
|
||||||
if (liveData->params.speedKmh < -99 || liveData->params.speedKmh > 200)
|
//liveData->params.indoorTemperature = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
||||||
liveData->params.speedKmh = 0;
|
//liveData->params.coolantTemp1C = (liveData->hexToDecFromResponse(14, 16, 1, false) / 2) - 40;
|
||||||
}
|
//liveData->params.coolantTemp2C = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
||||||
if (liveData->commandRequest.equals("2102")) {
|
|
||||||
liveData->params.auxPerc = liveData->hexToDecFromResponse(50, 52, 1, false);
|
|
||||||
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cluster module 7c6
|
/*uint8_t driveMode = liveData->hexToDecFromResponse(22, 24, 1, false);
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7C6")) {
|
liveData->params.forwardDriveMode = (driveMode == 4);
|
||||||
if (liveData->commandRequest.equals("22B002")) {
|
liveData->params.reverseDriveMode = (driveMode == 2);
|
||||||
liveData->params.odoKm = liveData->decFromResponse(18, 24);
|
liveData->params.parkModeOrNeutral = (driveMode == 1);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aircon 7b3
|
// IGPM
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7B3")) {
|
tempByte = liveData->hexToDecFromResponse(16, 18, 1, false);
|
||||||
if (liveData->commandRequest.equals("220100")) {
|
liveData->params.ignitionOnPrevious = liveData->params.ignitionOn;
|
||||||
liveData->params.indoorTemperature = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
liveData->params.ignitionOn = (bitRead(tempByte, 5) == 1);
|
||||||
liveData->params.outdoorTemperature = (liveData->hexToDecFromResponse(18, 20, 1, false) / 2) - 40;
|
if (liveData->params.ignitionOnPrevious && !liveData->params.ignitionOn)
|
||||||
}
|
liveData->params.automaticShutdownTimer = liveData->params.currentTime;
|
||||||
if (liveData->commandRequest.equals("220102") && liveData->responseRowMerged.substring(12, 14) == "00") {
|
liveData->params.lightInfo = liveData->hexToDecFromResponse(18, 20, 1, false);
|
||||||
liveData->params.coolantTemp1C = (liveData->hexToDecFromResponse(14, 16, 1, false) / 2) - 40;
|
liveData->params.headLights = (bitRead(liveData->params.lightInfo, 5) == 1);
|
||||||
liveData->params.coolantTemp2C = (liveData->hexToDecFromResponse(16, 18, 1, false) / 2) - 40;
|
liveData->params.dayLights = (bitRead(liveData->params.lightInfo, 3) == 1);
|
||||||
}
|
liveData->params.brakeLightInfo = liveData->hexToDecFromResponse(14, 16, 1, false);
|
||||||
}
|
liveData->params.brakeLights = (bitRead(liveData->params.brakeLightInfo, 5) == 1);
|
||||||
|
liveData->params.auxPerc = liveData->hexToDecFromResponse(50, 52, 1, false);
|
||||||
|
liveData->params.auxCurrentAmp = - liveData->hexToDecFromResponse(46, 50, 2, true) / 1000.0;
|
||||||
|
liveData->params.cumulativeEnergyChargedKWh = liveData->decFromResponse(82, 90) / 10.0;
|
||||||
|
if (liveData->params.cumulativeEnergyChargedKWhStart == -1)
|
||||||
|
liveData->params.cumulativeEnergyChargedKWhStart = liveData->params.cumulativeEnergyChargedKWh;
|
||||||
|
liveData->params.cumulativeEnergyDischargedKWh = liveData->decFromResponse(90, 98) / 10.0;
|
||||||
|
if (liveData->params.cumulativeEnergyDischargedKWhStart == -1)
|
||||||
|
liveData->params.cumulativeEnergyDischargedKWhStart = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
|
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
||||||
|
//liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, true);
|
||||||
|
liveData->params.batFanStatus = liveData->hexToDecFromResponse(60, 62, 2, true);
|
||||||
|
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(62, 64, 2, true);
|
||||||
|
liveData->params.motorRpm = liveData->hexToDecFromResponse(112, 116, 2, false);
|
||||||
|
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
||||||
|
liveData->params.batInletC = liveData->hexToDecFromResponse(50, 52, 1, true);
|
||||||
|
liveData->params.bmsUnknownTempA = liveData->hexToDecFromResponse(30, 32, 1, true);
|
||||||
|
liveData->params.batHeaterC = liveData->hexToDecFromResponse(52, 54, 1, true);
|
||||||
|
liveData->params.bmsUnknownTempB = liveData->hexToDecFromResponse(82, 84, 1, true);
|
||||||
|
liveData->params.coolingWaterTempC = liveData->hexToDecFromResponse(14, 16, 1, false);
|
||||||
|
liveData->params.bmsUnknownTempC = liveData->hexToDecFromResponse(18, 20, 1, true);
|
||||||
|
liveData->params.bmsUnknownTempD = liveData->hexToDecFromResponse(46, 48, 1, true);
|
||||||
|
liveData->params.tireFrontLeftPressureBar = liveData->hexToDecFromResponse(14, 16, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
|
liveData->params.tireFrontRightPressureBar = liveData->hexToDecFromResponse(22, 24, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
|
liveData->params.tireRearRightPressureBar = liveData->hexToDecFromResponse(30, 32, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
|
liveData->params.tireRearLeftPressureBar = liveData->hexToDecFromResponse(38, 40, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
||||||
|
liveData->params.tireFrontLeftTempC = liveData->hexToDecFromResponse(16, 18, 2, false) - 50; // === OK Valid
|
||||||
|
liveData->params.tireFrontRightTempC = liveData->hexToDecFromResponse(24, 26, 2, false) - 50; // === OK Valid
|
||||||
|
liveData->params.tireRearRightTempC = liveData->hexToDecFromResponse(32, 34, 2, false) - 50; // === OK Valid
|
||||||
|
liveData->params.tireRearLeftTempC = liveData->hexToDecFromResponse(40, 42, 2, false) - 50; // === OK Valid
|
||||||
|
|
||||||
// BMS 7e4
|
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7E4")) {
|
if ( liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw < liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)])
|
||||||
if (liveData->commandRequest.equals("220101")) {
|
liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
||||||
liveData->params.cumulativeEnergyChargedKWh = liveData->decFromResponse(82, 90) / 10.0;
|
if ( liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw > liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)])
|
||||||
if (liveData->params.cumulativeEnergyChargedKWhStart == -1)
|
liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
||||||
liveData->params.cumulativeEnergyChargedKWhStart = liveData->params.cumulativeEnergyChargedKWh;
|
liveData->params.chargingGraphBatMinTempC[int(liveData->params.socPerc)] = liveData->params.batMinC;
|
||||||
liveData->params.cumulativeEnergyDischargedKWh = liveData->decFromResponse(90, 98) / 10.0;
|
liveData->params.chargingGraphBatMaxTempC[int(liveData->params.socPerc)] = liveData->params.batMaxC;
|
||||||
if (liveData->params.cumulativeEnergyDischargedKWhStart == -1)
|
liveData->params.chargingGraphHeaterTempC[int(liveData->params.socPerc)] = liveData->params.batHeaterC;
|
||||||
liveData->params.cumulativeEnergyDischargedKWhStart = liveData->params.cumulativeEnergyDischargedKWh;
|
liveData->params.chargingGraphWaterCoolantTempC[int(liveData->params.socPerc)] = liveData->params.coolingWaterTempC;
|
||||||
liveData->params.availableDischargePower = liveData->decFromResponse(20, 24) / 100.0;
|
}
|
||||||
//liveData->params.isolationResistanceKOhm = liveData->hexToDecFromResponse(118, 122, 2, true);
|
}
|
||||||
liveData->params.batFanStatus = liveData->hexToDecFromResponse(60, 62, 2, true);
|
// BMS 7e4
|
||||||
liveData->params.batFanFeedbackHz = liveData->hexToDecFromResponse(62, 64, 2, true);
|
if (liveData->params.socPercPrevious - liveData->params.socPerc > 0) {
|
||||||
liveData->params.auxVoltage = liveData->hexToDecFromResponse(64, 66, 2, true) / 10.0;
|
byte index = (int(liveData->params.socPerc) == 4) ? 0 : (int)(liveData->params.socPerc / 10) + 1;
|
||||||
liveData->params.batVoltage = liveData->hexToDecFromResponse(30, 34, 2, false) / 10.0;
|
if ((int(liveData->params.socPerc) % 10 == 9 || int(liveData->params.socPerc) == 4) && liveData->params.soc10ced[index] == -1) {
|
||||||
if (liveData->params.batPowerKw < 0) // Reset charging start time
|
liveData->params.soc10ced[index] = liveData->params.cumulativeEnergyDischargedKWh;
|
||||||
liveData->params.chargingStartTime = liveData->params.currentTime;
|
liveData->params.soc10cec[index] = liveData->params.cumulativeEnergyChargedKWh;
|
||||||
liveData->params.batPowerKwh100 = liveData->params.batPowerKw / liveData->params.speedKmh * 100;
|
liveData->params.soc10odo[index] = liveData->params.odoKm;
|
||||||
liveData->params.batModuleTempC[0] = liveData->hexToDecFromResponse(38, 40, 1, true);
|
liveData->params.soc10time[index] = liveData->params.currentTime;
|
||||||
liveData->params.batModuleTempC[1] = liveData->hexToDecFromResponse(40, 42, 1, true);
|
}
|
||||||
liveData->params.batModuleTempC[2] = liveData->hexToDecFromResponse(42, 44, 1, true);
|
}
|
||||||
liveData->params.batModuleTempC[3] = liveData->hexToDecFromResponse(44, 46, 1, true);
|
|
||||||
liveData->params.motorRpm = liveData->hexToDecFromResponse(112, 116, 2, false);
|
|
||||||
|
|
||||||
// This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging)
|
|
||||||
liveData->params.batMinC = liveData->params.batMaxC = liveData->params.batModuleTempC[0];
|
|
||||||
for (uint16_t i = 1; i < liveData->params.batModuleTempCount; i++) {
|
|
||||||
if (liveData->params.batModuleTempC[i] < liveData->params.batMinC)
|
|
||||||
liveData->params.batMinC = liveData->params.batModuleTempC[i];
|
|
||||||
if (liveData->params.batModuleTempC[i] > liveData->params.batMaxC)
|
|
||||||
liveData->params.batMaxC = liveData->params.batModuleTempC[i];
|
|
||||||
}
|
|
||||||
liveData->params.batTempC = liveData->params.batMinC;
|
|
||||||
|
|
||||||
liveData->params.batInletC = liveData->hexToDecFromResponse(50, 52, 1, true);
|
|
||||||
if (liveData->params.speedKmh < 10 && liveData->params.batPowerKw >= 1 && liveData->params.socPerc > 0 && liveData->params.socPerc <= 100) {
|
|
||||||
if ( liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw < liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)])
|
|
||||||
liveData->params.chargingGraphMinKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
|
||||||
if ( liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] < 0 || liveData->params.batPowerKw > liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)])
|
|
||||||
liveData->params.chargingGraphMaxKw[int(liveData->params.socPerc)] = liveData->params.batPowerKw;
|
|
||||||
liveData->params.chargingGraphBatMinTempC[int(liveData->params.socPerc)] = liveData->params.batMinC;
|
|
||||||
liveData->params.chargingGraphBatMaxTempC[int(liveData->params.socPerc)] = liveData->params.batMaxC;
|
|
||||||
liveData->params.chargingGraphHeaterTempC[int(liveData->params.socPerc)] = liveData->params.batHeaterC;
|
|
||||||
liveData->params.chargingGraphWaterCoolantTempC[int(liveData->params.socPerc)] = liveData->params.coolingWaterTempC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BMS 7e4
|
|
||||||
if (liveData->commandRequest.equals("220102") && liveData->responseRowMerged.substring(12, 14) == "FF") {
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
liveData->params.cellVoltage[i] = liveData->hexToDecFromResponse(14 + (i * 2), 14 + (i * 2) + 2, 1, false) / 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BMS 7e4
|
|
||||||
if (liveData->commandRequest.equals("220103")) {
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
liveData->params.cellVoltage[32 + i] = liveData->hexToDecFromResponse(14 + (i * 2), 14 + (i * 2) + 2, 1, false) / 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BMS 7e4
|
|
||||||
if (liveData->commandRequest.equals("220104")) {
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
liveData->params.cellVoltage[64 + i] = liveData->hexToDecFromResponse(14 + (i * 2), 14 + (i * 2) + 2, 1, false) / 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BMS 7e4
|
|
||||||
if (liveData->commandRequest.equals("220105")) {
|
|
||||||
liveData->params.socPercPrevious = liveData->params.socPerc;
|
|
||||||
liveData->params.sohPerc = liveData->hexToDecFromResponse(56, 60, 2, false) / 10.0;
|
|
||||||
liveData->params.socPerc = liveData->hexToDecFromResponse(68, 70, 1, false) / 2.0;
|
|
||||||
|
|
||||||
// Soc10ced table, record x0% CEC/CED table (ex. 90%->89%, 80%->79%)
|
|
||||||
if (liveData->params.socPercPrevious - liveData->params.socPerc > 0) {
|
|
||||||
byte index = (int(liveData->params.socPerc) == 4) ? 0 : (int)(liveData->params.socPerc / 10) + 1;
|
|
||||||
if ((int(liveData->params.socPerc) % 10 == 9 || int(liveData->params.socPerc) == 4) && liveData->params.soc10ced[index] == -1) {
|
|
||||||
liveData->params.soc10ced[index] = liveData->params.cumulativeEnergyDischargedKWh;
|
|
||||||
liveData->params.soc10cec[index] = liveData->params.cumulativeEnergyChargedKWh;
|
|
||||||
liveData->params.soc10odo[index] = liveData->params.odoKm;
|
|
||||||
liveData->params.soc10time[index] = liveData->params.currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
liveData->params.bmsUnknownTempA = liveData->hexToDecFromResponse(30, 32, 1, true);
|
|
||||||
liveData->params.batHeaterC = liveData->hexToDecFromResponse(52, 54, 1, true);
|
|
||||||
liveData->params.bmsUnknownTempB = liveData->hexToDecFromResponse(82, 84, 1, true);
|
|
||||||
//
|
|
||||||
for (int i = 30; i < 32; i++) { // ai/aj position
|
|
||||||
liveData->params.cellVoltage[96 - 30 + i] = liveData->hexToDecFromResponse(14 + (i * 2), 14 + (i * 2) + 2, 1, false) / 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BMS 7e4
|
|
||||||
if (liveData->commandRequest.equals("220106")) {
|
|
||||||
liveData->params.coolingWaterTempC = liveData->hexToDecFromResponse(14, 16, 1, false);
|
|
||||||
liveData->params.bmsUnknownTempC = liveData->hexToDecFromResponse(18, 20, 1, true);
|
|
||||||
liveData->params.bmsUnknownTempD = liveData->hexToDecFromResponse(46, 48, 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TPMS 7a0
|
|
||||||
if (liveData->currentAtshRequest.equals("ATSH7A0")) {
|
|
||||||
if (liveData->commandRequest.equals("22c00b")) {
|
|
||||||
liveData->params.tireFrontLeftPressureBar = liveData->hexToDecFromResponse(14, 16, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireFrontRightPressureBar = liveData->hexToDecFromResponse(22, 24, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireRearRightPressureBar = liveData->hexToDecFromResponse(30, 32, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireRearLeftPressureBar = liveData->hexToDecFromResponse(38, 40, 2, false) / 72.51886900361; // === OK Valid *0.2 / 14.503773800722
|
|
||||||
liveData->params.tireFrontLeftTempC = liveData->hexToDecFromResponse(16, 18, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireFrontRightTempC = liveData->hexToDecFromResponse(24, 26, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireRearRightTempC = liveData->hexToDecFromResponse(32, 34, 2, false) - 50; // === OK Valid
|
|
||||||
liveData->params.tireRearLeftTempC = liveData->hexToDecFromResponse(40, 42, 2, false) - 50; // === OK Valid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +302,11 @@ void CarRenaultZoe::loadTestData() {
|
|||||||
liveData->responseRowMerged = "6161000AA820C8C8C8C2C2000153B400004669FF";
|
liveData->responseRowMerged = "6161000AA820C8C8C8C2C2000153B400004669FF";
|
||||||
parseRowMerged();
|
parseRowMerged();
|
||||||
|
|
||||||
|
// CLUSTER 743
|
||||||
|
liveData->currentAtshRequest = "ATSH743";
|
||||||
|
liveData->commandRequest = "220206";
|
||||||
|
liveData->responseRowMerged = "62020600015459";
|
||||||
|
parseRowMerged();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
niro
|
niro
|
||||||
@@ -459,5 +457,3 @@ void CarRenaultZoe::loadTestData() {
|
|||||||
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
liveData->params.soc10time[0] = liveData->params.soc10time[1] + 900;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CARRENAULTZOE_CPP
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef CARRENAULTZOE_H
|
#pragma once
|
||||||
#define CARRENAULTZOE_H
|
|
||||||
|
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
|
|
||||||
@@ -12,5 +11,3 @@ class CarRenaultZoe : public CarInterface {
|
|||||||
void parseRowMerged() override;
|
void parseRowMerged() override;
|
||||||
void loadTestData() override;
|
void loadTestData() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARRENAULTZOE_H
|
|
||||||
|
|||||||
@@ -1,13 +1,88 @@
|
|||||||
#ifndef COMMINTERFACE_CPP
|
|
||||||
#define COMMINTERFACE_CPP
|
|
||||||
|
|
||||||
#include "CommInterface.h"
|
#include "CommInterface.h"
|
||||||
//#include "BoardInterface.h"
|
#include "BoardInterface.h"
|
||||||
|
//#include "CarInterface.h"
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
|
|
||||||
void CommInterface::initComm(LiveData* pLiveData/*, BoardInterface* pBoard*/) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void CommInterface::initComm(LiveData* pLiveData, BoardInterface* pBoard) {
|
||||||
|
|
||||||
liveData = pLiveData;
|
liveData = pLiveData;
|
||||||
//board = pBoard;
|
board = pBoard;
|
||||||
|
response = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMMINTERFACE_CPP
|
/**
|
||||||
|
* Main loop
|
||||||
|
*/
|
||||||
|
void CommInterface::mainLoop() {
|
||||||
|
|
||||||
|
// Send command from TTY to OBD2
|
||||||
|
if (syslog->available()) {
|
||||||
|
ch = syslog->read();
|
||||||
|
if (ch == '\r' || ch == '\n') {
|
||||||
|
board->customConsoleCommand(response);
|
||||||
|
response = response + ch;
|
||||||
|
syslog->info(DEBUG_COMM, response);
|
||||||
|
executeCommand(response);
|
||||||
|
response = "";
|
||||||
|
} else {
|
||||||
|
response = response + ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop ChargingOn when status was not updated for more than 10 seconds
|
||||||
|
if(liveData->params.currentTime - liveData->params.lastChargingOnTime > 10 && liveData->params.chargingOn) {
|
||||||
|
liveData->params.chargingOn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can send next command from queue to OBD
|
||||||
|
if (liveData->canSendNextAtCommand) {
|
||||||
|
liveData->canSendNextAtCommand = false;
|
||||||
|
doNextQueueCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Do next AT command from queue
|
||||||
|
*/
|
||||||
|
bool CommInterface::doNextQueueCommand() {
|
||||||
|
|
||||||
|
// Restart loop with AT commands
|
||||||
|
if (liveData->commandQueueIndex >= liveData->commandQueueCount) {
|
||||||
|
liveData->commandQueueIndex = liveData->commandQueueLoopFrom;
|
||||||
|
board->redrawScreen();
|
||||||
|
|
||||||
|
// log every queue loop (temp) TODO and seconds interval
|
||||||
|
liveData->params.sdcardCanNotify = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send AT command to obd
|
||||||
|
liveData->commandRequest = liveData->commandQueue[liveData->commandQueueIndex].request;
|
||||||
|
liveData->commandStartChar = liveData->commandQueue[liveData->commandQueueIndex].startChar; // TODO: add to struct?
|
||||||
|
|
||||||
|
if (liveData->commandRequest.startsWith("ATSH")) {
|
||||||
|
liveData->currentAtshRequest = liveData->commandRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->infoNolf(DEBUG_COMM, ">>> ");
|
||||||
|
syslog->info(DEBUG_COMM, liveData->commandRequest);
|
||||||
|
liveData->responseRowMerged = "";
|
||||||
|
executeCommand(liveData->commandRequest);
|
||||||
|
liveData->commandQueueIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Parse result from OBD, merge frames to sigle response
|
||||||
|
*/
|
||||||
|
bool CommInterface::parseResponse() {
|
||||||
|
|
||||||
|
// 1 frame data
|
||||||
|
syslog->info(DEBUG_COMM, liveData->responseRow);
|
||||||
|
|
||||||
|
// Merge frames 0:xxxx 1:yyyy 2:zzzz to single response xxxxyyyyzzzz string
|
||||||
|
if (liveData->responseRow.length() >= 2 && liveData->responseRow.charAt(1) == ':') {
|
||||||
|
liveData->responseRowMerged += liveData->responseRow.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
#ifndef COMMINTERFACE_H
|
#pragma once
|
||||||
#define COMMINTERFACE_H
|
|
||||||
|
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
//#include "BoardInterface.h"
|
//#include "BoardInterface.h"
|
||||||
|
|
||||||
|
class BoardInterface; // Forward declaration
|
||||||
|
|
||||||
class CommInterface {
|
class CommInterface {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LiveData* liveData;
|
LiveData* liveData;
|
||||||
//BoardInterface* board;
|
BoardInterface* board;
|
||||||
|
char ch;
|
||||||
|
String response;
|
||||||
|
time_t lastDataSent;
|
||||||
public:
|
public:
|
||||||
void initComm(LiveData* pLiveData/*, BoardInterface* pBoard**/);
|
void initComm(LiveData* pLiveData, BoardInterface* pBoard);
|
||||||
virtual void connectDevice() = 0;
|
virtual void connectDevice() = 0;
|
||||||
virtual void disconnectDevice() = 0;
|
virtual void disconnectDevice() = 0;
|
||||||
virtual void scanDevices() = 0;
|
virtual void scanDevices() = 0;
|
||||||
|
virtual void mainLoop();
|
||||||
|
virtual void executeCommand(String cmd) = 0;
|
||||||
|
//
|
||||||
|
bool doNextQueueCommand();
|
||||||
|
bool parseResponse();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMMINTERFACE_H
|
|
||||||
|
|||||||
357
CommObd2Ble4.cpp
357
CommObd2Ble4.cpp
@@ -1,29 +1,360 @@
|
|||||||
#ifndef COMMOBD2BLE4_CPP
|
|
||||||
#define COMMOBD2BLE4_CPP
|
|
||||||
|
|
||||||
#include <BLEDevice.h>
|
#include <BLEDevice.h>
|
||||||
#include "CommObd2Ble4.h"
|
#include "CommObd2Ble4.h"
|
||||||
|
#include "BoardInterface.h"
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
|
|
||||||
|
CommObd2Ble4* commObj;
|
||||||
|
BoardInterface* boardObj;
|
||||||
|
LiveData* liveDataObj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect ble4 adapter
|
BLE callbacks
|
||||||
*/
|
*/
|
||||||
|
class MyClientCallback : public BLEClientCallbacks {
|
||||||
|
|
||||||
|
// On BLE connect
|
||||||
|
void onConnect(BLEClient* pclient) {
|
||||||
|
syslog->println("onConnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
// On BLE disconnect
|
||||||
|
void onDisconnect(BLEClient* pclient) {
|
||||||
|
liveDataObj->commConnected = false;
|
||||||
|
syslog->println("onDisconnect");
|
||||||
|
|
||||||
|
boardObj->displayMessage("BLE disconnected", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Scan for BLE servers and find the first one that advertises the service we are looking for.
|
||||||
|
*/
|
||||||
|
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||||
|
|
||||||
|
// Called for each advertising BLE server.
|
||||||
|
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||||
|
|
||||||
|
syslog->print("BLE advertised device found: ");
|
||||||
|
syslog->println(advertisedDevice.toString().c_str());
|
||||||
|
syslog->println(advertisedDevice.getAddress().toString().c_str());
|
||||||
|
|
||||||
|
// Add to device list (max. 9 devices allowed yet)
|
||||||
|
String tmpStr;
|
||||||
|
|
||||||
|
if (liveDataObj->scanningDeviceIndex < 10) { // && advertisedDevice.haveServiceUUID()
|
||||||
|
for (uint16_t i = 0; i < liveDataObj->menuItemsCount; ++i) {
|
||||||
|
if (liveDataObj->menuItems[i].id == 10001 + liveDataObj->scanningDeviceIndex) {
|
||||||
|
tmpStr = advertisedDevice.toString().c_str();
|
||||||
|
tmpStr.replace("Name: ", "");
|
||||||
|
tmpStr.replace("Address: ", "");
|
||||||
|
tmpStr.toCharArray(liveDataObj->menuItems[i].title, 48);
|
||||||
|
tmpStr = advertisedDevice.getAddress().toString().c_str();
|
||||||
|
tmpStr.toCharArray(liveDataObj->menuItems[i].obdMacAddress, 18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
liveDataObj->scanningDeviceIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (advertisedDevice.getServiceDataUUID().toString() != "<NULL>") {
|
||||||
|
// syslog->print("ServiceDataUUID: ");
|
||||||
|
// syslog->println(advertisedDevice.getServiceDataUUID().toString().c_str());
|
||||||
|
// if (advertisedDevice.getServiceUUID().toString() != "<NULL>") {
|
||||||
|
// syslog->print("ServiceUUID: ");
|
||||||
|
// syslog->println(advertisedDevice.getServiceUUID().toString().c_str());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(liveDataObj->settings.serviceUUID)) &&
|
||||||
|
(strcmp(advertisedDevice.getAddress().toString().c_str(), liveDataObj->settings.obdMacAddress) == 0)) {
|
||||||
|
syslog->println("Stop scanning. Found my BLE device.");
|
||||||
|
BLEDevice::getScan()->stop();
|
||||||
|
liveDataObj->foundMyBleDevice = new BLEAdvertisedDevice(advertisedDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t PIN = 1234;
|
||||||
|
|
||||||
|
/**
|
||||||
|
BLE Security
|
||||||
|
*/
|
||||||
|
class MySecurity : public BLESecurityCallbacks {
|
||||||
|
|
||||||
|
uint32_t onPassKeyRequest() {
|
||||||
|
syslog->printf("Pairing password: %d \r\n", PIN);
|
||||||
|
return PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPassKeyNotify(uint32_t pass_key) {
|
||||||
|
syslog->printf("onPassKeyNotify\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onConfirmPIN(uint32_t pass_key) {
|
||||||
|
syslog->printf("onConfirmPIN\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onSecurityRequest() {
|
||||||
|
syslog->printf("onSecurityRequest\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl) {
|
||||||
|
if (auth_cmpl.success) {
|
||||||
|
syslog->printf("onAuthenticationComplete\r\n");
|
||||||
|
} else {
|
||||||
|
syslog->println("Auth failure. Incorrect PIN?");
|
||||||
|
liveDataObj->bleConnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Ble notification callback
|
||||||
|
*/
|
||||||
|
static void notifyCallback (BLERemoteCharacteristic * pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
// Parse multiframes to single response
|
||||||
|
liveDataObj->responseRow = "";
|
||||||
|
for (int i = 0; i <= length; i++) {
|
||||||
|
ch = pData[i];
|
||||||
|
if (ch == '\r' || ch == '\n' || ch == '\0') {
|
||||||
|
if (liveDataObj->responseRow != "")
|
||||||
|
commObj->parseResponse();
|
||||||
|
liveDataObj->responseRow = "";
|
||||||
|
} else {
|
||||||
|
liveDataObj->responseRow += ch;
|
||||||
|
if (liveDataObj->responseRow == ">") {
|
||||||
|
if (liveDataObj->responseRowMerged != "") {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "merged:");
|
||||||
|
syslog->info(DEBUG_COMM, liveDataObj->responseRowMerged);
|
||||||
|
boardObj->parseRowMerged();
|
||||||
|
}
|
||||||
|
liveDataObj->responseRowMerged = "";
|
||||||
|
liveDataObj->canSendNextAtCommand = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Connect ble4 adapter
|
||||||
|
*/
|
||||||
void CommObd2Ble4::connectDevice() {
|
void CommObd2Ble4::connectDevice() {
|
||||||
Serial.println("COMM connectDevice");
|
|
||||||
|
commObj = this;
|
||||||
|
liveDataObj = liveData;
|
||||||
|
boardObj = board;
|
||||||
|
|
||||||
|
syslog->println("BLE4 connectDevice");
|
||||||
|
|
||||||
|
// Start BLE connection
|
||||||
|
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||||
|
BLEDevice::init("");
|
||||||
|
|
||||||
|
// Retrieve a Scanner and set the callback we want to use to be informed when we have detected a new device.
|
||||||
|
// Specify that we want active scanning and start the scan to run for 10 seconds.
|
||||||
|
syslog->println("Setup BLE scan");
|
||||||
|
liveData->pBLEScan = BLEDevice::getScan();
|
||||||
|
liveData->pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||||
|
liveData->pBLEScan->setInterval(1349);
|
||||||
|
liveData->pBLEScan->setWindow(449);
|
||||||
|
liveData->pBLEScan->setActiveScan(true);
|
||||||
|
|
||||||
|
// Skip BLE scan if middle button pressed
|
||||||
|
if (strcmp(liveData->settings.obdMacAddress, "00:00:00:00:00:00") != 0 && !board->skipAdapterScan()) {
|
||||||
|
syslog->println(liveData->settings.obdMacAddress);
|
||||||
|
startBleScan();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect device
|
Disconnect device
|
||||||
*/
|
*/
|
||||||
void CommObd2Ble4::disconnectDevice() {
|
void CommObd2Ble4::disconnectDevice() {
|
||||||
Serial.println("COMM disconnectDevice");
|
|
||||||
|
syslog->println("COMM disconnectDevice");
|
||||||
|
btStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan device list
|
Scan device list, from menu
|
||||||
*/
|
*/
|
||||||
void CommObd2Ble4::scanDevices() {
|
void CommObd2Ble4::scanDevices() {
|
||||||
Serial.println("COMM scanDevices");
|
|
||||||
|
syslog->println("COMM scanDevices");
|
||||||
|
startBleScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMMOBD2BLE4_CPP
|
///////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
Start ble scan
|
||||||
|
*/
|
||||||
|
void CommObd2Ble4::startBleScan() {
|
||||||
|
|
||||||
|
liveData->foundMyBleDevice = NULL;
|
||||||
|
liveData->scanningDeviceIndex = 0;
|
||||||
|
board->displayMessage(" > Scanning BLE4 devices", "40sec.or hold middle&RST");
|
||||||
|
|
||||||
|
// Start scanning
|
||||||
|
syslog->println("Scanning BLE devices...");
|
||||||
|
syslog->print("Looking for ");
|
||||||
|
syslog->println(liveData->settings.obdMacAddress);
|
||||||
|
BLEScanResults foundDevices = liveData->pBLEScan->start(40, false);
|
||||||
|
syslog->print("Devices found: ");
|
||||||
|
syslog->println(foundDevices.getCount());
|
||||||
|
syslog->println("Scan done!");
|
||||||
|
liveData->pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||||
|
|
||||||
|
char tmpStr1[20];
|
||||||
|
sprintf(tmpStr1, "Found %d devices", foundDevices.getCount());
|
||||||
|
board->displayMessage(" > Scanning BLE4 devices", tmpStr1);
|
||||||
|
|
||||||
|
// Scan devices from menu, show list of devices
|
||||||
|
if (liveData->menuCurrent == 9999) {
|
||||||
|
syslog->println("Display menu with devices");
|
||||||
|
liveData->menuVisible = true;
|
||||||
|
//liveData->menuCurrent = 9999;
|
||||||
|
liveData->menuItemSelected = 0;
|
||||||
|
board->showMenu();
|
||||||
|
} else {
|
||||||
|
// Redraw screen
|
||||||
|
if (liveData->foundMyBleDevice == NULL) {
|
||||||
|
board->displayMessage("Device not found", "Middle button - menu");
|
||||||
|
} else {
|
||||||
|
board->redrawScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Do connect BLE with server (OBD device)
|
||||||
|
*/
|
||||||
|
bool CommObd2Ble4::connectToServer(BLEAddress pAddress) {
|
||||||
|
|
||||||
|
board->displayMessage(" > Connecting device", "");
|
||||||
|
|
||||||
|
syslog->print("liveData->bleConnect ");
|
||||||
|
syslog->println(pAddress.toString().c_str());
|
||||||
|
board->displayMessage(" > Connecting device - init", pAddress.toString().c_str());
|
||||||
|
|
||||||
|
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
|
||||||
|
BLEDevice::setSecurityCallbacks(new MySecurity());
|
||||||
|
|
||||||
|
BLESecurity *pSecurity = new BLESecurity();
|
||||||
|
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); //
|
||||||
|
pSecurity->setCapability(ESP_IO_CAP_KBDISP);
|
||||||
|
pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
|
||||||
|
|
||||||
|
board->displayMessage(" > Connecting device", pAddress.toString().c_str());
|
||||||
|
liveData->pClient = BLEDevice::createClient();
|
||||||
|
liveData->pClient->setClientCallbacks(new MyClientCallback());
|
||||||
|
if (liveData->pClient->connect(pAddress, BLE_ADDR_TYPE_RANDOM) ) syslog->println("liveData->bleConnected");
|
||||||
|
syslog->println(" - liveData->bleConnected to server");
|
||||||
|
|
||||||
|
// Remote service
|
||||||
|
board->displayMessage(" > Connecting device", "Connecting service...");
|
||||||
|
BLERemoteService* pRemoteService = liveData->pClient->getService(BLEUUID(liveData->settings.serviceUUID));
|
||||||
|
if (pRemoteService == nullptr)
|
||||||
|
{
|
||||||
|
syslog->print("Failed to find our service UUID: ");
|
||||||
|
syslog->println(liveData->settings.serviceUUID);
|
||||||
|
board->displayMessage(" > Connecting device", "Unable to find service");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
syslog->println(" - Found our service");
|
||||||
|
|
||||||
|
// Get characteristics
|
||||||
|
board->displayMessage(" > Connecting device", "Connecting TxUUID...");
|
||||||
|
liveData->pRemoteCharacteristic = pRemoteService->getCharacteristic(BLEUUID(liveData->settings.charTxUUID));
|
||||||
|
if (liveData->pRemoteCharacteristic == nullptr) {
|
||||||
|
syslog->print("Failed to find our characteristic UUID: ");
|
||||||
|
syslog->println(liveData->settings.charTxUUID);//.toString().c_str());
|
||||||
|
board->displayMessage(" > Connecting device", "Unable to find TxUUID");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
syslog->println(" - Found our characteristic");
|
||||||
|
|
||||||
|
// Get characteristics
|
||||||
|
board->displayMessage(" > Connecting device", "Connecting RxUUID...");
|
||||||
|
liveData->pRemoteCharacteristicWrite = pRemoteService->getCharacteristic(BLEUUID(liveData->settings.charRxUUID));
|
||||||
|
if (liveData->pRemoteCharacteristicWrite == nullptr) {
|
||||||
|
syslog->print("Failed to find our characteristic UUID: ");
|
||||||
|
syslog->println(liveData->settings.charRxUUID);//.toString().c_str());
|
||||||
|
board->displayMessage(" > Connecting device", "Unable to find RxUUID");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
syslog->println(" - Found our characteristic write");
|
||||||
|
|
||||||
|
board->displayMessage(" > Connecting device", "Register callbacks...");
|
||||||
|
// Read the value of the characteristic.
|
||||||
|
if (liveData->pRemoteCharacteristic->canNotify()) {
|
||||||
|
syslog->println(" - canNotify");
|
||||||
|
if (liveData->pRemoteCharacteristic->canIndicate()) {
|
||||||
|
syslog->println(" - canIndicate");
|
||||||
|
const uint8_t indicationOn[] = {0x2, 0x0};
|
||||||
|
//const uint8_t indicationOff[] = {0x0,0x0};
|
||||||
|
liveData->pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)indicationOn, 2, true);
|
||||||
|
//liveData->pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notifyOff,2,true);
|
||||||
|
liveData->pRemoteCharacteristic->registerForNotify(notifyCallback, false);
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board->displayMessage(" > Connecting device", "Done...");
|
||||||
|
if (liveData->pRemoteCharacteristicWrite->canWrite()) {
|
||||||
|
syslog->println(" - canWrite");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Main loop
|
||||||
|
*/
|
||||||
|
void CommObd2Ble4::mainLoop() {
|
||||||
|
|
||||||
|
// Connect BLE device
|
||||||
|
if (liveData->bleConnect == true && liveData->foundMyBleDevice != NULL) {
|
||||||
|
liveData->pServerAddress = new BLEAddress(liveData->settings.obdMacAddress);
|
||||||
|
if (connectToServer(*liveData->pServerAddress)) {
|
||||||
|
|
||||||
|
liveData->commConnected = true;
|
||||||
|
liveData->bleConnect = false;
|
||||||
|
|
||||||
|
syslog->println("We are now connected to the BLE device.");
|
||||||
|
|
||||||
|
// Print message
|
||||||
|
board->displayMessage(" > Processing init AT cmds", "");
|
||||||
|
|
||||||
|
// Serve first command (ATZ)
|
||||||
|
doNextQueueCommand();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
syslog->println("We have failed to connect to the server; there is nothing more we will do.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent declaration
|
||||||
|
CommInterface::mainLoop();
|
||||||
|
|
||||||
|
if (board->scanDevices) {
|
||||||
|
board->scanDevices = false;
|
||||||
|
startBleScan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send command
|
||||||
|
*/
|
||||||
|
void CommObd2Ble4::executeCommand(String cmd) {
|
||||||
|
|
||||||
|
String tmpStr = cmd + "\r";
|
||||||
|
if (liveData->commConnected) {
|
||||||
|
liveData->pRemoteCharacteristicWrite->writeValue(tmpStr.c_str(), tmpStr.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef COMMOBD2BLE4_H
|
#pragma once
|
||||||
#define COMMOBD2BLE4_H
|
|
||||||
|
|
||||||
|
#include <BLEDevice.h>
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
#include "CommInterface.h"
|
#include "CommInterface.h"
|
||||||
|
|
||||||
@@ -12,6 +12,10 @@ class CommObd2Ble4 : public CommInterface {
|
|||||||
void connectDevice() override;
|
void connectDevice() override;
|
||||||
void disconnectDevice() override;
|
void disconnectDevice() override;
|
||||||
void scanDevices() override;
|
void scanDevices() override;
|
||||||
|
void mainLoop() override;
|
||||||
|
void executeCommand(String cmd) override;
|
||||||
|
//
|
||||||
|
void startBleScan();
|
||||||
|
bool connectToServer(BLEAddress pAddress);
|
||||||
|
//
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMMOBD2BLE4_H
|
|
||||||
|
|||||||
542
CommObd2Can.cpp
542
CommObd2Can.cpp
@@ -1,7 +1,539 @@
|
|||||||
#ifndef COMMINTERFACE_CPP
|
#include "CommObd2CAN.h"
|
||||||
#define COMMINTERFACE_CPP
|
#include "BoardInterface.h"
|
||||||
|
|
||||||
#include "CommInterface.h"
|
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
|
#include <mcp_CAN.h>
|
||||||
|
|
||||||
#endif // COMMINTERFACE_CPP
|
//#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Connect CAN adapter
|
||||||
|
*/
|
||||||
|
void CommObd2Can::connectDevice() {
|
||||||
|
|
||||||
|
syslog->println("CAN connectDevice");
|
||||||
|
|
||||||
|
//CAN = new MCP_CAN(pinCanCs); // todo: remove if smart pointer is ok
|
||||||
|
CAN.reset(new MCP_CAN(pinCanCs)); // smart pointer so it's automatically cleaned when out of context and also free to re-init
|
||||||
|
if (CAN == nullptr) {
|
||||||
|
syslog->println("Error: Not enough memory to instantiate CAN class");
|
||||||
|
syslog->println("init_can() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
|
||||||
|
if (CAN->begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ) == CAN_OK) {
|
||||||
|
syslog->println("MCP2515 Initialized Successfully!");
|
||||||
|
board->displayMessage(" > CAN init OK", "");
|
||||||
|
} else {
|
||||||
|
syslog->println("Error Initializing MCP2515...");
|
||||||
|
board->displayMessage(" > CAN init failed", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (liveData->settings.carType == CAR_BMW_I3_2014) {
|
||||||
|
//initialise mask and filter to allow only receipt of 0x7xx CAN IDs
|
||||||
|
CAN->init_Mask(0, 0, 0x07000000); // Init first mask...
|
||||||
|
CAN->init_Mask(1, 0, 0x07000000); // Init second mask...
|
||||||
|
for (uint8_t i = 0; i < 6; ++i) {
|
||||||
|
CAN->init_Filt(i, 0, 0x06000000); //Init filters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MCP2515_OK != CAN->setMode(MCP_NORMAL)) { // Set operation mode to normal so the MCP2515 sends acks to received data.
|
||||||
|
syslog->println("Error: CAN->setMode(MCP_NORMAL) failed");
|
||||||
|
board->displayMessage(" > CAN init failed", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pinMode(pinCanInt, INPUT); // Configuring pin for /INT input
|
||||||
|
|
||||||
|
// Serve first command (ATZ)
|
||||||
|
liveData->commConnected = true;
|
||||||
|
doNextQueueCommand();
|
||||||
|
|
||||||
|
syslog->println("init_can() done");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Disconnect device
|
||||||
|
*/
|
||||||
|
void CommObd2Can::disconnectDevice() {
|
||||||
|
|
||||||
|
liveData->commConnected = false;
|
||||||
|
// CAN->setMode(MCP_SLEEP);
|
||||||
|
syslog->println("COMM disconnectDevice");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Scan device list, from menu
|
||||||
|
*/
|
||||||
|
void CommObd2Can::scanDevices() {
|
||||||
|
|
||||||
|
syslog->println("COMM scanDevices");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Main loop
|
||||||
|
*/
|
||||||
|
void CommObd2Can::mainLoop() {
|
||||||
|
|
||||||
|
CommInterface::mainLoop();
|
||||||
|
|
||||||
|
// if delay between commands is defined, check if this delay is not expired
|
||||||
|
if (liveData->delayBetweenCommandsMs != 0) {
|
||||||
|
if (bResponseProcessed && (unsigned long)(millis() - lastDataSent) > liveData->delayBetweenCommandsMs) {
|
||||||
|
bResponseProcessed = false;
|
||||||
|
liveData->canSendNextAtCommand = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read data
|
||||||
|
const uint8_t firstByte = receivePID();
|
||||||
|
if ((firstByte & 0xf0) == 0x10) { // First frame, request another
|
||||||
|
sendFlowControlFrame();
|
||||||
|
delay(10);
|
||||||
|
for (uint16_t i = 0; i < 1000; i++) {
|
||||||
|
receivePID();
|
||||||
|
if (rxRemaining <= 2)
|
||||||
|
break;
|
||||||
|
delay(1);
|
||||||
|
// apply timeout for next frames loop too
|
||||||
|
if (lastDataSent != 0 && (unsigned long)(millis() - lastDataSent) > liveData->rxTimeoutMs) {
|
||||||
|
syslog->info(DEBUG_COMM, "CAN execution timeout (multiframe message).");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Process incomplette messages
|
||||||
|
if (liveData->responseRowMerged.length() > 7) {
|
||||||
|
processMergedResponse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastDataSent != 0 && (unsigned long)(millis() - lastDataSent) > liveData->rxTimeoutMs) {
|
||||||
|
syslog->info(DEBUG_COMM, "CAN execution timeout. Continue with next command.");
|
||||||
|
liveData->canSendNextAtCommand = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Send command to CAN bus
|
||||||
|
*/
|
||||||
|
void CommObd2Can::executeCommand(String cmd) {
|
||||||
|
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "executeCommand ");
|
||||||
|
syslog->info(DEBUG_COMM, cmd);
|
||||||
|
|
||||||
|
if (cmd.equals("") || cmd.startsWith("AT")) { // skip AT commands as not used by direct CAN connection
|
||||||
|
lastDataSent = 0;
|
||||||
|
liveData->canSendNextAtCommand = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send command
|
||||||
|
liveData->responseRowMerged = "";
|
||||||
|
liveData->currentAtshRequest.replace(" ", ""); // remove possible spaces
|
||||||
|
String atsh = "0" + liveData->currentAtshRequest.substring(4); // remove ATSH
|
||||||
|
cmd.replace(" ", ""); // remove possible spaces
|
||||||
|
sendPID(liveData->hexToDec(atsh, 2, false), cmd);
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Send PID
|
||||||
|
remark: parameter cmd as const reference to aviod copying
|
||||||
|
*/
|
||||||
|
void CommObd2Can::sendPID(const uint16_t pid, const String& cmd) {
|
||||||
|
|
||||||
|
uint8_t txBuf[8] = { 0 }; // init with zeroes
|
||||||
|
String tmpStr;
|
||||||
|
|
||||||
|
if (liveData->bAdditionalStartingChar)
|
||||||
|
{
|
||||||
|
struct Packet_t
|
||||||
|
{
|
||||||
|
uint8_t startChar;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t payload[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet_t* pPacket = (Packet_t*)txBuf;
|
||||||
|
pPacket->startChar = liveData->commandStartChar; // todo: handle similar way as cmd input param?
|
||||||
|
pPacket->length = cmd.length() / 2;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < sizeof(pPacket->payload); i++) {
|
||||||
|
tmpStr = cmd;
|
||||||
|
tmpStr = tmpStr.substring(i * 2, ((i + 1) * 2));
|
||||||
|
if (tmpStr != "") {
|
||||||
|
pPacket->payload[i] = liveData->hexToDec(tmpStr, 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct Packet_t
|
||||||
|
{
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t payload[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet_t* pPacket = (Packet_t*)txBuf;
|
||||||
|
pPacket->length = cmd.length() / 2;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < sizeof(pPacket->payload); i++) {
|
||||||
|
tmpStr = cmd;
|
||||||
|
tmpStr = tmpStr.substring(i * 2, ((i + 1) * 2));
|
||||||
|
if (tmpStr != "") {
|
||||||
|
pPacket->payload[i] = liveData->hexToDec(tmpStr, 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPid = pid;
|
||||||
|
bResponseProcessed = false;
|
||||||
|
const uint8_t sndStat = CAN->sendMsgBuf(pid, 0, 8, txBuf); // 11 bit
|
||||||
|
// uint8_t sndStat = CAN->sendMsgBuf(0x7e4, 1, 8, tmp); // 29 bit extended frame
|
||||||
|
if (sndStat == CAN_OK) {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "SENT ");
|
||||||
|
lastDataSent = millis();
|
||||||
|
} else {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "Error sending PID ");
|
||||||
|
lastDataSent = millis();
|
||||||
|
}
|
||||||
|
syslog->infoNolf(DEBUG_COMM, pid);
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
sprintf(msgString, " 0x%.2X", txBuf[i]);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, msgString);
|
||||||
|
}
|
||||||
|
syslog->info(DEBUG_COMM, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
sendFlowControlFrame
|
||||||
|
*/
|
||||||
|
void CommObd2Can::sendFlowControlFrame() {
|
||||||
|
|
||||||
|
uint8_t txBuf[8] = { 0x30, requestFramesCount /*request count*/, 20 /*ms between frames*/ , 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
// insert start char if needed
|
||||||
|
if (liveData->bAdditionalStartingChar) {
|
||||||
|
memmove(txBuf + 1, txBuf, 7);
|
||||||
|
txBuf[0] = liveData->commandStartChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t sndStat = CAN->sendMsgBuf(lastPid, 0, 8, txBuf); // 11 bit
|
||||||
|
if (sndStat == CAN_OK) {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "Flow control frame sent ");
|
||||||
|
} else {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "Error sending flow control frame ");
|
||||||
|
}
|
||||||
|
syslog->infoNolf(DEBUG_COMM, lastPid);
|
||||||
|
for (auto txByte : txBuf) {
|
||||||
|
sprintf(msgString, " 0x%.2X", txByte);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, msgString);
|
||||||
|
}
|
||||||
|
syslog->info(DEBUG_COMM, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Receive PID
|
||||||
|
*/
|
||||||
|
uint8_t CommObd2Can::receivePID() {
|
||||||
|
|
||||||
|
if (!digitalRead(pinCanInt)) // If CAN0_INT pin is low, read receive buffer
|
||||||
|
{
|
||||||
|
lastDataSent = millis();
|
||||||
|
syslog->infoNolf(DEBUG_COMM, " CAN READ ");
|
||||||
|
CAN->readMsgBuf(&rxId, &rxLen, rxBuf); // Read data: len = data length, buf = data byte(s)
|
||||||
|
|
||||||
|
if ((rxId & 0x80000000) == 0x80000000) // Determine if ID is standard (11 bits) or extended (29 bits)
|
||||||
|
sprintf(msgString, "Extended ID: 0x%.8lX DLC: %1d Data:", (rxId & 0x1FFFFFFF), rxLen);
|
||||||
|
else
|
||||||
|
sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", rxId, rxLen);
|
||||||
|
|
||||||
|
syslog->infoNolf(DEBUG_COMM, msgString);
|
||||||
|
|
||||||
|
if ((rxId & 0x40000000) == 0x40000000) { // Determine if message is a remote request frame.
|
||||||
|
sprintf(msgString, " REMOTE REQUEST FRAME");
|
||||||
|
syslog->infoNolf(DEBUG_COMM, msgString);
|
||||||
|
} else {
|
||||||
|
for (uint8_t i = 0; i < rxLen; i++) {
|
||||||
|
sprintf(msgString, " 0x%.2X", rxBuf[i]);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, msgString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this packet shall be discarded due to its length.
|
||||||
|
// If liveData->expectedPacketLength is set to 0, accept any length.
|
||||||
|
if(liveData->expectedMinimalPacketLength != 0 && rxLen < liveData->expectedMinimalPacketLength) {
|
||||||
|
syslog->info(DEBUG_COMM, " [Ignored packet]");
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter received messages (Ioniq only)
|
||||||
|
if(liveData->settings.carType == CAR_HYUNDAI_IONIQ_2018) {
|
||||||
|
long unsigned int atsh_response = liveData->hexToDec(liveData->currentAtshRequest.substring(4), 2, false) + 8;
|
||||||
|
|
||||||
|
if(rxId != atsh_response) {
|
||||||
|
syslog->info(DEBUG_COMM, " [Filtered packet]");
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->info(DEBUG_COMM, "");
|
||||||
|
processFrameBytes();
|
||||||
|
//processFrame();
|
||||||
|
} else {
|
||||||
|
//syslog->println(" CAN NOT READ ");
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t rxBuffOffset = liveData->bAdditionalStartingChar? 1 : 0;
|
||||||
|
return rxBuf[0 + rxBuffOffset]; // return byte containing frame type, which requires removing offset byte
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printHexBuffer(uint8_t* pData, const uint16_t length, const bool bAddNewLine)
|
||||||
|
{
|
||||||
|
char str[8] = { 0 };
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
sprintf(str, " 0x%.2X", pData[i]);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bAddNewLine) {
|
||||||
|
syslog->info(DEBUG_COMM, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffer2string(String& out_targetString, uint8_t* in_pBuffer, const uint16_t in_length)
|
||||||
|
{
|
||||||
|
char str[8] = { 0 };
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < in_length; i++) {
|
||||||
|
sprintf(str, "%.2X", in_pBuffer[i]);
|
||||||
|
out_targetString += str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CommObd2Can::enFrame_t CommObd2Can::getFrameType(const uint8_t firstByte) {
|
||||||
|
const uint8_t frameType = (firstByte & 0xf0) >> 4; // frame type is in bits 7 to 4
|
||||||
|
switch(frameType) {
|
||||||
|
case 0:
|
||||||
|
return enFrame_t::single;
|
||||||
|
case 1:
|
||||||
|
return enFrame_t::first;
|
||||||
|
case 2:
|
||||||
|
return enFrame_t::consecutive;
|
||||||
|
default:
|
||||||
|
return enFrame_t::unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Process can frame on byte level
|
||||||
|
https://en.wikipedia.org/wiki/ISO_15765-2
|
||||||
|
*/
|
||||||
|
bool CommObd2Can::processFrameBytes() {
|
||||||
|
const uint8_t rxBuffOffset = liveData->bAdditionalStartingChar ? 1 : 0;
|
||||||
|
uint8_t* pDataStart = rxBuf + rxBuffOffset; // set pointer to data start based on specific offset of car
|
||||||
|
const auto frameType = getFrameType(*pDataStart);
|
||||||
|
const uint8_t frameLenght = rxLen - rxBuffOffset;
|
||||||
|
|
||||||
|
switch (frameType) {
|
||||||
|
case enFrame_t::single: // Single frame
|
||||||
|
{
|
||||||
|
struct SingleFrame_t
|
||||||
|
{
|
||||||
|
uint8_t size : 4;
|
||||||
|
uint8_t frameType : 4;
|
||||||
|
uint8_t pData[];
|
||||||
|
};
|
||||||
|
|
||||||
|
SingleFrame_t* pSingleFrame = (SingleFrame_t*)pDataStart;
|
||||||
|
mergedData.assign(pSingleFrame->pData, pSingleFrame->pData + pSingleFrame->size);
|
||||||
|
|
||||||
|
rxRemaining = 0;
|
||||||
|
|
||||||
|
//syslog->print("----Processing SingleFrame payload: "); printHexBuffer(pSingleFrame->pData, pSingleFrame->size, true);
|
||||||
|
|
||||||
|
// single frame - process directly
|
||||||
|
buffer2string(liveData->responseRowMerged, mergedData.data(), mergedData.size());
|
||||||
|
liveData->vResponseRowMerged.assign(mergedData.begin(), mergedData.end());
|
||||||
|
processMergedResponse();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case enFrame_t::first: // First frame
|
||||||
|
{
|
||||||
|
struct FirstFrame_t
|
||||||
|
{
|
||||||
|
uint8_t sizeMSB : 4;
|
||||||
|
uint8_t frameType : 4;
|
||||||
|
uint8_t sizeLSB : 8;
|
||||||
|
uint8_t pData[];
|
||||||
|
|
||||||
|
uint16_t lengthOfFullPacket() { return (256 * sizeMSB) + sizeLSB; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
FirstFrame_t* pFirstFrame = (FirstFrame_t*)pDataStart;
|
||||||
|
|
||||||
|
rxRemaining = pFirstFrame->lengthOfFullPacket(); // length of complete data
|
||||||
|
|
||||||
|
mergedData.clear();
|
||||||
|
dataRows.clear();
|
||||||
|
|
||||||
|
const uint8_t framePayloadSize = frameLenght - sizeof(FirstFrame_t); // remove one byte of header
|
||||||
|
dataRows[0].assign(pFirstFrame->pData, pFirstFrame->pData + framePayloadSize);
|
||||||
|
rxRemaining -= framePayloadSize;
|
||||||
|
|
||||||
|
//syslog->print("----Processing FirstFrame payload: "); printHexBuffer(pFirstFrame->pData, framePayloadSize, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case enFrame_t::consecutive: // Consecutive frame
|
||||||
|
{
|
||||||
|
struct ConsecutiveFrame_t
|
||||||
|
{
|
||||||
|
uint8_t index : 4;
|
||||||
|
uint8_t frameType : 4;
|
||||||
|
uint8_t pData[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t structSize = sizeof(ConsecutiveFrame_t);
|
||||||
|
//syslog->print("[debug] sizeof(ConsecutiveFrame_t) is expected to be 1 and it's "); syslog->println(structSize);
|
||||||
|
|
||||||
|
ConsecutiveFrame_t* pConseqFrame = (ConsecutiveFrame_t*)pDataStart;
|
||||||
|
const uint8_t framePayloadSize = frameLenght - sizeof(ConsecutiveFrame_t); // remove one byte of header
|
||||||
|
dataRows[pConseqFrame->index].assign(pConseqFrame->pData, pConseqFrame->pData + framePayloadSize);
|
||||||
|
rxRemaining -= framePayloadSize;
|
||||||
|
|
||||||
|
//syslog->print("----Processing ConsecFrame payload: "); printHexBuffer(pConseqFrame->pData, framePayloadSize, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "Unknown frame type within CommObd2Can::processFrameBytes(): ");
|
||||||
|
syslog->info(DEBUG_COMM, (uint8_t)frameType);
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
} // \switch (frameType)
|
||||||
|
|
||||||
|
// Merge data if all data was received
|
||||||
|
if (rxRemaining <= 0) {
|
||||||
|
// multiple frames and no data remaining - merge everything to single packet
|
||||||
|
for (int i = 0; i < dataRows.size(); i++) {
|
||||||
|
//syslog->print("------merging packet index ");
|
||||||
|
//syslog->print(i);
|
||||||
|
//syslog->print(" with length ");
|
||||||
|
//syslog->println(dataRows[i].size());
|
||||||
|
|
||||||
|
mergedData.insert(mergedData.end(), dataRows[i].begin(), dataRows[i].end());
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer2string(liveData->responseRowMerged, mergedData.data(), mergedData.size()); // output for string parsing
|
||||||
|
liveData->vResponseRowMerged.assign(mergedData.begin(), mergedData.end()); // output for binary parsing
|
||||||
|
processMergedResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Process can frame
|
||||||
|
https://en.wikipedia.org/wiki/ISO_15765-2
|
||||||
|
*/
|
||||||
|
bool CommObd2Can::processFrame() {
|
||||||
|
|
||||||
|
const uint8_t frameType = (rxBuf[0] & 0xf0) >> 4;
|
||||||
|
uint8_t start = 1; // Single and Consecutive starts with pos 1
|
||||||
|
uint8_t index = 0; // 0 - f
|
||||||
|
|
||||||
|
liveData->responseRow = "";
|
||||||
|
switch (frameType) {
|
||||||
|
// Single frame
|
||||||
|
case 0:
|
||||||
|
rxRemaining = (rxBuf[1] & 0x0f);
|
||||||
|
requestFramesCount = 0;
|
||||||
|
break;
|
||||||
|
// First frame
|
||||||
|
case 1:
|
||||||
|
rxRemaining = ((rxBuf[0] & 0x0f) << 8) + rxBuf[1];
|
||||||
|
requestFramesCount = ceil((rxRemaining - 6) / 7.0);
|
||||||
|
liveData->responseRowMerged = "";
|
||||||
|
for (uint16_t i = 0; i < rxRemaining - 1; i++)
|
||||||
|
liveData->responseRowMerged += "00";
|
||||||
|
liveData->responseRow = "0:";
|
||||||
|
start = 2;
|
||||||
|
break;
|
||||||
|
// Consecutive frames
|
||||||
|
case 2:
|
||||||
|
index = (rxBuf[0] & 0x0f);
|
||||||
|
sprintf(msgString, "%.1X:", index);
|
||||||
|
liveData->responseRow = msgString; // convert 0..15 to ascii 0..F);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "> frametype:");
|
||||||
|
syslog->infoNolf(DEBUG_COMM, frameType);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, ", r: ");
|
||||||
|
syslog->infoNolf(DEBUG_COMM, rxRemaining);
|
||||||
|
syslog->infoNolf(DEBUG_COMM, " ");
|
||||||
|
|
||||||
|
for (uint8_t i = start; i < rxLen; i++) {
|
||||||
|
sprintf(msgString, "%.2X", rxBuf[i]);
|
||||||
|
liveData->responseRow += msgString;
|
||||||
|
rxRemaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog->infoNolf(DEBUG_COMM, ", r: ");
|
||||||
|
syslog->infoNolf(DEBUG_COMM, rxRemaining);
|
||||||
|
syslog->info(DEBUG_COMM, " ");
|
||||||
|
|
||||||
|
//parseResponse();
|
||||||
|
// We need to sort frames
|
||||||
|
// 1 frame data
|
||||||
|
syslog->info(DEBUG_COMM, liveData->responseRow);
|
||||||
|
// Merge frames 0:xxxx 1:yyyy 2:zzzz to single response xxxxyyyyzzzz string
|
||||||
|
if (liveData->responseRow.length() >= 2 && liveData->responseRow.charAt(1) == ':') {
|
||||||
|
//liveData->responseRowMerged += liveData->responseRow.substring(2);
|
||||||
|
uint8_t rowNo = liveData->hexToDec(liveData->responseRow.substring(0, 1), 1, false);
|
||||||
|
uint16_t startPos = (rowNo * 14) - ((rowNo > 0) ? 2 : 0);
|
||||||
|
uint16_t endPos = ((rowNo + 1) * 14) - ((rowNo > 0) ? 2 : 0);
|
||||||
|
liveData->responseRowMerged = liveData->responseRowMerged.substring(0, startPos) + liveData->responseRow.substring(2) + liveData->responseRowMerged.substring(endPos);
|
||||||
|
syslog->info(DEBUG_COMM, liveData->responseRowMerged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send response to board module
|
||||||
|
if (rxRemaining <= 2) {
|
||||||
|
processMergedResponse();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
processMergedResponse
|
||||||
|
*/
|
||||||
|
void CommObd2Can::processMergedResponse() {
|
||||||
|
syslog->infoNolf(DEBUG_COMM, "merged:");
|
||||||
|
syslog->info(DEBUG_COMM, liveData->responseRowMerged);
|
||||||
|
board->parseRowMerged();
|
||||||
|
|
||||||
|
liveData->responseRowMerged = "";
|
||||||
|
liveData->vResponseRowMerged.clear();
|
||||||
|
bResponseProcessed = true; // to allow delay untill next message
|
||||||
|
|
||||||
|
if (liveData->delayBetweenCommandsMs == 0) {
|
||||||
|
liveData->canSendNextAtCommand = true; // allow next command immediately
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,54 @@
|
|||||||
#ifndef COMMOBD2CAN_H
|
#pragma once
|
||||||
#define COMMOBD2CAN_H
|
|
||||||
|
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
|
#include "CommInterface.h"
|
||||||
|
#include <mcp_can.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class CommObd2Can : public CommInterface {
|
class CommObd2Can : public CommInterface {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
public:
|
const uint8_t pinCanInt = 15;
|
||||||
};
|
const uint8_t pinCanCs = 12;
|
||||||
|
std::unique_ptr <MCP_CAN> CAN;
|
||||||
|
long unsigned int rxId;
|
||||||
|
unsigned char rxLen = 0;
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
int16_t rxRemaining; // Remaining bytes to complete message, signed is ok
|
||||||
|
uint8_t requestFramesCount;
|
||||||
|
char msgString[128]; // Array to store serial string
|
||||||
|
uint16_t lastPid;
|
||||||
|
unsigned long lastDataSent = 0;
|
||||||
|
|
||||||
#endif // COMMOBD2CAN_H
|
std::vector<uint8_t> mergedData;
|
||||||
|
std::unordered_map<uint16_t, std::vector<uint8_t>> dataRows;
|
||||||
|
bool bResponseProcessed = false;
|
||||||
|
|
||||||
|
enum class enFrame_t
|
||||||
|
{
|
||||||
|
single = 0,
|
||||||
|
first = 1,
|
||||||
|
consecutive = 2,
|
||||||
|
unknown = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void connectDevice() override;
|
||||||
|
void disconnectDevice() override;
|
||||||
|
void scanDevices() override;
|
||||||
|
void mainLoop() override;
|
||||||
|
void executeCommand(String cmd) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendPID(const uint16_t pid, const String& cmd);
|
||||||
|
void sendFlowControlFrame();
|
||||||
|
uint8_t receivePID();
|
||||||
|
enFrame_t getFrameType(const uint8_t firstByte);
|
||||||
|
bool processFrameBytes();
|
||||||
|
bool processFrame();
|
||||||
|
void processMergedResponse();
|
||||||
|
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ M5STACK (Many thanks to DimZen)
|
|||||||
|
|
||||||
https://docs.google.com/document/d/17vJmeveNfN0exQy9wKC-5igU8zzNjsuOn1DPuPV_yJA/edit?usp=sharing
|
https://docs.google.com/document/d/17vJmeveNfN0exQy9wKC-5igU8zzNjsuOn1DPuPV_yJA/edit?usp=sharing
|
||||||
|
|
||||||
TTGO-T4 (older)
|
TTGO-T4 (older guide)
|
||||||
|
|
||||||
https://docs.google.com/document/d/1nEezrtXY-8X6mQ1hiZVWDjBVse1sXQg1SlnizaRmJwU/edit?usp=sharing
|
https://docs.google.com/document/d/1nEezrtXY-8X6mQ1hiZVWDjBVse1sXQg1SlnizaRmJwU/edit?usp=sharing
|
||||||
|
|
||||||
|
|||||||
33
LiveData.cpp
33
LiveData.cpp
@@ -1,16 +1,21 @@
|
|||||||
|
|
||||||
#ifndef LIVEDATA_CPP
|
|
||||||
#define LIVEDATA_CPP
|
|
||||||
|
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
|
||||||
|
LogSerial* syslog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug level
|
||||||
|
*/
|
||||||
|
void debug(String msg, uint8_t debugLevel) {
|
||||||
|
syslog->println(msg);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Init params with default values
|
Init params with default values
|
||||||
*/
|
*/
|
||||||
void LiveData::initParams() {
|
void LiveData::initParams() {
|
||||||
|
|
||||||
params.automaticShutdownTimer = 0;
|
params.mainLoopCounter = 0;
|
||||||
// SIM
|
// SIM
|
||||||
params.lastDataSent = 0;
|
params.lastDataSent = 0;
|
||||||
params.sim800l_enabled = false;
|
params.sim800l_enabled = false;
|
||||||
@@ -28,18 +33,22 @@ void LiveData::initParams() {
|
|||||||
params.gpsAlt = -1;
|
params.gpsAlt = -1;
|
||||||
// Car data
|
// Car data
|
||||||
params.ignitionOn = false;
|
params.ignitionOn = false;
|
||||||
params.ignitionOnPrevious = false;
|
params.lastIgnitionOnTime = 0;
|
||||||
params.operationTimeSec = 0;
|
params.operationTimeSec = 0;
|
||||||
params.chargingStartTime = params.currentTime = 0;
|
params.chargingStartTime = params.currentTime = 0;
|
||||||
params.lightInfo = 0;
|
params.chargingOn = false;
|
||||||
params.headLights = false;
|
params.headLights = false;
|
||||||
params.dayLights = false;
|
params.dayLights = false;
|
||||||
params.brakeLights = false;
|
params.brakeLights = false;
|
||||||
params.brakeLightInfo = 0;
|
params.trunkDoorOpen = false;
|
||||||
|
params.leftFrontDoorOpen = false;
|
||||||
|
params.rightFrontDoorOpen = false;
|
||||||
|
params.leftRearDoorOpen = false;
|
||||||
|
params.rightRearDoorOpen = false;
|
||||||
|
params.hoodDoorOpen = false;
|
||||||
params.forwardDriveMode = false;
|
params.forwardDriveMode = false;
|
||||||
params.reverseDriveMode = false;
|
params.reverseDriveMode = false;
|
||||||
params.parkModeOrNeutral = false;
|
params.parkModeOrNeutral = false;
|
||||||
params.espState = 0;
|
|
||||||
params.speedKmh = -1;
|
params.speedKmh = -1;
|
||||||
params.motorRpm = -1;
|
params.motorRpm = -1;
|
||||||
params.odoKm = -1;
|
params.odoKm = -1;
|
||||||
@@ -185,9 +194,3 @@ float LiveData::celsius2temperature(float inCelsius) {
|
|||||||
float LiveData::bar2pressure(float inBar) {
|
float LiveData::bar2pressure(float inBar) {
|
||||||
return (settings.pressureUnit == 'b') ? inBar : inBar * 14.503773800722;
|
return (settings.pressureUnit == 'b') ? inBar : inBar * 14.503773800722;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
#endif // LIVEDATA_CPP
|
|
||||||
|
|||||||
71
LiveData.h
71
LiveData.h
@@ -1,6 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
#ifndef LIVEDATA_H
|
|
||||||
#define LIVEDATA_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -9,6 +7,8 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <BLEDevice.h>
|
#include <BLEDevice.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "LogSerial.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// SUPPORTED CARS
|
// SUPPORTED CARS
|
||||||
#define CAR_KIA_ENIRO_2020_64 0
|
#define CAR_KIA_ENIRO_2020_64 0
|
||||||
@@ -18,11 +18,13 @@
|
|||||||
#define CAR_HYUNDAI_KONA_2020_39 4
|
#define CAR_HYUNDAI_KONA_2020_39 4
|
||||||
#define CAR_RENAULT_ZOE 5
|
#define CAR_RENAULT_ZOE 5
|
||||||
#define CAR_KIA_NIRO_PHEV 6
|
#define CAR_KIA_NIRO_PHEV 6
|
||||||
|
#define CAR_BMW_I3_2014 7
|
||||||
#define CAR_DEBUG_OBD2_KIA 999
|
#define CAR_DEBUG_OBD2_KIA 999
|
||||||
|
|
||||||
//
|
// COMM TYPE
|
||||||
#define COMM_TYPE_OBD2BLE4 0
|
#define COMM_TYPE_OBD2BLE4 0
|
||||||
#define COMM_TYPE_OBD2CAN 1
|
#define COMM_TYPE_OBD2CAN 1
|
||||||
|
#define COMM_TYPE_OBD2BT3 2
|
||||||
|
|
||||||
// SCREENS
|
// SCREENS
|
||||||
#define SCREEN_BLANK 0
|
#define SCREEN_BLANK 0
|
||||||
@@ -32,14 +34,18 @@
|
|||||||
#define SCREEN_CELLS 4
|
#define SCREEN_CELLS 4
|
||||||
#define SCREEN_CHARGING 5
|
#define SCREEN_CHARGING 5
|
||||||
#define SCREEN_SOC10 6
|
#define SCREEN_SOC10 6
|
||||||
#define SCREEN_DEBUG 7
|
|
||||||
|
//
|
||||||
|
#define MONTH_SEC 2678400
|
||||||
|
|
||||||
|
extern LogSerial* syslog;
|
||||||
|
|
||||||
// Structure with realtime values
|
// Structure with realtime values
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// System
|
// System
|
||||||
time_t currentTime;
|
time_t currentTime;
|
||||||
time_t chargingStartTime;
|
time_t chargingStartTime;
|
||||||
time_t automaticShutdownTimer;
|
uint32_t mainLoopCounter;
|
||||||
// SIM
|
// SIM
|
||||||
time_t lastDataSent;
|
time_t lastDataSent;
|
||||||
bool sim800l_enabled;
|
bool sim800l_enabled;
|
||||||
@@ -55,7 +61,9 @@ typedef struct {
|
|||||||
char sdcardFilename[32];
|
char sdcardFilename[32];
|
||||||
// Car params
|
// Car params
|
||||||
bool ignitionOn;
|
bool ignitionOn;
|
||||||
bool ignitionOnPrevious;
|
bool chargingOn;
|
||||||
|
time_t lastIgnitionOnTime;
|
||||||
|
time_t lastChargingOnTime;
|
||||||
uint64_t operationTimeSec;
|
uint64_t operationTimeSec;
|
||||||
bool sdcardCanNotify;
|
bool sdcardCanNotify;
|
||||||
bool forwardDriveMode;
|
bool forwardDriveMode;
|
||||||
@@ -64,9 +72,15 @@ typedef struct {
|
|||||||
bool headLights;
|
bool headLights;
|
||||||
bool dayLights;
|
bool dayLights;
|
||||||
bool brakeLights;
|
bool brakeLights;
|
||||||
uint8_t lightInfo;
|
bool trunkDoorOpen;
|
||||||
|
bool leftFrontDoorOpen;
|
||||||
|
bool rightFrontDoorOpen;
|
||||||
|
bool leftRearDoorOpen;
|
||||||
|
bool rightRearDoorOpen;
|
||||||
|
bool hoodDoorOpen;
|
||||||
|
/* uint8_t lightInfo;
|
||||||
uint8_t brakeLightInfo;
|
uint8_t brakeLightInfo;
|
||||||
uint8_t espState;
|
uint8_t espState;*/
|
||||||
float batteryTotalAvailableKWh;
|
float batteryTotalAvailableKWh;
|
||||||
float speedKmh;
|
float speedKmh;
|
||||||
float motorRpm;
|
float motorRpm;
|
||||||
@@ -106,6 +120,7 @@ typedef struct {
|
|||||||
float auxPerc;
|
float auxPerc;
|
||||||
float auxCurrentAmp;
|
float auxCurrentAmp;
|
||||||
float auxVoltage;
|
float auxVoltage;
|
||||||
|
float auxTemperature;
|
||||||
float indoorTemperature;
|
float indoorTemperature;
|
||||||
float outdoorTemperature;
|
float outdoorTemperature;
|
||||||
float tireFrontLeftTempC;
|
float tireFrontLeftTempC;
|
||||||
@@ -161,11 +176,11 @@ typedef struct {
|
|||||||
// =================================
|
// =================================
|
||||||
byte defaultScreen; // 1 .. 6
|
byte defaultScreen; // 1 .. 6
|
||||||
byte lcdBrightness; // 0 - auto, 1 .. 100%
|
byte lcdBrightness; // 0 - auto, 1 .. 100%
|
||||||
byte debugScreen; // 0 - off, 1 - on
|
byte sleepModeEnabled; // 0 - off, 1 - on
|
||||||
byte predrawnChargingGraphs; // 0 - off, 1 - on
|
byte predrawnChargingGraphs; // 0 - off, 1 - on
|
||||||
// === settings version 4
|
// === settings version 4
|
||||||
// =================================
|
// =================================
|
||||||
byte commType; // 0 - OBD2 BLE4 adapter, 1 - CAN
|
byte commType; // 0 - OBD2 BLE4 adapter, 1 - CAN, 2 - BT3
|
||||||
// Wifi
|
// Wifi
|
||||||
byte wifiEnabled; // 0/1
|
byte wifiEnabled; // 0/1
|
||||||
char wifiSsid[32];
|
char wifiSsid[32];
|
||||||
@@ -189,23 +204,36 @@ typedef struct {
|
|||||||
// === settings version 5
|
// === settings version 5
|
||||||
// =================================
|
// =================================
|
||||||
byte gpsHwSerialPort; // 255-off, 0,1,2 - hw serial
|
byte gpsHwSerialPort; // 255-off, 0,1,2 - hw serial
|
||||||
|
byte gprsHwSerialPort; // 255-off, 0,1,2 - hw serial
|
||||||
|
// === settings version 6
|
||||||
|
// =================================
|
||||||
|
byte serialConsolePort; // 255-off, 0 - hw serial (std)
|
||||||
|
uint8_t debugLevel; // 0 - info only, 1 - debug communication (BLE/CAN), 2 - debug GSM, 3 - debug SDcard
|
||||||
|
uint16_t sdcardLogIntervalSec; // every x seconds
|
||||||
|
uint16_t gprsLogIntervalSec; // every x seconds
|
||||||
//
|
//
|
||||||
} SETTINGS_STRUC;
|
} SETTINGS_STRUC;
|
||||||
|
|
||||||
|
// LiveData class
|
||||||
//
|
|
||||||
class LiveData {
|
class LiveData {
|
||||||
protected:
|
protected:
|
||||||
public:
|
public:
|
||||||
// Command loop
|
// Command loop
|
||||||
|
struct Command_t {
|
||||||
|
uint8_t startChar; // special starting character used by some cars
|
||||||
|
String request;
|
||||||
|
};
|
||||||
|
|
||||||
uint16_t commandQueueCount;
|
uint16_t commandQueueCount;
|
||||||
uint16_t commandQueueLoopFrom;
|
uint16_t commandQueueLoopFrom;
|
||||||
String commandQueue[300];
|
std::vector<Command_t> commandQueue;
|
||||||
String responseRow;
|
String responseRow;
|
||||||
String responseRowMerged;
|
String responseRowMerged;
|
||||||
|
std::vector<uint8_t> vResponseRowMerged;
|
||||||
uint16_t commandQueueIndex;
|
uint16_t commandQueueIndex;
|
||||||
bool canSendNextAtCommand = false;
|
bool canSendNextAtCommand = false;
|
||||||
String commandRequest = "";
|
uint8_t commandStartChar;
|
||||||
|
String commandRequest = ""; // TODO: us Command_t struct
|
||||||
String currentAtshRequest = "";
|
String currentAtshRequest = "";
|
||||||
// Menu
|
// Menu
|
||||||
bool menuVisible = false;
|
bool menuVisible = false;
|
||||||
@@ -216,9 +244,10 @@ class LiveData {
|
|||||||
uint16_t scanningDeviceIndex = 0;
|
uint16_t scanningDeviceIndex = 0;
|
||||||
MENU_ITEM* menuItems;
|
MENU_ITEM* menuItems;
|
||||||
|
|
||||||
|
// Comm
|
||||||
|
boolean commConnected = true;
|
||||||
// Bluetooth4
|
// Bluetooth4
|
||||||
boolean bleConnect = true;
|
boolean bleConnect = true;
|
||||||
boolean bleConnected = false;
|
|
||||||
BLEAddress *pServerAddress;
|
BLEAddress *pServerAddress;
|
||||||
BLERemoteCharacteristic* pRemoteCharacteristic;
|
BLERemoteCharacteristic* pRemoteCharacteristic;
|
||||||
BLERemoteCharacteristic* pRemoteCharacteristicWrite;
|
BLERemoteCharacteristic* pRemoteCharacteristicWrite;
|
||||||
@@ -226,6 +255,12 @@ class LiveData {
|
|||||||
BLEClient* pClient;
|
BLEClient* pClient;
|
||||||
BLEScan* pBLEScan;
|
BLEScan* pBLEScan;
|
||||||
|
|
||||||
|
// Canbus
|
||||||
|
bool bAdditionalStartingChar = false; // some cars uses additional starting character in beginning of tx and rx messages
|
||||||
|
uint8_t expectedMinimalPacketLength = 0; // what length of packet should be accepted. Set to 0 to accept any length
|
||||||
|
uint16_t rxTimeoutMs = 100; // timeout for receiving of CAN response
|
||||||
|
uint16_t delayBetweenCommandsMs = 0; // delay between commands, set to 0 if no delay is needed
|
||||||
|
|
||||||
// Params
|
// Params
|
||||||
PARAMS_STRUC params; // Realtime sensor values
|
PARAMS_STRUC params; // Realtime sensor values
|
||||||
// Settings
|
// Settings
|
||||||
@@ -240,7 +275,3 @@ class LiveData {
|
|||||||
float celsius2temperature(float inCelsius);
|
float celsius2temperature(float inCelsius);
|
||||||
float bar2pressure(float inBar);
|
float bar2pressure(float inBar);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
#endif // LIVEDATA_H
|
|
||||||
|
|||||||
15
LogSerial.cpp
Normal file
15
LogSerial.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "LogSerial.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
LogSerial::LogSerial() : HardwareSerial(0) {
|
||||||
|
HardwareSerial::begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set debug level
|
||||||
|
*/
|
||||||
|
void LogSerial::setDebugLevel(uint8_t aDebugLevel) {
|
||||||
|
debugLevel = aDebugLevel;
|
||||||
|
}
|
||||||
58
LogSerial.h
Normal file
58
LogSerial.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <HardwareSerial.h>
|
||||||
|
|
||||||
|
// DEBUG LEVEL
|
||||||
|
#define DEBUG_NONE 0
|
||||||
|
#define DEBUG_COMM 1 // filter comm
|
||||||
|
#define DEBUG_GSM 2 // filter gsm messages
|
||||||
|
#define DEBUG_SDCARD 3 // filter sdcard
|
||||||
|
|
||||||
|
//
|
||||||
|
class LogSerial: public HardwareSerial {
|
||||||
|
protected:
|
||||||
|
uint8_t debugLevel;
|
||||||
|
public:
|
||||||
|
LogSerial();
|
||||||
|
//
|
||||||
|
void setDebugLevel(uint8_t aDebugLevel);
|
||||||
|
// info
|
||||||
|
template <class T, typename... Args> void info(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
println(msg);
|
||||||
|
}
|
||||||
|
template <class T, typename... Args> void infoNolf(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
print(msg);
|
||||||
|
}
|
||||||
|
// warning
|
||||||
|
template <class T, typename... Args> void warn(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
print("WARN ");
|
||||||
|
println(msg);
|
||||||
|
}
|
||||||
|
template <class T, typename... Args> void warnNolf(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
print("WARN ");
|
||||||
|
print(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
template <class T, typename... Args> void err(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
print("ERR ");
|
||||||
|
println(msg);
|
||||||
|
}
|
||||||
|
template <class T, typename... Args> void errNolf(uint8_t aDebugLevel, T msg) {
|
||||||
|
if (debugLevel != DEBUG_NONE && aDebugLevel != DEBUG_NONE && aDebugLevel != debugLevel)
|
||||||
|
return;
|
||||||
|
print("ERR ");
|
||||||
|
print(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
41
README.md
41
README.md
@@ -1,31 +1,30 @@
|
|||||||
# evDash (old enirodashboard)
|
# evDash (old enirodashboard)
|
||||||
|
|
||||||
Supported devices
|
Supported devices
|
||||||
1. LILYGO TTGO T4 v1.3
|
1. M5STACK CORE1 IOT Development Kit (best option)
|
||||||
2. M5STACK CORE1 IOT Development Kit
|
2. LILYGO TTGO T4 v1.3 (!!! limited support, no SDcard/GSM/GPS/CAN module)
|
||||||
|
|
||||||
Working only with electric vehicles
|
Working only with electric vehicles
|
||||||
Kia e-NIRO (EV), Hyundai Kona EV, Hyundai Ioniq EV, Kia Niro Phev 8.9kWh
|
Kia e-NIRO (EV), Hyundai Kona EV, Hyundai Ioniq EV, Kia Niro Phev 8.9kWh
|
||||||
Vgate iCar Pro Bluetooth 4.0 (BLE4) OBD2 adapter is required. See Release notes, quick installation via flash tool bellow.
|
Vgate iCar Pro Bluetooth 4.0 (BLE4) OBD2 adapter is required or CAN (m5 COMMU module).
|
||||||
|
See Release notes, quick installation via flash tool bellow.
|
||||||
|
|
||||||
Use it at your own risk!
|
Use it at your own risk!
|
||||||
Author: nick.n17@gmail.com (Lubos Petrovic / Slovakia)
|
|
||||||
|
|
||||||
## Supporting me
|
evDash Discord server: https://discord.gg/rfAvH7xzTr
|
||||||
|
|
||||||
- Buy Me a Beer via paypal https://www.paypal.me/nickn17
|
|
||||||
- EU companies can support me via IBAN/Invoice (my company is non-VAT payer in Slovakia).
|
|
||||||
|
|
||||||
Many thanks to Blas, Jens, Калин, Aleš Dokupil and others for help. Thank you for supporting me.
|
|
||||||
|
|
||||||
## Required hardware
|
## Required hardware
|
||||||
Board
|
Board
|
||||||
- M5STACK CORE1 IOT Development Kit(~EUR 35)
|
- M5STACK CORE1 IOT Development Kit(~EUR 35)
|
||||||
https://rlx.sk/sk/m5stack/7285-esp32-basic-core-iot-development-kit-m5-k001-m5stack.html
|
https://rlx.sk/sk/m5stack/7285-esp32-basic-core-iot-development-kit-m5-k001-m5stack.html
|
||||||
|
- optional M5 COMMU (CAN) module
|
||||||
|
- optional M5 GPS NEO-M8N (with external atenna)
|
||||||
|
- optional M5 SIM800L GPS module (dev)
|
||||||
|
|
||||||
or
|
or
|
||||||
- LILYGO TTGO T4 v1.3 (~USD $30) https://www.banggood.com/LILYGO-TTGO-T-Watcher-BTC-Ticker-ESP32-For-Bitcoin-Price-Program-4M-SPI-Flash-Psram-LCD-Display-Module-p-1345292.html
|
- older device LILYGO TTGO T4 v1.3 (~USD $30)
|
||||||
I RECOMMEND TO REMOVE LION BATTERY DUE TO HIGH SUMMER TEMPERATURES
|
https://www.banggood.com/LILYGO-TTGO-T-Watcher-BTC-Ticker-ESP32-For-Bitcoin-Price-Program-4M-SPI-Flash-Psram-LCD-Display-Module-p-1345292.html
|
||||||
|
I RECOMMEND TO REMOVE LION BATTERY DUE TO HIGH SUMMER TEMPERATURES
|
||||||
|
|
||||||
OBD2 adapter
|
OBD2 adapter
|
||||||
- Supported is only this model... Vgate iCar Pro Bluetooth 4.0 (BLE4) OBD2 (~USD $30)
|
- Supported is only this model... Vgate iCar Pro Bluetooth 4.0 (BLE4) OBD2 (~USD $30)
|
||||||
@@ -51,15 +50,19 @@ See INSTALLATION.md
|
|||||||
|
|
||||||
Screen list
|
Screen list
|
||||||
- no0. blank screen, lcd off
|
- no0. blank screen, lcd off
|
||||||
- no1. auto mode (summary info / speed kmh / charging graph)
|
- no1. automatic mode (summary info / speed kmh / charging graph)
|
||||||
- no2. summary info (default)
|
- no2. summary info
|
||||||
- no3. speed kmh + kwh/100km (or kw for discharge)
|
- no3. speed kmh + kwh/100km
|
||||||
- no4. battery cells + battery module temperatures
|
- no4. battery cells + battery module temperatures
|
||||||
- no5. charging graph
|
- no5. charging graph
|
||||||
- no6. consumption table. Can be used to measure available battery capacity!
|
- no6. consumption table. Can be used to measure available battery capacity.
|
||||||
- no7. debug screen (default off in the menu)
|
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
[](https://www.youtube.com/watch?v=Jg5VP2P58Yg&)
|
## Supporting me
|
||||||
|
|
||||||
|
- nick.n17@gmail.com (Lubos Petrovic / Slovakia)
|
||||||
|
- Buy Me a Beer via paypal https://www.paypal.me/nickn17
|
||||||
|
- Many thanks to all evDash contributors.
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
### Next version
|
### Next version
|
||||||
|
|
||||||
|
### v2.2.0 2020-12-29
|
||||||
|
- Direct CAN support with m5 COMMU module (instead obd2 BLE4 adapter). RECOMMENDED
|
||||||
|
- EvDash deep sleep & wake up for Hyundai Ioniq/Kona & Kia e-Niro (kolaCZek).
|
||||||
|
- Send data via GPRS to own server (kolaCZek). Simple web api project https://github.com/kolaCZek/evDash_serverapi)
|
||||||
|
- Better support for Hyundai Ioniq (kolaCZek).
|
||||||
|
- Kia e-niro - added support for open doors/hood/trunk.
|
||||||
|
- Serial console off/on and improved logging & debug level setting
|
||||||
|
- Avoid GPS on UART0 collision with serial console.
|
||||||
|
- DEV initial support for Bmw i3 (Janulo)
|
||||||
|
- Command queue refactoring (Janulo)
|
||||||
|
- Sdcard is working only with m5stack
|
||||||
|
- Removed debug screen
|
||||||
|
- M5 mute speaker fix
|
||||||
|
|
||||||
### v2.1.1 2020-12-14
|
### v2.1.1 2020-12-14
|
||||||
- tech refactoring: `hexToDecFromResponse`, `decFromResponse`
|
- tech refactoring: `hexToDecFromResponse`, `decFromResponse`
|
||||||
- added support for GPS module on HW UART (user HWUART=2 for m5stack NEO-M8N)
|
- added support for GPS module on HW UART (user HWUART=2 for m5stack NEO-M8N)
|
||||||
|
|||||||
13
SIM800L.cpp
13
SIM800L.cpp
@@ -45,6 +45,9 @@ const char AT_CMD_CFUN0[] PROGMEM = "AT+CFUN=0"; //
|
|||||||
const char AT_CMD_CFUN1[] PROGMEM = "AT+CFUN=1"; // Switch normal power mode
|
const char AT_CMD_CFUN1[] PROGMEM = "AT+CFUN=1"; // Switch normal power mode
|
||||||
const char AT_CMD_CFUN4[] PROGMEM = "AT+CFUN=4"; // Switch sleep power mode
|
const char AT_CMD_CFUN4[] PROGMEM = "AT+CFUN=4"; // Switch sleep power mode
|
||||||
|
|
||||||
|
const char AC_CMD_CSCLK0[] PROGMEM = "AT+CSCLK=0"; // AT+CSCLK=0 command
|
||||||
|
const char AC_CMD_CSCLK2[] PROGMEM = "AT+CSCLK=2"; // AT+CSCLK=2 command
|
||||||
|
|
||||||
const char AT_CMD_CREG_TEST[] PROGMEM = "AT+CREG?"; // Check the network registration status
|
const char AT_CMD_CREG_TEST[] PROGMEM = "AT+CREG?"; // Check the network registration status
|
||||||
const char AT_CMD_SAPBR_GPRS[] PROGMEM = "AT+SAPBR=3,1,\"Contype\",\"GPRS\""; // Configure the GPRS bearer
|
const char AT_CMD_SAPBR_GPRS[] PROGMEM = "AT+SAPBR=3,1,\"Contype\",\"GPRS\""; // Configure the GPRS bearer
|
||||||
const char AT_CMD_SAPBR_APN[] PROGMEM = "AT+SAPBR=3,1,\"APN\","; // Configure the APN for the GPRS
|
const char AT_CMD_SAPBR_APN[] PROGMEM = "AT+SAPBR=3,1,\"APN\","; // Configure the APN for the GPRS
|
||||||
@@ -721,6 +724,16 @@ bool SIM800L::setPowerMode(PowerMode powerMode) {
|
|||||||
return currentPowerMode == powerMode;
|
return currentPowerMode == powerMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SIM800L::exitSleepMode() {
|
||||||
|
sendCommand_P(AC_CMD_CSCLK0);
|
||||||
|
purgeSerial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SIM800L::enterSleepMode() {
|
||||||
|
sendCommand_P(AC_CMD_CSCLK2);
|
||||||
|
purgeSerial();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status function: Check the strengh of the signal
|
* Status function: Check the strengh of the signal
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class SIM800L {
|
|||||||
|
|
||||||
// Define the power mode (for parameter: see PowerMode enum)
|
// Define the power mode (for parameter: see PowerMode enum)
|
||||||
bool setPowerMode(PowerMode powerMode);
|
bool setPowerMode(PowerMode powerMode);
|
||||||
|
void enterSleepMode();
|
||||||
|
void exitSleepMode();
|
||||||
|
|
||||||
// Enable/disable GPRS
|
// Enable/disable GPRS
|
||||||
bool setupGPRS(const char *apn);
|
bool setupGPRS(const char *apn);
|
||||||
|
|||||||
24
config.h
24
config.h
@@ -1,10 +1,9 @@
|
|||||||
#ifndef CONFIG_H
|
#pragma once
|
||||||
#define CONFIG_H
|
|
||||||
|
|
||||||
#include <BLEDevice.h>
|
#include <BLEDevice.h>
|
||||||
|
|
||||||
#define APP_VERSION "v2.1.1"
|
#define APP_VERSION "v2.2.0"
|
||||||
#define APP_RELEASE_DATE "2020-12-14"
|
#define APP_RELEASE_DATE "2020-12-29"
|
||||||
|
|
||||||
// TFT COLORS FOR TTGO
|
// TFT COLORS FOR TTGO
|
||||||
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
|
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
|
||||||
@@ -48,13 +47,8 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// SIM800L
|
// SIM800L
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef SIM800L_ENABLED
|
|
||||||
#define SIM800L_RX 16
|
|
||||||
#define SIM800L_TX 17
|
|
||||||
#define SIM800L_RST 5
|
#define SIM800L_RST 5
|
||||||
#define SIM800L_TIMER 60
|
#define SIM800L_TIMER 60
|
||||||
#endif //SIM800L_ENABLED
|
|
||||||
|
|
||||||
// MENU ITEM
|
// MENU ITEM
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -67,9 +61,14 @@ typedef struct {
|
|||||||
} MENU_ITEM;
|
} MENU_ITEM;
|
||||||
|
|
||||||
#define MENU_VEHICLE_TYPE 1
|
#define MENU_VEHICLE_TYPE 1
|
||||||
|
#define MENU_ADAPTER_TYPE 5
|
||||||
#define MENU_SAVE_SETTINGS 9
|
#define MENU_SAVE_SETTINGS 9
|
||||||
#define MENU_APP_VERSION 10
|
#define MENU_APP_VERSION 10
|
||||||
//
|
//
|
||||||
|
#define MENU_ADAPTER_BLE4 501
|
||||||
|
#define MENU_ADAPTER_CAN 502
|
||||||
|
#define MENU_ADAPTER_BT3 503
|
||||||
|
//
|
||||||
#define MENU_WIFI 301
|
#define MENU_WIFI 301
|
||||||
#define MENU_GPRS 302
|
#define MENU_GPRS 302
|
||||||
#define MENU_NTP 303
|
#define MENU_NTP 303
|
||||||
@@ -80,8 +79,10 @@ typedef struct {
|
|||||||
#define MENU_PREDRAWN_GRAPHS 308
|
#define MENU_PREDRAWN_GRAPHS 308
|
||||||
#define MENU_REMOTE_UPLOAD 309
|
#define MENU_REMOTE_UPLOAD 309
|
||||||
#define MENU_HEADLIGHTS_REMINDER 310
|
#define MENU_HEADLIGHTS_REMINDER 310
|
||||||
#define MENU_DEBUG_SCREEN 311
|
#define MENU_SLEEP_MODE 311
|
||||||
#define MENU_GPS 312
|
#define MENU_GPS 312
|
||||||
|
#define MENU_SERIAL_CONSOLE 313
|
||||||
|
#define MENU_DEBUG_LEVEL 314
|
||||||
//
|
//
|
||||||
#define MENU_DISTANCE_UNIT 401
|
#define MENU_DISTANCE_UNIT 401
|
||||||
#define MENU_TEMPERATURE_UNIT 402
|
#define MENU_TEMPERATURE_UNIT 402
|
||||||
@@ -95,6 +96,5 @@ typedef struct {
|
|||||||
#define MENU_SDCARD_AUTOSTARTLOG 3042
|
#define MENU_SDCARD_AUTOSTARTLOG 3042
|
||||||
#define MENU_SDCARD_MOUNT_STATUS 3043
|
#define MENU_SDCARD_MOUNT_STATUS 3043
|
||||||
#define MENU_SDCARD_REC 3044
|
#define MENU_SDCARD_REC 3044
|
||||||
|
#define MENU_SDCARD_INTERVAL 3045
|
||||||
//
|
//
|
||||||
|
|
||||||
#endif // CONFIG_H
|
|
||||||
|
|||||||
BIN
dist/m5stack_core1/evDash.ino.bin
vendored
BIN
dist/m5stack_core1/evDash.ino.bin
vendored
Binary file not shown.
BIN
dist/ttgo_t4_v13/evDash.ino.bin
vendored
BIN
dist/ttgo_t4_v13/evDash.ino.bin
vendored
Binary file not shown.
640
evDash.ino
640
evDash.ino
@@ -1,20 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
Project renamed from eNiroDashboard to evDash
|
Project renamed from eNiroDashboard to evDash
|
||||||
|
|
||||||
!! working only with OBD BLE 4.0 adapters
|
|
||||||
!! Supported adapter is Vgate ICar Pro (must be BLE4.0 version)
|
|
||||||
!! Not working with standard BLUETOOTH 3 adapters
|
|
||||||
|
|
||||||
Serial console commands
|
Serial console commands
|
||||||
|
|
||||||
serviceUUID=xxx
|
serviceUUID=xxx
|
||||||
charTxUUID=xxx
|
charTxUUID=xxx
|
||||||
charRxUUID=xxx
|
charRxUUID=xxx
|
||||||
wifiSsid=xxx
|
wifiSsid=xxx
|
||||||
wifiPassword=xxx
|
wifiPassword=xxx
|
||||||
gprsApn=xxx
|
gprsApn=xxx
|
||||||
remoteApiUrl=xxx
|
remoteApiUrl=xxx
|
||||||
remoteApiKey=xxx
|
remoteApiKey=xxx
|
||||||
|
|
||||||
Required libraries
|
Required libraries
|
||||||
- esp32 board support
|
- esp32 board support
|
||||||
@@ -31,10 +27,8 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Boards
|
// Boards
|
||||||
#define BOARD_TTGO_T4
|
//#define BOARD_TTGO_T4
|
||||||
//#define BOARD_M5STACK_CORE
|
#define BOARD_M5STACK_CORE
|
||||||
|
|
||||||
//#define SIM800L_ENABLED
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@@ -49,8 +43,6 @@
|
|||||||
#include "BoardM5stackCore.h"
|
#include "BoardM5stackCore.h"
|
||||||
#endif // BOARD_M5STACK_CORE
|
#endif // BOARD_M5STACK_CORE
|
||||||
|
|
||||||
#include <BLEDevice.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "LiveData.h"
|
#include "LiveData.h"
|
||||||
#include "CarInterface.h"
|
#include "CarInterface.h"
|
||||||
@@ -59,485 +51,34 @@
|
|||||||
#include "CarRenaultZoe.h"
|
#include "CarRenaultZoe.h"
|
||||||
#include "CarKiaNiroPhev.h"
|
#include "CarKiaNiroPhev.h"
|
||||||
#include "CarKiaDebugObd2.h"
|
#include "CarKiaDebugObd2.h"
|
||||||
|
#include "CarBmwI3.h"
|
||||||
#ifdef SIM800L_ENABLED
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include "SIM800L.h"
|
|
||||||
|
|
||||||
SIM800L* sim800l;
|
|
||||||
HardwareSerial SerialGPRS(2);
|
|
||||||
#endif //SIM800L_ENABLED
|
|
||||||
|
|
||||||
// Temporary variables
|
|
||||||
char ch;
|
|
||||||
String line;
|
|
||||||
|
|
||||||
// Board, Car, Livedata (params, settings)
|
// Board, Car, Livedata (params, settings)
|
||||||
BoardInterface* board;
|
BoardInterface* board;
|
||||||
CarInterface* car;
|
CarInterface* car;
|
||||||
LiveData* liveData;
|
LiveData* liveData;
|
||||||
|
|
||||||
/**
|
|
||||||
Do next AT command from queue
|
|
||||||
*/
|
|
||||||
bool doNextAtCommand() {
|
|
||||||
|
|
||||||
// Restart loop with AT commands
|
|
||||||
if (liveData->commandQueueIndex >= liveData->commandQueueCount) {
|
|
||||||
liveData->commandQueueIndex = liveData->commandQueueLoopFrom;
|
|
||||||
board->redrawScreen();
|
|
||||||
// log every queue loop (temp)
|
|
||||||
liveData->params.sdcardCanNotify = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send AT command to obd
|
|
||||||
liveData->commandRequest = liveData->commandQueue[liveData->commandQueueIndex];
|
|
||||||
if (liveData->commandRequest.startsWith("ATSH")) {
|
|
||||||
liveData->currentAtshRequest = liveData->commandRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print(">>> ");
|
|
||||||
Serial.println(liveData->commandRequest);
|
|
||||||
String tmpStr = liveData->commandRequest + "\r";
|
|
||||||
liveData->pRemoteCharacteristicWrite->writeValue(tmpStr.c_str(), tmpStr.length());
|
|
||||||
liveData->commandQueueIndex++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse result from OBD, create single line liveData->responseRowMerged
|
|
||||||
*/
|
|
||||||
bool parseRow() {
|
|
||||||
|
|
||||||
// Simple 1 line responses
|
|
||||||
Serial.print("");
|
|
||||||
Serial.println(liveData->responseRow);
|
|
||||||
|
|
||||||
// Merge 0:xxxx 1:yyyy 2:zzzz to single xxxxyyyyzzzz string
|
|
||||||
if (liveData->responseRow.length() >= 2 && liveData->responseRow.charAt(1) == ':') {
|
|
||||||
if (liveData->responseRow.charAt(0) == '0') {
|
|
||||||
liveData->responseRowMerged = "";
|
|
||||||
}
|
|
||||||
liveData->responseRowMerged += liveData->responseRow.substring(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse merged row (after merge completed)
|
|
||||||
*/
|
|
||||||
bool parseRowMerged() {
|
|
||||||
|
|
||||||
Serial.print("merged:");
|
|
||||||
Serial.println(liveData->responseRowMerged);
|
|
||||||
|
|
||||||
// Catch output for debug screen
|
|
||||||
if (board->displayScreen == SCREEN_DEBUG) {
|
|
||||||
if (board->debugCommandIndex == liveData->commandQueueIndex) {
|
|
||||||
board->debugAtshRequest = liveData->currentAtshRequest;
|
|
||||||
board->debugCommandRequest = liveData->commandRequest;
|
|
||||||
board->debugLastString = liveData->responseRowMerged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse by selected car interface
|
|
||||||
car->parseRowMerged();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
BLE callbacks
|
|
||||||
*/
|
|
||||||
class MyClientCallback : public BLEClientCallbacks {
|
|
||||||
|
|
||||||
/**
|
|
||||||
On BLE connect
|
|
||||||
*/
|
|
||||||
void onConnect(BLEClient* pclient) {
|
|
||||||
Serial.println("onConnect");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
On BLE disconnect
|
|
||||||
*/
|
|
||||||
void onDisconnect(BLEClient* pclient) {
|
|
||||||
//connected = false;
|
|
||||||
Serial.println("onDisconnect");
|
|
||||||
board->displayMessage("BLE disconnected", "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
Scan for BLE servers and find the first one that advertises the service we are looking for.
|
|
||||||
*/
|
|
||||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Called for each advertising BLE server.
|
|
||||||
*/
|
|
||||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
|
||||||
|
|
||||||
Serial.print("BLE advertised device found: ");
|
|
||||||
Serial.println(advertisedDevice.toString().c_str());
|
|
||||||
Serial.println(advertisedDevice.getAddress().toString().c_str());
|
|
||||||
|
|
||||||
// Add to device list (max. 9 devices allowed yet)
|
|
||||||
String tmpStr;
|
|
||||||
|
|
||||||
if (liveData->scanningDeviceIndex < 10/* && advertisedDevice.haveServiceUUID()*/) {
|
|
||||||
for (uint16_t i = 0; i < liveData->menuItemsCount; ++i) {
|
|
||||||
if (liveData->menuItems[i].id == 10001 + liveData->scanningDeviceIndex) {
|
|
||||||
tmpStr = advertisedDevice.toString().c_str();
|
|
||||||
tmpStr.replace("Name: ", "");
|
|
||||||
tmpStr.replace("Address: ", "");
|
|
||||||
tmpStr.toCharArray(liveData->menuItems[i].title, 48);
|
|
||||||
tmpStr = advertisedDevice.getAddress().toString().c_str();
|
|
||||||
tmpStr.toCharArray(liveData->menuItems[i].obdMacAddress, 18);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
liveData->scanningDeviceIndex++;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (advertisedDevice.getServiceDataUUID().toString() != "<NULL>") {
|
|
||||||
Serial.print("ServiceDataUUID: ");
|
|
||||||
Serial.println(advertisedDevice.getServiceDataUUID().toString().c_str());
|
|
||||||
if (advertisedDevice.getServiceUUID().toString() != "<NULL>") {
|
|
||||||
Serial.print("ServiceUUID: ");
|
|
||||||
Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(liveData->settings.serviceUUID)) &&
|
|
||||||
(strcmp(advertisedDevice.getAddress().toString().c_str(), liveData->settings.obdMacAddress) == 0)) {
|
|
||||||
Serial.println("Stop scanning. Found my BLE device.");
|
|
||||||
BLEDevice::getScan()->stop();
|
|
||||||
liveData->foundMyBleDevice = new BLEAdvertisedDevice(advertisedDevice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t PIN = 1234;
|
|
||||||
|
|
||||||
/**
|
|
||||||
BLE Security
|
|
||||||
*/
|
|
||||||
class MySecurity : public BLESecurityCallbacks {
|
|
||||||
|
|
||||||
uint32_t onPassKeyRequest() {
|
|
||||||
Serial.printf("Pairing password: %d \r\n", PIN);
|
|
||||||
return PIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPassKeyNotify(uint32_t pass_key) {
|
|
||||||
Serial.printf("onPassKeyNotify\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onConfirmPIN(uint32_t pass_key) {
|
|
||||||
Serial.printf("onConfirmPIN\r\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onSecurityRequest() {
|
|
||||||
Serial.printf("onSecurityRequest\r\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl) {
|
|
||||||
if (auth_cmpl.success) {
|
|
||||||
Serial.printf("onAuthenticationComplete\r\n");
|
|
||||||
} else {
|
|
||||||
Serial.println("Auth failure. Incorrect PIN?");
|
|
||||||
liveData->bleConnect = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
Ble notification callback
|
|
||||||
*/
|
|
||||||
static void notifyCallback (BLERemoteCharacteristic * pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
|
|
||||||
|
|
||||||
char ch;
|
|
||||||
|
|
||||||
// Parse multi line response to single lines
|
|
||||||
liveData->responseRow = "";
|
|
||||||
for (int i = 0; i <= length; i++) {
|
|
||||||
ch = pData[i];
|
|
||||||
if (ch == '\r' || ch == '\n' || ch == '\0') {
|
|
||||||
if (liveData->responseRow != "")
|
|
||||||
parseRow();
|
|
||||||
liveData->responseRow = "";
|
|
||||||
} else {
|
|
||||||
liveData->responseRow += ch;
|
|
||||||
if (liveData->responseRow == ">") {
|
|
||||||
if (liveData->responseRowMerged != "") {
|
|
||||||
parseRowMerged();
|
|
||||||
}
|
|
||||||
liveData->responseRowMerged = "";
|
|
||||||
liveData->canSendNextAtCommand = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Do connect BLE with server (OBD device)
|
|
||||||
*/
|
|
||||||
bool connectToServer(BLEAddress pAddress) {
|
|
||||||
|
|
||||||
board->displayMessage(" > Connecting device", "");
|
|
||||||
|
|
||||||
Serial.print("liveData->bleConnect ");
|
|
||||||
Serial.println(pAddress.toString().c_str());
|
|
||||||
board->displayMessage(" > Connecting device - init", pAddress.toString().c_str());
|
|
||||||
|
|
||||||
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
|
|
||||||
BLEDevice::setSecurityCallbacks(new MySecurity());
|
|
||||||
|
|
||||||
BLESecurity *pSecurity = new BLESecurity();
|
|
||||||
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); //
|
|
||||||
pSecurity->setCapability(ESP_IO_CAP_KBDISP);
|
|
||||||
pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
|
|
||||||
|
|
||||||
board->displayMessage(" > Connecting device", pAddress.toString().c_str());
|
|
||||||
liveData->pClient = BLEDevice::createClient();
|
|
||||||
liveData->pClient->setClientCallbacks(new MyClientCallback());
|
|
||||||
if (liveData->pClient->connect(pAddress, BLE_ADDR_TYPE_RANDOM) ) Serial.println("liveData->bleConnected");
|
|
||||||
Serial.println(" - liveData->bleConnected to server");
|
|
||||||
|
|
||||||
// Remote service
|
|
||||||
board->displayMessage(" > Connecting device", "Connecting service...");
|
|
||||||
BLERemoteService* pRemoteService = liveData->pClient->getService(BLEUUID(liveData->settings.serviceUUID));
|
|
||||||
if (pRemoteService == nullptr)
|
|
||||||
{
|
|
||||||
Serial.print("Failed to find our service UUID: ");
|
|
||||||
Serial.println(liveData->settings.serviceUUID);
|
|
||||||
board->displayMessage(" > Connecting device", "Unable to find service");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Serial.println(" - Found our service");
|
|
||||||
|
|
||||||
// Get characteristics
|
|
||||||
board->displayMessage(" > Connecting device", "Connecting TxUUID...");
|
|
||||||
liveData->pRemoteCharacteristic = pRemoteService->getCharacteristic(BLEUUID(liveData->settings.charTxUUID));
|
|
||||||
if (liveData->pRemoteCharacteristic == nullptr) {
|
|
||||||
Serial.print("Failed to find our characteristic UUID: ");
|
|
||||||
Serial.println(liveData->settings.charTxUUID);//.toString().c_str());
|
|
||||||
board->displayMessage(" > Connecting device", "Unable to find TxUUID");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Serial.println(" - Found our characteristic");
|
|
||||||
|
|
||||||
// Get characteristics
|
|
||||||
board->displayMessage(" > Connecting device", "Connecting RxUUID...");
|
|
||||||
liveData->pRemoteCharacteristicWrite = pRemoteService->getCharacteristic(BLEUUID(liveData->settings.charRxUUID));
|
|
||||||
if (liveData->pRemoteCharacteristicWrite == nullptr) {
|
|
||||||
Serial.print("Failed to find our characteristic UUID: ");
|
|
||||||
Serial.println(liveData->settings.charRxUUID);//.toString().c_str());
|
|
||||||
board->displayMessage(" > Connecting device", "Unable to find RxUUID");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Serial.println(" - Found our characteristic write");
|
|
||||||
|
|
||||||
board->displayMessage(" > Connecting device", "Register callbacks...");
|
|
||||||
// Read the value of the characteristic.
|
|
||||||
if (liveData->pRemoteCharacteristic->canNotify()) {
|
|
||||||
Serial.println(" - canNotify");
|
|
||||||
//liveData->pRemoteCharacteristic->registerForNotify(notifyCallback);
|
|
||||||
if (liveData->pRemoteCharacteristic->canIndicate()) {
|
|
||||||
Serial.println(" - canIndicate");
|
|
||||||
const uint8_t indicationOn[] = {0x2, 0x0};
|
|
||||||
//const uint8_t indicationOff[] = {0x0,0x0};
|
|
||||||
liveData->pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)indicationOn, 2, true);
|
|
||||||
//liveData->pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notifyOff,2,true);
|
|
||||||
liveData->pRemoteCharacteristic->registerForNotify(notifyCallback, false);
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
board->displayMessage(" > Connecting device", "Done...");
|
|
||||||
if (liveData->pRemoteCharacteristicWrite->canWrite()) {
|
|
||||||
Serial.println(" - canWrite");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Start ble scan
|
|
||||||
*/
|
|
||||||
void startBleScan() {
|
|
||||||
|
|
||||||
liveData->foundMyBleDevice = NULL;
|
|
||||||
liveData->scanningDeviceIndex = 0;
|
|
||||||
board->displayMessage(" > Scanning BLE4 devices", "40sec.or hold middle&RST");
|
|
||||||
|
|
||||||
// Start scanning
|
|
||||||
Serial.println("Scanning BLE devices...");
|
|
||||||
Serial.print("Looking for ");
|
|
||||||
Serial.println(liveData->settings.obdMacAddress);
|
|
||||||
BLEScanResults foundDevices = liveData->pBLEScan->start(40, false);
|
|
||||||
Serial.print("Devices found: ");
|
|
||||||
Serial.println(foundDevices.getCount());
|
|
||||||
Serial.println("Scan done!");
|
|
||||||
liveData->pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
|
||||||
|
|
||||||
char tmpStr1[20];
|
|
||||||
sprintf(tmpStr1, "Found %d devices", foundDevices.getCount());
|
|
||||||
board->displayMessage(" > Scanning BLE4 devices", tmpStr1);
|
|
||||||
|
|
||||||
// Scan devices from menu, show list of devices
|
|
||||||
if (liveData->menuItemSelected == 2) {
|
|
||||||
Serial.println("Display menu with devices");
|
|
||||||
liveData->menuVisible = true;
|
|
||||||
liveData->menuCurrent = 9999;
|
|
||||||
liveData->menuItemSelected = 0;
|
|
||||||
board->showMenu();
|
|
||||||
} else {
|
|
||||||
// Redraw screen
|
|
||||||
if (liveData->foundMyBleDevice == NULL) {
|
|
||||||
board->displayMessage("Device not found", "Middle button - menu");
|
|
||||||
} else {
|
|
||||||
board->redrawScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
SIM800L
|
|
||||||
*/
|
|
||||||
#ifdef SIM800L_ENABLED
|
|
||||||
bool sim800lSetup() {
|
|
||||||
Serial.println("Setting SIM800L module");
|
|
||||||
|
|
||||||
SerialGPRS.begin(9600);
|
|
||||||
|
|
||||||
sim800l = new SIM800L((Stream *)&SerialGPRS, SIM800L_RST, 512 , 512);
|
|
||||||
// SIM800L DebugMode:
|
|
||||||
//sim800l = new SIM800L((Stream *)&SerialGPRS, SIM800L_RST, 512 , 512, (Stream *)&Serial);
|
|
||||||
|
|
||||||
bool sim800l_ready = sim800l->isReady();
|
|
||||||
for (uint8_t i = 0; i < 5 && !sim800l_ready; i++) {
|
|
||||||
Serial.println("Problem to initialize SIM800L module, retry in 1 sec");
|
|
||||||
delay(1000);
|
|
||||||
sim800l_ready = sim800l->isReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sim800l_ready) {
|
|
||||||
Serial.println("Problem to initialize SIM800L module");
|
|
||||||
} else {
|
|
||||||
Serial.println("SIM800L module initialized");
|
|
||||||
|
|
||||||
Serial.print("Setting GPRS APN to: ");
|
|
||||||
Serial.println(liveData->settings.gprsApn);
|
|
||||||
|
|
||||||
bool sim800l_gprs = sim800l->setupGPRS(liveData->settings.gprsApn);
|
|
||||||
for (uint8_t i = 0; i < 5 && !sim800l_gprs; i++) {
|
|
||||||
Serial.println("Problem to set GPRS APN, retry in 1 sec");
|
|
||||||
delay(1000);
|
|
||||||
sim800l_gprs = sim800l->setupGPRS(liveData->settings.gprsApn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sim800l_gprs) {
|
|
||||||
liveData->params.sim800l_enabled = true;
|
|
||||||
Serial.println("GPRS APN set OK");
|
|
||||||
} else {
|
|
||||||
Serial.println("Problem to set GPRS APN");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendDataViaGPRS() {
|
|
||||||
Serial.println("Sending data via GPRS");
|
|
||||||
|
|
||||||
NetworkRegistration network = sim800l->getRegistrationStatus();
|
|
||||||
if (network != REGISTERED_HOME && network != REGISTERED_ROAMING) {
|
|
||||||
Serial.println("SIM800L module not connected to network, skipping data send");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!sim800l->isConnectedGPRS()) {
|
|
||||||
Serial.println("GPRS not connected... Connecting");
|
|
||||||
bool connected = sim800l->connectGPRS();
|
|
||||||
for (uint8_t i = 0; i < 5 && !connected; i++) {
|
|
||||||
Serial.println("Problem to connect GPRS, retry in 1 sec");
|
|
||||||
delay(1000);
|
|
||||||
connected = sim800l->connectGPRS();
|
|
||||||
}
|
|
||||||
if(connected) {
|
|
||||||
Serial.println("GPRS connected!");
|
|
||||||
} else {
|
|
||||||
Serial.println("GPRS not connected! Reseting SIM800L module!");
|
|
||||||
sim800l->reset();
|
|
||||||
sim800lSetup();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println("Start HTTP POST...");
|
|
||||||
|
|
||||||
StaticJsonDocument<512> jsonData;
|
|
||||||
|
|
||||||
jsonData["apikey"] = liveData->settings.remoteApiKey;
|
|
||||||
jsonData["carType"] = liveData->settings.carType;
|
|
||||||
jsonData["socPerc"] = liveData->params.socPerc;
|
|
||||||
jsonData["sohPerc"] = liveData->params.sohPerc;
|
|
||||||
jsonData["batPowerKw"] = liveData->params.batPowerKw;
|
|
||||||
jsonData["batPowerAmp"] = liveData->params.batPowerAmp;
|
|
||||||
jsonData["batVoltage"] = liveData->params.batVoltage;
|
|
||||||
jsonData["auxVoltage"] = liveData->params.auxVoltage;
|
|
||||||
jsonData["auxAmp"] = liveData->params.auxCurrentAmp;
|
|
||||||
jsonData["batMinC"] = liveData->params.batMinC;
|
|
||||||
jsonData["batMaxC"] = liveData->params.batMaxC;
|
|
||||||
jsonData["batInletC"] = liveData->params.batInletC;
|
|
||||||
jsonData["batFanStatus"] = liveData->params.batFanStatus;
|
|
||||||
jsonData["speedKmh"] = liveData->params.speedKmh;
|
|
||||||
jsonData["cumulativeEnergyChargedKWh"] = liveData->params.cumulativeEnergyChargedKWh;
|
|
||||||
jsonData["cumulativeEnergyDischargedKWh"] = liveData->params.cumulativeEnergyDischargedKWh;
|
|
||||||
|
|
||||||
char payload[512];
|
|
||||||
serializeJson(jsonData, payload);
|
|
||||||
|
|
||||||
Serial.print("Sending payload: ");
|
|
||||||
Serial.println(payload);
|
|
||||||
|
|
||||||
Serial.print("Remote API server: ");
|
|
||||||
Serial.println(liveData->settings.remoteApiUrl);
|
|
||||||
|
|
||||||
uint16_t rc = sim800l->doPost(liveData->settings.remoteApiUrl, "application/json", payload, 10000, 10000);
|
|
||||||
if (rc == 200) {
|
|
||||||
Serial.println("HTTP POST successful");
|
|
||||||
} else {
|
|
||||||
// Failed...
|
|
||||||
Serial.print("HTTP POST error: ");
|
|
||||||
Serial.println(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif //SIM800L_ENABLED
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Setup device
|
Setup device
|
||||||
*/
|
*/
|
||||||
void setup(void) {
|
void setup(void) {
|
||||||
|
|
||||||
// Serial console, init structures
|
// Serial console
|
||||||
Serial.begin(115200);
|
syslog = new LogSerial();
|
||||||
Serial.println("");
|
syslog->println("\nBooting device...");
|
||||||
Serial.println("Booting device...");
|
|
||||||
|
|
||||||
// Init settings/params, board library
|
// Init settings/params
|
||||||
line = "";
|
|
||||||
liveData = new LiveData();
|
liveData = new LiveData();
|
||||||
liveData->initParams();
|
liveData->initParams();
|
||||||
|
|
||||||
|
// Turn off serial console
|
||||||
|
if (liveData->settings.serialConsolePort == 255) {
|
||||||
|
syslog->println("Serial console disabled...");
|
||||||
|
syslog->flush();
|
||||||
|
syslog->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init board
|
||||||
#ifdef BOARD_TTGO_T4
|
#ifdef BOARD_TTGO_T4
|
||||||
board = new BoardTtgoT4v13();
|
board = new BoardTtgoT4v13();
|
||||||
#endif // BOARD_TTGO_T4
|
#endif // BOARD_TTGO_T4
|
||||||
@@ -548,124 +89,47 @@ void setup(void) {
|
|||||||
board->loadSettings();
|
board->loadSettings();
|
||||||
board->initBoard();
|
board->initBoard();
|
||||||
|
|
||||||
// Car interface
|
// Init selected car interface
|
||||||
if (liveData->settings.carType == CAR_KIA_ENIRO_2020_64 || liveData->settings.carType == CAR_HYUNDAI_KONA_2020_64 ||
|
switch (liveData->settings.carType) {
|
||||||
liveData->settings.carType == CAR_KIA_ENIRO_2020_39 || liveData->settings.carType == CAR_HYUNDAI_KONA_2020_39) {
|
case CAR_KIA_ENIRO_2020_39:
|
||||||
car = new CarKiaEniro();
|
case CAR_KIA_ENIRO_2020_64:
|
||||||
} else if (liveData->settings.carType == CAR_HYUNDAI_IONIQ_2018) {
|
case CAR_HYUNDAI_KONA_2020_39:
|
||||||
car = new CarHyundaiIoniq();
|
case CAR_HYUNDAI_KONA_2020_64:
|
||||||
} else if (liveData->settings.carType == CAR_KIA_NIRO_PHEV) {
|
car = new CarKiaEniro();
|
||||||
car = new CarKiaNiroPhev();
|
break;
|
||||||
} else if (liveData->settings.carType == CAR_RENAULT_ZOE) {
|
case CAR_HYUNDAI_IONIQ_2018:
|
||||||
car = new CarRenaultZoe();
|
car = new CarHyundaiIoniq();
|
||||||
} else {
|
break;
|
||||||
// if (liveData->settings.carType == CAR_DEBUG_OBD2_KIA)
|
case CAR_KIA_NIRO_PHEV:
|
||||||
car = new CarKiaDebugObd2();
|
car = new CarKiaNiroPhev();
|
||||||
|
break;
|
||||||
|
case CAR_RENAULT_ZOE:
|
||||||
|
car = new CarRenaultZoe();
|
||||||
|
break;
|
||||||
|
case CAR_BMW_I3_2014:
|
||||||
|
car = new CarBmwI3();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
car = new CarKiaDebugObd2();
|
||||||
}
|
}
|
||||||
|
|
||||||
car->setLiveData(liveData);
|
car->setLiveData(liveData);
|
||||||
car->activateCommandQueue();
|
car->activateCommandQueue();
|
||||||
board->attachCar(car);
|
board->attachCar(car);
|
||||||
board->debugCommandIndex = liveData->commandQueueLoopFrom;
|
|
||||||
|
// Finish board setup
|
||||||
|
board->afterSetup();
|
||||||
|
|
||||||
// Redraw screen
|
// Redraw screen
|
||||||
board->redrawScreen();
|
board->redrawScreen();
|
||||||
|
|
||||||
// Init time library
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 1589011873;
|
|
||||||
settimeofday(&tv, NULL);
|
|
||||||
struct tm now;
|
|
||||||
getLocalTime(&now, 0);
|
|
||||||
liveData->params.chargingStartTime = liveData->params.currentTime = mktime(&now);
|
|
||||||
|
|
||||||
// Start BLE connection
|
|
||||||
Serial.println("Start BLE with PIN auth");
|
|
||||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
|
||||||
BLEDevice::init("");
|
|
||||||
|
|
||||||
// Retrieve a Scanner and set the callback we want to use to be informed when we have detected a new device.
|
|
||||||
// Specify that we want active scanning and start the scan to run for 10 seconds.
|
|
||||||
Serial.println("Setup BLE scan");
|
|
||||||
liveData->pBLEScan = BLEDevice::getScan();
|
|
||||||
liveData->pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
|
||||||
liveData->pBLEScan->setInterval(1349);
|
|
||||||
liveData->pBLEScan->setWindow(449);
|
|
||||||
liveData->pBLEScan->setActiveScan(true);
|
|
||||||
|
|
||||||
// Skip BLE scan if middle button pressed
|
|
||||||
if (strcmp(liveData->settings.obdMacAddress, "00:00:00:00:00:00") != 0 && !board->skipAdapterScan()) {
|
|
||||||
Serial.println(liveData->settings.obdMacAddress);
|
|
||||||
startBleScan();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SIM800L_ENABLED
|
|
||||||
sim800lSetup();
|
|
||||||
#endif //SIM800L_ENABLED
|
|
||||||
|
|
||||||
// Hold right button
|
|
||||||
board->afterSetup();
|
|
||||||
|
|
||||||
// End
|
// End
|
||||||
Serial.println("Device setup completed");
|
syslog->println("Device setup completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Loop
|
Main loop
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// Connect BLE device
|
|
||||||
if (liveData->bleConnect == true && liveData->foundMyBleDevice != NULL) {
|
|
||||||
liveData->pServerAddress = new BLEAddress(liveData->settings.obdMacAddress);
|
|
||||||
if (connectToServer(*liveData->pServerAddress)) {
|
|
||||||
|
|
||||||
liveData->bleConnected = true;
|
|
||||||
liveData->bleConnect = false;
|
|
||||||
|
|
||||||
Serial.println("We are now connected to the BLE device.");
|
|
||||||
|
|
||||||
// Print message
|
|
||||||
board->displayMessage(" > Processing init AT cmds", "");
|
|
||||||
|
|
||||||
// Serve first command (ATZ)
|
|
||||||
doNextAtCommand();
|
|
||||||
} else {
|
|
||||||
Serial.println("We have failed to connect to the server; there is nothing more we will do.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send command from TTY to OBD2
|
|
||||||
if (Serial.available()) {
|
|
||||||
ch = Serial.read();
|
|
||||||
if (ch == '\r' || ch == '\n') {
|
|
||||||
board->customConsoleCommand(line);
|
|
||||||
line = line + ch;
|
|
||||||
Serial.println(line);
|
|
||||||
if (liveData->bleConnected) {
|
|
||||||
liveData->pRemoteCharacteristicWrite->writeValue(line.c_str(), line.length());
|
|
||||||
}
|
|
||||||
line = "";
|
|
||||||
} else {
|
|
||||||
line = line + ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can send next command from queue to OBD
|
|
||||||
if (liveData->canSendNextAtCommand) {
|
|
||||||
liveData->canSendNextAtCommand = false;
|
|
||||||
doNextAtCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SIM800L_ENABLED
|
|
||||||
if (liveData->params.lastDataSent + SIM800L_TIMER < liveData->params.currentTime && liveData->params.sim800l_enabled) {
|
|
||||||
sendDataViaGPRS();
|
|
||||||
liveData->params.lastDataSent = liveData->params.currentTime;
|
|
||||||
}
|
|
||||||
#endif // SIM800L_ENABLED
|
|
||||||
|
|
||||||
board->mainLoop();
|
board->mainLoop();
|
||||||
if (board->scanDevices) {
|
|
||||||
board->scanDevices = false;
|
|
||||||
startBleScan();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
menu.h
43
menu.h
@@ -1,11 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "config.h";
|
|
||||||
|
|
||||||
MENU_ITEM menuItemsSource[100] = {
|
MENU_ITEM menuItemsSource[100] = {
|
||||||
|
|
||||||
{0, 0, 0, "<- exit menu"},
|
{0, 0, 0, "<- exit menu"},
|
||||||
{MENU_VEHICLE_TYPE, 0, -1, "Vehicle type"},
|
{MENU_VEHICLE_TYPE, 0, -1, "Vehicle type"},
|
||||||
|
{MENU_ADAPTER_TYPE, 0, -1, "Adapter type"},
|
||||||
{2, 0, -1, "Select OBD2 BLE4 adapter"},
|
{2, 0, -1, "Select OBD2 BLE4 adapter"},
|
||||||
{3, 0, -1, "Others"},
|
{3, 0, -1, "Others"},
|
||||||
{4, 0, -1, "Units"},
|
{4, 0, -1, "Units"},
|
||||||
@@ -21,14 +22,22 @@ MENU_ITEM menuItemsSource[100] = {
|
|||||||
{104, 1, -1, "Kia eNiro 2020 39kWh"},
|
{104, 1, -1, "Kia eNiro 2020 39kWh"},
|
||||||
{105, 1, -1, "Hyundai Kona 2020 39kWh"},
|
{105, 1, -1, "Hyundai Kona 2020 39kWh"},
|
||||||
{106, 1, -1, "Renault Zoe 22kWh (DEV)"},
|
{106, 1, -1, "Renault Zoe 22kWh (DEV)"},
|
||||||
{107, 1, -1, "Kia Niro PHEV 8.9kWh"},
|
{107, 1, -1, "Kia Niro PHEV 8.9kWh (DEV)"},
|
||||||
|
{108, 1, -1, "BMW i3 2014 22kWh (DEV)"},
|
||||||
{120, 1, -1, "Debug OBD2 Kia"},
|
{120, 1, -1, "Debug OBD2 Kia"},
|
||||||
|
|
||||||
|
{MENU_ADAPTER_BLE4-1, MENU_ADAPTER_TYPE, 0, "<- parent menu"},
|
||||||
|
{MENU_ADAPTER_BLE4, MENU_ADAPTER_TYPE, -1, "Bluetooth 4 (BLE4)"},
|
||||||
|
{MENU_ADAPTER_CAN, MENU_ADAPTER_TYPE, -1, "CAN bus (MCP2515-1/SO)"},
|
||||||
|
//{MENU_ADAPTER_BT3, MENU_ADAPTER_TYPE, -1, "Bluetooth 3 (dev)"},
|
||||||
|
|
||||||
{300, 3, 0, "<- parent menu"},
|
{300, 3, 0, "<- parent menu"},
|
||||||
// {MENU_WIFI, 3, -1, "[dev] WiFi network"},
|
// {MENU_WIFI, 3, -1, "[dev] WiFi network"},
|
||||||
{MENU_SDCARD, 3, -1, "SD card"},
|
{MENU_SDCARD, 3, -1, "SD card"},
|
||||||
{MENU_GPS, 3, -1, "GPS"},
|
{MENU_GPS, 3, -1, "GPS"},
|
||||||
{MENU_GPRS, 3, -1, "[dev] GSM/GPRS"},
|
{MENU_GPRS, 3, -1, "GSM/GPRS"},
|
||||||
|
{MENU_SERIAL_CONSOLE, 3, -1, "Serial console"},
|
||||||
|
{MENU_DEBUG_LEVEL, 3, -1, "Debug level"},
|
||||||
//{MENU_REMOTE_UPLOAD, 3, -1, "[dev] Remote upload"},
|
//{MENU_REMOTE_UPLOAD, 3, -1, "[dev] Remote upload"},
|
||||||
//{MENU_NTP, 3, -1, "[dev] NTP"},
|
//{MENU_NTP, 3, -1, "[dev] NTP"},
|
||||||
{MENU_SCREEN_ROTATION, 3, -1, "Screen rotation"},
|
{MENU_SCREEN_ROTATION, 3, -1, "Screen rotation"},
|
||||||
@@ -36,20 +45,7 @@ MENU_ITEM menuItemsSource[100] = {
|
|||||||
{MENU_SCREEN_BRIGHTNESS, 3, -1, "LCD brightness"},
|
{MENU_SCREEN_BRIGHTNESS, 3, -1, "LCD brightness"},
|
||||||
{MENU_PREDRAWN_GRAPHS, 3, -1, "Pre-drawn ch.graphs"},
|
{MENU_PREDRAWN_GRAPHS, 3, -1, "Pre-drawn ch.graphs"},
|
||||||
{MENU_HEADLIGHTS_REMINDER, 3, -1, "Headlight reminder"},
|
{MENU_HEADLIGHTS_REMINDER, 3, -1, "Headlight reminder"},
|
||||||
{MENU_DEBUG_SCREEN, 3, -1, "Debug screen"},
|
{MENU_SLEEP_MODE, 3, -1, "SleepMode"},
|
||||||
|
|
||||||
/*
|
|
||||||
// NTP
|
|
||||||
byte ntpEnabled; // 0/1
|
|
||||||
byte ntpTimezone;
|
|
||||||
byte ntpDaySaveTime; // 0/1
|
|
||||||
// GPRS SIM800L
|
|
||||||
byte gprsEnabled; // 0/1
|
|
||||||
char gprsApn[64];
|
|
||||||
// Remote upload
|
|
||||||
byte remoteUploadEnabled; // 0/1
|
|
||||||
char remoteApiUrl[64];
|
|
||||||
char remoteApiKey[32];*/
|
|
||||||
|
|
||||||
{400, 4, 0, "<- parent menu"},
|
{400, 4, 0, "<- parent menu"},
|
||||||
{MENU_DISTANCE_UNIT, 4, -1, "Distance"},
|
{MENU_DISTANCE_UNIT, 4, -1, "Distance"},
|
||||||
@@ -61,11 +57,12 @@ MENU_ITEM menuItemsSource[100] = {
|
|||||||
{MENU_WIFI_SSID, 301, -1, "SSID"},
|
{MENU_WIFI_SSID, 301, -1, "SSID"},
|
||||||
{MENU_WIFI_PASSWORD, 301, -1, "Password"},
|
{MENU_WIFI_PASSWORD, 301, -1, "Password"},
|
||||||
|
|
||||||
{3040, 304, 3, "<- parent menu"},
|
{MENU_SDCARD*10, MENU_SDCARD, 3, "<- parent menu"},
|
||||||
{MENU_SDCARD_ENABLED, 304, -1, "SD enabled"},
|
{MENU_SDCARD_ENABLED, MENU_SDCARD, -1, "SD enabled"},
|
||||||
{MENU_SDCARD_AUTOSTARTLOG, 304, -1, "Autostart log enabled"},
|
{MENU_SDCARD_AUTOSTARTLOG, MENU_SDCARD, -1, "Autostart log enabled"},
|
||||||
{MENU_SDCARD_MOUNT_STATUS, 304, -1, "Status"},
|
{MENU_SDCARD_MOUNT_STATUS, MENU_SDCARD, -1, "Status"},
|
||||||
{MENU_SDCARD_REC, 304, -1, "Record"},
|
{MENU_SDCARD_REC, MENU_SDCARD, -1, "Record"},
|
||||||
|
//{MENU_SDCARD_INTERVAL, MENU_SDCARD, -1, "Log interval sec."},
|
||||||
|
|
||||||
{3060, 306, 3, "<- parent menu"},
|
{3060, 306, 3, "<- parent menu"},
|
||||||
{3061, 306, -1, "Auto mode"},
|
{3061, 306, -1, "Auto mode"},
|
||||||
|
|||||||
BIN
screenshots/v2.jpg
Normal file
BIN
screenshots/v2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
BIN
screenshots/v2_m5charging2.jpg
Normal file
BIN
screenshots/v2_m5charging2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
screenshots/v2_m5speed.jpg
Normal file
BIN
screenshots/v2_m5speed.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
Reference in New Issue
Block a user