New error handling code

This commit is contained in:
Warky 2024-12-04 19:46:06 +02:00
parent c4fe00fb40
commit bf95ffed05

View File

@ -1,52 +1,45 @@
#include <Wire.h> #include <Wire.h>
#include <RTClib.h> #include <RTClib.h>
#include <NeoSWSerial.h> #include <NeoSWSerial.h>
#include <ModbusMaster.h> #include <ModbusMaster.h>
#include "util.h" #include "util.h"
#include "register_map_vsd.h" #include "register_map_vsd.h"
// #include <SD.h>
#include <SPI.h> #include <SPI.h>
#include <SdFat.h> #include <SdFat.h>
#define SD_CS_PIN 10 // Chip Select for SD Card
// RS485 pins #define SD_CS_PIN 10
#define DE_RE_PIN 4 #define DE_RE_PIN 4
#define RX_PIN 8 // SoftwareSerial RX pin #define RX_PIN 8
#define TX_PIN 7 // SoftwareSerial TX pin #define TX_PIN 7
#define SLAVE_ID 1 //From 1 10 (Normally 1) #define SLAVE_ID 1
#define SERIAL_BAUDRATE 9600 #define SERIAL_BAUDRATE 9600
#define MODBUS_SERIAL_BAUDRATE 19200 #define MODBUS_SERIAL_BAUDRATE 19200
#define SERIAL_CONFIG SERIAL_8E1
#define LED_A_PID 3 #define LED_A_PID 3
#define LED_B_PID 5 #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) #define SPI_CLOCK SD_SCK_MHZ(50)
#if HAS_SDIO_CLASS #if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO) #define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI #elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK) #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) #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; SdFat32 sd;
// SdExFat sd;
File dataFile; File dataFile;
NeoSWSerial modbusSerial(RX_PIN, TX_PIN); // Create a software serial instance NeoSWSerial modbusSerial(RX_PIN, TX_PIN);
ModbusMaster node; ModbusMaster node;
unsigned long lastRefreshTime = 0; unsigned long lastRefreshTime = 0;
bool headerWritten = false; bool headerWritten = false;
bool booted = false; bool booted = false;
void flicker(uint8_t pin, uint8_t times, uint16_t speed) void flicker(uint8_t pin, uint8_t times, uint16_t speed) {
{ while(times--) {
for (int i = 0; i < times; i++)
{
delay(speed); delay(speed);
digitalWrite(pin, HIGH); digitalWrite(pin, HIGH);
delay(speed); delay(speed);
@ -54,64 +47,40 @@ void flicker(uint8_t pin, uint8_t times, uint16_t speed)
} }
} }
void setup() void setup() {
{
booted = false; booted = false;
pinMode(LED_A_PID, OUTPUT); pinMode(LED_A_PID, OUTPUT);
pinMode(LED_B_PID, OUTPUT); pinMode(LED_B_PID, OUTPUT);
digitalWrite(LED_A_PID, LOW); digitalWrite(LED_A_PID, LOW);
digitalWrite(LED_B_PID, HIGH); digitalWrite(LED_B_PID, HIGH);
Serial.begin(SERIAL_BAUDRATE); // For debugging Serial.begin(SERIAL_BAUDRATE);
Serial.println(F("Startup \n")); Serial.println(F("Startup \n"));
// Initialize RTC if (!rtc.begin()) {
if (!rtc.begin())
{
Serial.println(F("Couldn't find RTC\n")); 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_B_PID, HIGH);
digitalWrite(LED_A_PID, HIGH); digitalWrite(LED_A_PID, HIGH);
return; return;
} }
if (rtc.lostPower()) if (rtc.lostPower()) {
{
Serial.println(F("RTC lost power, let's set the time!\n")); 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__))); 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); pinMode(SD_CS_PIN, OUTPUT);
if (!sd.begin(SD_CONFIG)) {
// 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))
{
flicker(LED_B_PID, 2, 1000); flicker(LED_B_PID, 2, 1000);
digitalWrite(LED_B_PID, HIGH); digitalWrite(LED_B_PID, HIGH);
sd.initErrorHalt(&Serial); sd.initErrorHalt(&Serial);
// 2 Times slow and stay on, SD Card initilize error
return; return;
} }
Serial.println(F("SD card initialized.\n"));
Serial.println(F("Initialize RS485 module / Modbus \n"));
pinMode(DE_RE_PIN, OUTPUT); 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); modbusSerial.begin(MODBUS_SERIAL_BAUDRATE);
node.begin(SLAVE_ID, modbusSerial); node.begin(SLAVE_ID, modbusSerial);
@ -122,185 +91,176 @@ void setup()
booted = true; booted = true;
} }
void preTransmission() void preTransmission() {
{ digitalWrite(DE_RE_PIN, HIGH);
// Serial.println(F("Transmitting Start"));
digitalWrite(DE_RE_PIN, HIGH); // Enable RS485 transmit
digitalWrite(LED_A_PID, HIGH); digitalWrite(LED_A_PID, HIGH);
} }
void postTransmission() void postTransmission() {
{ digitalWrite(DE_RE_PIN, LOW);
digitalWrite(DE_RE_PIN, LOW); // Disable RS485 transmit
digitalWrite(LED_A_PID, LOW); digitalWrite(LED_A_PID, LOW);
// Serial.println(F("Transmitting End"));
} }
void primeFileDate() void writeDateTime(File &file) {
{
if (!dataFile)
{
Serial.println(F("Error opening file"));
return;
}
DateTime now = rtc.now(); DateTime now = rtc.now();
// Log the current date and time file.print('\n');
dataFile.print("\n"); file.print(now.year(), DEC);
dataFile.print(now.year(), DEC); file.print('-');
dataFile.print('-'); file.print(now.month(), DEC);
dataFile.print(now.month(), DEC); file.print('-');
dataFile.print('-'); file.print(now.day(), DEC);
dataFile.print(now.day(), DEC); file.print(' ');
dataFile.print(" "); file.print(now.hour(), DEC);
dataFile.print(now.hour(), DEC); file.print(':');
dataFile.print(':'); file.print(now.minute(), DEC);
dataFile.print(now.minute(), DEC); file.print(':');
dataFile.print(':'); file.print(now.second(), DEC);
dataFile.print(now.second(), DEC); file.print(',');
dataFile.print(F(","));
} }
String getFilename() void getFilename(char* buffer) {
{
DateTime now = rtc.now(); DateTime now = rtc.now();
String mb = F("pm8k_"); sprintf(buffer, "pm8k_%d%02d%02d.csv", now.year(), now.month(), now.day());
mb += now.year();
mb += now.month();
mb += now.day();
mb += F(".csv");
return mb;
} }
// const char[20] filename = "20240523.csv"; float readRegisterWithRetry(uint16_t addr, uint8_t regtype) {
for(uint8_t retry = 0; retry < MAX_RETRIES; retry++) {
void loop() delay(10);
{ uint8_t result = node.readHoldingRegisters(addr - 1, 2);
if (!booted) if(result == node.ku8MBSuccess) {
{ switch(regtype) {
Serial.print(F("\nBoot failed, cycle ")); case 1:
return node.getResponseBuffer(0);
delay(10000); case 2:
digitalWrite(LED_A_PID, LOW); return getRegisterFloat(node.getResponseBuffer(0), node.getResponseBuffer(1));
return; case 3:
return getRegisterInt64(node.getResponseBuffer(0), node.getResponseBuffer(1),
node.getResponseBuffer(2), node.getResponseBuffer(3));
} }
delay(100);
String writebuffer;
if (millis() - lastRefreshTime >= 1000)
{
lastRefreshTime += 1000;
Serial.print(F("\nTime: "));
Serial.print(rtc.now().timestamp());
// Serial.print("\nHeep:");
// Serial.print(ESP.getFreeHeap());
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) 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);
}
return ERROR_VALUE;
}
void writeHeader() {
if (!headerWritten) {
dataFile.print("\nDate Time,"); dataFile.print("\nDate Time,");
for (int i = 0; i < totalReg; i++) const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]);
{ for (uint16_t i = 0; i < totalReg; i++) {
const uint16_t regaddr = pgm_read_word(&registers[i].regaddr); const uint16_t regaddr = pgm_read_word(&registers[i].regaddr);
dataFile.print("@"); dataFile.print("@");
dataFile.print(regaddr); dataFile.print(regaddr);
dataFile.print(","); dataFile.print(",");
} }
headerWritten = true; headerWritten = true;
flicker(LED_A_PID, 50, 10); // 10 flickers, written header flicker(LED_A_PID, 50, 10);
}
} }
primeFileDate();
Serial.print("\n"); void loop() {
Serial.println(totalReg); if (!booted) {
delay(10000);
digitalWrite(LED_A_PID, LOW);
return;
}
// First pass - read all base registers if (millis() - lastRefreshTime >= 1000) {
lastRefreshTime += 1000;
char filename[20];
getFilename(filename);
if (!dataFile.open(filename, FILE_WRITE)) {
flicker(LED_B_PID, 6, 500);
return;
}
for (int i = 0; i < totalReg; i++) { writeHeader();
writeDateTime(dataFile);
const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]);
float baseValues[4] = {ERROR_VALUE, ERROR_VALUE, ERROR_VALUE, ERROR_VALUE};
uint8_t errorCount = 0;
// Single pass for both reading and processing
for (uint16_t i = 0; i < totalReg; i++) {
const uint16_t regaddr = pgm_read_word(&registers[i].regaddr); const uint16_t regaddr = pgm_read_word(&registers[i].regaddr);
const uint8_t regtype = pgm_read_word(&registers[i].regtype); const uint8_t regtype = pgm_read_word(&registers[i].regtype);
if (regaddr > 0 && regtype <= 3) { // Only read direct registers
delay(10);
uint8_t result = node.readHoldingRegisters(regaddr - 1, 2);
delay(10);
if (result == node.ku8MBSuccess) {
switch(regtype) {
case 1:
rawValues[i] = node.getResponseBuffer(0);
break;
case 2:
rawValues[i] = getRegisterFloat(node.getResponseBuffer(0), node.getResponseBuffer(1));
break;
case 3:
rawValues[i] = getRegisterInt64(node.getResponseBuffer(0), node.getResponseBuffer(1),
node.getResponseBuffer(2), node.getResponseBuffer(3));
break;
}
}
}
}
// Second pass - process all registers including derived values
for (int i = 0; i < totalReg; i++) {
const uint8_t regtype = pgm_read_word(&registers[i].regtype);
const float scale = pgm_read_float(&registers[i].scale); const float scale = pgm_read_float(&registers[i].scale);
float value = 0; float value = ERROR_VALUE;
switch(regtype) { if (regtype <= 3 && regaddr > 0) {
case 1: value = readRegisterWithRetry(regaddr, regtype);
case 2: if (value == ERROR_VALUE) {
case 3: errorCount++;
value = rawValues[i] * scale; 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; break;
}
}
if (validBase) {
switch(regtype) {
case 4: case 4:
value = calculateStatusWord(rawValues) * scale; value = calculateStatusWord(baseValues);
break; break;
case 5: case 5:
value = calculateThermal(rawValues) * scale; value = calculateThermal(baseValues);
break; break;
case 6: case 6:
value = calculatePower(rawValues) * scale; value = calculatePower(baseValues);
break; break;
case 7: case 7:
value = calculateRPM(rawValues) * scale; value = calculateRPM(baseValues);
break; break;
} }
}
}
if (value != ERROR_VALUE) {
value *= scale;
}
dataFile.print(value); dataFile.print(value);
dataFile.print(","); dataFile.print(',');
} }
dataFile.close();
Serial.print(F("\nRead buffer: "));
delay(10);
if (dataFile) if (errorCount > 0) {
{ Serial.print(F("Cycle completed with "));
dataFile.close(); // Close the file Serial.print(errorCount);
Serial.print(F("Data written to SD card: ")); Serial.println(F(" errors"));
Serial.print(filename.c_str()); flicker(LED_B_PID, errorCount, 200);
Serial.print(F("\n")); } else {
Serial.println(F("Cycle completed successfully"));
flicker(LED_A_PID, 4, 100);
} }
Serial.print(F("\n\n")); if (errorCount > 5) {
Serial.println(F("Too many errors, aborting cycle"));
flicker(LED_A_PID, 4, 100); // Cycle written 4 quick flickers dataFile.close();
return;
}
} }
// // Check if the read was successful
} }