diff --git a/Software/ChainLube/platformio.ini b/Software/ChainLube/platformio.ini index c275a9d..76a4cc6 100644 --- a/Software/ChainLube/platformio.ini +++ b/Software/ChainLube/platformio.ini @@ -48,4 +48,6 @@ lib_deps = sstaub/Ticker @ ^4.2.0 s00500/ESPUI @ ^2.0.0 coryjfowler/mcp_can @ ^1.5.0 - robtillaart/I2C_EEPROM @ ^1.5.2 \ No newline at end of file + robtillaart/I2C_EEPROM @ ^1.5.2 + plerup/EspSoftwareSerial @ ^6.15.2 + mikalhart/TinyGPSPlus @ ^1.0.3 \ No newline at end of file diff --git a/Software/ChainLube/src/dtc.cpp b/Software/ChainLube/src/dtc.cpp new file mode 100644 index 0000000..190fedb --- /dev/null +++ b/Software/ChainLube/src/dtc.cpp @@ -0,0 +1,76 @@ +#include "dtc.h" + +DTCEntry_s DTCStorage[MAX_DTC_STORAGE]; + +void MaintainDTC(uint32_t DTC_no, boolean active) +{ + for (int i = 0; i < MAX_DTC_STORAGE; i++) + { + if (DTCStorage[i].Number == DTC_no) + { + if (active == true) + { + DTCStorage[i].timestamp = millis(); + DTCStorage[i].active = DTC_ACTIVE; + return; + } + else + { + DTCStorage[i].active = DTCStorage[i].active == DTC_ACTIVE ? DTC_PREVIOUS : DTC_NONE; + return; + } + } + } + + // DTC was not found with upper iteration, but is active + // so we need to look for free space to store DTC + if (active == true) + { + for (int i = 0; i < MAX_DTC_STORAGE; i++) + { + if (DTCStorage[i].Number == 0) + { + DTCStorage[i].timestamp = millis(); + DTCStorage[i].active = DTC_ACTIVE; + return; + } + } + } +} + +void ClearDTC(uint32_t DTC_no) +{ + for (int i = 0; i < MAX_DTC_STORAGE; i++) + { + if (DTCStorage[i].Number == DTC_no) + { + DTCStorage[i].Number = 0; + } + } +} + +void ClearAllDTC() +{ + for (int i = 0; i < MAX_DTC_STORAGE; i++) + DTCStorage[i].Number = 0; +} + +uint32_t getlastDTC(boolean only_active) +{ + uint8_t pointer = 0; + uint32_t lasttimestamp = 0; + + for (int i = 0; i < MAX_DTC_STORAGE; i++) + { + if (DTCStorage[i].Number > 0 && DTCStorage[i].timestamp > lasttimestamp) + { + if (only_active == false || DTCStorage[i].active == DTC_ACTIVE) + { + pointer = i; + lasttimestamp = DTCStorage[i].timestamp; + } + } + } + + return pointer > 0 ? DTCStorage[pointer].Number : 0; +} diff --git a/Software/ChainLube/src/dtc.h b/Software/ChainLube/src/dtc.h new file mode 100644 index 0000000..3ed4a00 --- /dev/null +++ b/Software/ChainLube/src/dtc.h @@ -0,0 +1,29 @@ +#ifndef _DTC_H_ +#define _DTC_H_ + +#include + +#define MAX_DTC_STORAGE 16 + +#define DTC_NO_GPS_SERIAL 100 + +typedef enum DTCActive_e +{ +DTC_ACTIVE, +DTC_PREVIOUS, +DTC_NONE +} DTCActive_s; + +typedef struct DTCEntry_s +{ + uint32_t Number; + uint32_t timestamp; + DTCActive_s active; +} DTCEntry_t; + +void MaintainDTC(uint32_t DTC_no, boolean active); +void ClearDTC(uint32_t DTC_no); +void ClearAllDTC(); +uint32_t getlastDTC(boolean only_active); + +#endif \ No newline at end of file diff --git a/Software/ChainLube/src/gps.cpp b/Software/ChainLube/src/gps.cpp new file mode 100644 index 0000000..15e29d4 --- /dev/null +++ b/Software/ChainLube/src/gps.cpp @@ -0,0 +1,70 @@ +#include "gps.h" + +SoftwareSerial swSerGps; +TinyGPSPlus gps; + +void Init_GPS() +{ + uint32_t baudrate; + switch (LubeConfig.GPSBaudRate) + { + case BAUD_9600: + baudrate = 9600; + break; + case BAUD_115200: + baudrate = 115200; + break; + default: + baudrate = 4800; + break; + } + + Serial.printf(PSTR("Init GPS with Baud %d\n"), baudrate); + + swSerGps.begin(baudrate, SWSERIAL_8N1, GPIO_TRIGGER, -1, false, 256); + swSerGps.enableRx(true); + // high speed half duplex, turn off interrupts during tx + swSerGps.enableIntTx(false); + swSerGps.enableTx(false); + + // swSerGps.enableTx(true); + // swSerGps.write("Test"); + // swSerGps.enableTx(false); +} + +uint32_t Process_GPS_WheelSpeed() +{ + static uint32_t lastRecTimestamp; + static uint32_t lastValidSpeedTimestamp; + uint16_t RearWheelSpeed_kmh; + + while (swSerGps.available() > 0) + { + uint8_t incoming = swSerGps.read(); + if (gps.encode(incoming)) + { + RearWheelSpeed_kmh = gps.speed.isValid() ? gps.speed.kmph() : 0; + + if (RearWheelSpeed_kmh > 0) + { + uint32_t RWP_millimeter_per_second = ((uint32_t)RearWheelSpeed_kmh * 1000000) / 3600; + + uint32_t timesincelast = millis() - lastValidSpeedTimestamp; + lastValidSpeedTimestamp = millis(); + + uint32_t milimeters_to_add = (RWP_millimeter_per_second * timesincelast) / 1000; + + return milimeters_to_add; + } + lastRecTimestamp = millis(); + } + } + + if (millis() > lastRecTimestamp + 10000) + { + globals.systemStatus = sysStat_Error; + MaintainDTC(DTC_NO_GPS_SERIAL, true); + } + + return 0; +} diff --git a/Software/ChainLube/src/gps.h b/Software/ChainLube/src/gps.h new file mode 100644 index 0000000..12a0cda --- /dev/null +++ b/Software/ChainLube/src/gps.h @@ -0,0 +1,13 @@ +#ifndef _GPS_H_ +#define _GPS_H_ + +#include +#include +#include "config.h" +#include "common.h" +#include "dtc.h" + +void Init_GPS(); +uint32_t Process_GPS_WheelSpeed(); + +#endif \ No newline at end of file diff --git a/Software/ChainLube/src/main.cpp b/Software/ChainLube/src/main.cpp index 71e7618..153506e 100644 --- a/Software/ChainLube/src/main.cpp +++ b/Software/ChainLube/src/main.cpp @@ -15,6 +15,8 @@ #include "config.h" #include "globals.h" #include "can.h" +#include "gps.h" +#include "dtc.h" #ifdef REMOTE_DEBUG #include @@ -114,7 +116,7 @@ void setup() attachInterrupt(digitalPinToInterrupt(GPIO_TRIGGER), trigger_ISR, FALLING); break; case SOURCE_GPS: - + Init_GPS(); break; case SOURCE_TIME: @@ -206,6 +208,7 @@ void loop() case SOURCE_TIME: break; case SOURCE_GPS: + wheelDistance = Process_GPS_WheelSpeed(); break; } @@ -561,17 +564,33 @@ void LED_Process(uint8_t override, CRGB SetColor) void Display_Process() { + static tSystem_Status oldSysStatus = sysStat_Startup; + + if (oldSysStatus != globals.systemStatus) + { + u8x8.clearDisplay(); + u8x8.drawString(0, 0, "KTM ChainLube V1"); + oldSysStatus = globals.systemStatus; + } + u8x8.setCursor(0, 1); uint32_t DistRemain = globals.systemStatus == sysStat_Normal ? LubeConfig.DistancePerLube_Default : LubeConfig.DistancePerLube_Rain; DistRemain -= TravelDistance_highRes / 1000; - u8x8.printf("Mode: %10s\n", globals.systemStatustxt); - u8x8.printf("next Lube: %4dm\n", DistRemain); - u8x8.printf("Tank: %8dml\n", PersistenceData.tankRemain_µl / 1000); - u8x8.printf("WiFi: %10s\n", (WiFi.getMode() == WIFI_AP ? "AP" : WiFi.getMode() == WIFI_OFF ? "OFF" - : WiFi.getMode() == WIFI_STA ? "CLIENT" - : "UNKNOWN")); - u8x8.printf("Source: %8s\n", SpeedSourceString[LubeConfig.SpeedSource]); - u8x8.printf("EE_PDS: %6d s\n", EEPROMCyclicPDSTicker.remaining() / 1000); + u8x8.printf(PSTR("Mode: %10s\n"), globals.systemStatustxt); + if (globals.systemStatus == sysStat_Error) + { + u8x8.printf(PSTR("last DTC: %6d\n"), getlastDTC(false)); + } + else + { + u8x8.printf(PSTR("next Lube: %4dm\n"), DistRemain); + u8x8.printf(PSTR("Tank: %8dml\n"), PersistenceData.tankRemain_µl / 1000); + u8x8.printf(PSTR("WiFi: %10s\n"), (WiFi.getMode() == WIFI_AP ? "AP" : WiFi.getMode() == WIFI_OFF ? "OFF" + : WiFi.getMode() == WIFI_STA ? "CLIENT" + : "UNKNOWN")); + u8x8.printf(PSTR("Source: %8s\n"), SpeedSourceString[LubeConfig.SpeedSource]); + u8x8.printf("%s\n", WiFi.localIP().toString().c_str()); + } u8x8.refreshDisplay(); }