21#ifndef LSH_CORE_PERIPHERALS_OUTPUT_ACTUATOR_HPP
22#define LSH_CORE_PERIPHERALS_OUTPUT_ACTUATOR_HPP
30#ifdef CONFIG_USE_FAST_ACTUATORS
36#if !CONFIG_USE_COMPACT_ACTUATOR_SWITCH_TIMES && (LSH_EFFECTIVE_ACTUATOR_DEBOUNCE_TIME_MS != 0U || LSH_STATIC_CONFIG_AUTO_OFF_ACTUATORS > 0)
37#define LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME 1
39#define LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME 0
42#if LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME || (CONFIG_USE_COMPACT_ACTUATOR_SWITCH_TIMES && LSH_STATIC_CONFIG_AUTO_OFF_ACTUATORS > 0)
43#define LSH_CORE_ACTUATOR_NEEDS_SWITCH_TIMESTAMP 1
45#define LSH_CORE_ACTUATOR_NEEDS_SWITCH_TIMESTAMP 0
55 static constexpr uint8_t ACTUATOR_FLAG_ACTUAL_STATE = 0x01U;
56 static constexpr uint8_t ACTUATOR_FLAG_PROTECTED = 0x02U;
58 static constexpr auto initialFlags(
bool normalState)
noexcept -> uint8_t
60 return normalState ? ACTUATOR_FLAG_ACTUAL_STATE : 0U;
63#ifndef CONFIG_USE_FAST_ACTUATORS
64 const uint8_t pinNumber;
66 const uint8_t pinMask;
67 volatile uint8_t *
const pinPort;
76 pinMask(binding.
mask), pinPort(binding.
pinPort), flags(initialFlags(normalState))
81 const uint8_t oldSREG = SREG;
85 *this->pinPort &= ~this->pinMask;
89 *this->pinPort |= this->pinMask;
95#if defined(LSH_DEBUG) || defined(LSH_STATIC_CONFIG_RUNTIME_CHECKS)
96 uint8_t index = UINT8_MAX;
99#if LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME
100 uint32_t lastTimeSwitched = 0U;
109 void writePinState(
bool state)
111#ifdef CONFIG_USE_FAST_ACTUATORS
114 *this->pinPort &= ~this->pinMask;
118 *this->pinPort |= this->pinMask;
121 digitalWrite(this->pinNumber,
static_cast<uint8_t
>(state));
132 void updateCachedStateFlag(
bool state)
136 this->flags |= ACTUATOR_FLAG_ACTUAL_STATE;
140 this->flags &=
static_cast<uint8_t
>(~ACTUATOR_FLAG_ACTUAL_STATE);
150 [[nodiscard]]
auto wouldChangeState(
bool state)
const ->
bool
152 const uint8_t stateFlag = state ? ACTUATOR_FLAG_ACTUAL_STATE : 0U;
153 return (this->flags & ACTUATOR_FLAG_ACTUAL_STATE) != stateFlag;
163 [[nodiscard]]
auto debounceAllowsSwitch(uint32_t now_ms)
const ->
bool
165#if LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME
166 using constants::timings::ACTUATOR_DEBOUNCE_TIME_MS;
167 return ACTUATOR_DEBOUNCE_TIME_MS == 0U || (now_ms - this->lastTimeSwitched >= ACTUATOR_DEBOUNCE_TIME_MS);
169 static_cast<void>(now_ms);
183 [[nodiscard]]
auto applyStateChange(
bool state, uint32_t now_ms, uint8_t actuatorIndex) -> bool;
193 template <u
int8_t ActuatorIndex>
194 [[nodiscard]] __attribute__((always_inline))
inline auto applyStateChangeStatic(
bool state, uint32_t now_ms) ->
bool
196 static_assert(ActuatorIndex < CONFIG_MAX_ACTUATORS,
"ActuatorIndex is outside the generated static profile.");
197 if (!this->debounceAllowsSwitch(now_ms))
202 this->writePinState(state);
203 this->updateCachedStateFlag(state);
204#if LSH_CORE_ACTUATOR_NEEDS_LOCAL_SWITCH_TIME
205 this->lastTimeSwitched = now_ms;
207 Actuators::updatePackedStateStatic<ActuatorIndex>(state);
208#if CONFIG_USE_COMPACT_ACTUATOR_SWITCH_TIMES && LSH_STATIC_CONFIG_AUTO_OFF_ACTUATORS > 0
223 [[nodiscard]]
auto runtimeIndex()
const -> uint8_t
225#if defined(LSH_DEBUG) || defined(LSH_STATIC_CONFIG_RUNTIME_CHECKS)
233#ifndef CONFIG_USE_FAST_ACTUATORS
240 explicit LSH_OPTIONAL_CONSTEXPR_CTOR
Actuator(uint8_t pin,
bool normalState =
false) noexcept :
241 pinNumber(pin), flags(initialFlags(normalState))
245 digitalWrite(pin,
static_cast<uint8_t
>(normalState));
246 pinMode(pin, OUTPUT);
255 template <u
int8_t Pin>
257 Actuator(static_cast<uint8_t>(Pin), normalState)
266 explicit Actuator(uint8_t pin,
bool normalState =
false) noexcept :
Actuator(lsh::core::avr::makeFastOutputPinBinding(pin), normalState)
276 template <u
int8_t Pin>
278 Actuator(lsh::core::avr::makeFastOutputPinBinding(lsh::core::PinTag<Pin>{}), normalState)
293 [[nodiscard]]
auto setState(
bool state) -> bool;
294 [[nodiscard]]
auto setState(
bool state, uint32_t now_ms)
298 [[nodiscard]]
auto setStateForIndex(uint8_t actuatorIndex,
bool state, uint32_t now_ms)
301 template <u
int8_t ActuatorIndex> [[nodiscard]]
auto setStateStatic(
bool state) ->
bool
303 if (!this->wouldChangeState(state))
307#if LSH_CORE_ACTUATOR_NEEDS_SWITCH_TIMESTAMP
310 return this->applyStateChangeStatic<ActuatorIndex>(state, 0U);
314 template <u
int8_t ActuatorIndex> [[nodiscard]]
auto setStateStatic(
bool state, uint32_t now_ms) ->
bool
316 if (!this->wouldChangeState(state))
320 return this->applyStateChangeStatic<ActuatorIndex>(state, now_ms);
328 [[nodiscard]]
auto getIndex() const -> uint8_t;
329 [[nodiscard]] auto
getState() const ->
bool;
333 [[nodiscard]] auto
toggleState(uint32_t now_ms) ->
bool;
337 template <uint8_t ActuatorIndex> [[nodiscard]] auto toggleStateStatic() ->
bool
339 return this->setStateStatic<ActuatorIndex>((this->flags & ACTUATOR_FLAG_ACTUAL_STATE) == 0U);
342 template <u
int8_t ActuatorIndex> [[nodiscard]]
auto toggleStateStatic(uint32_t now_ms) ->
bool
344 return this->setStateStatic<ActuatorIndex>((this->flags & ACTUATOR_FLAG_ACTUAL_STATE) == 0U, now_ms);
Declares the manager for the global collection of Actuator objects.
Typed helpers for AVR fast I/O access without Arduino macro casts.
Represents an actuator (relay) attached to a digital pin.
Definition actuator.hpp:53
auto checkAutoOffTimer(uint32_t now_ms, uint32_t autoOffTimer_ms) -> bool
Checks the provided auto-off timer, switch OFF the actuator if it's over.
Definition actuator.cpp:255
auto setStateForIndex(uint8_t actuatorIndex, bool state) -> bool
Set the new actuator state with a generated dense runtime index.
Definition actuator.cpp:81
auto toggleStateForIndex(uint8_t actuatorIndex) -> bool
Toggle the actuator with a generated dense runtime index.
Definition actuator.cpp:229
void setIndex(uint8_t indexToSet)
store the actuator index in Actuators namespace array.
Definition actuator.cpp:146
auto setProtected(bool hasProtection) -> Actuator &
Set protection against some turn ON/OFF behaviour.
Definition actuator.cpp:161
auto toggleState() -> bool
Switch the state of the actuator (if it was OFF is going to be ON and vice versa).
Definition actuator.cpp:205
LSH_OPTIONAL_CONSTEXPR_CTOR Actuator(lsh::core::PinTag< Pin >, bool normalState=false) noexcept
Construct an actuator from a compile-time pin tag on the slow-I/O path.
Definition actuator.hpp:256
auto getState() const -> bool
Get the state of the actuator.
Definition actuator.cpp:194
auto setState(bool state) -> bool
Set the new actuator state if the new state can be set.
Definition actuator.cpp:39
auto getIndex() const -> uint8_t
Get the actuator index on Actuators namespace array.
Definition actuator.cpp:179
auto checkAutoOffTimerForIndex(uint8_t actuatorIndex, uint32_t now_ms, uint32_t autoOffTimer_ms) -> bool
Checks an auto-off timer with the generated dense actuator index.
Definition actuator.cpp:269
LSH_OPTIONAL_CONSTEXPR_CTOR Actuator(uint8_t pin, bool normalState=false) noexcept
Construct a new Actuator object, conventional IO version.
Definition actuator.hpp:240
Centralized C++ feature-detection macros for lsh-core.
void recordSwitchTime(uint8_t actuatorIndex, uint32_t now_ms)
Records the latest switch time for an actuator when compact actuator timer storage is enabled.
Definition actuator_manager.cpp:155
auto getTime() -> uint32_t
Gets the cached timestamp from the last timeKeeper::update() call.
Definition time_keeper.hpp:42
Compile-time pin tag used to route peripheral construction through constant pin paths.
Type-level wrapper around one Arduino pin number.
Definition pin_tag.hpp:41
Resolved fast-output binding for one Arduino pin.
Definition avr_fast_io.hpp:62
volatile uint8_t * modePort
Final AVR DDR register used to configure the pin direction.
Definition avr_fast_io.hpp:65
volatile uint8_t * pinPort
Final AVR output register used to drive the pin.
Definition avr_fast_io.hpp:64
uint8_t mask
Final bit mask for the pin inside the AVR port.
Definition avr_fast_io.hpp:63
Declares a utility for consistent time management within the main loop.
Centralizes all build-time configurable timing constants for the framework.
Internal bridge that imports static profile resources into the library's scope.