From bf95ffed05863d702de67b9cf8abcbbcd8f960f5 Mon Sep 17 00:00:00 2001 From: Warky Date: Wed, 4 Dec 2024 19:46:06 +0200 Subject: [PATCH] New error handling code --- .../modbus-sd-VSD-generic.ino | 356 ++++++++---------- 1 file changed, 158 insertions(+), 198 deletions(-) diff --git a/firmware/modbus-sd-VSD-generic/modbus-sd-VSD-generic.ino b/firmware/modbus-sd-VSD-generic/modbus-sd-VSD-generic.ino index e617035..4648d2a 100644 --- a/firmware/modbus-sd-VSD-generic/modbus-sd-VSD-generic.ino +++ b/firmware/modbus-sd-VSD-generic/modbus-sd-VSD-generic.ino @@ -1,52 +1,45 @@ #include #include - #include #include #include "util.h" #include "register_map_vsd.h" - -// #include - #include #include -#define SD_CS_PIN 10 // Chip Select for SD Card -// RS485 pins + +#define SD_CS_PIN 10 #define DE_RE_PIN 4 -#define RX_PIN 8 // SoftwareSerial RX pin -#define TX_PIN 7 // SoftwareSerial TX pin -#define SLAVE_ID 1 //From 1 – 10 (Normally 1) +#define RX_PIN 8 +#define TX_PIN 7 +#define SLAVE_ID 1 #define SERIAL_BAUDRATE 9600 #define MODBUS_SERIAL_BAUDRATE 19200 -#define SERIAL_CONFIG SERIAL_8E1 #define LED_A_PID 3 #define LED_B_PID 5 +#define MAX_RETRIES 3 +#define ERROR_VALUE -999.99 -// Try to select the best SD card configuration. #define SPI_CLOCK SD_SCK_MHZ(50) #if HAS_SDIO_CLASS #define SD_CONFIG SdioConfig(FIFO_SDIO) #elif ENABLE_DEDICATED_SPI #define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK) -#else // HAS_SDIO_CLASS +#else #define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK) -#endif // HAS_SDIO_CLASS +#endif -RTC_DS3231 rtc; // Create an RTC object +RTC_DS3231 rtc; SdFat32 sd; -// SdExFat sd; File dataFile; -NeoSWSerial modbusSerial(RX_PIN, TX_PIN); // Create a software serial instance +NeoSWSerial modbusSerial(RX_PIN, TX_PIN); ModbusMaster node; unsigned long lastRefreshTime = 0; bool headerWritten = false; bool booted = false; -void flicker(uint8_t pin, uint8_t times, uint16_t speed) -{ - for (int i = 0; i < times; i++) - { +void flicker(uint8_t pin, uint8_t times, uint16_t speed) { + while(times--) { delay(speed); digitalWrite(pin, HIGH); delay(speed); @@ -54,64 +47,40 @@ void flicker(uint8_t pin, uint8_t times, uint16_t speed) } } -void setup() -{ +void setup() { booted = false; pinMode(LED_A_PID, OUTPUT); pinMode(LED_B_PID, OUTPUT); digitalWrite(LED_A_PID, LOW); digitalWrite(LED_B_PID, HIGH); - Serial.begin(SERIAL_BAUDRATE); // For debugging + Serial.begin(SERIAL_BAUDRATE); Serial.println(F("Startup \n")); - // Initialize RTC - if (!rtc.begin()) - { + if (!rtc.begin()) { Serial.println(F("Couldn't find RTC\n")); - flicker(LED_B_PID, 4, 1000); // 4 times on LED b is RTC Error + flicker(LED_B_PID, 4, 1000); digitalWrite(LED_B_PID, HIGH); digitalWrite(LED_A_PID, HIGH); return; } - if (rtc.lostPower()) - { + if (rtc.lostPower()) { Serial.println(F("RTC lost power, let's set the time!\n")); - // Comment out the following line once the time is set to avoid resetting on every start rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); - flicker(LED_B_PID, 4, 500); // 6 times fast on LED b is RTC reset + flicker(LED_B_PID, 4, 500); } - Serial.print(F("Time: ")); - Serial.print(rtc.now().timestamp()); - Serial.println(F("\n")); - - // Initialize SD card - Serial.println(F("SD card initializing...")); pinMode(SD_CS_PIN, OUTPUT); - - // if (!SD.begin(SPI_HALF_SPEED, SD_CS_PIN )) - // { - // Serial.println(F("SD card initialization failed!\n")); - // return; - // } - // Initialize the SD. - if (!sd.begin(SD_CONFIG)) - { + if (!sd.begin(SD_CONFIG)) { flicker(LED_B_PID, 2, 1000); digitalWrite(LED_B_PID, HIGH); sd.initErrorHalt(&Serial); - - // 2 Times slow and stay on, SD Card initilize error return; } - Serial.println(F("SD card initialized.\n")); - - Serial.println(F("Initialize RS485 module / Modbus \n")); pinMode(DE_RE_PIN, OUTPUT); - digitalWrite(DE_RE_PIN, LOW); // Set to LOW for receiving mode initially + digitalWrite(DE_RE_PIN, LOW); modbusSerial.begin(MODBUS_SERIAL_BAUDRATE); node.begin(SLAVE_ID, modbusSerial); @@ -122,185 +91,176 @@ void setup() booted = true; } -void preTransmission() -{ - // Serial.println(F("Transmitting Start")); - digitalWrite(DE_RE_PIN, HIGH); // Enable RS485 transmit +void preTransmission() { + digitalWrite(DE_RE_PIN, HIGH); digitalWrite(LED_A_PID, HIGH); } -void postTransmission() -{ - - digitalWrite(DE_RE_PIN, LOW); // Disable RS485 transmit +void postTransmission() { + digitalWrite(DE_RE_PIN, LOW); digitalWrite(LED_A_PID, LOW); - // Serial.println(F("Transmitting End")); } -void primeFileDate() -{ - if (!dataFile) - { - Serial.println(F("Error opening file")); - return; +void writeDateTime(File &file) { + DateTime now = rtc.now(); + file.print('\n'); + file.print(now.year(), DEC); + file.print('-'); + file.print(now.month(), DEC); + file.print('-'); + file.print(now.day(), DEC); + file.print(' '); + file.print(now.hour(), DEC); + file.print(':'); + file.print(now.minute(), DEC); + file.print(':'); + file.print(now.second(), DEC); + file.print(','); +} + +void getFilename(char* buffer) { + DateTime now = rtc.now(); + sprintf(buffer, "pm8k_%d%02d%02d.csv", now.year(), now.month(), now.day()); +} + +float readRegisterWithRetry(uint16_t addr, uint8_t regtype) { + for(uint8_t retry = 0; retry < MAX_RETRIES; retry++) { + delay(10); + uint8_t result = node.readHoldingRegisters(addr - 1, 2); + if(result == node.ku8MBSuccess) { + switch(regtype) { + case 1: + return node.getResponseBuffer(0); + case 2: + return getRegisterFloat(node.getResponseBuffer(0), node.getResponseBuffer(1)); + case 3: + return getRegisterInt64(node.getResponseBuffer(0), node.getResponseBuffer(1), + node.getResponseBuffer(2), node.getResponseBuffer(3)); + } + } + Serial.print(F("Read error at register ")); + Serial.print(addr); + Serial.print(F(", attempt ")); + Serial.print(retry + 1); + Serial.print(F(" of ")); + Serial.print(MAX_RETRIES); + Serial.print(F(", error code: ")); + Serial.println(result); + + delay(50 * (retry + 1)); + flicker(LED_B_PID, 1, 50); } - DateTime now = rtc.now(); - // Log the current date and time - dataFile.print("\n"); - dataFile.print(now.year(), DEC); - dataFile.print('-'); - dataFile.print(now.month(), DEC); - dataFile.print('-'); - dataFile.print(now.day(), DEC); - dataFile.print(" "); - dataFile.print(now.hour(), DEC); - dataFile.print(':'); - dataFile.print(now.minute(), DEC); - dataFile.print(':'); - dataFile.print(now.second(), DEC); - dataFile.print(F(",")); + return ERROR_VALUE; } -String getFilename() -{ - DateTime now = rtc.now(); - String mb = F("pm8k_"); - mb += now.year(); - mb += now.month(); - mb += now.day(); - mb += F(".csv"); - - return mb; +void writeHeader() { + if (!headerWritten) { + dataFile.print("\nDate Time,"); + const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]); + for (uint16_t i = 0; i < totalReg; i++) { + const uint16_t regaddr = pgm_read_word(®isters[i].regaddr); + dataFile.print("@"); + dataFile.print(regaddr); + dataFile.print(","); + } + headerWritten = true; + flicker(LED_A_PID, 50, 10); + } } -// const char[20] filename = "20240523.csv"; - -void loop() -{ - if (!booted) - { - Serial.print(F("\nBoot failed, cycle ")); - +void loop() { + if (!booted) { delay(10000); digitalWrite(LED_A_PID, LOW); return; } - delay(100); - String writebuffer; - if (millis() - lastRefreshTime >= 1000) - { + if (millis() - lastRefreshTime >= 1000) { lastRefreshTime += 1000; + char filename[20]; + getFilename(filename); - Serial.print(F("\nTime: ")); - Serial.print(rtc.now().timestamp()); - // Serial.print("\nHeep:"); - // Serial.print(ESP.getFreeHeap()); + if (!dataFile.open(filename, FILE_WRITE)) { + flicker(LED_B_PID, 6, 500); + return; + } + + writeHeader(); + writeDateTime(dataFile); + const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]); - float rawValues[totalReg] = {0}; - // Open File - String filename = getFilename(); - Serial.print(F("Open Card ")); - Serial.print(filename.c_str()); - Serial.print("\n"); - if (!dataFile.open(filename.c_str(), FILE_WRITE)) - { - flicker(LED_B_PID, 6, 500); // Six quick flickers. SD Card error - Serial.println(F("Failed to Open Card ")); - } - if (!headerWritten) - { - dataFile.print("\nDate Time,"); - for (int i = 0; i < totalReg; i++) - { - const uint16_t regaddr = pgm_read_word(®isters[i].regaddr); - dataFile.print("@"); - dataFile.print(regaddr); - dataFile.print(","); - } - headerWritten = true; - flicker(LED_A_PID, 50, 10); // 10 flickers, written header - } - primeFileDate(); - - Serial.print("\n"); - Serial.println(totalReg); - - // First pass - read all base registers + float baseValues[4] = {ERROR_VALUE, ERROR_VALUE, ERROR_VALUE, ERROR_VALUE}; + uint8_t errorCount = 0; - - for (int i = 0; i < totalReg; i++) { + // Single pass for both reading and processing + for (uint16_t i = 0; i < totalReg; i++) { const uint16_t regaddr = pgm_read_word(®isters[i].regaddr); const uint8_t regtype = pgm_read_word(®isters[i].regtype); - - if (regaddr > 0 && regtype <= 3) { // Only read direct registers - delay(10); - uint8_t result = node.readHoldingRegisters(regaddr - 1, 2); - delay(10); + const float scale = pgm_read_float(®isters[i].scale); + float value = ERROR_VALUE; - if (result == node.ku8MBSuccess) { + if (regtype <= 3 && regaddr > 0) { + value = readRegisterWithRetry(regaddr, regtype); + if (value == ERROR_VALUE) { + errorCount++; + if (errorCount > 5) { + dataFile.close(); + flicker(LED_B_PID, 10, 100); + return; + } + } + if (i < 4) baseValues[i] = value; + } else { + bool validBase = true; + for(uint8_t j = 0; j < 4; j++) { + if (baseValues[j] == ERROR_VALUE) { + validBase = false; + break; + } + } + + if (validBase) { switch(regtype) { - case 1: - rawValues[i] = node.getResponseBuffer(0); + case 4: + value = calculateStatusWord(baseValues); break; - case 2: - rawValues[i] = getRegisterFloat(node.getResponseBuffer(0), node.getResponseBuffer(1)); + case 5: + value = calculateThermal(baseValues); break; - case 3: - rawValues[i] = getRegisterInt64(node.getResponseBuffer(0), node.getResponseBuffer(1), - node.getResponseBuffer(2), node.getResponseBuffer(3)); + case 6: + value = calculatePower(baseValues); + break; + case 7: + value = calculateRPM(baseValues); break; } } } + + if (value != ERROR_VALUE) { + value *= scale; + } + dataFile.print(value); + dataFile.print(','); } - // Second pass - process all registers including derived values - for (int i = 0; i < totalReg; i++) { - const uint8_t regtype = pgm_read_word(®isters[i].regtype); - const float scale = pgm_read_float(®isters[i].scale); - float value = 0; - - switch(regtype) { - case 1: - case 2: - case 3: - value = rawValues[i] * scale; - break; - case 4: - value = calculateStatusWord(rawValues) * scale; - break; - case 5: - value = calculateThermal(rawValues) * scale; - break; - case 6: - value = calculatePower(rawValues) * scale; - break; - case 7: - value = calculateRPM(rawValues) * scale; - break; - } - - dataFile.print(value); - dataFile.print(","); + dataFile.close(); + + + if (errorCount > 0) { + Serial.print(F("Cycle completed with ")); + Serial.print(errorCount); + Serial.println(F(" errors")); + flicker(LED_B_PID, errorCount, 200); + } else { + Serial.println(F("Cycle completed successfully")); + flicker(LED_A_PID, 4, 100); } - - Serial.print(F("\nRead buffer: ")); - delay(10); - - if (dataFile) - { - dataFile.close(); // Close the file - Serial.print(F("Data written to SD card: ")); - Serial.print(filename.c_str()); - Serial.print(F("\n")); + if (errorCount > 5) { + Serial.println(F("Too many errors, aborting cycle")); + dataFile.close(); + return; } - - Serial.print(F("\n\n")); - - flicker(LED_A_PID, 4, 100); // Cycle written 4 quick flickers } - - // // Check if the read was successful -} +} \ No newline at end of file