From 8b166ac4e93aa867cb3a07395ecddf2f87406948 Mon Sep 17 00:00:00 2001 From: Stuart Pittaway <1201909+stuartpittaway@users.noreply.github.com> Date: Wed, 5 Jan 2022 10:35:43 +0000 Subject: [PATCH] Bug fix branch #70 (#78) * Improvements for controllers with lots of modules --- .../include/PacketRequestGenerator.h | 69 +- ESPController/src/DIYBMSServer.cpp | 298 +++--- ESPController/src/PacketReceiveProcessor.cpp | 10 +- ESPController/src/PacketRequestGenerator.cpp | 79 +- ESPController/src/main.cpp | 969 +++++++++--------- ESPController/web_src/default.htm | 1 + ESPController/web_src/pagecode.js | 2 + 7 files changed, 731 insertions(+), 697 deletions(-) diff --git a/ESPController/include/PacketRequestGenerator.h b/ESPController/include/PacketRequestGenerator.h index 53d71fe1..93ff99d5 100644 --- a/ESPController/include/PacketRequestGenerator.h +++ b/ESPController/include/PacketRequestGenerator.h @@ -5,60 +5,67 @@ #include #include -//command byte -// WRRR CCCC -// W = 1 bit indicator packet was processed (controller send (0) module processed (1)) -// R = 3 bits reserved not used -// C = 4 bits command (16 possible commands) +// command byte +// WRRR CCCC +// W = 1 bit indicator packet was processed (controller send (0) module processed (1)) +// R = 3 bits reserved not used +// C = 4 bits command (16 possible commands) -//commands -// 1000 0000 = set bank identity -// 0000 0001 = read voltage and status -// 0000 0010 = identify module (flash leds) -// 0000 0011 = Read temperature -// 0000 0100 = Report number of bad packets -// 0000 0101 = Report settings/configuration +// commands +// 1000 0000 = set bank identity +// 0000 0001 = read voltage and status +// 0000 0010 = identify module (flash leds) +// 0000 0011 = Read temperature +// 0000 0100 = Report number of bad packets +// 0000 0101 = Report settings/configuration class PacketRequestGenerator { public: PacketRequestGenerator(cppQueue *requestQ) { _requestq = requestQ; } ~PacketRequestGenerator() {} - void sendGetSettingsRequest(uint8_t cellid); - void sendIdentifyModuleRequest(uint8_t cellid); - void sendSaveSetting(uint8_t m, uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown, float Calibration); - void sendSaveGlobalSetting(uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown); - void sendReadBadPacketCounter(uint8_t startmodule, uint8_t endmodule); + bool sendGetSettingsRequest(uint8_t cellid); + bool sendIdentifyModuleRequest(uint8_t cellid); + bool sendSaveSetting(uint8_t m, uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown, float Calibration); + bool sendSaveGlobalSetting(uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown); + bool sendReadBadPacketCounter(uint8_t startmodule, uint8_t endmodule); - void sendCellVoltageRequest(uint8_t startmodule, uint8_t endmodule); - void sendCellTemperatureRequest(uint8_t startmodule, uint8_t endmodule); - void sendReadBalancePowerRequest(uint8_t startmodule, uint8_t endmodule); - void sendReadBalanceCurrentCountRequest(uint8_t startmodule, uint8_t endmodule); - void sendReadPacketsReceivedRequest(uint8_t startmodule, uint8_t endmodule); - void sendBadPacketCounterReset(); - void sendTimingRequest(); - void sendResetBalanceCurrentCounter(); + bool sendCellVoltageRequest(uint8_t startmodule, uint8_t endmodule); + bool sendCellTemperatureRequest(uint8_t startmodule, uint8_t endmodule); + bool sendReadBalancePowerRequest(uint8_t startmodule, uint8_t endmodule); + bool sendReadBalanceCurrentCountRequest(uint8_t startmodule, uint8_t endmodule); + bool sendReadPacketsReceivedRequest(uint8_t startmodule, uint8_t endmodule); + bool sendBadPacketCounterReset(); + bool sendTimingRequest(); + bool sendResetBalanceCurrentCounter(); - uint32_t packetsGenerated = 0; + uint16_t queueLength() { + return _requestq->getCount(); + } + void ResetCounters() + { + packetsGenerated = 0; + } + uint32_t packetsGenerated = 0; + private: cppQueue *_requestq; - void pushPacketToQueue(PacketStruct *_packetbuffer); - void setPacketAddress(PacketStruct *_packetbuffer, uint8_t module); + bool pushPacketToQueue(PacketStruct *_packetbuffer); + void setPacketAddress(PacketStruct *_packetbuffer, uint8_t module); void setPacketAddressModuleRange(PacketStruct *_packetbuffer, uint8_t startmodule, uint8_t endmodule); void setPacketAddressBroadcast(PacketStruct *_packetbuffer); void setmoduledataFFFF(PacketStruct *_packetbuffer); void clearSettingsForAllModules(); - void BuildAndSendRequest(COMMAND command,uint8_t startmodule, uint8_t endmodule); - void BuildAndSendRequest(COMMAND command); + bool BuildAndSendRequest(COMMAND command, uint8_t startmodule, uint8_t endmodule); + bool BuildAndSendRequest(COMMAND command); void clearPacket(PacketStruct *_packetbuffer) { memset(_packetbuffer, 0, sizeof(PacketStruct)); } - }; #endif diff --git a/ESPController/src/DIYBMSServer.cpp b/ESPController/src/DIYBMSServer.cpp index c72dd8ce..42698f44 100644 --- a/ESPController/src/DIYBMSServer.cpp +++ b/ESPController/src/DIYBMSServer.cpp @@ -88,8 +88,8 @@ void DIYBMSServer::generateUUID() { uint8_t uuidNumber[16]; // UUIDs in binary form are 16 bytes long - //ESP32 has inbuilt random number generator - //https://techtutorialsx.com/2017/12/22/esp32-arduino-random-number-generation/ + // ESP32 has inbuilt random number generator + // https://techtutorialsx.com/2017/12/22/esp32-arduino-random-number-generation/ for (uint8_t x = 0; x < 16; x++) { uuidNumber[x] = random(0xFF); @@ -97,7 +97,7 @@ void DIYBMSServer::generateUUID() UUIDString = uuidToString(uuidNumber); - //481efb3f-0400-0000-101f-fb3fd01efb3f + // 481efb3f-0400-0000-101f-fb3fd01efb3f UUIDStringLast2Chars = UUIDString.substring(34); } @@ -156,11 +156,11 @@ void DIYBMSServer::saveConfigurationToSDCard(AsyncWebServerRequest *request) struct tm timeinfo; - //getLocalTime has delay() functions in it :-( + // getLocalTime has delay() functions in it :-( if (getLocalTime(&timeinfo, 1)) { timeinfo.tm_year += 1900; - //Month is 0 to 11 based! + // Month is 0 to 11 based! timeinfo.tm_mon++; } else @@ -171,10 +171,10 @@ void DIYBMSServer::saveConfigurationToSDCard(AsyncWebServerRequest *request) char filename[128]; sprintf(filename, "/backup_config_%04u%02u%02u_%02u%02u%02u.json", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); - //ESP_LOGI(TAG, "Creating folder"); + // ESP_LOGI(TAG, "Creating folder"); //_sdcard->mkdir("/diybms"); - //Get the file + // Get the file ESP_LOGI(TAG, "Generating SD file %s", filename); if (_sdcard->exists(filename)) @@ -185,7 +185,7 @@ void DIYBMSServer::saveConfigurationToSDCard(AsyncWebServerRequest *request) StaticJsonDocument<4096> doc; - //This code builds up a JSON document which mirrors the structure "diybms_eeprom_settings" + // This code builds up a JSON document which mirrors the structure "diybms_eeprom_settings" JsonObject root = doc.createNestedObject("diybms_settings"); root["totalNumberOfBanks"] = _mysettings->totalNumberOfBanks; @@ -248,8 +248,8 @@ void DIYBMSServer::saveConfigurationToSDCard(AsyncWebServerRequest *request) { String elementName = String("rule") + String(rr); - //Map enum to string so when this file is re-imported we are not locked to specific index offsets - //which may no longer map to the correct rule + // Map enum to string so when this file is re-imported we are not locked to specific index offsets + // which may no longer map to the correct rule switch (rr) { case Rule::EmergencyStop: @@ -309,7 +309,7 @@ void DIYBMSServer::saveConfigurationToSDCard(AsyncWebServerRequest *request) { relaystate.add(_mysettings->rulerelaystate[rr][rt]); } - } //end for + } // end for JsonObject victron = root.createNestedObject("victron"); JsonArray cvl = victron.createNestedArray("cvl"); @@ -330,7 +330,7 @@ struct diybms_eeprom_settings }; */ - //wifi["password"] = DIYBMSSoftAP::Config()->wifi_passphrase; + // wifi["password"] = DIYBMSSoftAP::Config()->wifi_passphrase; File file = _sdcard->open(filename, "w"); serializeJson(doc, file); @@ -360,7 +360,7 @@ void DIYBMSServer::saveWifiConfigToSDCard(AsyncWebServerRequest *request) ESP_LOGI(TAG, "Creating folder"); _sdcard->mkdir("/diybms"); - //Get the file + // Get the file ESP_LOGI(TAG, "Generating SD file %s", wificonfigfilename); StaticJsonDocument<1024> doc; @@ -437,7 +437,7 @@ void DIYBMSServer::avrProgrammer(AsyncWebServerRequest *request) else { // File open - //ESP_LOGI(TAG, "Loaded manifest.json"); + // ESP_LOGI(TAG, "Loaded manifest.json"); JsonArray toplevel = jsonmanifest["avrprog"]; @@ -452,7 +452,7 @@ void DIYBMSServer::avrProgrammer(AsyncWebServerRequest *request) JsonObject x = toplevel[filenumber]; - //serializeJsonPretty(x, SERIAL_DEBUG); + // serializeJsonPretty(x, SERIAL_DEBUG); _avrsettings.efuse = strtoul(x["efuse"].as().c_str(), nullptr, 16); _avrsettings.hfuse = strtoul(x["hfuse"].as().c_str(), nullptr, 16); @@ -468,12 +468,12 @@ void DIYBMSServer::avrProgrammer(AsyncWebServerRequest *request) _avrsettings.progresult = 0xFF; _avrsettings.inProgress = true; - //Fire task to start the AVR programming + // Fire task to start the AVR programming xTaskNotify(avrprog_task_handle, 0x00, eNotifyAction::eNoAction); } else { - //No files! + // No files! SendFailure(request); return; } @@ -518,7 +518,7 @@ void DIYBMSServer::disableAVRprog(AsyncWebServerRequest *request) _avrsettings.programmingModeEnabled = false; - //Try and remount the SD card + // Try and remount the SD card (*DIYBMSServer::_sdcardaction_callback)(1); SendSuccess(request); @@ -563,26 +563,32 @@ void DIYBMSServer::resetCounters(AsyncWebServerRequest *request) if (!validateXSS(request)) return; - canbus_messages_failed_sent = 0; - canbus_messages_received = 0; - canbus_messages_sent = 0; + // Ask modules to reset bad packet counters + // If this fails, queue could be full so return error + if (_prg->sendBadPacketCounterReset() && _prg->sendResetBalanceCurrentCounter()) + { - //Ask modules to reset bad packet counters - _prg->sendBadPacketCounterReset(); - _prg->sendResetBalanceCurrentCounter(); + canbus_messages_failed_sent = 0; + canbus_messages_received = 0; + canbus_messages_sent = 0; - for (uint8_t i = 0; i < maximum_controller_cell_modules; i++) - { - cmi[i].badPacketCount = 0; - cmi[i].PacketReceivedCount = 0; - } + for (uint8_t i = 0; i < maximum_controller_cell_modules; i++) + { + cmi[i].badPacketCount = 0; + cmi[i].PacketReceivedCount = 0; + } - //Reset internal counters on CONTROLLER - _receiveProc->ResetCounters(); + // Reset internal counters on CONTROLLER + _receiveProc->ResetCounters(); - _prg->packetsGenerated = 0; + _prg->ResetCounters(); - SendSuccess(request); + SendSuccess(request); + } + else + { + SendFailure(request); + } } void DIYBMSServer::saveDisplaySetting(AsyncWebServerRequest *request) @@ -602,7 +608,7 @@ void DIYBMSServer::saveDisplaySetting(AsyncWebServerRequest *request) _mysettings->graph_voltagelow = p1->value().toFloat(); } - //Validate high is greater than low + // Validate high is greater than low if (_mysettings->graph_voltagelow > _mysettings->graph_voltagehigh) { _mysettings->graph_voltagelow = 0; @@ -660,7 +666,7 @@ void DIYBMSServer::saveInfluxDBSetting(AsyncWebServerRequest *request) saveConfiguration(); - //ConfigHasChanged = REBOOT_COUNT_DOWN; + // ConfigHasChanged = REBOOT_COUNT_DOWN; SendSuccess(request); } @@ -745,7 +751,7 @@ void DIYBMSServer::saveCurrentMonRelay(AsyncWebServerRequest *request) return; currentmonitoring_struct newvalues; - //Set everything to zero/false + // Set everything to zero/false memset(&newvalues, 0, sizeof(currentmonitoring_struct)); if (request->hasParam("TempCompEnabled", true)) @@ -799,7 +805,7 @@ void DIYBMSServer::saveCurrentMonAdvanced(AsyncWebServerRequest *request) return; currentmonitoring_struct newvalues; - //Set everything to zero/false + // Set everything to zero/false memset(&newvalues, 0, sizeof(currentmonitoring_struct)); if (request->hasParam("cmcalibration", true)) @@ -891,7 +897,7 @@ void DIYBMSServer::saveCurrentMonSettings(AsyncWebServerRequest *request) } else { - //If the parameter isn't there its FALSE/unchecked + // If the parameter isn't there its FALSE/unchecked _mysettings->currentMonitoringEnabled = false; } @@ -903,7 +909,7 @@ void DIYBMSServer::saveCurrentMonSettings(AsyncWebServerRequest *request) if (_mysettings->currentMonitoringEnabled == false) { - //Switch off current monitor, clear out the values + // Switch off current monitor, clear out the values memset(¤tMonitor, 0, sizeof(currentmonitoring_struct)); currentMonitor.validReadings = false; } @@ -953,7 +959,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) if (!validateXSS(request)) return; - //relaytype + // relaytype for (int i = 0; i < RELAY_TOTAL; i++) { String name = "relaytype"; @@ -961,7 +967,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) if (request->hasParam(name.c_str(), true, false)) { AsyncWebParameter *p1 = request->getParam(name.c_str(), true, false); - //Default + // Default RelayType oldValue = _mysettings->relaytype[i]; if (p1->value().equals("Pulse")) { @@ -974,14 +980,14 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) if (oldValue != _mysettings->relaytype[i]) { - //The type of relay has changed - we probably need to reset something here + // The type of relay has changed - we probably need to reset something here ESP_LOGI(TAG, "Type of relay has changed"); previousRelayState[i] = RelayState::RELAY_X; } } } - //Relay default + // Relay default for (int i = 0; i < RELAY_TOTAL; i++) { String name = "defaultrelay"; @@ -989,7 +995,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) if (request->hasParam(name.c_str(), true, false)) { AsyncWebParameter *p1 = request->getParam(name.c_str(), true, false); - //Default + // Default _mysettings->rulerelaydefault[i] = RelayState::RELAY_OFF; if (p1->value().equals("On")) { @@ -1001,7 +1007,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) for (int rule = 0; rule < RELAY_RULES; rule++) { - //TODO: This STRING doesnt work properly if its on a single line! + // TODO: This STRING doesnt work properly if its on a single line! String name = "rule"; name = name + (rule); name = name + "value"; @@ -1012,7 +1018,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) _mysettings->rulevalue[rule] = p1->value().toInt(); } - //TODO: This STRING doesnt work properly if its on a single line! + // TODO: This STRING doesnt work properly if its on a single line! String hname = "rule"; hname = hname + (rule); hname = hname + "hysteresis"; @@ -1022,10 +1028,10 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) _mysettings->rulehysteresis[rule] = p1->value().toInt(); } - //Rule/relay processing + // Rule/relay processing for (int i = 0; i < RELAY_TOTAL; i++) { - //TODO: This STRING doesnt work properly if its on a single line! + // TODO: This STRING doesnt work properly if its on a single line! String name = "rule"; name = name + (rule); name = name + "relay"; @@ -1038,7 +1044,7 @@ void DIYBMSServer::saveRuleConfiguration(AsyncWebServerRequest *request) } } - //Reset state of rules after updating the new values + // Reset state of rules after updating the new values for (int8_t r = 0; r < RELAY_RULES; r++) { _rules->rule_outcome[r] = false; @@ -1062,7 +1068,7 @@ void DIYBMSServer::saveStorage(AsyncWebServerRequest *request) } else { - //Switch off logging + // Switch off logging _mysettings->loggingEnabled = false; } @@ -1070,7 +1076,7 @@ void DIYBMSServer::saveStorage(AsyncWebServerRequest *request) { AsyncWebParameter *p1 = request->getParam("loggingFreq", true); _mysettings->loggingFrequencySeconds = p1->value().toInt(); - //Validate + // Validate if (_mysettings->loggingFrequencySeconds < 15 || _mysettings->loggingFrequencySeconds > 600) { _mysettings->loggingFrequencySeconds = 15; @@ -1118,7 +1124,7 @@ void DIYBMSServer::saveNTP(AsyncWebServerRequest *request) saveConfiguration(); - //ConfigHasChanged = REBOOT_COUNT_DOWN; + // ConfigHasChanged = REBOOT_COUNT_DOWN; SendSuccess(request); } @@ -1232,23 +1238,28 @@ void DIYBMSServer::saveGlobalSetting(AsyncWebServerRequest *request) AsyncWebParameter *p2 = request->getParam("BypassThresholdmV", true); _mysettings->BypassThresholdmV = p2->value().toInt(); - saveConfiguration(); - - _prg->sendSaveGlobalSetting(_mysettings->BypassThresholdmV, _mysettings->BypassOverTempShutdown); + if (_prg->sendSaveGlobalSetting(_mysettings->BypassThresholdmV, _mysettings->BypassOverTempShutdown)) + { + saveConfiguration(); - uint8_t totalModules = _mysettings->totalNumberOfBanks * _mysettings->totalNumberOfSeriesModules; + uint8_t totalModules = _mysettings->totalNumberOfBanks * _mysettings->totalNumberOfSeriesModules; - for (uint8_t i = 0; i < totalModules; i++) - { - if (cmi[i].valid) + for (uint8_t i = 0; i < totalModules; i++) { - cmi[i].BypassThresholdmV = _mysettings->BypassThresholdmV; - cmi[i].BypassOverTempShutdown = _mysettings->BypassOverTempShutdown; + if (cmi[i].valid) + { + cmi[i].BypassThresholdmV = _mysettings->BypassThresholdmV; + cmi[i].BypassOverTempShutdown = _mysettings->BypassOverTempShutdown; + } } - } - //Just returns NULL - SendSuccess(request); + // Just returns NULL + SendSuccess(request); + } + else + { + SendFailure(request); + } } else { @@ -1269,7 +1280,7 @@ void DIYBMSServer::saveSetting(AsyncWebServerRequest *request) if (request->hasParam("m", true)) { AsyncWebParameter *module = request->getParam("m", true); - //Will this overflow? + // Will this overflow? uint8_t m = module->value().toInt(); if (m > maximum_controller_cell_modules) @@ -1283,15 +1294,15 @@ void DIYBMSServer::saveSetting(AsyncWebServerRequest *request) uint16_t BypassThresholdmV = 0xFFFF; // Resistance of bypass load - //float LoadResistance = 0xFFFF; - //Voltage Calibration + // float LoadResistance = 0xFFFF; + // Voltage Calibration float Calibration = 0xFFFF; - //Reference voltage (millivolt) normally 2.00mV - //float mVPerADC = 0xFFFF; - //Internal Thermistor settings - //uint16_t Internal_BCoefficient = 0xFFFF; - //External Thermistor settings - //uint16_t External_BCoefficient = 0xFFFF; + // Reference voltage (millivolt) normally 2.00mV + // float mVPerADC = 0xFFFF; + // Internal Thermistor settings + // uint16_t Internal_BCoefficient = 0xFFFF; + // External Thermistor settings + // uint16_t External_BCoefficient = 0xFFFF; if (request->hasParam("BypassOverTempShutdown", true)) { @@ -1431,15 +1442,13 @@ void DIYBMSServer::settings(AsyncWebServerRequest *request) JsonObject settings = root.createNestedObject("settings"); - //settings["Version"] = String(GIT_VERSION); - //settings["CompileDate"] = String(COMPILE_DATE_TIME); + // settings["Version"] = String(GIT_VERSION); + // settings["CompileDate"] = String(COMPILE_DATE_TIME); settings["totalnumberofbanks"] = _mysettings->totalNumberOfBanks; settings["totalseriesmodules"] = _mysettings->totalNumberOfSeriesModules; settings["baudrate"] = _mysettings->baudRate; - - settings["bypassthreshold"] = _mysettings->BypassThresholdmV; settings["bypassovertemp"] = _mysettings->BypassOverTempShutdown; @@ -1487,7 +1496,7 @@ void DIYBMSServer::fileSystemListDirectory(AsyncResponseStream *response, fs::FS { if (file.isDirectory()) { - //Hide the diybms folder where the config files are kept + // Hide the diybms folder where the config files are kept if (levels && String(file.name()).startsWith("/diybms") == false) { fileSystemListDirectory(response, fs, file.name(), levels - 1); @@ -1506,7 +1515,7 @@ void DIYBMSServer::fileSystemListDirectory(AsyncResponseStream *response, fs::FS file = root.openNextFile(); } - //Trailing null to cope with trailing ',' + // Trailing null to cope with trailing ',' response->print("null"); } @@ -1527,7 +1536,7 @@ void DIYBMSServer::rs485settings(AsyncWebServerRequest *request) response->print(",\"stopbits\":"); response->print(_mysettings->rs485stopbits); - //The END... + // The END... response->print('}'); response->addHeader("Cache-Control", "no-store"); @@ -1542,7 +1551,7 @@ void DIYBMSServer::currentmonitor(AsyncWebServerRequest *request) PrintStreamCommaBoolean(response, "\"enabled\":", _mysettings->currentMonitoringEnabled); PrintStreamComma(response, "\"address\":", _mysettings->currentMonitoringModBusAddress); - //Convert to milliseconds + // Convert to milliseconds uint32_t x = 0; if (currentMonitor.validReadings) { @@ -1579,7 +1588,7 @@ void DIYBMSServer::currentmonitor(AsyncWebServerRequest *request) PrintStreamComma(response, "\"firmwarev\":", currentMonitor.modbus.firmwareversion); PrintStreamComma(response, "\"firmwaredate\":", currentMonitor.modbus.firmwaredatetime); - //Boolean flag values + // Boolean flag values PrintStreamCommaBoolean(response, "\"TMPOL\":", currentMonitor.TemperatureOverLimit); PrintStreamCommaBoolean(response, "\"CURROL\":", currentMonitor.CurrentOverLimit); PrintStreamCommaBoolean(response, "\"CURRUL\":", currentMonitor.CurrentUnderLimit); @@ -1589,7 +1598,7 @@ void DIYBMSServer::currentmonitor(AsyncWebServerRequest *request) PrintStreamCommaBoolean(response, "\"TempCompEnabled\":", currentMonitor.TempCompEnabled); PrintStreamCommaBoolean(response, "\"ADCRange4096mV\":", currentMonitor.ADCRange4096mV); - //Trigger values + // Trigger values PrintStreamCommaBoolean(response, "\"T_TMPOL\":", currentMonitor.RelayTriggerTemperatureOverLimit); PrintStreamCommaBoolean(response, "\"T_CURROL\":", currentMonitor.RelayTriggerCurrentOverLimit); PrintStreamCommaBoolean(response, "\"T_CURRUL\":", currentMonitor.RelayTriggerCurrentUnderLimit); @@ -1601,7 +1610,7 @@ void DIYBMSServer::currentmonitor(AsyncWebServerRequest *request) PrintStreamComma(response, "\"shuntmv\":", currentMonitor.modbus.shuntmillivolt); PrintStream(response, "\"shuntmaxcur\":", currentMonitor.modbus.shuntmaxcurrent); - //The END... + // The END... response->print('}'); response->addHeader("Cache-Control", "no-store"); @@ -1613,7 +1622,7 @@ void DIYBMSServer::avrstorage(AsyncWebServerRequest *request) AsyncResponseStream *response = request->beginResponseStream("application/json"); //{"avrprog":{"avrprog":[{"board":"V400","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V400_ca58bde0.bin","ver":"ca58bde0"},{"board":"V410","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V410_ca58bde0.bin","ver":"ca58bde0"},{"board":"V420","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V420_ca58bde0.bin","ver":"ca58bde0"},{"board":"V420_SWAPR19R20","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V420_SWAPR19R20_ca58bde0.bin","ver":"ca58bde0"},{"board":"V421","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V421_ca58bde0.bin","ver":"ca58bde0"},{"board":"V421_LTO","efuse":"F4","hfuse":"D6","lfuse":"62","mcu":"1e9315","name":"fw_V421_LTO_ca58bde0.bin","ver":"ca58bde0"}]}} - //See if we can open and process the AVR PROGRAMMER manifest file + // See if we can open and process the AVR PROGRAMMER manifest file response->print("{"); response->print("\"ProgModeEnabled\":"); response->print(_avrsettings.programmingModeEnabled ? "1" : "0"); @@ -1639,11 +1648,11 @@ void DIYBMSServer::avrstorage(AsyncWebServerRequest *request) } else { - //No files! + // No files! response->print("{}"); } - //The END... + // The END... response->print('}'); response->addHeader("Cache-Control", "no-store"); @@ -1656,10 +1665,10 @@ void DIYBMSServer::storage(AsyncWebServerRequest *request) info.available = _sd_card_installed; - //Lock VSPI bus during operation (not sure if this is acutally needed, as the SD class may have cached these values) + // Lock VSPI bus during operation (not sure if this is acutally needed, as the SD class may have cached these values) if (_hal->GetVSPIMutex()) { - //Convert to KiB + // Convert to KiB info.totalkilobytes = SD.totalBytes() / 1024; info.usedkilobytes = SD.usedBytes() / 1024; _hal->ReleaseVSPIMutex(); @@ -1684,7 +1693,7 @@ void DIYBMSServer::storage(AsyncWebServerRequest *request) PrintStreamComma(response, "\"total\":", info.totalkilobytes); PrintStreamComma(response, "\"used\":", info.usedkilobytes); response->print("\"files\":["); - //File listing goes here + // File listing goes here if (info.available) { if (_hal->GetVSPIMutex()) @@ -1704,7 +1713,7 @@ void DIYBMSServer::storage(AsyncWebServerRequest *request) response->print(']'); response->print("}"); - //The END... + // The END... response->print('}'); response->print('}'); @@ -1726,8 +1735,8 @@ void DIYBMSServer::integration(AsyncWebServerRequest *request) mqtt["port"] = _mysettings->mqtt_port; mqtt["server"] = _mysettings->mqtt_server; mqtt["username"] = _mysettings->mqtt_username; - //We don't output the password in the json file as this could breach security - //mqtt["password"] =_mysettings->mqtt_password; + // We don't output the password in the json file as this could breach security + // mqtt["password"] =_mysettings->mqtt_password; JsonObject influxdb = root.createNestedObject("influxdb"); influxdb["enabled"] = _mysettings->influxdb_enabled; @@ -1771,28 +1780,28 @@ void DIYBMSServer::downloadFile(AsyncWebServerRequest *request) String type = request->getParam("type", false)->value(); String file = request->getParam("file", false)->value(); - //Do some really simple validation here to prevent files being downloaded, - //which could be a security risk. - //See: directory traversal vulnerability + // Do some really simple validation here to prevent files being downloaded, + // which could be a security risk. + // See: directory traversal vulnerability if (file.startsWith("/") == false) { - //All file names must start at the root - request->send(400); //400 bad request + // All file names must start at the root + request->send(400); // 400 bad request return; } if (file.startsWith("//") == true) { - //All file names must start at the root - request->send(400); //400 bad request + // All file names must start at the root + request->send(400); // 400 bad request return; } if (file.startsWith("/diybms/") == true) { - //Prevent downloads from /diybms/ folder - request->send(401); //401 Unauthorized + // Prevent downloads from /diybms/ folder + request->send(401); // 401 Unauthorized return; } @@ -1802,7 +1811,7 @@ void DIYBMSServer::downloadFile(AsyncWebServerRequest *request) if (_hal->GetVSPIMutex()) { - //Get the file + // Get the file ESP_LOGI(TAG, "Download SDCard file %s", file.c_str()); request->send(*_sdcard, file, "application/octet-stream", true, nullptr); @@ -1820,7 +1829,7 @@ void DIYBMSServer::downloadFile(AsyncWebServerRequest *request) } } - request->send(400); //400 bad request + request->send(400); // 400 bad request } void DIYBMSServer::modules(AsyncWebServerRequest *request) @@ -1882,7 +1891,7 @@ void DIYBMSServer::handleRestartController(AsyncWebServerRequest *request) void DIYBMSServer::monitor3(AsyncWebServerRequest *request) { - //DynamicJsonDocument doc(maximum_controller_cell_modules * 50); + // DynamicJsonDocument doc(maximum_controller_cell_modules * 50); AsyncResponseStream *response = request->beginResponseStream("application/json"); uint8_t totalModules = _mysettings->totalNumberOfBanks * _mysettings->totalNumberOfSeriesModules; @@ -1898,7 +1907,7 @@ void DIYBMSServer::monitor3(AsyncWebServerRequest *request) } else { - //Return NULL + // Return NULL response->print("null"); } if (i < comma) @@ -1917,7 +1926,7 @@ void DIYBMSServer::monitor3(AsyncWebServerRequest *request) } else { - //Return NULL + // Return NULL response->print("null"); } if (i < comma) @@ -1936,7 +1945,7 @@ void DIYBMSServer::monitor3(AsyncWebServerRequest *request) } else { - //Return NULL + // Return NULL response->print("null"); } if (i < comma) @@ -1967,7 +1976,7 @@ void DIYBMSServer::PrintStreamCommaBoolean(AsyncResponseStream *response, const void DIYBMSServer::PrintStreamCommaFloat(AsyncResponseStream *response, const char *text, float value) { response->print(text); - //Print value to 6 decimal places + // Print value to 6 decimal places response->print(value, 6); response->print(','); } @@ -2007,6 +2016,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) PrintStreamComma(response, "\"ignored\":", _receiveProc->totalNotProcessedErrors); PrintStreamComma(response, "\"roundtrip\":", _receiveProc->packetTimerMillisecond); PrintStreamComma(response, "\"oos\":", _receiveProc->totalOutofSequenceErrors); + PrintStreamComma(response, "\"qlen\":", _prg->queueLength()); PrintStreamComma(response, "\"activerules\":", _rules->active_rule_count); PrintStreamComma(response, "\"uptime\":", (uint32_t)(esp_timer_get_time() / (uint64_t)1e+6)); @@ -2015,9 +2025,9 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) PrintStreamComma(response, "\"can_sent\":", canbus_messages_sent); PrintStreamComma(response, "\"can_rec\":", canbus_messages_received); - //Output last 2 charaters from security cookie, to allow browser to detect when its - //no longer in sync with the back end and report warning. - //Technically this downgrades the complexity of the XSS key, as it reduces key length. + // Output last 2 charaters from security cookie, to allow browser to detect when its + // no longer in sync with the back end and report warning. + // Technically this downgrades the complexity of the XSS key, as it reduces key length. response->print("\"sec\":\""); response->print(UUIDStringLast2Chars); response->print("\","); @@ -2029,7 +2039,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) { if (_rules->ErrorCodes[i] != InternalErrorCode::NoError) { - //Comma if not zero + // Comma if not zero if (count) { response->print(comma); @@ -2047,7 +2057,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) { if (_rules->WarningCodes[i] != InternalWarningCode::NoWarning) { - //Comma if not zero + // Comma if not zero if (count) { response->print(comma); @@ -2059,12 +2069,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } response->print("],"); - //voltages + // voltages response->print(F("\"voltages\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2074,7 +2084,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } else { - //Module is not yet valid so return null values... + // Module is not yet valid so return null values... response->print(null); } } @@ -2084,7 +2094,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2094,19 +2104,19 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } else { - //Module is not yet valid so return null values... + // Module is not yet valid so return null values... response->print(null); } } response->print("],"); - //maxvoltages + // maxvoltages response->print(F("\"maxvoltages\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2116,7 +2126,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } else { - //Module is not yet valid so return null values... + // Module is not yet valid so return null values... response->print(null); } } @@ -2124,12 +2134,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //inttemp + // inttemp response->print(F("\"inttemp\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2139,7 +2149,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } else { - //Module is not yet valid so return null values... + // Module is not yet valid so return null values... response->print(null); } } @@ -2147,12 +2157,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //exttemp + // exttemp response->print(F("\"exttemp\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2162,7 +2172,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) } else { - //Module is not yet valid so return null values... + // Module is not yet valid so return null values... response->print(null); } } @@ -2170,12 +2180,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //bypass + // bypass response->print(F("\"bypass\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2192,12 +2202,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //bypasshot + // bypasshot response->print(F("\"bypasshot\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2214,12 +2224,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //bypasspwm + // bypasspwm response->print(F("\"bypasspwm\":[")); for (uint8_t i = 0; i < totalModules; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2236,12 +2246,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //bypasspwm + // bypasspwm response->print(F("\"bankv\":[")); for (uint8_t i = 0; i < _mysettings->totalNumberOfBanks; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2251,12 +2261,12 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(comma); - //bypasspwm + // bypasspwm response->print(F("\"voltrange\":[")); for (uint8_t i = 0; i < _mysettings->totalNumberOfBanks; i++) { - //Comma if not zero + // Comma if not zero if (i) response->print(comma); @@ -2268,7 +2278,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print(F("\"current\":[")); if (_mysettings->currentMonitoringEnabled && currentMonitor.validReadings) { - //Output current monitor values, this is inside an array, so could be more than 1 + // Output current monitor values, this is inside an array, so could be more than 1 response->print(F("{\"c\":")); response->print(currentMonitor.modbus.current, 4); response->print(F(",\"v\":")); @@ -2291,7 +2301,7 @@ void DIYBMSServer::monitor2(AsyncWebServerRequest *request) response->print("]"); - //The END... + // The END... response->print('}'); response->addHeader("Cache-Control", "no-store"); @@ -2640,7 +2650,7 @@ void DIYBMSServer::StartServer(AsyncWebServer *webserver, } }); - //Read endpoints + // Read endpoints _myserver->on("/monitor2.json", HTTP_GET, DIYBMSServer::monitor2); _myserver->on("/monitor3.json", HTTP_GET, DIYBMSServer::monitor3); _myserver->on("/integration.json", HTTP_GET, DIYBMSServer::integration); @@ -2657,7 +2667,7 @@ void DIYBMSServer::StartServer(AsyncWebServer *webserver, _myserver->on("/rs485settings.json", HTTP_GET, DIYBMSServer::rs485settings); _myserver->on("/victron.json", HTTP_GET, DIYBMSServer::getvictron); - //POST method endpoints + // POST method endpoints _myserver->on("/savesetting.json", HTTP_POST, DIYBMSServer::saveSetting); _myserver->on("/saveglobalsetting.json", HTTP_POST, DIYBMSServer::saveGlobalSetting); _myserver->on("/savemqtt.json", HTTP_POST, DIYBMSServer::saveMQTTSetting); @@ -2681,13 +2691,13 @@ void DIYBMSServer::StartServer(AsyncWebServer *webserver, _myserver->on("/wificonfigtofile.json", HTTP_POST, DIYBMSServer::saveWifiConfigToSDCard); _myserver->on("/saveconfigtofile.json", HTTP_POST, DIYBMSServer::saveConfigurationToSDCard); - //Current monitor services/settings + // Current monitor services/settings _myserver->on("/savers485settings.json", HTTP_POST, DIYBMSServer::saveRS485Settings); _myserver->on("/savecurrentmon.json", HTTP_POST, DIYBMSServer::saveCurrentMonSettings); _myserver->on("/savecmbasic.json", HTTP_POST, DIYBMSServer::saveCurrentMonBasic); _myserver->on("/savecmadvanced.json", HTTP_POST, DIYBMSServer::saveCurrentMonAdvanced); _myserver->on("/savecmrelay.json", HTTP_POST, DIYBMSServer::saveCurrentMonRelay); - //Victron stuff + // Victron stuff _myserver->on("/savevictron.json", HTTP_POST, DIYBMSServer::saveVictron); _myserver->onNotFound(DIYBMSServer::handleNotFound); diff --git a/ESPController/src/PacketReceiveProcessor.cpp b/ESPController/src/PacketReceiveProcessor.cpp index 76aed016..c9f5b9b9 100644 --- a/ESPController/src/PacketReceiveProcessor.cpp +++ b/ESPController/src/PacketReceiveProcessor.cpp @@ -42,7 +42,7 @@ bool PacketReceiveProcessor::ProcessReply(PacketStruct *receivebuffer) if (ReplyWasProcessedByAModule()) { - //ESP_LOGD(TAG, "Hops %u, start %u end %u", _packetbuffer.hops, _packetbuffer.start_address, _packetbuffer.end_address); + //ESP_LOGD(TAG, "Hops %u, start %u end %u, command=%u", _packetbuffer.hops, _packetbuffer.start_address, _packetbuffer.end_address,ReplyForCommand()); switch (ReplyForCommand()) { @@ -68,12 +68,15 @@ bool PacketReceiveProcessor::ProcessReply(PacketStruct *receivebuffer) //ESP_LOGD(TAG, "Updated volt status cells %u to %u", _packetbuffer.start_address, _packetbuffer.end_address); + + //TODO: REVIEW THIS LOGIC if (_packetbuffer.end_address == _packetbuffer.hops - 1) { //We have just processed a voltage reading for the entire chain of modules (all banks) //at this point we should update any display or rules logic //as we have a clean snapshot of voltages and statues + ESP_LOGD(TAG, "Finished all reads"); if (voltageandstatussnapshot_task_handle != NULL) { xTaskNotify(voltageandstatussnapshot_task_handle, 0x00, eNotifyAction::eNoAction); @@ -111,15 +114,14 @@ bool PacketReceiveProcessor::ProcessReply(PacketStruct *receivebuffer) #if defined(PACKET_LOGGING_RECEIVE) SERIAL_DEBUG.println(F("*OK*")); #endif + return true; } else { //Error count for a request that was not processed by any module in the string totalNotProcessedErrors++; -#if defined(PACKET_LOGGING_RECEIVE) - SERIAL_DEBUG.println(F("*IGNORE*")); -#endif + ESP_LOGD(TAG, "Modules ignored request"); } } else diff --git a/ESPController/src/PacketRequestGenerator.cpp b/ESPController/src/PacketRequestGenerator.cpp index ea45211b..ca172c8b 100644 --- a/ESPController/src/PacketRequestGenerator.cpp +++ b/ESPController/src/PacketRequestGenerator.cpp @@ -9,7 +9,7 @@ void PacketRequestGenerator::clearSettingsForAllModules() } } -void PacketRequestGenerator::sendSaveGlobalSetting(uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown) +bool PacketRequestGenerator::sendSaveGlobalSetting(uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown) { PacketStruct _packetbuffer; clearPacket(&_packetbuffer); @@ -23,12 +23,16 @@ void PacketRequestGenerator::sendSaveGlobalSetting(uint16_t BypassThresholdmV, u setmoduledataFFFF(&_packetbuffer); _packetbuffer.moduledata[6] = BypassOverTempShutdown; _packetbuffer.moduledata[7] = BypassThresholdmV; - pushPacketToQueue(&_packetbuffer); + if (pushPacketToQueue(&_packetbuffer)) { + clearSettingsForAllModules(); - clearSettingsForAllModules(); + return true; + } + + return false; } -void PacketRequestGenerator::sendSaveSetting(uint8_t m, uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown, float Calibration) +bool PacketRequestGenerator::sendSaveSetting(uint8_t m, uint16_t BypassThresholdmV, uint8_t BypassOverTempShutdown, float Calibration) { PacketStruct _packetbuffer; clearPacket(&_packetbuffer); @@ -62,86 +66,95 @@ void PacketRequestGenerator::sendSaveSetting(uint8_t m, uint16_t BypassThreshold _packetbuffer.moduledata[7] = BypassThresholdmV; //_packetbuffer.moduledata[8] = Internal_BCoefficient; //_packetbuffer.moduledata[9] = External_BCoefficient; - pushPacketToQueue(&_packetbuffer); + return pushPacketToQueue(&_packetbuffer); } -void PacketRequestGenerator::sendReadBadPacketCounter(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendReadBadPacketCounter(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadBadPacketCounter, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadBadPacketCounter, startmodule, endmodule); } -void PacketRequestGenerator::sendCellVoltageRequest(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendCellVoltageRequest(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadVoltageAndStatus, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadVoltageAndStatus, startmodule, endmodule); } -void PacketRequestGenerator::sendIdentifyModuleRequest(uint8_t cellid) +bool PacketRequestGenerator::sendIdentifyModuleRequest(uint8_t cellid) { - BuildAndSendRequest(COMMAND::Identify, cellid, cellid); + return BuildAndSendRequest(COMMAND::Identify, cellid, cellid); } -void PacketRequestGenerator::sendTimingRequest() +bool PacketRequestGenerator::sendTimingRequest() { //Ask all modules to simple pass on a NULL request/packet for timing purposes - BuildAndSendRequest(COMMAND::Timing); + return BuildAndSendRequest(COMMAND::Timing); } -void PacketRequestGenerator::sendGetSettingsRequest(uint8_t cellid) +bool PacketRequestGenerator::sendGetSettingsRequest(uint8_t cellid) { - BuildAndSendRequest(COMMAND::ReadSettings, cellid, cellid); + return BuildAndSendRequest(COMMAND::ReadSettings, cellid, cellid); } -void PacketRequestGenerator::sendCellTemperatureRequest(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendCellTemperatureRequest(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadTemperature, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadTemperature, startmodule, endmodule); } -void PacketRequestGenerator::sendReadBalanceCurrentCountRequest(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendReadBalanceCurrentCountRequest(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadBalanceCurrentCounter, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadBalanceCurrentCounter, startmodule, endmodule); } -void PacketRequestGenerator::sendReadPacketsReceivedRequest(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendReadPacketsReceivedRequest(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadPacketReceivedCounter, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadPacketReceivedCounter, startmodule, endmodule); } -void PacketRequestGenerator::sendReadBalancePowerRequest(uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::sendReadBalancePowerRequest(uint8_t startmodule, uint8_t endmodule) { - BuildAndSendRequest(COMMAND::ReadBalancePowerPWM, startmodule, endmodule); + return BuildAndSendRequest(COMMAND::ReadBalancePowerPWM, startmodule, endmodule); } -void PacketRequestGenerator::sendBadPacketCounterReset() +bool PacketRequestGenerator::sendBadPacketCounterReset() { - BuildAndSendRequest(COMMAND::ResetBadPacketCounter); + return BuildAndSendRequest(COMMAND::ResetBadPacketCounter); } -void PacketRequestGenerator::sendResetBalanceCurrentCounter() +bool PacketRequestGenerator::sendResetBalanceCurrentCounter() { - BuildAndSendRequest(COMMAND::ResetBalanceCurrentCounter); + return BuildAndSendRequest(COMMAND::ResetBalanceCurrentCounter); } -void PacketRequestGenerator::BuildAndSendRequest(COMMAND command) +bool PacketRequestGenerator::BuildAndSendRequest(COMMAND command) { + //ESP_LOGD(TAG,"Build %u",command); + PacketStruct _packetbuffer; clearPacket(&_packetbuffer); setPacketAddressBroadcast(&_packetbuffer); _packetbuffer.command = command; - pushPacketToQueue(&_packetbuffer); + return pushPacketToQueue(&_packetbuffer); } -void PacketRequestGenerator::BuildAndSendRequest(COMMAND command, uint8_t startmodule, uint8_t endmodule) +bool PacketRequestGenerator::BuildAndSendRequest(COMMAND command, uint8_t startmodule, uint8_t endmodule) { + //ESP_LOGD(TAG,"Build %u, %u to %u",command,startmodule,endmodule); + PacketStruct _packetbuffer; clearPacket(&_packetbuffer); setPacketAddressModuleRange(&_packetbuffer, startmodule, endmodule); _packetbuffer.command = command; - pushPacketToQueue(&_packetbuffer); + return pushPacketToQueue(&_packetbuffer); } -void PacketRequestGenerator::pushPacketToQueue(PacketStruct *_packetbuffer) +bool PacketRequestGenerator::pushPacketToQueue(PacketStruct *_packetbuffer) { - _requestq->push(_packetbuffer); + if (!_requestq->push(_packetbuffer)) { + //ESP_LOGE(TAG,"Queue full"); + return false; + } + packetsGenerated++; + return true; } void PacketRequestGenerator::setPacketAddressModuleRange(PacketStruct *_packetbuffer, uint8_t startmodule, uint8_t endmodule) diff --git a/ESPController/src/main.cpp b/ESPController/src/main.cpp index c46daf50..877f7b89 100644 --- a/ESPController/src/main.cpp +++ b/ESPController/src/main.cpp @@ -73,7 +73,7 @@ HAL_ESP32 hal; volatile bool emergencyStop = false; bool _sd_card_installed = false; -//Used for WIFI hostname and also sent to Victron over CANBUS +// Used for WIFI hostname and also sent to Victron over CANBUS char hostname[16]; extern bool _tft_screen_available; @@ -125,7 +125,7 @@ TaskHandle_t rs485_rx_task_handle = NULL; TaskHandle_t victron_canbus_tx_task_handle = NULL; TaskHandle_t victron_canbus_rx_task_handle = NULL; -//This large array holds all the information about the modules +// This large array holds all the information about the modules CellModuleInfo cmi[maximum_controller_cell_modules]; avrprogramsettings _avrsettings; @@ -139,8 +139,8 @@ avrprogramsettings _avrsettings; // Instantiate queue to hold packets ready for transmission // TODO: Move to RTOS queues instead -cppQueue requestQueue(sizeof(PacketStruct), 24, FIFO); -cppQueue replyQueue(sizeof(PacketStruct), 8, FIFO); +cppQueue requestQueue(sizeof(PacketStruct), 30, FIFO); +cppQueue replyQueue(sizeof(PacketStruct), 4, FIFO); PacketRequestGenerator prg = PacketRequestGenerator(&requestQueue); PacketReceiveProcessor receiveProc = PacketReceiveProcessor(); @@ -161,24 +161,24 @@ void LED(uint8_t bits) hal.Led(bits); } -//When triggered, the VOLTAGE and STATUS in the CellModuleInfo structure are accurate and consistant at this point in time. -//Good point to apply rules and update screen/statistics +// When triggered, the VOLTAGE and STATUS in the CellModuleInfo structure are accurate and consistant at this point in time. +// Good point to apply rules and update screen/statistics void voltageandstatussnapshot_task(void *param) { for (;;) { - //Wait until this task is triggered, when + // Wait until this task is triggered, when ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //ESP_LOGD(TAG, "Snap"); + // ESP_LOGD(TAG, "Snap"); if (_tft_screen_available) { - //Refresh the TFT display + // Refresh the TFT display xTaskNotify(updatetftdisplay_task_handle, 0x00, eNotifyAction::eNoAction); } - } //end for + } // end for } // Sets the RS485 serial parameters after they have been changed @@ -200,11 +200,11 @@ void SetupRS485() ESP_LOGD(TAG, "Setup RS485"); /* TEST RS485 */ - //Zero all data to start with + // Zero all data to start with memset(¤tMonitor, 0, sizeof(currentmonitoring_struct)); - //if (mysettings.currentMonitoringEnabled) { - //} + // if (mysettings.currentMonitoringEnabled) { + // } uart_config_t uart_config = { .baud_rate = mysettings.rs485baudrate, @@ -292,16 +292,16 @@ void avrprog_task(void *param) { for (;;) { - //Wait until this task is triggered + // Wait until this task is triggered ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //Wake up the display + // Wake up the display if (tftwakeup_task_handle != NULL) { xTaskNotify(tftwakeup_task_handle, 0x01, eNotifyAction::eSetValueWithOverwrite); } - //TODO: This needs to be passed into this as a parameter + // TODO: This needs to be passed into this as a parameter avrprogramsettings *s; s = (avrprogramsettings *)param; @@ -311,35 +311,35 @@ void avrprog_task(void *param) if (_sd_card_installed) { - //Unmount SD card so we don't have issues on SPI bus + // Unmount SD card so we don't have issues on SPI bus unmountSDCard(); } - //Now we load the file into program array, from LITTLEFS (SPIFF) + // Now we load the file into program array, from LITTLEFS (SPIFF) if (LITTLEFS.exists(s->filename)) { File binaryfile = LITTLEFS.open(s->filename); s->programsize = binaryfile.size(); - //Reserve the SPI bus for programming purposes + // Reserve the SPI bus for programming purposes if (hal.GetVSPIMutex()) { - //Stop tasks which may want to use something on the VSPI - //prevents corruption of programming or SD CARD contents - //vTaskSuspend(sdcardlog_task_handle); - //vTaskSuspend(sdcardlog_outputs_task_handle); + // Stop tasks which may want to use something on the VSPI + // prevents corruption of programming or SD CARD contents + // vTaskSuspend(sdcardlog_task_handle); + // vTaskSuspend(sdcardlog_outputs_task_handle); hal.SwapGPIO0ToOutput(); - //This will block for the 6 seconds it takes to program ATTINY841... - //although AVRISP_PROGRAMMER will call the watchdog to prevent reboots + // This will block for the 6 seconds it takes to program ATTINY841... + // although AVRISP_PROGRAMMER will call the watchdog to prevent reboots uint32_t starttime = millis(); AVRISP_PROGRAMMER isp = AVRISP_PROGRAMMER(&(hal.vspi), GPIO_NUM_0, false, VSPI_SCK); ESP_LOGI(TAG, "Programming AVR"); - //This would be much better using a stream instead of a in ram buffer + // This would be much better using a stream instead of a in ram buffer s->progresult = isp.ProgramAVRDevice(&tftdisplay_avrprogrammer_progress, s->mcu, s->programsize, binaryfile, s->lfuse, s->hfuse, s->efuse); s->duration = millis() - starttime; @@ -349,20 +349,20 @@ void avrprog_task(void *param) if (s->progresult == AVRISP_PROGRAMMER_RESULT::SUCCESS) { - //sprintf(message, "Programming complete, duration %ums, %i bytes", s->duration, programsize); + // sprintf(message, "Programming complete, duration %ums, %i bytes", s->duration, programsize); ESP_LOGI(TAG, "Success"); } else { - //sprintf(message, "Programming failed, reason %i", (int)progresult); + // sprintf(message, "Programming failed, reason %i", (int)progresult); ESP_LOGE(TAG, "Failed %i", s->progresult); } binaryfile.close(); - //Resume tasks after programming is complete - //vTaskResume(sdcardlog_task_handle); - //vTaskResume(sdcardlog_outputs_task_handle); + // Resume tasks after programming is complete + // vTaskResume(sdcardlog_task_handle); + // vTaskResume(sdcardlog_outputs_task_handle); } else { @@ -376,67 +376,67 @@ void avrprog_task(void *param) s->inProgress = false; - //Refresh the display, after programming is complete + // Refresh the display, after programming is complete xTaskNotify(updatetftdisplay_task_handle, 0x00, eNotifyAction::eNoAction); - //If we unmounted the SD card, remount it here + // If we unmounted the SD card, remount it here if (old_sd_card_installed) { mountSDCard(); } - } //end for + } // end for } -//Output a status log to the SD Card in CSV format +// Output a status log to the SD Card in CSV format void sdcardlog_task(void *param) { for (;;) { - //Wait X seconds + // Wait X seconds for (size_t i = 0; i < mysettings.loggingFrequencySeconds; i++) { - //Delay 1 second + // Delay 1 second vTaskDelay(1000 / portTICK_PERIOD_MS); } if (_sd_card_installed && !_avrsettings.programmingModeEnabled && mysettings.loggingEnabled && _controller_state == ControllerState::Running && hal.IsVSPIMutexAvailable()) { - //ESP_LOGD(TAG, "sdcardlog_task"); + // ESP_LOGD(TAG, "sdcardlog_task"); struct tm timeinfo; - //getLocalTime has delay() functions in it :-( + // getLocalTime has delay() functions in it :-( if (getLocalTime(&timeinfo, 1)) { timeinfo.tm_year += 1900; - //Month is 0 to 11 based! + // Month is 0 to 11 based! timeinfo.tm_mon++; - //ESP_LOGD(TAG, "%04u-%02u-%02u %02u:%02u:%02u", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); + // ESP_LOGD(TAG, "%04u-%02u-%02u %02u:%02u:%02u", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); char filename[32]; sprintf(filename, "/data_%04u%02u%02u.csv", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday); File file; - //Prevent other devices using the VSPI bus + // Prevent other devices using the VSPI bus if (hal.GetVSPIMutex()) { if (SD.exists(filename)) { - //Open existing file (assumes there is enough SD card space to log) + // Open existing file (assumes there is enough SD card space to log) file = SD.open(filename, FILE_APPEND); - //ESP_LOGD(TAG, "Open log %s", filename); + // ESP_LOGD(TAG, "Open log %s", filename); } else { - //Create a new file + // Create a new file uint64_t freeSpace = SD.totalBytes() - SD.usedBytes(); - //Ensure there is more than 25MB of free space on SD card before creating a file + // Ensure there is more than 25MB of free space on SD card before creating a file if (freeSpace > (uint64_t)(25 * 1024 * 1024)) { - //Create the file + // Create the file File file = SD.open(filename, FILE_WRITE); if (file) { @@ -474,7 +474,7 @@ void sdcardlog_task(void *param) else { ESP_LOGE(TAG, "SD card has less than 25MiB remaining, logging stopped"); - //We had an error, so switch off logging (this is only in memory so not written perm.) + // We had an error, so switch off logging (this is only in memory so not written perm.) mysettings.loggingEnabled = false; } } @@ -488,7 +488,7 @@ void sdcardlog_task(void *param) for (uint8_t i = 0; i < TotalNumberOfCells(); i++) { - //This may output invalid data when controller is first powered up + // This may output invalid data when controller is first powered up sprintf(dataMessage, "%u,%i,%i,%c,%u,%c,%u,%u", cmi[i].voltagemV, cmi[i].internalTemp, cmi[i].externalTemp, cmi[i].inBypass ? 'Y' : 'N', @@ -508,11 +508,11 @@ void sdcardlog_task(void *param) else { ESP_LOGE(TAG, "Failed to create/append SD logging file"); - //We had an error opening the file, so switch off logging - //mysettings.loggingEnabled = false; + // We had an error opening the file, so switch off logging + // mysettings.loggingEnabled = false; } - //Now log the current monitor + // Now log the current monitor if (mysettings.currentMonitoringEnabled) { char cmon_filename[32]; @@ -522,19 +522,19 @@ void sdcardlog_task(void *param) if (SD.exists(cmon_filename)) { - //Open existing file (assumes there is enough SD card space to log) + // Open existing file (assumes there is enough SD card space to log) file = SD.open(cmon_filename, FILE_APPEND); - //ESP_LOGD(TAG, "Open log %s", filename); + // ESP_LOGD(TAG, "Open log %s", filename); } else { - //Create a new file + // Create a new file uint64_t freeSpace = SD.totalBytes() - SD.usedBytes(); - //Ensure there is more than 25MB of free space on SD card before creating a file + // Ensure there is more than 25MB of free space on SD card before creating a file if (freeSpace > (uint64_t)(25 * 1024 * 1024)) { - //Create the file + // Create the file File file = SD.open(cmon_filename, FILE_WRITE); if (file) { @@ -545,7 +545,7 @@ void sdcardlog_task(void *param) else { ESP_LOGE(TAG, "SD card has less than 25MiB remaining, logging stopped"); - //We had an error, so switch off logging (this is only in memory so not written perm.) + // We had an error, so switch off logging (this is only in memory so not written perm.) mysettings.loggingEnabled = false; } } @@ -573,31 +573,31 @@ void sdcardlog_task(void *param) else { ESP_LOGE(TAG, "Failed to create/append SD logging file"); - //We had an error opening the file, so switch off logging - //mysettings.loggingEnabled = false; + // We had an error opening the file, so switch off logging + // mysettings.loggingEnabled = false; } - } //end of logging for current monitor + } // end of logging for current monitor } else { ESP_LOGE(TAG, "Invalid datetime"); } - //Must be the last thing... + // Must be the last thing... hal.ReleaseVSPIMutex(); } } - } //end for loop + } // end for loop - //vTaskDelete( NULL ); + // vTaskDelete( NULL ); } -//Writes a status log of the OUTPUT STATUES to the SD Card in CSV format +// Writes a status log of the OUTPUT STATUES to the SD Card in CSV format void sdcardlog_outputs_task(void *param) { for (;;) { - //Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html + // Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if (_sd_card_installed && !_avrsettings.programmingModeEnabled && mysettings.loggingEnabled) @@ -605,44 +605,44 @@ void sdcardlog_outputs_task(void *param) ESP_LOGD(TAG, "sdcardlog_outputs_task"); struct tm timeinfo; - //getLocalTime has delay() functions in it :-( + // getLocalTime has delay() functions in it :-( if (getLocalTime(&timeinfo, 1)) { timeinfo.tm_year += 1900; - //Month is 0 to 11 based! + // Month is 0 to 11 based! timeinfo.tm_mon++; - //ESP_LOGD(TAG, "%04u-%02u-%02u %02u:%02u:%02u", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); + // ESP_LOGD(TAG, "%04u-%02u-%02u %02u:%02u:%02u", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); char filename[32]; sprintf(filename, "/output_status_%04u%02u%02u.csv", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday); File file; - //Prevent other devices using the VSPI bus + // Prevent other devices using the VSPI bus if (hal.GetVSPIMutex()) { if (SD.exists(filename)) { - //Open existing file (assumes there is enough SD card space to log) + // Open existing file (assumes there is enough SD card space to log) file = SD.open(filename, FILE_APPEND); - //ESP_LOGD(TAG, "Open log %s", filename); + // ESP_LOGD(TAG, "Open log %s", filename); } else { - //Create a new file + // Create a new file uint64_t freeSpace = SD.totalBytes() - SD.usedBytes(); - //Ensure there is more than 25MB of free space on SD card before creating a file + // Ensure there is more than 25MB of free space on SD card before creating a file if (freeSpace > (uint64_t)(25 * 1024 * 1024)) { - //Create the file + // Create the file File file = SD.open(filename, FILE_WRITE); if (file) { - //ESP_LOGD(TAG, "Create log %s", filename); + // ESP_LOGD(TAG, "Create log %s", filename); file.print("DateTime,Bits,"); @@ -661,8 +661,8 @@ void sdcardlog_outputs_task(void *param) else { ESP_LOGE(TAG, "SD card has less than 25MiB remaining, logging stopped"); - //We had an error, so switch off logging - //mysettings.loggingEnabled = false; + // We had an error, so switch off logging + // mysettings.loggingEnabled = false; } } @@ -677,7 +677,7 @@ void sdcardlog_outputs_task(void *param) for (uint8_t i = 0; i < RELAY_TOTAL; i++) { - //This may output invalid data when controller is first powered up + // This may output invalid data when controller is first powered up sprintf(dataMessage, "%c", previousRelayState[i] == RelayState::RELAY_ON ? 'Y' : 'N'); file.print(dataMessage); if (i < RELAY_TOTAL - 1) @@ -693,8 +693,8 @@ void sdcardlog_outputs_task(void *param) else { ESP_LOGE(TAG, "Failed to create/append SD logging file"); - //We had an error opening the file, so switch off logging - //mysettings.loggingEnabled = false; + // We had an error opening the file, so switch off logging + // mysettings.loggingEnabled = false; } } else @@ -702,47 +702,47 @@ void sdcardlog_outputs_task(void *param) ESP_LOGE(TAG, "Invalid datetime"); } - //Must be the last thing... + // Must be the last thing... hal.ReleaseVSPIMutex(); - } //end if - } //end if - } //end for loop + } // end if + } // end if + } // end for loop - //vTaskDelete( NULL ); + // vTaskDelete( NULL ); } -//Disable the BOOT button from acting as a WIFI RESET -//button which clears the EEPROM settings for WIFI connection +// Disable the BOOT button from acting as a WIFI RESET +// button which clears the EEPROM settings for WIFI connection void wifiresetdisable_task(void *param) { for (;;) { - //Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html + // Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //Wait for 20 seconds before disabling button/pin + // Wait for 20 seconds before disabling button/pin for (size_t i = 0; i < 20; i++) { - //Wait 1 second + // Wait 1 second vTaskDelay(1000 / portTICK_PERIOD_MS); } hal.SwapGPIO0ToOutput(); } - //vTaskDelete( NULL ); + // vTaskDelete( NULL ); } void ledoff_task(void *param) { for (;;) { - //Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html + // Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //Wait 100ms + // Wait 100ms vTaskDelay(100 / portTICK_PERIOD_MS); - //LED OFF - //ESP_LOGD(TAG, "Led off") + // LED OFF + // ESP_LOGD(TAG, "Led off") LED(RGBLED::OFF); } } @@ -751,20 +751,20 @@ void tca6408_isr_task(void *param) { for (;;) { - //Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html + // Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(TAG, "tca6408_isr"); // Read ports A/B/C/D inputs (on TCA6408) uint8_t v = hal.ReadTCA6408InputRegisters(); - //P0=A + // P0=A InputState[0] = (v & B00000001) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //P1=B + // P1=B InputState[1] = (v & B00000010) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //P2=C + // P2=C InputState[2] = (v & B00000100) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //P3=D + // P3=D InputState[3] = (v & B00001000) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; } } @@ -773,23 +773,23 @@ void tca9534_isr_task(void *param) { for (;;) { - //Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html + // Wait until this task is triggered https://www.freertos.org/ulTaskNotifyTake.html ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(TAG, "tca9534_isr"); - //Read ports - //The 9534 deals with internal LED outputs and spare IO on J10 + // Read ports + // The 9534 deals with internal LED outputs and spare IO on J10 uint8_t v = hal.ReadTCA9534InputRegisters(); - //P4= J13 PIN 1 = WAKE UP TFT FOR DISPLAYS WITHOUT TOUCH + // P4= J13 PIN 1 = WAKE UP TFT FOR DISPLAYS WITHOUT TOUCH InputState[4] = (v & B00010000) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //P6 = spare I/O (on PCB pin) + // P6 = spare I/O (on PCB pin) InputState[5] = (v & B01000000) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //P7 = Emergency Stop + // P7 = Emergency Stop InputState[6] = (v & B10000000) == 0 ? enumInputState::INPUT_LOW : enumInputState::INPUT_HIGH; - //Emergency Stop (J1) has triggered + // Emergency Stop (J1) has triggered if (InputState[6] == enumInputState::INPUT_LOW) { emergencyStop = true; @@ -797,7 +797,7 @@ void tca9534_isr_task(void *param) if (InputState[4] == enumInputState::INPUT_LOW) { - //Wake screen on pin going low + // Wake screen on pin going low if (tftwakeup_task_handle != NULL) { xTaskNotify(tftwakeup_task_handle, 0x00, eNotifyAction::eNoAction); @@ -815,14 +815,14 @@ void IRAM_ATTR WifiPasswordClear() { if (digitalRead(GPIO_NUM_0) == LOW) { - //Button pressed, store time + // Button pressed, store time WifiPasswordClearTime = millis() + 4000; ResetWifi = false; } else { - //Button released - //Did user press button for longer than 4 seconds? + // Button released + // Did user press button for longer than 4 seconds? if (millis() > WifiPasswordClearTime) { ResetWifi = true; @@ -830,7 +830,7 @@ void IRAM_ATTR WifiPasswordClear() } } -//Triggered when TCA6408 INT pin goes LOW +// Triggered when TCA6408 INT pin goes LOW void IRAM_ATTR TCA6408Interrupt() { if (tca6408_isr_task_handle != NULL) @@ -839,7 +839,7 @@ void IRAM_ATTR TCA6408Interrupt() } } -//Triggered when TCA9534A INT pin goes LOW +// Triggered when TCA9534A INT pin goes LOW void IRAM_ATTR TCA9534AInterrupt() { if (tca9534_isr_task_handle != NULL) @@ -892,8 +892,8 @@ const char *packetType(uint8_t cmd) void dumpPacketToDebug(char indicator, PacketStruct *buffer) { - //Filter on some commands - //if ((buffer->command & 0x0F) != COMMAND::Timing) return; + // Filter on some commands + // if ((buffer->command & 0x0F) != COMMAND::Timing) return; ESP_LOGD(TAG, "%c %02X-%02X H:%02X C:%02X SEQ:%04X CRC:%04X %s", indicator, @@ -905,7 +905,7 @@ void dumpPacketToDebug(char indicator, PacketStruct *buffer) buffer->crc, packetType(buffer->command & 0x0F)); - //ESP_LOG_BUFFER_HEX("packet", &(buffer->moduledata[0]), sizeof(buffer->moduledata), ESP_LOG_DEBUG); + // ESP_LOG_BUFFER_HEX("packet", &(buffer->moduledata[0]), sizeof(buffer->moduledata), ESP_LOG_DEBUG); } const char *ControllerStateString(ControllerState value) @@ -938,11 +938,11 @@ void SetControllerState(ControllerState newState) switch (_controller_state) { case ControllerState::PowerUp: - //Purple during start up, don't use the LED as thats not setup at this state + // Purple during start up, don't use the LED as thats not setup at this state hal.Led(RGBLED::Purple); break; case ControllerState::ConfigurationSoftAP: - //Don't use the LED as thats not setup at this state + // Don't use the LED as thats not setup at this state hal.Led(RGBLED::White); break; case ControllerState::Stabilizing: @@ -950,11 +950,11 @@ void SetControllerState(ControllerState newState) break; case ControllerState::Running: LED(RGBLED::Green); - //Fire task to switch off BOOT button after 30 seconds + // Fire task to switch off BOOT button after 30 seconds xTaskNotify(wifiresetdisable_task_handle, 0x00, eNotifyAction::eNoAction); break; case ControllerState::Unknown: - //Do nothing + // Do nothing break; } } @@ -977,8 +977,8 @@ void replyqueue_task(void *param) { for (;;) { - //Delay 1 second - vTaskDelay(pdMS_TO_TICKS(1000)); + // Delay 1 second + vTaskDelay(pdMS_TO_TICKS(500)); while (!replyQueue.isEmpty()) { @@ -987,32 +987,23 @@ void replyqueue_task(void *param) #if defined(PACKET_LOGGING_RECEIVE) // Process decoded incoming packet -//dumpPacketToDebug('R', &ps); +// dumpPacketToDebug('R', &ps); #endif if (!receiveProc.ProcessReply(&ps)) { - //Error blue + // Error blue LED(RGBLED::Blue); ESP_LOGE(TAG, "Packet Failed"); - //SERIAL_DEBUG.print(F("*FAIL*")); - //dumpPacketToDebug('F', &ps); + // SERIAL_DEBUG.print(F("*FAIL*")); + // dumpPacketToDebug('F', &ps); } - //Small delay to allow watchdog to be fed + // Small delay to allow watchdog to be fed vTaskDelay(pdMS_TO_TICKS(10)); } - - /* - //Debug - copy module zero to all the other cells for testing - //large capacity battery banks - for (size_t i = 1; i < TotalNumberOfCells(); i++) - { - memcpy(&cmi[i], &cmi[0], sizeof(CellModuleInfo)); - } -*/ } } @@ -1023,28 +1014,40 @@ void onPacketReceived() if ((ps.command & 0x0F) == COMMAND::Timing) { - //Timestamp at the earliest possible moment + // Timestamp at the earliest possible moment uint32_t t = millis(); ps.moduledata[2] = (t & 0xFFFF0000) >> 16; ps.moduledata[3] = t & 0x0000FFFF; - //Ensure CRC is correct + // Ensure CRC is correct ps.crc = CRC16::CalculateArray((uint8_t *)&ps, sizeof(PacketStruct) - 2); } if (!replyQueue.push(&ps)) { - ESP_LOGE(TAG, "*Failed to queue reply*"); + ESP_LOGE(TAG, "Reply Q full"); } + // ESP_LOGI(TAG,"Reply Q length %i",replyQueue.getCount()); } void transmit_task(void *param) { for (;;) { - //Delay 1 second - vTaskDelay(pdMS_TO_TICKS(1000)); + // Delay based on comms speed, ensure the first module has time to process and clear the request + // before sending another packet + uint16_t delay_ms = 900; - //TODO: Move to proper RTOS QUEUE... + if (mysettings.baudRate == 9600) + { + delay_ms = 450; + } + else if (mysettings.baudRate == 5000) + { + delay_ms = 700; + } + + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + // TODO: Move to proper RTOS QUEUE... if (requestQueue.isEmpty() == false) { // Called to transmit the next packet in the queue need to ensure this procedure @@ -1058,7 +1061,7 @@ void transmit_task(void *param) if (transmitBuffer.command == COMMAND::Timing) { - //Timestamp at the last possible moment + // Timestamp at the last possible moment uint32_t t = millis(); transmitBuffer.moduledata[0] = (t & 0xFFFF0000) >> 16; transmitBuffer.moduledata[1] = t & 0x0000FFFF; @@ -1075,9 +1078,9 @@ void transmit_task(void *param) } } -//Runs the rules and populates rule_outcome array with true/false for each rule -//Rules based on module parameters/readings like voltage and temperature -//are only processed once every module has returned at least 1 reading/communication +// Runs the rules and populates rule_outcome array with true/false for each rule +// Rules based on module parameters/readings like voltage and temperature +// are only processed once every module has returned at least 1 reading/communication void ProcessRules() { rules.ClearValues(); @@ -1089,17 +1092,17 @@ void ProcessRules() uint16_t totalConfiguredModules = TotalNumberOfCells(); if (totalConfiguredModules > maximum_controller_cell_modules) { - //System is configured with more than maximum modules - abort! + // System is configured with more than maximum modules - abort! rules.SetError(InternalErrorCode::TooManyModules); } if (receiveProc.totalModulesFound > 0 && receiveProc.totalModulesFound != totalConfiguredModules) { - //Found more or less modules than configured for + // Found more or less modules than configured for rules.SetError(InternalErrorCode::ModuleCountMismatch); } - //Communications error... + // Communications error... if (receiveProc.HasCommsTimedOut()) { rules.SetError(InternalErrorCode::CommunicationsError); @@ -1108,7 +1111,7 @@ void ProcessRules() if (rules.rule_outcome[Rule::EmergencyStop]) { - //Lowest 3 bits are RGB led GREEN/RED/BLUE + // Lowest 3 bits are RGB led GREEN/RED/BLUE rules.SetError(InternalErrorCode::ErrorEmergencyStop); } @@ -1140,13 +1143,13 @@ void ProcessRules() if (cmi[0].settingsCached && cmi[cellid].CodeVersionNumber != cmi[0].CodeVersionNumber) { - //Do all the modules have the same version of code as module zero? + // Do all the modules have the same version of code as module zero? rules.SetWarning(InternalWarningCode::ModuleInconsistantCodeVersion); } if (cmi[0].settingsCached && cmi[cellid].BoardVersionNumber != cmi[0].BoardVersionNumber) { - //Do all the modules have the same hardware revision? + // Do all the modules have the same hardware revision? rules.SetWarning(InternalWarningCode::ModuleInconsistantBoardRevision); } } @@ -1168,7 +1171,7 @@ void ProcessRules() if (rules.invalidModuleCount > 0) { - //Some modules are not yet valid + // Some modules are not yet valid rules.SetError(InternalErrorCode::WaitingForModulesToReply); } @@ -1187,25 +1190,25 @@ void ProcessRules() if (_controller_state == ControllerState::Stabilizing) { - //Check for zero volt modules - not a problem whilst we are in stabilizing start up mode + // Check for zero volt modules - not a problem whilst we are in stabilizing start up mode if (rules.zeroVoltageModuleCount == 0 && rules.invalidModuleCount == 0) { - //Every module has been read and they all returned a voltage move to running state + // Every module has been read and they all returned a voltage move to running state SetControllerState(ControllerState::Running); } } if (rules.rule_outcome[Rule::EmergencyStop]) { - //Lowest 3 bits are RGB led GREEN/RED/BLUE + // Lowest 3 bits are RGB led GREEN/RED/BLUE LED(RGBLED::Red); } if (rules.numberOfActiveErrors > 0 && _tft_screen_available) { - //We have active errors + // We have active errors - //Wake up the screen, this will also trigger it to update the display + // Wake up the screen, this will also trigger it to update the display if (tftwakeup_task_handle != NULL) { xTaskNotify(tftwakeup_task_handle, 0x00, eNotifyAction::eNoAction); @@ -1217,26 +1220,26 @@ void pulse_relay_off_task(void *param) { for (;;) { - //Wait until this task is triggered + // Wait until this task is triggered ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //Now wait 200ms before switching off the relays + // Now wait 200ms before switching off the relays vTaskDelay(pdMS_TO_TICKS(200)); for (int8_t y = 0; y < RELAY_TOTAL; y++) { if (previousRelayPulse[y]) { - //We now need to rapidly turn off the relay after a fixed period of time (pulse mode) - //However we leave the relay and previousRelayState looking like the relay has triggered (it has!) - //to prevent multiple pulses being sent on each rule refresh + // We now need to rapidly turn off the relay after a fixed period of time (pulse mode) + // However we leave the relay and previousRelayState looking like the relay has triggered (it has!) + // to prevent multiple pulses being sent on each rule refresh hal.SetOutputState(y, previousRelayState[y] == RelayState::RELAY_ON ? RelayState::RELAY_OFF : RelayState::RELAY_ON); previousRelayPulse[y] = false; } } - //Fire task to record state of outputs to SD Card + // Fire task to record state of outputs to SD Card xTaskNotify(sdcardlog_outputs_task_handle, 0x00, eNotifyAction::eNoAction); } } @@ -1245,10 +1248,10 @@ void rules_task(void *param) { for (;;) { - //3 seconds + // 3 seconds vTaskDelay(pdMS_TO_TICKS(3000)); - //Run the rules + // Run the rules ProcessRules(); #if defined(RULES_LOGGING) @@ -1263,20 +1266,20 @@ void rules_task(void *param) RelayState relay[RELAY_TOTAL]; - //Set defaults based on configuration + // Set defaults based on configuration for (int8_t y = 0; y < RELAY_TOTAL; y++) { relay[y] = mysettings.rulerelaydefault[y] == RELAY_ON ? RELAY_ON : RELAY_OFF; } - //Test the rules (in reverse order) + // Test the rules (in reverse order) for (int8_t n = RELAY_RULES - 1; n >= 0; n--) { if (rules.rule_outcome[n] == true) { for (int8_t y = 0; y < RELAY_TOTAL; y++) { - //Dont change relay if its set to ignore/X + // Dont change relay if its set to ignore/X if (mysettings.rulerelaystate[n][y] != RELAY_X) { if (mysettings.rulerelaystate[n][y] == RELAY_ON) @@ -1299,11 +1302,11 @@ void rules_task(void *param) if (previousRelayState[n] != relay[n]) { changes++; - //Would be better here to use the WRITE8 to lower i2c traffic + // Would be better here to use the WRITE8 to lower i2c traffic ESP_LOGI(TAG, "Set Relay %i=%i", n, relay[n] == RelayState::RELAY_ON ? 1 : 0); - //This would be better if we worked out the bit pattern first and then just submitted that as a single i2c read/write transaction + // This would be better if we worked out the bit pattern first and then just submitted that as a single i2c read/write transaction hal.SetOutputState(n, relay[n]); @@ -1326,7 +1329,7 @@ void rules_task(void *param) if (changes) { - //Fire task to record state of outputs to SD Card + // Fire task to record state of outputs to SD Card xTaskNotify(sdcardlog_outputs_task_handle, 0x00, eNotifyAction::eNoAction); } } @@ -1336,12 +1339,13 @@ void enqueue_task(void *param) { for (;;) { - //Ensure we service the cell modules every 5 or 10 seconds, depending on number of cells being serviced - //slower stops the queues from overflowing when a lot of cells are being monitored + // Ensure we service the cell modules every 5 or 10 seconds, depending on number of cells being serviced + // slower stops the queues from overflowing when a lot of cells are being monitored + // TODO: SCALE THIS BASED ON COMMS BAUD RATES vTaskDelay(pdMS_TO_TICKS((TotalNumberOfCells() <= maximum_cell_modules_per_packet) ? 5000 : 10000)); LED(RGBLED::Green); - //Fire task to switch off LED in a few ms + // Fire task to switch off LED in a few ms xTaskNotify(ledoff_task_handle, 0x00, eNotifyAction::eNoAction); uint16_t i = 0; @@ -1353,28 +1357,38 @@ void enqueue_task(void *param) { uint16_t endmodule = (startmodule + maximum_cell_modules_per_packet) - 1; - //Limit to number of modules we have configured + // Limit to number of modules we have configured if (endmodule > max) { endmodule = max - 1; } - //Need to watch overflow of the uint8 here... - prg.sendCellVoltageRequest(startmodule, endmodule); - prg.sendCellTemperatureRequest(startmodule, endmodule); + // Request voltage, but if queue is full, sleep and try again (other threads will reduce the queue) + while (prg.sendCellVoltageRequest(startmodule, endmodule) == false) + { + vTaskDelay(pdMS_TO_TICKS(500)); + } + // Same for temperature + while (prg.sendCellTemperatureRequest(startmodule, endmodule) == false) + { + vTaskDelay(pdMS_TO_TICKS(500)); + } - //If any module is in bypass then request PWM reading for whole bank + // If any module is in bypass then request PWM reading for whole bank for (uint8_t m = startmodule; m <= endmodule; m++) { if (cmi[m].inBypass) { - prg.sendReadBalancePowerRequest(startmodule, endmodule); - //We only need 1 reading for whole bank + while (prg.sendReadBalancePowerRequest(startmodule, endmodule) == false) + { + vTaskDelay(pdMS_TO_TICKS(500)); + } + // We only need 1 reading for whole bank break; } } - //Move to the next bank + // Move to the next bank startmodule = endmodule + 1; i += maximum_cell_modules_per_packet; } @@ -1430,7 +1444,7 @@ void connectToMqtt() { if (mqttClient.connected() == false) { - //ESP_LOGD(TAG, "MQTT Enabled"); + // ESP_LOGD(TAG, "MQTT Enabled"); mqttClient.setServer(mysettings.mqtt_server, mysettings.mqtt_port); mqttClient.setCredentials(mysettings.mqtt_username, mysettings.mqtt_password); @@ -1441,7 +1455,7 @@ void connectToMqtt() if (mysettings.mqtt_enabled == false && mqttClient.connected()) { - //We are connected but shouldn't be! + // We are connected but shouldn't be! ESP_LOGI(TAG, "Disconnecting MQTT"); mqttClient.disconnect(true); } @@ -1451,7 +1465,7 @@ void influxdb_task(void *param) { for (;;) { - //Delay between transmissions + // Delay between transmissions vTaskDelay(pdMS_TO_TICKS(8000)); if (mysettings.influxdb_enabled && WiFi.isConnected() && rules.invalidModuleCount == 0 && _controller_state == ControllerState::Running && rules.rule_outcome[Rule::BMSError] == false) @@ -1477,8 +1491,7 @@ void SetupOTA() type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() - ESP_LOGI(TAG, "Start updating %s", type); - }); + ESP_LOGI(TAG, "Start updating %s", type); }); ArduinoOTA.onEnd([]() { ESP_LOGD(TAG, "\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) @@ -1495,8 +1508,7 @@ void SetupOTA() else if (error == OTA_RECEIVE_ERROR) ESP_LOGE(TAG, "Receive Failed"); else if (error == OTA_END_ERROR) - ESP_LOGE(TAG, "End Failed"); - }); + ESP_LOGE(TAG, "End Failed"); }); ArduinoOTA.setHostname(WiFi.getHostname()); ArduinoOTA.setMdnsEnabled(true); @@ -1510,7 +1522,7 @@ void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) ESP_LOGI(TAG, "Request NTP from %s", mysettings.ntpServer); - //Use native ESP32 code + // Use native ESP32 code configTime(mysettings.timeZone * 3600 + mysettings.minutesTimeZone * 60, mysettings.daylight * 3600, mysettings.ntpServer); /* @@ -1549,7 +1561,7 @@ void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) ESP_LOGI(TAG, "You can access DIYBMS interface at http://%s.local or http://%s", WiFi.getHostname(), WiFi.localIP().toString().c_str()); - //Wake up the screen, this will show the IP address etc. + // Wake up the screen, this will show the IP address etc. if (tftwakeup_task_handle != NULL) { xTaskNotify(tftwakeup_task_handle, 0x01, eNotifyAction::eSetValueWithOverwrite); @@ -1560,10 +1572,10 @@ void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { ESP_LOGE(TAG, "Disconnected from Wi-Fi."); - //Indicate to loop() to reconnect, seems to be - //ESP issues using Wifi from timers - https://github.com/espressif/arduino-esp32/issues/2686 + // Indicate to loop() to reconnect, seems to be + // ESP issues using Wifi from timers - https://github.com/espressif/arduino-esp32/issues/2686 - //Wake up the screen, this will also trigger it to update the display + // Wake up the screen, this will also trigger it to update the display if (tftwakeup_task_handle != NULL) { xTaskNotify(tftwakeup_task_handle, 0x01, eNotifyAction::eSetValueWithOverwrite); @@ -1579,12 +1591,12 @@ void mqtt2(void *param) { for (;;) { - //Delay 25 seconds + // Delay 25 seconds vTaskDelay(pdMS_TO_TICKS(25000)); if (mysettings.mqtt_enabled && mqttClient.connected()) { - //ESP_LOGI(TAG, "Send MQTT Status"); + // ESP_LOGI(TAG, "Send MQTT Status"); char topic[80]; char jsonbuffer[400]; @@ -1602,6 +1614,7 @@ void mqtt2(void *param) root["badcrc"] = receiveProc.totalCRCErrors; root["ignored"] = receiveProc.totalNotProcessedErrors; root["oos"] = receiveProc.totalOutofSequenceErrors; + root["sendqlvl"] = requestQueue.getCount(); root["roundtrip"] = receiveProc.packetTimerMillisecond; serializeJson(doc, jsonbuffer, sizeof(jsonbuffer)); @@ -1609,10 +1622,10 @@ void mqtt2(void *param) mqttClient.publish(topic, 0, false, jsonbuffer); #if defined(MQTT_LOGGING) ESP_LOGD(TAG, "MQTT %s %s", topic, jsonbuffer); -//SERIAL_DEBUG.print("MQTT - ");SERIAL_DEBUG.print(topic); SERIAL_DEBUG.print('='); SERIAL_DEBUG.println(jsonbuffer); +// SERIAL_DEBUG.print("MQTT - ");SERIAL_DEBUG.print(topic); SERIAL_DEBUG.print('='); SERIAL_DEBUG.println(jsonbuffer); #endif - //Output bank level information (just voltage for now) + // Output bank level information (just voltage for now) for (int8_t bank = 0; bank < mysettings.totalNumberOfBanks; bank++) { doc.clear(); @@ -1623,11 +1636,11 @@ void mqtt2(void *param) mqttClient.publish(topic, 0, false, jsonbuffer); #if defined(MQTT_LOGGING) ESP_LOGD(TAG, "MQTT %s %s", topic, jsonbuffer); -//SERIAL_DEBUG.print("MQTT - ");SERIAL_DEBUG.print(topic); SERIAL_DEBUG.print('='); SERIAL_DEBUG.println(jsonbuffer); +// SERIAL_DEBUG.print("MQTT - ");SERIAL_DEBUG.print(topic); SERIAL_DEBUG.print('='); SERIAL_DEBUG.println(jsonbuffer); #endif } - //Using Json for below reduced MQTT messages from 14 to 2. Could be combined into same json object too. But even better is status + event driven. + // Using Json for below reduced MQTT messages from 14 to 2. Could be combined into same json object too. But even better is status + event driven. doc.clear(); // Need to clear the json object for next message sprintf(topic, "%s/rule", mysettings.mqtt_topic); for (uint8_t i = 0; i < RELAY_RULES; i++) @@ -1653,8 +1666,8 @@ void mqtt2(void *param) #endif mqttClient.publish(topic, 0, false, jsonbuffer); - } //end if - } //end for + } // end if + } // end for } uint16_t calculateCRC(const uint8_t *frame, uint8_t bufferSize) @@ -1677,12 +1690,12 @@ uint16_t calculateCRC(const uint8_t *frame, uint8_t bufferSize) return temp; /* // Reverse byte order. - uint16_t temp2 = temp >> 8; - temp = (temp << 8) | temp2; - temp &= 0xFFFF; - // the returned value is already swapped - // crcLo byte is first & crcHi byte is last - return temp; + uint16_t temp2 = temp >> 8; + temp = (temp << 8) | temp2; + temp &= 0xFFFF; + // the returned value is already swapped + // crcLo byte is first & crcHi byte is last + return temp; */ } @@ -1690,7 +1703,7 @@ uint8_t SetMobusRegistersFromFloat(uint8_t *cmd, uint8_t ptr, float value) { FloatUnionType fut; fut.value = value; - //4 bytes + // 4 bytes cmd[ptr] = (uint8_t)(fut.word[0] >> 8); ptr++; cmd[ptr] = (uint8_t)(fut.word[0] & 0xFF); @@ -1705,9 +1718,9 @@ uint8_t SetMobusRegistersFromFloat(uint8_t *cmd, uint8_t ptr, float value) void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint16_t batterycapacity, float fullchargevolt, float tailcurrent, float chargeefficiency) { - //Its possible that the RS485_TX task may have already requested some data - //at the exact split second of this call, but we ignore that - //given this infreqent usage of this function + // Its possible that the RS485_TX task may have already requested some data + // at the exact split second of this call, but we ignore that + // given this infreqent usage of this function uint16_t chargeeff = chargeefficiency * 100.0; @@ -1716,19 +1729,19 @@ void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint // Write Multiple Holding Registers uint8_t cmd[] = { - //The Slave Address + // The Slave Address diyBMSCurrentMonitorModbusAddress, - //The Function Code 16 + // The Function Code 16 16, - //Data Address of the first register (zero based so 18 = register 40019) + // Data Address of the first register (zero based so 18 = register 40019) 0, 18, - //number of registers to write + // number of registers to write 0, 8, - //number of data bytes to follow (2 registers x 2 bytes each = 4 bytes) + // number of data bytes to follow (2 registers x 2 bytes each = 4 bytes) 16, - //value to write to register 40019 |40019|shunt_max_current (unsigned int16) + // value to write to register 40019 |40019|shunt_max_current (unsigned int16) (uint8_t)(shuntmaxcur >> 8), (uint8_t)(shuntmaxcur & 0xFF), - //value to write to register 40020 |40020|shunt_millivolt (unsigned int16) + // value to write to register 40020 |40020|shunt_millivolt (unsigned int16) (uint8_t)(shuntmv >> 8), (uint8_t)(shuntmv & 0xFF), //|40021|Battery Capacity (ah) (unsigned int16) (uint8_t)(batterycapacity >> 8), (uint8_t)(batterycapacity & 0xFF), @@ -1738,7 +1751,7 @@ void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint 0, 0, 0, 0, //|40026|Charge efficiency factor % (unsigned int16) (scale x100 eg. 10000 = 100.00%, 9561 = 95.61%) (uint8_t)(chargeeff >> 8), (uint8_t)(chargeeff & 0xFF), - //CRC + // CRC 0, 0}; uint8_t ptr = SetMobusRegistersFromFloat(cmd, 13, fullchargevolt); @@ -1746,7 +1759,7 @@ void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint uint16_t temp = calculateCRC(cmd, sizeof(cmd) - 2); - //Byte swap the Hi and Lo bytes + // Byte swap the Hi and Lo bytes uint16_t crc16 = (temp << 8) | (temp >> 8); cmd[sizeof(cmd) - 2] = crc16 >> 8; // split crc into 2 bytes @@ -1754,21 +1767,21 @@ void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint if (hal.GetRS485Mutex()) { - //Ensure we have empty receive buffer + // Ensure we have empty receive buffer uart_flush_input(rs485_uart_num); - //Send the bytes (actually just put them into the TX FIFO buffer) + // Send the bytes (actually just put them into the TX FIFO buffer) uart_write_bytes(rs485_uart_num, (char *)cmd, sizeof(cmd)); hal.ReleaseRS485Mutex(); ESP_LOGD(TAG, "Send MODBUS request"); - //Zero all data + // Zero all data memset(¤tMonitor, 0, sizeof(currentmonitoring_struct)); currentMonitor.validReadings = false; - //Notify the receive task that a packet should be on its way + // Notify the receive task that a packet should be on its way if (rs485_rx_task_handle != NULL) { xTaskNotify(rs485_rx_task_handle, 0x00, eNotifyAction::eNoAction); @@ -1778,7 +1791,7 @@ void CurrentMonitorSetBasicSettings(uint16_t shuntmv, uint16_t shuntmaxcur, uint uint8_t frame[256]; -//Save the current monitor advanced settings back to the device over MODBUS/RS485 +// Save the current monitor advanced settings back to the device over MODBUS/RS485 void CurrentMonitorSetRelaySettings(currentmonitoring_struct newvalues) { uint8_t flag1 = 0; @@ -1786,10 +1799,10 @@ void CurrentMonitorSetRelaySettings(currentmonitoring_struct newvalues) flag1 += newvalues.TempCompEnabled ? B00000010 : 0; - //Use the previous value for setting the ADCRange4096mV flag + // Use the previous value for setting the ADCRange4096mV flag flag1 += currentMonitor.ADCRange4096mV ? B00000001 : 0; - //Apply new settings + // Apply new settings flag2 += newvalues.RelayTriggerTemperatureOverLimit ? bit(DIAG_ALRT_FIELD::TMPOL) : 0; flag2 += newvalues.RelayTriggerCurrentOverLimit ? bit(DIAG_ALRT_FIELD::SHNTOL) : 0; flag2 += newvalues.RelayTriggerCurrentUnderLimit ? bit(DIAG_ALRT_FIELD::SHNTUL) : 0; @@ -1813,24 +1826,24 @@ Flag 2 // Write Multiple Holding Registers uint8_t cmd[] = { - //The Slave Address + // The Slave Address diyBMSCurrentMonitorModbusAddress, - //The Function Code 16 + // The Function Code 16 16, - //Data Address of the first register (9=40010, Various status flags) + // Data Address of the first register (9=40010, Various status flags) 0, 9, - //number of registers to write + // number of registers to write 0, 1, - //number of data bytes to follow (2 registers x 2 bytes each = 4 bytes) + // number of data bytes to follow (2 registers x 2 bytes each = 4 bytes) 2, - //value to write to register 40010 + // value to write to register 40010 flag1, flag2, - //CRC + // CRC 0, 0}; uint16_t temp = calculateCRC(cmd, sizeof(cmd) - 2); - //Byte swap the Hi and Lo bytes + // Byte swap the Hi and Lo bytes uint16_t crc16 = (temp << 8) | (temp >> 8); cmd[sizeof(cmd) - 2] = crc16 >> 8; // split crc into 2 bytes @@ -1838,10 +1851,10 @@ Flag 2 if (hal.GetRS485Mutex()) { - //Ensure we have empty receive buffer + // Ensure we have empty receive buffer uart_flush_input(rs485_uart_num); - //Send the bytes (actually just put them into the TX FIFO buffer) + // Send the bytes (actually just put them into the TX FIFO buffer) uart_write_bytes(rs485_uart_num, (char *)cmd, sizeof(cmd)); hal.ReleaseRS485Mutex(); @@ -1849,58 +1862,58 @@ Flag 2 ESP_LOGD(TAG, "Write register 10 = %u %u", flag1, flag2); - //Zero all data + // Zero all data memset(¤tMonitor, 0, sizeof(currentmonitoring_struct)); currentMonitor.validReadings = false; - //Notify the receive task that a packet should be on its way + // Notify the receive task that a packet should be on its way if (rs485_rx_task_handle != NULL) { xTaskNotify(rs485_rx_task_handle, 0x00, eNotifyAction::eNoAction); } } -//Save the current monitor advanced settings back to the device over MODBUS/RS485 +// Save the current monitor advanced settings back to the device over MODBUS/RS485 void CurrentMonitorSetAdvancedSettings(currentmonitoring_struct newvalues) { // Write Multiple Holding Registers uint8_t cmd[] = { - //The Slave Address + // The Slave Address diyBMSCurrentMonitorModbusAddress, - //The Function Code 16 + // The Function Code 16 16, - //Data Address of the first register (|40028|INA_REGISTER::SHUNT_CAL (unsigned int16)) + // Data Address of the first register (|40028|INA_REGISTER::SHUNT_CAL (unsigned int16)) 0, 27, - //number of registers to write + // number of registers to write 0, 13, - //number of data bytes to follow (2 registers x 6 bytes each) + // number of data bytes to follow (2 registers x 6 bytes each) 2 * 13, - //value to write to register 40028 - //21 = shuntcal + // value to write to register 40028 + // 21 = shuntcal (uint8_t)(newvalues.modbus.shuntcal >> 8), (uint8_t)(newvalues.modbus.shuntcal & 0xFF), - //value to write to register 40029 - //temperaturelimit + // value to write to register 40029 + // temperaturelimit (uint8_t)(newvalues.modbus.temperaturelimit >> 8), (uint8_t)(newvalues.modbus.temperaturelimit & 0xFF), - //overvoltagelimit 40030 + // overvoltagelimit 40030 0, 0, 0, 0, - //undervoltagelimit 40032 + // undervoltagelimit 40032 0, 0, 0, 0, - //overcurrentlimit 40034 + // overcurrentlimit 40034 0, 0, 0, 0, - //undercurrentlimit 40029 + // undercurrentlimit 40029 0, 0, 0, 0, - //overpowerlimit 40038 + // overpowerlimit 40038 0, 0, 0, 0, - //shunttempcoefficient 40 + // shunttempcoefficient 40 (uint8_t)(newvalues.modbus.shunttempcoefficient >> 8), (uint8_t)(newvalues.modbus.shunttempcoefficient & 0xFF), - //CRC + // CRC 0, 0}; - //ESP_LOGD(TAG, "temp limit=%i", newvalues.temperaturelimit); - //ESP_LOGD(TAG, "shuntcal=%u", newvalues.shuntcal); + // ESP_LOGD(TAG, "temp limit=%i", newvalues.temperaturelimit); + // ESP_LOGD(TAG, "shuntcal=%u", newvalues.shuntcal); - //Register 18 = shunt_max_current - //Register 19 = shunt_millivolt + // Register 18 = shunt_max_current + // Register 19 = shunt_millivolt uint8_t ptr = SetMobusRegistersFromFloat(cmd, 11, newvalues.modbus.overvoltagelimit); ptr = SetMobusRegistersFromFloat(cmd, ptr, newvalues.modbus.undervoltagelimit); @@ -1921,7 +1934,7 @@ void CurrentMonitorSetAdvancedSettings(currentmonitoring_struct newvalues) uint16_t temp = calculateCRC(cmd, sizeof(cmd) - 2); - //Byte swap the Hi and Lo bytes + // Byte swap the Hi and Lo bytes uint16_t crc16 = (temp << 8) | (temp >> 8); cmd[sizeof(cmd) - 2] = crc16 >> 8; // split crc into 2 bytes @@ -1929,10 +1942,10 @@ void CurrentMonitorSetAdvancedSettings(currentmonitoring_struct newvalues) if (hal.GetRS485Mutex()) { - //Ensure we have empty receive buffer + // Ensure we have empty receive buffer uart_flush_input(rs485_uart_num); - //Send the bytes (actually just put them into the TX FIFO buffer) + // Send the bytes (actually just put them into the TX FIFO buffer) uart_write_bytes(rs485_uart_num, (char *)cmd, sizeof(cmd)); hal.ReleaseRS485Mutex(); @@ -1940,39 +1953,39 @@ void CurrentMonitorSetAdvancedSettings(currentmonitoring_struct newvalues) ESP_LOGD(TAG, "Advanced save settings"); - //Zero all data + // Zero all data memset(¤tMonitor, 0, sizeof(currentmonitoring_struct)); currentMonitor.validReadings = false; - //Notify the receive task that a packet should be on its way + // Notify the receive task that a packet should be on its way if (rs485_rx_task_handle != NULL) { xTaskNotify(rs485_rx_task_handle, 0x00, eNotifyAction::eNoAction); } } -//Swap the two 16 bit words in a 32bit word +// Swap the two 16 bit words in a 32bit word static inline unsigned int word16swap32(unsigned int __bsx) { return ((__bsx & 0xffff0000) >> 16) | ((__bsx & 0x0000ffff) << 16); } -//Extract the current monitor MODBUS registers into our internal STRUCTURE variables +// Extract the current monitor MODBUS registers into our internal STRUCTURE variables void ProcessCurrentMonitorRegisterReply(uint8_t length) { - //ESP_LOGD(TAG, "Modbus len=%i, struct len=%i", length, sizeof(currentmonitor_raw_modbus)); + // ESP_LOGD(TAG, "Modbus len=%i, struct len=%i", length, sizeof(currentmonitor_raw_modbus)); - //ESP_LOG_BUFFER_HEXDUMP(TAG, &frame[3], length, esp_log_level_t::ESP_LOG_DEBUG); + // ESP_LOG_BUFFER_HEXDUMP(TAG, &frame[3], length, esp_log_level_t::ESP_LOG_DEBUG); if (sizeof(currentmonitor_raw_modbus) != length) { - //Abort if the packet sizes are different + // Abort if the packet sizes are different memset(¤tMonitor.modbus, 0, sizeof(currentmonitor_raw_modbus)); currentMonitor.validReadings = false; return; } - //Now byte swap to align to ESP32 endiness, and copy as we go into new structure + // Now byte swap to align to ESP32 endiness, and copy as we go into new structure uint8_t *ptr = (uint8_t *)¤tMonitor.modbus; for (size_t i = 0; i < length; i += 2) { @@ -1981,22 +1994,22 @@ void ProcessCurrentMonitorRegisterReply(uint8_t length) ptr[i + 1] = temp; } - //Finally, we have to fix the 32 bit fields + // Finally, we have to fix the 32 bit fields currentMonitor.modbus.milliamphour_out = word16swap32(currentMonitor.modbus.milliamphour_out); currentMonitor.modbus.milliamphour_in = word16swap32(currentMonitor.modbus.milliamphour_in); currentMonitor.modbus.firmwareversion = word16swap32(currentMonitor.modbus.firmwareversion); currentMonitor.modbus.firmwaredatetime = word16swap32(currentMonitor.modbus.firmwaredatetime); - //ESP_LOG_BUFFER_HEXDUMP(TAG, ¤tMonitor.modbus, sizeof(currentmonitor_raw_modbus), esp_log_level_t::ESP_LOG_DEBUG); + // ESP_LOG_BUFFER_HEXDUMP(TAG, ¤tMonitor.modbus, sizeof(currentmonitor_raw_modbus), esp_log_level_t::ESP_LOG_DEBUG); currentMonitor.timestamp = esp_timer_get_time(); - //High byte + // High byte uint8_t flag1 = currentMonitor.modbus.flags >> 8; - //Low byte + // Low byte uint8_t flag2 = currentMonitor.modbus.flags; - //ESP_LOGD(TAG, "Read relay trigger settings %u %u", flag1, flag2); + // ESP_LOGD(TAG, "Read relay trigger settings %u %u", flag1, flag2); /* 16|TMPOL|Read only @@ -2036,7 +2049,7 @@ void ProcessCurrentMonitorRegisterReply(uint8_t length) currentMonitor.RelayTriggerVoltageUnderlimit = flag2 & bit(DIAG_ALRT_FIELD::BUSUL); currentMonitor.RelayTriggerPowerOverLimit = flag2 & bit(DIAG_ALRT_FIELD::POL); currentMonitor.RelayState = flag2 & B00000010; - //Last bit is for factory reset (always zero) + // Last bit is for factory reset (always zero) currentMonitor.chargeefficiency = ((float)currentMonitor.modbus.raw_chargeefficiency) / 100.0; currentMonitor.stateofcharge = ((float)currentMonitor.modbus.raw_stateofcharge) / 100.0; @@ -2397,27 +2410,27 @@ void ProcessCurrentMonitorRegisterReply_OLD(uint8_t length) } */ -//RS485 receive +// RS485 receive void rs485_rx(void *param) { for (;;) { - //Wait until this task is triggered (sending task triggers it) + // Wait until this task is triggered (sending task triggers it) ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - //Delay 50ms for the data to arrive + // Delay 50ms for the data to arrive vTaskDelay(pdMS_TO_TICKS(50)); int len = 0; if (hal.GetRS485Mutex()) { - //Wait 200ms before timeout + // Wait 200ms before timeout len = uart_read_bytes(rs485_uart_num, frame, sizeof(frame), (200 / portTICK_RATE_MS)); hal.ReleaseRS485Mutex(); } - //Min packet length of 5 bytes + // Min packet length of 5 bytes if (len > 5) { uint8_t id = frame[0]; @@ -2425,12 +2438,12 @@ void rs485_rx(void *param) uint16_t crc = ((frame[len - 2] << 8) | frame[len - 1]); // combine the crc Low & High bytes uint16_t temp = calculateCRC(frame, len - 2); - //Swap bytes to match MODBUS ordering + // Swap bytes to match MODBUS ordering uint16_t calculatedCRC = (temp << 8) | (temp >> 8); ESP_LOGD(TAG, "Rec %i bytes, id=%u", len, id); - //ESP_LOG_BUFFER_HEXDUMP(TAG, frame, len, esp_log_level_t::ESP_LOG_DEBUG); + // ESP_LOG_BUFFER_HEXDUMP(TAG, frame, len, esp_log_level_t::ESP_LOG_DEBUG); if (calculatedCRC == crc) { @@ -2441,7 +2454,7 @@ void rs485_rx(void *param) uint8_t cmd = frame[1] & B01111111; uint8_t length = frame[2]; - //ESP_LOGD(TAG, "CRC pass Id=%u F=%u L=%u", id, cmd, length); + // ESP_LOGD(TAG, "CRC pass Id=%u F=%u L=%u", id, cmd, length); if (id == diyBMSCurrentMonitorModbusAddress && cmd == 3) { @@ -2449,11 +2462,11 @@ void rs485_rx(void *param) if (_tft_screen_available) { - //Refresh the TFT display + // Refresh the TFT display xTaskNotify(updatetftdisplay_task_handle, 0x00, eNotifyAction::eNoAction); } - } //end diybms current monitor command 3 + } // end diybms current monitor command 3 if (id == diyBMSCurrentMonitorModbusAddress && cmd == 16) { @@ -2472,13 +2485,13 @@ void rs485_rx(void *param) } else { - //We didn't receive anything on RS485 + // We didn't receive anything on RS485 ESP_LOGE(TAG, "Short packet %i bytes", len); - //Indicate that the current monitor values are now invalid/unknown + // Indicate that the current monitor values are now invalid/unknown currentMonitor.validReadings = false; } - //for (int i = 0; i < len; i++) { dumpByte(data[i]); } + // for (int i = 0; i < len; i++) { dumpByte(data[i]); } } } @@ -2486,20 +2499,20 @@ void victron_canbus_tx(void *param) { for (;;) { - //Delay 1 seconds + // Delay 1 seconds vTaskDelay(pdMS_TO_TICKS(1000)); if (mysettings.VictronEnabled) { - //minimum CAN-IDs required for the core functionality are 0x351, 0x355, 0x356 and 0x35A. + // minimum CAN-IDs required for the core functionality are 0x351, 0x355, 0x356 and 0x35A. - //351 message must be sent at least every 3 seconds - or Victron will stop charge/discharge + // 351 message must be sent at least every 3 seconds - or Victron will stop charge/discharge victron_message_351(); - //Delay a little whilst sending packets to give ESP32 some breathing room and not flood the CANBUS + // Delay a little whilst sending packets to give ESP32 some breathing room and not flood the CANBUS vTaskDelay(pdMS_TO_TICKS(100)); - //Advertise the diyBMS name on CANBUS + // Advertise the diyBMS name on CANBUS victron_message_370_371(); victron_message_35e(); victron_message_35a(); @@ -2515,7 +2528,7 @@ void victron_canbus_tx(void *param) vTaskDelay(pdMS_TO_TICKS(100)); - //Detail about individual cells + // Detail about individual cells victron_message_373(); victron_message_374_375_376_377(); } @@ -2531,13 +2544,13 @@ void victron_canbus_rx(void *param) if (mysettings.VictronEnabled) { - //Wait for message to be received + // Wait for message to be received can_message_t message; esp_err_t res = can_receive(&message, pdMS_TO_TICKS(10000)); if (res == ESP_OK) { canbus_messages_received++; - //ESP_LOGI(TAG, "CANBUS received message"); + // ESP_LOGI(TAG, "CANBUS received message"); /* SERIAL_DEBUG.println("Message received\n"); @@ -2584,42 +2597,42 @@ void victron_canbus_rx(void *param) } else { - //Canbus is disbled, sleep.... + // Canbus is disbled, sleep.... vTaskDelay(pdMS_TO_TICKS(2000)); } } } -//This is the request we send to diyBMS current monitor, it pulls back 38 registers -//this is all the registers diyBMS current monitor has -//Holding Registers = command 3 +// This is the request we send to diyBMS current monitor, it pulls back 38 registers +// this is all the registers diyBMS current monitor has +// Holding Registers = command 3 -//RS485 transmit +// RS485 transmit void rs485_tx(void *param) { - //8 byte request + // 8 byte request uint8_t cmd[] = {0, 0, 0, 0, 0, 0, 0, 0}; for (;;) { - //Delay 5 seconds + // Delay 5 seconds vTaskDelay(pdMS_TO_TICKS(5000)); if (mysettings.currentMonitoringEnabled == true) { - //ESP_LOGD(TAG, "RS485 TX"); + // ESP_LOGD(TAG, "RS485 TX"); cmd[0] = diyBMSCurrentMonitorModbusAddress; - //Input registers - 46 of them (92 bytes + headers + crc = 83 byte reply) + // Input registers - 46 of them (92 bytes + headers + crc = 83 byte reply) cmd[1] = 3; cmd[5] = 46; - //Ideally we poll the current monitor and only ask it for a small subset of registers - //the first 12 registers are the most useful, so only need the others when we want to get the configuration data + // Ideally we poll the current monitor and only ask it for a small subset of registers + // the first 12 registers are the most useful, so only need the others when we want to get the configuration data uint16_t temp = calculateCRC(cmd, sizeof(cmd) - 2); - //Byte swap the Hi and Lo bytes + // Byte swap the Hi and Lo bytes uint16_t crc16 = (temp << 8) | (temp >> 8); cmd[sizeof(cmd) - 2] = crc16 >> 8; // split crc into 2 bytes @@ -2627,33 +2640,33 @@ void rs485_tx(void *param) if (hal.GetRS485Mutex()) { - //Ensure we have empty receive buffer + // Ensure we have empty receive buffer uart_flush_input(rs485_uart_num); - //Send the bytes (actually just put them into the TX FIFO buffer) + // Send the bytes (actually just put them into the TX FIFO buffer) uart_write_bytes(rs485_uart_num, (char *)cmd, sizeof(cmd)); hal.ReleaseRS485Mutex(); - //Notify the receive task that a packet should be on its way + // Notify the receive task that a packet should be on its way if (rs485_rx_task_handle != NULL) { xTaskNotify(rs485_rx_task_handle, 0x00, eNotifyAction::eNoAction); } } - } //end if + } // end if } } void mqtt1(void *param) { - //Send a few MQTT packets and keep track so we send the next batch on following calls + // Send a few MQTT packets and keep track so we send the next batch on following calls static uint8_t mqttStartModule = 0; static int64_t lastcurrentMonitortimestamp = 0; for (;;) { - //Delay 5 seconds + // Delay 5 seconds vTaskDelay(pdMS_TO_TICKS(5000)); if (mysettings.mqtt_enabled && mqttClient.connected() == false) @@ -2668,7 +2681,7 @@ void mqtt1(void *param) char jsonbuffer[300]; StaticJsonDocument<300> doc; - //If the BMS is in error, stop sending MQTT packets for the data + // If the BMS is in error, stop sending MQTT packets for the data if (!rules.rule_outcome[Rule::BMSError]) { @@ -2682,8 +2695,8 @@ void mqtt1(void *param) while (i < TotalNumberOfCells() && counter < 8) { - //ESP_LOGI(TAG, "Send MQTT for module %u", i); - //Only send valid module data + // ESP_LOGI(TAG, "Send MQTT for module %u", i); + // Only send valid module data if (cmi[i].valid) { uint8_t bank = i / mysettings.totalNumberOfSeriesModules; @@ -2716,14 +2729,14 @@ void mqtt1(void *param) i++; } - //After transmitting this many packets over MQTT, store our current state and exit the function. - //this prevents flooding the ESP controllers wifi stack and potentially causing reboots/fatal exceptions + // After transmitting this many packets over MQTT, store our current state and exit the function. + // this prevents flooding the ESP controllers wifi stack and potentially causing reboots/fatal exceptions mqttStartModule = i; } if (mysettings.currentMonitoringEnabled) { - //Send current monitor data + // Send current monitor data doc.clear(); // Need to clear the json object for next message sprintf(topic, "%s/modbus/A%u", mysettings.mqtt_topic, mysettings.currentMonitoringModBusAddress); @@ -2731,7 +2744,7 @@ void mqtt1(void *param) if (currentMonitor.validReadings && currentMonitor.timestamp != lastcurrentMonitortimestamp) { - //Send current monitor data if its valid and not sent before + // Send current monitor data if its valid and not sent before doc["voltage"] = currentMonitor.modbus.voltage; doc["current"] = currentMonitor.modbus.current; doc["mAhIn"] = currentMonitor.modbus.milliamphour_in; @@ -2767,38 +2780,38 @@ void LoadConfiguration() ESP_LOGI(TAG, "Apply default config"); - //Zero all the bytes + // Zero all the bytes memset(&mysettings, 0, sizeof(mysettings)); - //Default to a single module + // Default to a single module mysettings.totalNumberOfBanks = 1; mysettings.totalNumberOfSeriesModules = 1; - //Default serial port speed + // Default serial port speed mysettings.baudRate = COMMS_BAUD_RATE; mysettings.BypassOverTempShutdown = 65; - //4.10V bypass + // 4.10V bypass mysettings.BypassThresholdmV = 4100; mysettings.graph_voltagehigh = 4.5; mysettings.graph_voltagelow = 2.75; - //EEPROM settings are invalid so default configuration + // EEPROM settings are invalid so default configuration mysettings.mqtt_enabled = false; mysettings.mqtt_port = 1883; mysettings.VictronEnabled = false; - //Charge current limit (CCL) + // Charge current limit (CCL) mysettings.ccl[VictronDVCC::Default] = 10 * 10; - //Charge voltage limit (CVL) + // Charge voltage limit (CVL) mysettings.cvl[VictronDVCC::Default] = 12 * 10; - //Discharge current limit (DCL) + // Discharge current limit (DCL) mysettings.dcl[VictronDVCC::Default] = 10 * 10; - //Balance + // Balance mysettings.ccl[VictronDVCC::Balance] = 10 * 10; mysettings.cvl[VictronDVCC::Balance] = 10 * 10; mysettings.dcl[VictronDVCC::Balance] = 10 * 10; - //Error + // Error mysettings.ccl[VictronDVCC::ControllerError] = 0 * 10; mysettings.cvl[VictronDVCC::ControllerError] = 0 * 10; mysettings.dcl[VictronDVCC::ControllerError] = 0 * 10; @@ -2818,7 +2831,7 @@ void LoadConfiguration() strcpy(mysettings.language, "en"); - //Default to EMONPI default MQTT settings + // Default to EMONPI default MQTT settings strcpy(mysettings.mqtt_topic, "emon/diybms"); strcpy(mysettings.mqtt_server, "192.168.0.26"); strcpy(mysettings.mqtt_username, "emonpi"); @@ -2839,26 +2852,26 @@ void LoadConfiguration() mysettings.rulerelaydefault[x] = RELAY_OFF; } - //Emergency stop + // Emergency stop mysettings.rulevalue[Rule::EmergencyStop] = 0; - //Internal BMS error (communication issues, fault readings from modules etc) + // Internal BMS error (communication issues, fault readings from modules etc) mysettings.rulevalue[Rule::BMSError] = 0; - //Current monitoring maximum AMPS + // Current monitoring maximum AMPS mysettings.rulevalue[Rule::CurrentMonitorOverCurrentAmps] = 100; - //Individual cell over voltage + // Individual cell over voltage mysettings.rulevalue[Rule::ModuleOverVoltage] = 4150; - //Individual cell under voltage + // Individual cell under voltage mysettings.rulevalue[Rule::ModuleUnderVoltage] = 3000; - //Individual cell over temperature (external probe) + // Individual cell over temperature (external probe) mysettings.rulevalue[Rule::ModuleOverTemperatureExternal] = 55; - //Pack over voltage (mV) + // Pack over voltage (mV) mysettings.rulevalue[Rule::ModuleUnderTemperatureExternal] = 5; - //Pack under voltage (mV) + // Pack under voltage (mV) mysettings.rulevalue[Rule::BankOverVoltage] = 4200 * 8; - //RULE_PackUnderVoltage + // RULE_PackUnderVoltage mysettings.rulevalue[Rule::BankUnderVoltage] = 3000 * 8; - mysettings.rulevalue[Rule::Timer1] = 60 * 8; //8am - mysettings.rulevalue[Rule::Timer2] = 60 * 17; //5pm + mysettings.rulevalue[Rule::Timer1] = 60 * 8; // 8am + mysettings.rulevalue[Rule::Timer2] = 60 * 17; // 5pm mysettings.rulevalue[Rule::ModuleOverTemperatureInternal] = 60; mysettings.rulevalue[Rule::ModuleUnderTemperatureInternal] = 5; @@ -2870,7 +2883,7 @@ void LoadConfiguration() { mysettings.rulehysteresis[i] = mysettings.rulevalue[i]; - //Set all relays to don't care + // Set all relays to don't care for (size_t x = 0; x < RELAY_TOTAL; x++) { mysettings.rulerelaystate[i][x] = RELAY_X; @@ -2883,107 +2896,93 @@ void LoadConfiguration() } } -uint8_t lazyTimerMode = 0; -//Do activities which are not critical to the system like background loading of config, or updating timing results etc. +// Do activities which are not critical to the system like background loading of config, or updating timing results etc. void lazy_tasks(void *param) { for (;;) { - //Delay 6.5 seconds - vTaskDelay(pdMS_TO_TICKS(6500)); + // TODO: Perhaps this should be based on some improved logic - based on number of modules in system? + // Delay 6.5 seconds + + ESP_LOGI(TAG, "Sleep"); + TickType_t delay_ticks = pdMS_TO_TICKS(6500); + vTaskDelay(delay_ticks); - if (requestQueue.getRemainingCount() > 6) + // Task 1 + ESP_LOGI(TAG, "Task 1"); + // Send a "ping" message through the cells to get a round trip time + while (prg.sendTimingRequest() == false) { - bool done_for_this_loop = false; + vTaskDelay(pdMS_TO_TICKS(1000)); + } - lazyTimerMode++; + // Sleep between sections to give the ESP a chance to do other stuff + vTaskDelay(delay_ticks); - if (lazyTimerMode == 1 && !done_for_this_loop) - { - //Send a "ping" message through the cells to get a round trip time - prg.sendTimingRequest(); - done_for_this_loop = true; - } - - if (lazyTimerMode == 2 && !done_for_this_loop) + // Task 2 + ESP_LOGI(TAG, "Task 2"); + uint8_t counter = 0; + // Find modules that don't have settings cached and request them + for (uint8_t module = 0; module < TotalNumberOfCells(); module++) + { + if (cmi[module].valid && !cmi[module].settingsCached) { - done_for_this_loop = true; - uint8_t counter = 0; - //Find modules that don't have settings cached and request them - for (uint8_t module = 0; module < TotalNumberOfCells(); module++) + while (prg.sendGetSettingsRequest(module) == false) { - if (cmi[module].valid && !cmi[module].settingsCached) - { - if (requestQueue.getRemainingCount() < 6) - { - //Exit here to avoid flooding the queue - break; - } - - prg.sendGetSettingsRequest(module); - counter++; - } - } + vTaskDelay(pdMS_TO_TICKS(1000)); + }; + counter++; } + } - if (!done_for_this_loop) - { - - //Send these requests to all banks of modules - uint16_t i = 0; - uint16_t max = TotalNumberOfCells(); - - uint8_t startmodule = 0; - - while (i < max) - { - uint16_t endmodule = (startmodule + maximum_cell_modules_per_packet) - 1; - - //Limit to number of modules we have configured - if (endmodule > max) - { - endmodule = max - 1; - } + // Sleep between sections to give the ESP a chance to do other stuff + vTaskDelay(delay_ticks); - if (lazyTimerMode == 3) - { - prg.sendReadBalanceCurrentCountRequest(startmodule, endmodule); - } + // Task 3 + // Send these requests to all banks of modules + uint16_t i = 0; + uint16_t max = TotalNumberOfCells(); - if (lazyTimerMode == 4) - { - prg.sendReadPacketsReceivedRequest(startmodule, endmodule); - } + uint8_t startmodule = 0; - //Ask for bad packet count (saves battery power if we dont ask for this all the time) - if (lazyTimerMode == 5) - { - prg.sendReadBadPacketCounter(startmodule, endmodule); - } + while (i < max) + { + uint16_t endmodule = (startmodule + maximum_cell_modules_per_packet) - 1; - //Move to the next bank - startmodule = endmodule + 1; - i += maximum_cell_modules_per_packet; - } //end while + // Limit to number of modules we have configured + if (endmodule > max) + { + endmodule = max - 1; } - //Reset at end of cycle - if (lazyTimerMode >= 5) + ESP_LOGI(TAG, "Task 3, s=%i e=%i", startmodule, endmodule); + while (prg.sendReadBalanceCurrentCountRequest(startmodule, endmodule) == false) { - lazyTimerMode = 0; + vTaskDelay(pdMS_TO_TICKS(1000)); } - } - else - { - //Exit here to avoid overflowing the queue - ESP_LOGE(TAG, "ERR: Lazy overflow Q=%i", requestQueue.getRemainingCount()); - } - } //end for + while (prg.sendReadPacketsReceivedRequest(startmodule, endmodule) == false) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + while (prg.sendReadBadPacketCounter(startmodule, endmodule) == false) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + // Delay per bank/loop + vTaskDelay(delay_ticks); + + // Move to the next bank + startmodule = endmodule + 1; + i += maximum_cell_modules_per_packet; + } // end while + + } // end for } void resetAllRules() { - //Clear all rules + // Clear all rules for (int8_t r = 0; r < RELAY_RULES; r++) { rules.rule_outcome[r] = false; @@ -2998,14 +2997,14 @@ bool CaptureSerialInput(HardwareSerial stream, char *buffer, int buffersize, boo while (true) { - //Abort after 30 seconds of inactivity + // Abort after 30 seconds of inactivity if (millis() > timer) return false; - //We should add a timeout in here, and return FALSE when we abort.... + // We should add a timeout in here, and return FALSE when we abort.... while (stream.available()) { - //Reset timer on serial input + // Reset timer on serial input timer = millis() + 30000; int data = stream.read(); @@ -3019,7 +3018,7 @@ bool CaptureSerialInput(HardwareSerial stream, char *buffer, int buffersize, boo } else if (data == '\n') { - //Ignore + // Ignore } else if (data == '\r') { @@ -3028,13 +3027,13 @@ bool CaptureSerialInput(HardwareSerial stream, char *buffer, int buffersize, boo stream.write("\r\n"); // output CRLF buffer[length] = '\0'; - //Soak up any other characters on the buffer and throw away + // Soak up any other characters on the buffer and throw away while (stream.available()) { stream.read(); } - //Return to caller + // Return to caller return true; } @@ -3044,14 +3043,14 @@ bool CaptureSerialInput(HardwareSerial stream, char *buffer, int buffersize, boo { if (OnlyDigits && (data < '0' || data > '9')) { - //We need to filter out non-digit characters + // We need to filter out non-digit characters } else { buffer[length++] = data; if (ShowPasswordChar) { - //Hide real character + // Hide real character stream.write('*'); } else @@ -3088,7 +3087,7 @@ void TerminalBasedWifiSetup(HardwareSerial stream) stream.print(':'); stream.print(WiFi.SSID(i)); - //Pad out the wifi names into 2 columns + // Pad out the wifi names into 2 columns for (size_t spaces = WiFi.SSID(i).length(); spaces < 36; spaces++) { stream.print(' '); @@ -3206,7 +3205,7 @@ bool LoadWiFiConfigFromSDCard(bool existingConfigValid) File file = SD.open(wificonfigfilename); DeserializationError error = deserializeJson(json, file); file.close(); - //Release Mutex as quickly as possible + // Release Mutex as quickly as possible hal.ReleaseVSPIMutex(); if (error != DeserializationError::Ok) { @@ -3219,12 +3218,12 @@ bool LoadWiFiConfigFromSDCard(bool existingConfigValid) JsonObject wifi = json["wifi"]; wifi_eeprom_settings _config; - //Pointer to existing configuration + // Pointer to existing configuration wifi_eeprom_settings *_config_existing; _config_existing = DIYBMSSoftAP::Config(); - //Clear config + // Clear config memset(&_config, 0, sizeof(_config)); String ssid = wifi["ssid"].as(); @@ -3232,7 +3231,7 @@ bool LoadWiFiConfigFromSDCard(bool existingConfigValid) ssid.toCharArray(_config.wifi_ssid, sizeof(_config.wifi_ssid)); password.toCharArray(_config.wifi_passphrase, sizeof(_config.wifi_passphrase)); - //Our configuration is different, so store the details in EEPROM and flash the LED a few times + // Our configuration is different, so store the details in EEPROM and flash the LED a few times if (existingConfigValid == false || strcmp(_config_existing->wifi_ssid, _config.wifi_ssid) != 0 || strcmp(_config_existing->wifi_passphrase, _config.wifi_passphrase) != 0) { ESP_LOGD(TAG, "Wifi JSON SSID=%s", _config.wifi_ssid); @@ -3258,7 +3257,7 @@ bool LoadWiFiConfigFromSDCard(bool existingConfigValid) } else { - //Didn't find the file, but still need to release mutex + // Didn't find the file, but still need to release mutex hal.ReleaseVSPIMutex(); } } @@ -3277,7 +3276,7 @@ void setup() const char *diybms_logo = "\r\n\r\n\r\n _ __ \r\n _| o |_) |\\/| (_ \r\n (_| | \\/ |_) | | __) \r\n / "; - //ESP32 we use the USB serial interface for console/debug messages + // ESP32 we use the USB serial interface for console/debug messages SERIAL_DEBUG.begin(115200, SERIAL_8N1); SERIAL_DEBUG.setDebugOutput(true); @@ -3297,15 +3296,15 @@ void setup() _avrsettings.inProgress = false; _avrsettings.programmingModeEnabled = false; - //See if we can get a sensible reading from the TFT touch chip XPT2046 - //if we can, then a screen is fitted, so enable it + // See if we can get a sensible reading from the TFT touch chip XPT2046 + // if we can, then a screen is fitted, so enable it _tft_screen_available = hal.IsScreenAttached(); if (_tft_screen_available) { ESP_LOGI(TAG, "TFT screen is INSTALLED"); - //Only attach, if device is fitted otherwise false triggers may occur - //Touch screen IRQ (GPIO_NUM_36) is active LOW (XPT2046 chip) + // Only attach, if device is fitted otherwise false triggers may occur + // Touch screen IRQ (GPIO_NUM_36) is active LOW (XPT2046 chip) attachInterrupt(TOUCH_IRQ, TFTScreenTouchInterrupt, FALLING); } else @@ -3326,12 +3325,12 @@ void setup() else { ESP_LOGI(TAG, "LITTLEFS mounted, totalBytes=%u, usedBytes=%u", LITTLEFS.totalBytes(), LITTLEFS.usedBytes()); - //listDir(LITTLEFS, "/", 0); + // listDir(LITTLEFS, "/", 0); } mountSDCard(); - //Switch CAN chip TJA1051T/3 ON + // Switch CAN chip TJA1051T/3 ON hal.CANBUSEnable(true); hal.ConfigureCAN(); @@ -3339,7 +3338,7 @@ void setup() hal.ConfigureVSPI(); init_tft_display(); - //Pre configure the array + // Pre configure the array memset(&cmi, 0, sizeof(cmi)); for (size_t i = 0; i < maximum_controller_cell_modules; i++) { @@ -3351,7 +3350,7 @@ void setup() LoadConfiguration(); ESP_LOGI("Config loaded"); - //Receive is IO2 which means the RX1 plug must be disconnected for programming to work! + // Receive is IO2 which means the RX1 plug must be disconnected for programming to work! SERIAL_DATA.begin(mysettings.baudRate, SERIAL_8N1, 2, 32); // Serial for comms to modules myPacketSerial.begin(&SERIAL_DATA, &onPacketReceived, sizeof(PacketStruct), SerialPacketReceiveBuffer, sizeof(SerialPacketReceiveBuffer)); @@ -3381,26 +3380,26 @@ void setup() xTaskCreate(victron_canbus_tx, "viccantx", 3000, nullptr, 1, &victron_canbus_tx_task_handle); xTaskCreate(victron_canbus_rx, "viccanrx", 3000, nullptr, 1, &victron_canbus_rx_task_handle); - //We process the transmit queue every 1 second (this needs to be lower delay than the queue fills) - //and slower than it takes a single module to process a command (about 200ms @ 2400baud) + // We process the transmit queue every 1 second (this needs to be lower delay than the queue fills) + // and slower than it takes a single module to process a command (about 200ms @ 2400baud) xTaskCreate(transmit_task, "tx", 2048, nullptr, configMAX_PRIORITIES - 3, &transmit_task_handle); xTaskCreate(replyqueue_task, "rxq", 2048, nullptr, configMAX_PRIORITIES - 2, &replyqueue_task_handle); xTaskCreate(lazy_tasks, "lazyt", 2048, nullptr, 1, &lazy_task_handle); xTaskCreate(pulse_relay_off_task, "pulse", 2048, nullptr, configMAX_PRIORITIES - 1, &pulse_relay_off_task_handle); - //Set relay defaults + // Set relay defaults for (int8_t y = 0; y < RELAY_TOTAL; y++) { previousRelayState[y] = mysettings.rulerelaydefault[y]; - //Set relay defaults + // Set relay defaults hal.SetOutputState(y, mysettings.rulerelaydefault[y]); } - //Fire task to record state of outputs to SD Card + // Fire task to record state of outputs to SD Card xTaskNotify(sdcardlog_outputs_task_handle, 0x00, eNotifyAction::eNoAction); - //Allow user to press SPACE BAR key on serial terminal - //to enter text based WIFI setup + // Allow user to press SPACE BAR key on serial terminal + // to enter text based WIFI setup SERIAL_DEBUG.print(F("Press SPACE BAR to enter terminal based configuration....")); for (size_t i = 0; i < (3000 / 250); i++) { @@ -3408,7 +3407,7 @@ void setup() while (SERIAL_DEBUG.available()) { int x = SERIAL_DEBUG.read(); - //SPACE BAR + // SPACE BAR if (x == 32) { TerminalBasedWifiSetup(SERIAL_DEBUG); @@ -3419,29 +3418,29 @@ void setup() SERIAL_DEBUG.println(F("skipped")); SERIAL_DEBUG.flush(); - //Retrieve the EEPROM WIFI settings + // Retrieve the EEPROM WIFI settings bool EepromConfigValid = DIYBMSSoftAP::LoadConfigFromEEPROM(); if (LoadWiFiConfigFromSDCard(EepromConfigValid)) { - //We need to reload the configuration, as it was updated... + // We need to reload the configuration, as it was updated... EepromConfigValid = DIYBMSSoftAP::LoadConfigFromEEPROM(); } - //Temporarly force WIFI settings - //wifi_eeprom_settings xxxx; - //strcpy(xxxx.wifi_ssid,"XXXXXX"); - //strcpy(xxxx.wifi_passphrase,"XXXXXX"); - //Settings::WriteConfig("diybmswifi",(char *)&config, sizeof(config)); - //clearAPSettings = 0; + // Temporarly force WIFI settings + // wifi_eeprom_settings xxxx; + // strcpy(xxxx.wifi_ssid,"XXXXXX"); + // strcpy(xxxx.wifi_passphrase,"XXXXXX"); + // Settings::WriteConfig("diybmswifi",(char *)&config, sizeof(config)); + // clearAPSettings = 0; if (!EepromConfigValid) { - //We have just started up and the EEPROM is empty of configuration + // We have just started up and the EEPROM is empty of configuration SetControllerState(ControllerState::ConfigurationSoftAP); ESP_LOGI(TAG, "Setup Access Point"); - //We are in initial power on mode (factory reset) + // We are in initial power on mode (factory reset) DIYBMSSoftAP::SetupAccessPoint(&server); } else @@ -3450,34 +3449,34 @@ void setup() would try to act as both a client and an access-point */ WiFi.onEvent(onWifiConnect, system_event_id_t::SYSTEM_EVENT_STA_GOT_IP); WiFi.onEvent(onWifiDisconnect, system_event_id_t::SYSTEM_EVENT_STA_DISCONNECTED); - //Newer IDF version will need this... - //WiFi.onEvent(onWifiConnect, arduino_event_id_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); - //WiFi.onEvent(onWifiDisconnect, arduino_event_id_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); + // Newer IDF version will need this... + // WiFi.onEvent(onWifiConnect, arduino_event_id_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); + // WiFi.onEvent(onWifiDisconnect, arduino_event_id_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); mqttClient.onConnect(onMqttConnect); mqttClient.onDisconnect(onMqttDisconnect); connectToMqtt(); - xTaskCreate(enqueue_task, "enqueue", 1024, nullptr, configMAX_PRIORITIES / 2, &enqueue_task_handle); + xTaskCreate(enqueue_task, "enqueue", 2048, nullptr, configMAX_PRIORITIES / 2, &enqueue_task_handle); xTaskCreate(rules_task, "rules", 2048, nullptr, configMAX_PRIORITIES - 5, &rule_task_handle); xTaskCreate(influxdb_task, "influxdb", 6000, nullptr, 1, &influxdb_task_handle); - //We have just started... + // We have just started... SetControllerState(ControllerState::Stabilizing); hal.TFTScreenBacklight(false); - //Attempt connection in setup(), loop() will also try every 30 seconds + // Attempt connection in setup(), loop() will also try every 30 seconds connectToWifi(); - //We generate a unique number which is used in all following JSON requests - //we use this as a simple method to avoid cross site scripting attacks - //This MUST be done once the WIFI is switched on otherwise only PSEUDO random - //data is generated!! + // We generate a unique number which is used in all following JSON requests + // we use this as a simple method to avoid cross site scripting attacks + // This MUST be done once the WIFI is switched on otherwise only PSEUDO random + // data is generated!! DIYBMSServer::generateUUID(); - //Wake screen on power up + // Wake screen on power up xTaskNotify(tftwakeup_task_handle, 0x00, eNotifyAction::eNoAction); } } @@ -3493,11 +3492,11 @@ void loop() if (_controller_state != ControllerState::ConfigurationSoftAP) { - //on first pass wifitimer is zero + // on first pass wifitimer is zero if (currentMillis - wifitimer > 30000) { - //Attempt to connect to WiFi every 30 seconds, this caters for when WiFi drops - //such as AP reboot, its written to return without action if we are already connected + // Attempt to connect to WiFi every 30 seconds, this caters for when WiFi drops + // such as AP reboot, its written to return without action if we are already connected connectToWifi(); wifitimer = currentMillis; connectToMqtt(); @@ -3563,7 +3562,7 @@ void loop() { if (touchscreen.touched()) { - + TS_Point p = touchscreen.getPoint(); SERIAL_DEBUG.print("Pressure = "); SERIAL_DEBUG.print(p.z); @@ -3572,7 +3571,7 @@ void loop() SERIAL_DEBUG.print(", y = "); SERIAL_DEBUG.print(p.y); SERIAL_DEBUG.println(); - + } hal.ReleaseVSPIMutex(); @@ -3582,10 +3581,10 @@ void loop() */ if (ResetWifi) { - //Password reset, turn LED CYAN + // Password reset, turn LED CYAN LED(RGBLED::Cyan); - //Wipe EEPROM WIFI setting + // Wipe EEPROM WIFI setting DIYBMSSoftAP::FactoryReset(); ResetWifi = false; } diff --git a/ESPController/web_src/default.htm b/ESPController/web_src/default.htm index 4a139bab..d2b25fa1 100644 --- a/ESPController/web_src/default.htm +++ b/ESPController/web_src/default.htm @@ -110,6 +110,7 @@
Packets rec'd:
Roundtrip (ms):
Uptime:
+
Send Q length:
CAN sent:
CAN received:
diff --git a/ESPController/web_src/pagecode.js b/ESPController/web_src/pagecode.js index a7271886..fcf016d8 100644 --- a/ESPController/web_src/pagecode.js +++ b/ESPController/web_src/pagecode.js @@ -364,11 +364,13 @@ function queryBMS() { if (jsondata.roundtrip == 0) { $("#roundtrip").hide(); } else { $("#roundtrip .v").html(jsondata.roundtrip); $("#roundtrip").show(); } if (jsondata.oos == 0) { $("#oos").hide(); } else { $("#oos .v").html(jsondata.oos); $("#oos").show(); } + if (jsondata.can_fail == 0) { $("#canfail").hide(); } else { $("#canfail .v").html(jsondata.can_fail); $("#canfail").show(); } if (jsondata.can_sent == 0) { $("#cansent").hide(); } else { $("#cansent .v").html(jsondata.can_sent); $("#cansent").show(); } if (jsondata.can_rec == 0) { $("#canrecd").hide(); } else { $("#canrecd .v").html(jsondata.can_rec); $("#canrecd").show(); } + if (jsondata.qlen == 0) { $("#qlen").hide(); } else { $("#qlen .v").html(jsondata.qlen); $("#qlen").show(); } $("#uptime .v").html(secondsToHms(jsondata.uptime)); $("#uptime").show();