New error handling code
This commit is contained in:
parent
c4fe00fb40
commit
bf95ffed05
@ -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) {
|
||||||
{
|
DateTime now = rtc.now();
|
||||||
if (!dataFile)
|
file.print('\n');
|
||||||
{
|
file.print(now.year(), DEC);
|
||||||
Serial.println(F("Error opening file"));
|
file.print('-');
|
||||||
return;
|
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();
|
return ERROR_VALUE;
|
||||||
// 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(","));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getFilename()
|
void writeHeader() {
|
||||||
{
|
if (!headerWritten) {
|
||||||
DateTime now = rtc.now();
|
dataFile.print("\nDate Time,");
|
||||||
String mb = F("pm8k_");
|
const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]);
|
||||||
mb += now.year();
|
for (uint16_t i = 0; i < totalReg; i++) {
|
||||||
mb += now.month();
|
const uint16_t regaddr = pgm_read_word(®isters[i].regaddr);
|
||||||
mb += now.day();
|
dataFile.print("@");
|
||||||
mb += F(".csv");
|
dataFile.print(regaddr);
|
||||||
|
dataFile.print(",");
|
||||||
return mb;
|
}
|
||||||
|
headerWritten = true;
|
||||||
|
flicker(LED_A_PID, 50, 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char[20] filename = "20240523.csv";
|
void loop() {
|
||||||
|
if (!booted) {
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if (!booted)
|
|
||||||
{
|
|
||||||
Serial.print(F("\nBoot failed, cycle "));
|
|
||||||
|
|
||||||
delay(10000);
|
delay(10000);
|
||||||
digitalWrite(LED_A_PID, LOW);
|
digitalWrite(LED_A_PID, LOW);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delay(100);
|
|
||||||
String writebuffer;
|
|
||||||
|
|
||||||
if (millis() - lastRefreshTime >= 1000)
|
if (millis() - lastRefreshTime >= 1000) {
|
||||||
{
|
|
||||||
lastRefreshTime += 1000;
|
lastRefreshTime += 1000;
|
||||||
|
char filename[20];
|
||||||
|
getFilename(filename);
|
||||||
|
|
||||||
Serial.print(F("\nTime: "));
|
if (!dataFile.open(filename, FILE_WRITE)) {
|
||||||
Serial.print(rtc.now().timestamp());
|
flicker(LED_B_PID, 6, 500);
|
||||||
// Serial.print("\nHeep:");
|
return;
|
||||||
// Serial.print(ESP.getFreeHeap());
|
}
|
||||||
|
|
||||||
|
writeHeader();
|
||||||
|
writeDateTime(dataFile);
|
||||||
|
|
||||||
const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]);
|
const uint16_t totalReg = sizeof(registers) / sizeof(registers[0]);
|
||||||
float rawValues[totalReg] = {0};
|
float baseValues[4] = {ERROR_VALUE, ERROR_VALUE, ERROR_VALUE, ERROR_VALUE};
|
||||||
// Open File
|
uint8_t errorCount = 0;
|
||||||
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
|
|
||||||
|
|
||||||
|
// Single pass for both reading and processing
|
||||||
for (int i = 0; i < totalReg; i++) {
|
for (uint16_t i = 0; i < totalReg; i++) {
|
||||||
const uint16_t regaddr = pgm_read_word(®isters[i].regaddr);
|
const uint16_t regaddr = pgm_read_word(®isters[i].regaddr);
|
||||||
const uint8_t regtype = pgm_read_word(®isters[i].regtype);
|
const uint8_t regtype = pgm_read_word(®isters[i].regtype);
|
||||||
|
const float scale = pgm_read_float(®isters[i].scale);
|
||||||
if (regaddr > 0 && regtype <= 3) { // Only read direct registers
|
float value = ERROR_VALUE;
|
||||||
delay(10);
|
|
||||||
uint8_t result = node.readHoldingRegisters(regaddr - 1, 2);
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
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) {
|
switch(regtype) {
|
||||||
case 1:
|
case 4:
|
||||||
rawValues[i] = node.getResponseBuffer(0);
|
value = calculateStatusWord(baseValues);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 5:
|
||||||
rawValues[i] = getRegisterFloat(node.getResponseBuffer(0), node.getResponseBuffer(1));
|
value = calculateThermal(baseValues);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 6:
|
||||||
rawValues[i] = getRegisterInt64(node.getResponseBuffer(0), node.getResponseBuffer(1),
|
value = calculatePower(baseValues);
|
||||||
node.getResponseBuffer(2), node.getResponseBuffer(3));
|
break;
|
||||||
|
case 7:
|
||||||
|
value = calculateRPM(baseValues);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value != ERROR_VALUE) {
|
||||||
|
value *= scale;
|
||||||
|
}
|
||||||
|
dataFile.print(value);
|
||||||
|
dataFile.print(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second pass - process all registers including derived values
|
dataFile.close();
|
||||||
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);
|
if (errorCount > 0) {
|
||||||
float value = 0;
|
Serial.print(F("Cycle completed with "));
|
||||||
|
Serial.print(errorCount);
|
||||||
switch(regtype) {
|
Serial.println(F(" errors"));
|
||||||
case 1:
|
flicker(LED_B_PID, errorCount, 200);
|
||||||
case 2:
|
} else {
|
||||||
case 3:
|
Serial.println(F("Cycle completed successfully"));
|
||||||
value = rawValues[i] * scale;
|
flicker(LED_A_PID, 4, 100);
|
||||||
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(",");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errorCount > 5) {
|
||||||
Serial.print(F("\nRead buffer: "));
|
Serial.println(F("Too many errors, aborting cycle"));
|
||||||
delay(10);
|
dataFile.close();
|
||||||
|
return;
|
||||||
if (dataFile)
|
|
||||||
{
|
|
||||||
dataFile.close(); // Close the file
|
|
||||||
Serial.print(F("Data written to SD card: "));
|
|
||||||
Serial.print(filename.c_str());
|
|
||||||
Serial.print(F("\n"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.print(F("\n\n"));
|
|
||||||
|
|
||||||
flicker(LED_A_PID, 4, 100); // Cycle written 4 quick flickers
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// // Check if the read was successful
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user