Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Mk2_3phase_RFdatalog_temp/ewma_avg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @author Frédéric Metrich (frederic.metrich@live.fr)
* @brief This file implements an Exponentially Weighted Moving Average template class
* @version 0.1
* @date 2024-02-27
* @date 2026-10-01
*
* @section description Description
* The Exponentially Weighted Moving Average (EWMA) is a quantitative or statistical measure used to model or describe a time series.
Expand All @@ -27,7 +27,7 @@
* This comes with some restrictions on the alpha parameter, but the benefit of full integer math wins
* on the side-drawback.
*
* @copyright Copyright (c) 2024
* @copyright Copyright (c) 2024-2026
*
*/

Expand Down Expand Up @@ -114,8 +114,12 @@ class EWMA_average
* Moving Average (EMA), Double EMA (DEMA), and Triple EMA (TEMA).
*
* @param input The new input value to process.
*
* @note Not inlined, even with a single caller: on AVR, inlined code reaches a static
* instance's six int32 with absolute lds/sts (4 bytes per byte accessed), the
* function through its this pointer with ld/st/ldd/std (2 bytes) - 78 bytes less.
*/
void addValue(int32_t input)
__attribute__((noinline)) void addValue(int32_t input)
{
ema_raw = ema_raw - ema + input;
ema = ema_raw >> round_up_to_power_of_2(A);
Expand Down Expand Up @@ -151,8 +155,12 @@ class EWMA_average
* @brief Get the Triple Exponentially Weighted Moving Average (TEMA).
*
* @return auto The TEMA value.
*
* @note Not inlined: it is read in several places (relay decisions, datalog output), and
* each inlined copy would read a static instance's averages with absolute lds
* (4 bytes per byte), against ld/ldd through this (2 bytes) - 70 bytes less.
*/
auto getAverageT() const
__attribute__((noinline)) auto getAverageT() const
{
return 3 * (ema - ema_ema) + ema_ema_ema;
}
Expand Down
36 changes: 28 additions & 8 deletions Mk2_3phase_RFdatalog_temp/utils_pins.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @author Frédéric Metrich (frederic.metrich@live.fr)
* @brief Some utility functions for pins manipulation
* @version 0.1
* @date 2026-01-29
* @date 2026-10-01
*
* @copyright Copyright (c) 2023-2026
*
Expand Down Expand Up @@ -71,23 +71,32 @@ void constexpr togglePin(const uint8_t pin)
*
* @param pin pin to change [2..13]
* @param bState state to be set
*
* @details For a pin only known at run time (a relay). The ADC ISR writes the load pins,
* possibly on the same port, so the port must not be read-modified-written here:
* the pin is toggled through PINx instead, where writing a 1 toggles that bit of
* PORTx and writing a 0 leaves the others alone. Only the caller changes this pin,
* so reading its state first is safe.
*/
inline constexpr void setPinState(const uint8_t pin, const bool bState)
inline void setPinState(const uint8_t pin, const bool bState)
{
if (bState)
{
setPinON(pin);
}
else
const volatile uint8_t &port{ (pin < 8) ? PORTD : ((pin < 14) ? PORTB : PORTC) };
volatile uint8_t &toggle{ (pin < 8) ? PIND : ((pin < 14) ? PINB : PINC) };
const uint8_t mask{ static_cast< uint8_t >(1U << ((pin < 8) ? pin : ((pin < 14) ? pin - 8 : pin - 14))) };

if (static_cast< bool >(port & mask) != bState)
{
setPinOFF(pin);
toggle = mask;
}
}

/**
* @brief Set the Pin state to ON for the specified pin
*
* @param pin pin to change [2..13]
*
* @warning Atomic (a single sbi/cbi) only for a pin known at compile time. For a pin known at
* run time it is a read-modify-write of the port: from loop(), use setPinState().
*/
inline constexpr void setPinON(const uint8_t pin)
{
Expand All @@ -109,6 +118,10 @@ inline constexpr void setPinON(const uint8_t pin)
* @brief Set the Pins state to ON
*
* @param pins The pins to change
*
* @warning Read-modify-write of PORTD and PORTB: only safe from the ADC ISR (its sole caller),
* which cannot be interrupted. From loop(), use setPinState() or togglePin(): an ISR
* landing in the middle would have its load pin changes written back to the old state.
*/
inline void setPinsON(const uint16_t pins)
{
Expand All @@ -120,6 +133,9 @@ inline void setPinsON(const uint16_t pins)
* @brief Set the Pin state to OFF for the specified pin
*
* @param pin pin to change [2..13]
*
* @warning Atomic (a single sbi/cbi) only for a pin known at compile time. For a pin known at
* run time it is a read-modify-write of the port: from loop(), use setPinState().
*/
inline constexpr void setPinOFF(const uint8_t pin)
{
Expand All @@ -141,6 +157,10 @@ inline constexpr void setPinOFF(const uint8_t pin)
* @brief Set the Pins state to OFF
*
* @param pins The pins to change
*
* @warning Read-modify-write of PORTD and PORTB: only safe from the ADC ISR (its sole caller),
* which cannot be interrupted. From loop(), use setPinState() or togglePin(): an ISR
* landing in the middle would have its load pin changes written back to the old state.
*/
inline void setPinsOFF(const uint16_t pins)
{
Expand Down
70 changes: 20 additions & 50 deletions Mk2_3phase_RFdatalog_temp/utils_relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @author Frédéric Metrich (frederic.metrich@live.fr)
* @brief Some utility functions for the relay output feature
* @version 0.1
* @date 2026-01-29
* @date 2026-10-01
*
* @copyright Copyright (c) 2023-2026
*
Expand Down Expand Up @@ -173,25 +173,14 @@ class relayOutput
if (currentAvgPower < surplusThreshold || isOverrideActive)
{
bit_clear(overrideBitmask, relay_pin); // Clear override bit if it was set
return try_turnON();
return try_switch(true);
}

// Handle both positive and negative import thresholds
if (importThreshold >= 0)
// Positive threshold: turn OFF when importing > threshold (normal mode).
// Negative threshold: turn OFF when surplus < abs(threshold) (battery mode).
if (currentAvgPower > importThreshold)
{
// Positive threshold: turn OFF when importing > threshold (normal mode)
if (currentAvgPower > importThreshold)
{
return try_turnOFF();
}
}
else
{
// Negative threshold: turn OFF when surplus < abs(threshold) (battery mode)
if (currentAvgPower > importThreshold) // importThreshold is negative, so this checks surplus < abs(threshold)
{
return try_turnOFF();
}
return try_switch(false);
}

return false;
Expand Down Expand Up @@ -234,55 +223,34 @@ class relayOutput

/**
* @brief Force the relay OFF when diversion is disabled
*
*
* @return bool True if state has changed
* @details This method attempts to turn OFF the relay, respecting the minimum ON time constraint
*/
bool forceOFF() const
{
return try_turnOFF();
return try_switch(false);
}

private:
/**
* @brief Turn ON the relay if the 'time' condition is met
* @brief Turn the relay ON or OFF if the 'time' condition is met
*
* @param on True to turn the relay ON, false to turn it OFF
* @return bool True if state has changed
*/
bool try_turnON() const
bool try_switch(const bool on) const
{
if (relayIsON || duration < minOFF)
if ((relayIsON == on) || (duration < (on ? minOFF : minON)))
{
return false;
}

setPinON(relay_pin);
setPinState(relay_pin, on);

DBUGLN(F("Relay turned ON!"));
DBUGLN(on ? F("Relay turned ON!") : F("Relay turned OFF!"));

relayIsON = true;
duration = 0;

return true;
}

/**
* @brief Turn OFF the relay if the 'time' condition is met
*
* @return bool True if state has changed
*/
bool try_turnOFF() const
{
if (!relayIsON || duration < minON)
{
return false;
}

setPinOFF(relay_pin);

DBUGLN(F("Relay turned OFF!"));

relayIsON = false;
relayIsON = on;
duration = 0;

return true;
Expand Down Expand Up @@ -434,13 +402,15 @@ class RelayEngine
return;
}

if (ewma_average.getAverageT() > 0)
const auto currentAvgPower{ ewma_average.getAverageT() };

if (currentAvgPower > 0)
{
// Currently importing, try to turn OFF some relays
uint8_t idx{ N };
do
{
if (relay[--idx].proceed_relay(ewma_average.getAverageT(), overrideBitmask))
if (relay[--idx].proceed_relay(currentAvgPower, overrideBitmask))
{
settle_change = 60;
return;
Expand All @@ -453,7 +423,7 @@ class RelayEngine
uint8_t idx{ 0 };
do
{
if (relay[idx].proceed_relay(ewma_average.getAverageT(), overrideBitmask))
if (relay[idx].proceed_relay(currentAvgPower, overrideBitmask))
{
settle_change = 60;
return;
Expand Down
Loading