Persistent alarm state in emulated EEPROM
Core/Src/app_fish_tank.c #define FLASH_MAGIC_16 ((uint16_t)0x7A4D)
#define VA_MAGIC ((uint16_t)0x1001)
#define VIRTADDR_KEYCOUNT ((uint16_t)0x1002)
#define VIRTADDR_LOWLEVEL ((uint16_t)0x1003)
typedef struct {
uint16_t magic;
uint16_t keyPressedCount;
bool lowLevelWasReached;
} DataFlash;
uint16_t VirtAddVarTab[NB_OF_VAR] = {
VA_MAGIC,
VIRTADDR_KEYCOUNT,
VIRTADDR_LOWLEVEL
};
This snippet defines the persisted values: magic value, button counter and low-level flag. After power loss, the controller should not forget that an alarm state was reached.
Startup reaction to remembered low-level state
Core/Src/app_fish_tank.c static void App_ApplyStoredRelayState(void)
{
if (app.flashData.lowLevelWasReached) {
App_SetRelayEnabled(false);
Send("AC Relay: Disable
");
app.disableACRelay = true;
app.goToSleepMode = false;
app.lowLevelWasReachedPrev = true;
app.blinkLedFromTick = HAL_GetTick();
} else {
App_SetRelayEnabled(true);
Send("AC Relay: Enable
");
app.disableACRelay = false;
}
}
After reset the device restores the last important state. If low level was previously reached, the AC relay is disabled, the LED is on and the device does not immediately go to sleep.
Sleep through WFE
Core/Src/app_fish_tank.c static void App_EnterSleepIfAllowed(void)
{
if (!app.goToSleepMode) {
return;
}
Send("Going to sleep mode!
");
__SEV();
__WFE();
__WFE();
HAL_SuspendTick();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFE);
HAL_ResumeTick();
}
This is the power-saving part. The code clears the event mechanism with SEV/WFE/WFE, suspends SysTick and enters Sleep Mode until an event arrives.
Alarm reset and relay-disable conditions
Core/Src/app_fish_tank.c static void App_HandleKeyPress(void)
{
if (app.flashData.keyPressedCount < UINT16_MAX) {
app.flashData.keyPressedCount++;
}
app.flashData.lowLevelWasReached = false;
app.lowLevelWasReachedPrev = false;
app.disableACRelay = false;
Send("Key pressed
");
Send("FloatSensor Reset !
");
App_SetRelayEnabled(true);
if (EE_WriteVariable(VIRTADDR_KEYCOUNT, app.flashData.keyPressedCount) != EE_OK) {
Send("Blad zapisu KeyPressedCount!
");
}
if (EE_WriteVariable(VIRTADDR_LOWLEVEL, 0U) != EE_OK) {
Send("Blad zapisu LowLevelWasReached!
");
}
app.goToSleepMode = true;
HAL_Delay(100U);
}
static void App_HandleLowWaterDetected(void)
{
if (app.lowLevelWasReachedPrev) {
return;
}
Send("FloatSensor Low Level !
");
app.lowLevelWasReachedPrev = true;
app.flashData.lowLevelWasReached = true;
if (!app.disableACRelay) {
App_SetRelayEnabled(false);
Send("Stan wody: NISKI
");
Send("AC Relay: Disable
");
app.disableACRelay = true;
if (EE_WriteVariable(VIRTADDR_LOWLEVEL, 1U) != EE_OK) {
Send("Blad zapisu LowLevelWasReached!
");
}
}
app.blinkLedFromTick = HAL_GetTick();
app.goToSleepMode = false;
}
The logic has two scenarios: the button resets the alarm only when the level sensor is inactive, while an active FloatSensor stores the alarm and disables the relay. This is the core protection logic.