From bbfc4e10e22ed55c9a29351438b73de2ce989ff2 Mon Sep 17 00:00:00 2001 From: jfmartel Date: Sat, 2 May 2026 08:50:16 -0400 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lior=C3=A9=20le=20reset=20LTE=20et=20aj?= =?UTF-8?q?out=20power=20relay=20watchdog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChaletLora.X/Source/ChaletPowerRelay.c | 12 + ChaletLora.X/Source/ChaletPowerRelay.h | 1 + ChaletLora.X/Source/LoraWatchdog.h | 2 +- ChaletLora.X/Source/SIM7080GInterface.c | 11 +- ChaletLora.X/Source/SIM7080GInterface.h | 2 +- ChaletLora.X/Source/Terminal.c | 49 +- ChaletLora.X/Source/WiFiCtrl.h | 2 +- ChaletLora.X/Source/main.c | 2 +- ChaletLora.X/Source/versionbuild.h | 2 +- .../production/ChaletLora.X.production.elf | Bin 1055707 -> 1055999 bytes .../production/ChaletLora.X.production.hex | 16460 ++++++++-------- .../production/ChaletLora.X.production.map | 2289 ++- .../nbproject/Makefile-genesis.properties | 4 +- ChaletLora.X/nbproject/configurations.xml | 29 - ChaletLora.X/nbproject/private/private.xml | 24 +- 15 files changed, 9484 insertions(+), 9405 deletions(-) diff --git a/ChaletLora.X/Source/ChaletPowerRelay.c b/ChaletLora.X/Source/ChaletPowerRelay.c index e6ba667..6f220e5 100644 --- a/ChaletLora.X/Source/ChaletPowerRelay.c +++ b/ChaletLora.X/Source/ChaletPowerRelay.c @@ -3,6 +3,7 @@ #include "ChaletPowerRelay.h" #include "BoardCfg.h" #include "timer.h" +#include "BatteryMonitor.h" #define PIN_ACTIVE 1 #define PIN_INACTIVE 0 @@ -46,6 +47,12 @@ void ChaletPowerRelayTick() } } + //LVD: if battery voltage is too low, turn off the power relay + if(PowerRelayState == CHALET_POWER_RELAY_ON_STATE && GetBatteryVoltage(0) < POWER_RELAY_LVD_VOLTAGE_TRESHOLD) + { + ChaletPowerRelayTurnOff(); + } + if(IsTimerExpired(CHALET_POWER_RELAY_AUTOTURNOFF_TIMER)) { ChaletPowerRelayTurnOff(); @@ -59,6 +66,11 @@ void ChaletPowerRelayKickTimer() bool ChaletPowerRelayTurnOn() { + //LVD: if battery voltage is too low, turn off the power relay + if(GetBatteryVoltage(0) < POWER_RELAY_LVD_VOLTAGE_TRESHOLD) + { + return false; + } POWER_RELAY_ON_PIN = PIN_ACTIVE; TimerStart(CHALET_POWER_RELAY_COIL_TIMER,CHALET_POWER_RELAY_COIL_TIMEOUT); // PowerRelayState = CHALET_POWER_RELAY_ON_STATE; diff --git a/ChaletLora.X/Source/ChaletPowerRelay.h b/ChaletLora.X/Source/ChaletPowerRelay.h index 92a94e1..94577d0 100644 --- a/ChaletLora.X/Source/ChaletPowerRelay.h +++ b/ChaletLora.X/Source/ChaletPowerRelay.h @@ -10,6 +10,7 @@ #include "define.h" #define CHALET_OFFLINE_POWER_RELAY_RESET_TIMEOUT 43200 //43,200 = 12 hours in seconds +#define POWER_RELAY_LVD_VOLTAGE_TRESHOLD (float)12.00 enum eChaletPowerRelayState { diff --git a/ChaletLora.X/Source/LoraWatchdog.h b/ChaletLora.X/Source/LoraWatchdog.h index dcfcd3e..022cef2 100644 --- a/ChaletLora.X/Source/LoraWatchdog.h +++ b/ChaletLora.X/Source/LoraWatchdog.h @@ -9,7 +9,7 @@ #define LORAWATCHDOG_H #include "define.h" -#define LORA_WATCHDOG_MODULE_RESET_TIMEOUT 3600000 //1h Time without comm. before we reset the LoRa module +#define LORA_WATCHDOG_MODULE_RESET_TIMEOUT 900000 // 15 minutes //3600000 //1h Time without comm. before we reset the LoRa module #define LORA_WATCHDOG_REBOOT_TIMEOUT 1200000 //20 minutes Time to reboot after we reset the LoRa module #define LORA_WATCHDOG_MODULE_OFF_TIMEOUT 4000 //Keep the LoRa module off for 2 seconds when reseting it. diff --git a/ChaletLora.X/Source/SIM7080GInterface.c b/ChaletLora.X/Source/SIM7080GInterface.c index 25ef5a3..31c5105 100644 --- a/ChaletLora.X/Source/SIM7080GInterface.c +++ b/ChaletLora.X/Source/SIM7080GInterface.c @@ -34,15 +34,18 @@ bool mMasterConnected; bool mMasterSocketError; bool mAPNConnected; -void InitLTEModule() +void InitLTEModule(bool FunctionnalReset) { mLTEModuleSMState = LTE_MODULE_SM_INIT_STATE; mLTEModuleOperationSMState = LTE_MODULE_OPERATION_INIT_STATE; mLTEModuleOperationSMSubState = LTE_MODULE_OPERATION_NOMINAL_SUBSTATE; mNbCmdCharsReceived = 0; mIsPassthroughEnabled = false; - mModuleSerialDebugEnabled = false; - mPICSerialDebugEnabled = false; + if(FunctionnalReset == false) + { + mModuleSerialDebugEnabled = false; + mPICSerialDebugEnabled = false; + } mCurrentCmd = LTE_MODULE_NO_CMD; mIsInitializing = true; mNbMasterReconnectCount = 0; @@ -54,7 +57,7 @@ void InitLTEModule() } int LTEModuleReset() { - InitLTEModule(); + InitLTEModule(true); return RET_OK; } diff --git a/ChaletLora.X/Source/SIM7080GInterface.h b/ChaletLora.X/Source/SIM7080GInterface.h index 78944f6..b33a807 100644 --- a/ChaletLora.X/Source/SIM7080GInterface.h +++ b/ChaletLora.X/Source/SIM7080GInterface.h @@ -125,7 +125,7 @@ enum eLTEModuleOperationSMEvents -void InitLTEModule(); +void InitLTEModule(bool FunctionnalReset); void LTEModuleSM(int SMEvent); void TickLTEModule(); void LTEModuleOperationSM(int OperationEvent); diff --git a/ChaletLora.X/Source/Terminal.c b/ChaletLora.X/Source/Terminal.c index 15d1368..87321a2 100644 --- a/ChaletLora.X/Source/Terminal.c +++ b/ChaletLora.X/Source/Terminal.c @@ -48,6 +48,8 @@ const uint32_t *mBootloaderMagicWord = (uint32_t *) BOOTLOAD_VERSION_ADDRESS; static BYTE mHelpString[] = "Here is the list of the available commands:\n\r\n\r" "help : Shows this window\n\r" +"\ncpu [command] Control CPU\n" +" - Available [command] argument are: reboot\n" "\npower [state] Set chalet's 12V Inverter feed power state. This command controls the main power relay\n" " - Available [state] argument are: on\n" " off\n" @@ -74,6 +76,7 @@ static BYTE mHelpString1[] = "\nlte [command] [value] : bootloader mode control " pic (debug PIC comm only)\n" " both (debug both PIC and LTE module comm )\n" " off (disable LTE debug)\n" +" reset (reset the lte module)\n" "\nHave a good day!\n"; BYTE *mHelpStringPtr; @@ -180,9 +183,31 @@ void ParseNewBuffer(void) if(strncmp(mCmdString,"help",strlen("help")) == 0) { SendTerminalData(mHelpString,strlen(mHelpString)); - + SendTerminalData(mHelpString1,strlen(mHelpString1)); } + else if(strncmp(mCmdString,"cpu",strlen("cpu")) == 0) + { + if(strlen(mDataString1) == 0) + { + TerminalPrintString("\n[command] parameter is invalid. Type 'help' for more info\n"); + return; + } + + if(strncmp(mDataString1,"reboot",strlen("reboot")) == 0) + { + TerminalPrintString("\nRebooting CPU... goodbye!!\n"); + TurnOFFWiFi(); + Sleep(100); + SoftReset(); + } + else + { + TerminalPrintString("\n[command] parameter is invalid. Type 'help' for valid values\n"); + } + + TerminalPrintString("\n"); + } else if(strncmp(mCmdString,"power",strlen("power")) == 0) { @@ -448,14 +473,15 @@ void ParseNewBuffer(void) TerminalPrintString("\n[command] parameter is invalid. Type 'help' for more info\n"); return; } - if(strlen(mDataString2) == 0) - { - TerminalPrintString("\n[value] parameter is invalid. Type 'help' for more info\n"); - return; - } + if(strncmp(mDataString1,"passthrough",strlen("passthrough")) == 0) { + if(strlen(mDataString2) == 0) + { + TerminalPrintString("\n[value] parameter is invalid. Type 'help' for more info\n"); + return; + } if(strncmp(mDataString2,"on",strlen("on")) == 0) { LTEEnterSerialPassthrough(); @@ -474,6 +500,11 @@ void ParseNewBuffer(void) } if(strncmp(mDataString1,"debug",strlen("debug")) == 0) { + if(strlen(mDataString2) == 0) + { + TerminalPrintString("\n[value] parameter is invalid. Type 'help' for more info\n"); + return; + } if(strncmp(mDataString2,"module",strlen("module")) == 0) { if(LTEEnableSerialDebug(true,false) == RET_OK) @@ -518,6 +549,12 @@ void ParseNewBuffer(void) } } + if(strncmp(mDataString1,"reset",strlen("reset")) == 0) + { + TerminalPrintString("\nResetting LTE module...\n"); + LTEModuleReset(); + } + } else if(strncmp(mCmdString,"debug",strlen(mCmdString)) == 0) { diff --git a/ChaletLora.X/Source/WiFiCtrl.h b/ChaletLora.X/Source/WiFiCtrl.h index 588030d..430059b 100644 --- a/ChaletLora.X/Source/WiFiCtrl.h +++ b/ChaletLora.X/Source/WiFiCtrl.h @@ -186,7 +186,7 @@ int IsBootloaderClientConnected(); #define STATIC_IP_ADDRESS_1 192 #define STATIC_IP_ADDRESS_2 168 #define STATIC_IP_ADDRESS_3 50 -#define STATIC_IP_ADDRESS_4 125 +#define STATIC_IP_ADDRESS_4 123 #define GATEWAY_ADDRESS_1 192 #define GATEWAY_ADDRESS_2 168 diff --git a/ChaletLora.X/Source/main.c b/ChaletLora.X/Source/main.c index 2007bff..2f9decf 100644 --- a/ChaletLora.X/Source/main.c +++ b/ChaletLora.X/Source/main.c @@ -112,7 +112,7 @@ int main(void) InitSPIFlash(); InitLCDCtrl(); - InitLTEModule(); + InitLTEModule(false); LTENetworkInterfaceInit(); diff --git a/ChaletLora.X/Source/versionbuild.h b/ChaletLora.X/Source/versionbuild.h index a06dab4..c7f3c49 100644 --- a/ChaletLora.X/Source/versionbuild.h +++ b/ChaletLora.X/Source/versionbuild.h @@ -1,4 +1,4 @@ -#define VERSIONNUMBER "CHALET_V01.02.2" //shall be 15 chars... +#define VERSIONNUMBER "CHALET_V01.02.5" //shall be 15 chars... //Force DHCP instead of static IP. //#define VERSIONNUMBER "CHALET_V01.00.1" //shall be 15 chars... diff --git a/ChaletLora.X/dist/ChaletDuinoV2_795F512H_/production/ChaletLora.X.production.elf b/ChaletLora.X/dist/ChaletDuinoV2_795F512H_/production/ChaletLora.X.production.elf index 03f4eded744e644dfb8e9d888fc26c4705a350d4..c62130fd8bb92ed4bb1a9b54255f52b943a22d24 100644 GIT binary patch delta 139673 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