Struct Balling

Source
pub struct Balling {
    config: BallingConfig,
    durations_until_next_dosing: [Duration; 4],
    pump_is_active: [bool; 4],
    dosing_intervals: [Duration; 4],
    lock_error_channel_send_schedule_check: bool,
    lock_error_channel_receive_schedule_check: bool,
    pub execute_command_received: bool,
    pub pump_id_requested: i32,
    pub last_ping_instant: Instant,
    pub database_ping_interval: Duration,
    pub lock_warn_inapplicable_command_signal_handler: bool,
    pub lock_error_channel_receive_termination: bool,
}
Expand description

Contains the configuration and the implementation for the Balling dosing control. Thread communication of this component is as follows:

graph LR balling[Balling Dosing Control] --> signal_handler[Signal Handler] signal_handler --> balling signal_handler --> mineral_injection[Mineral Injection] balling --> mineral_injection mineral_injection --> relay_manager[Relay Manager] relay_manager --> mineral_injection balling --> schedule_check[Schedule Check] schedule_check --> balling messaging[Messaging] --> balling
Communication channel to and from the relay manager is forwarded to implementation of MineralInjectionTrait. Signal handler is communicating both directly with balling and with the implementation of MineralInjectionTrait.

Fields§

§config: BallingConfig

configuration data for Balling dosing control

§durations_until_next_dosing: [Duration; 4]

Durations until next dosing

§pump_is_active: [bool; 4]

Configuration data processed into an array: activation

§dosing_intervals: [Duration; 4]

Configuration data processed into an array: dosing intervals

§lock_error_channel_send_schedule_check: bool

inhibition flag to avoid flooding the log file with repeated messages to send request via the channel to schedule check

§lock_error_channel_receive_schedule_check: bool

inhibition flag to avoid flooding the log file with repeated messages to receive request via the channel from schedule check

§execute_command_received: bool

communication from trait implementation: request to execute a certain Balling mineral dosing has been received

§pump_id_requested: i32

communication from trait implementation: id of pump to be executed requested externally

§last_ping_instant: Instant

recording when the last database ping happened

§database_ping_interval: Duration

database ping interval

§lock_warn_inapplicable_command_signal_handler: bool

inhibition flag to avoid flooding the log file with repeated messages about having received inapplicable command via the channel

§lock_error_channel_receive_termination: bool

inhibition flag to avoid flooding the log file with repeated messages about failure to receive termination signal via the channel

Implementations§

Source§

impl Balling

Source

pub fn new( config: BallingConfig, database_ping_interval: Duration, sql_interface_balling: &mut SqlInterfaceBalling, ) -> Result<Balling, BallingError>

Creates a new Balling control instance.

This constructor initializes the Balling dosing control module. It performs several pre-flight checks, including validating the schedule_check_interval and dosing intervals from the configuration, ensuring that a database entry exists for every active pump, and calculating the initial countdowns for each pump based on their last recorded dosing times.

§Arguments
  • config - Configuration data for the Balling dosing control, loaded from a TOML file.
  • sql_interface_balling - A mutable reference to a SqlInterfaceBalling instance, providing the specific SQL interface for Balling dosing operations.
  • database_ping_interval - A Duration instance, providing the interval to ping the database.
§Returns

A Result containing a new, initialized Balling instance on success.

§Errors

This function will return a BallingError if any of the initial setup steps fail:

  • The schedule_check_interval in the configuration is zero (ScheduleCheckIntervalZero).
  • Any configured dosing interval is zero or shorter than the schedule_check_interval (InvalidDosingInterval, DosingIntervalShorterThanCheckInterval).
  • A pump is marked as active in the config, but no corresponding set values are found in the database (SetValueRetrievalError).
  • It fails to calculate the initial countdown for any pump due to a database error or data conversion issue.
Source

fn check_valid_dosing_intervals( config: &BallingConfig, ) -> Result<(), BallingError>

Checks that configured dosing intervals are valid and logical.

This function validates two conditions for each active pump:

  1. The dosing interval must not be zero.
  2. The dosing interval must be greater than or equal to the schedule_check_interval.
§Arguments
  • config - A reference to the BallingConfig containing the dosing intervals and the check interval.
§Returns

An empty Result (Ok(())) if all configured dosing intervals for active pumps are valid.

§Errors

This function will return a BallingError if an invalid configuration is detected:

  • InvalidDosingInterval: If an active pump’s dosing interval is set to 0.
  • DosingIntervalShorterThanCheckInterval: If an active pump’s dosing interval is shorter than the main schedule_check_interval, which would lead to illogical scheduling.
Source

fn check_database_vs_config( sql_interface_balling: &mut SqlInterfaceBalling, config: &BallingConfig, ) -> Result<(), BallingError>

Verifies that a database entry exists for every pump marked as active in the configuration.

This function ensures that the application doesn’t try to operate a pump that lacks the necessary set values (e.g., flow rate, volume) in the database.

§Arguments
  • sql_interface_balling - A mutable reference to the SqlInterfaceBalling instance.
  • config - A reference to the BallingConfig to check which pumps are active.
§Returns

An empty Result (Ok(())) if a database entry is found for every active pump.

§Errors

Returns BallingError::SetValueRetrievalError if an active pump is missing its corresponding configuration entry in the ballingsetvals table. The error will wrap the underlying SqlInterfaceError.

Source

fn get_target_dosing_interval( config: &BallingConfig, pump_id: i64, ) -> Result<u32, BallingError>

Retrieves the configured dosing interval for a specific pump.

§Arguments
  • config - A reference to the BallingConfig containing the dosing intervals.
  • pump_id - The ID of the pump (1, 2, 3, or 4) for which to get the interval.
§Returns

A Result containing the configured dosing interval (u32) in seconds for the specified pump.

§Errors

Returns BallingError::CountdownCalculationInvalidPumpId if the provided pump_id is not one of the recognized values (1, 2, 3, or 4).

Source

fn calc_duration_until_next_dosing( config: &BallingConfig, sql_interface_balling: &mut SqlInterfaceBalling, pump_id: i64, ) -> Result<Duration, BallingError>

Calculates the remaining time (countdown) until the next scheduled dosing for a specific pump.

This function determines how much time is left until a pump’s next dosing event. It retrieves the target interval from the configuration and the elapsed time since the last dosing from the database. The duration is the interval minus the elapsed time. If no previous dosing event exists, the duration is set to the target interval applying a cautious strategy.

§Arguments
  • config - A reference to the BallingConfig containing the dosing intervals.
  • sql_interface_balling - A mutable reference to the SqlInterfaceBalling instance.
  • pump_id - The unique identifier of the pump (1-4) for which to calculate the countdown.
§Returns

A Result containing the calculated duration until the next dosing. This value is 0 if the dosing is overdue.

§Errors

This function will return a BallingError if:

  • The pump_id is invalid (CountdownCalculationInvalidPumpId).
  • The configured dosing interval for the pump is zero (InvalidDosingInterval).
  • The database query to get the duration since the last dosing fails (ReadDurationSinceLastDosingFailure).
  • The retrieved duration from the database is negative or cannot be converted to u32 (CalculateDurationSinceLastDosingFailure).
Source

fn calc_target_dosing_duration_millis(balling_setval: &BallingSetVal) -> u32

Calculates the target dosing duration in milliseconds based on the pump’s flow rate and desired volume.

This private helper function determines how long a dosing pump needs to run to dispense a specific volume of fluid, given its flow rate.

§Arguments
  • balling_setval - A reference to a BallingSetVal struct, which contains the dosing_speed (flow rate in ml/sec) and dosing_volume (target volume in ml).
§Returns

A u32 representing the calculated dosing duration in milliseconds. Returns 0 if either dosing_speed or dosing_volume is zero or negative, indicating that no dosing should occur due to invalid parameters.

Source

fn calc_actual_dosing_volume( balling_setval: &BallingSetVal, actual_dosing_duration_millis: u32, ) -> f32

Calculates the actual volume of fluid dosed based on the pump’s flow rate and the actual run duration.

This private helper function determines the precise volume dispensed, taking into account the pump’s calibrated flow rate and the actual time it was active.

§Arguments
  • balling_setval - A reference to a BallingSetVal struct, containing the pump’s dosing_speed (flow rate in ml/sec).
  • actual_dosing_duration_millis - The actual duration (in milliseconds) that the pump was active.
§Returns

An f32 representing the actual volume of fluid dosed (in milliliters). Returns 0.0 if dosing_speed is zero or negative, or if actual_dosing_duration_millis is zero, indicating that no fluid was dispensed.

Source

fn execute_dosing( &mut self, pump_id: u32, pump_device: AquariumDevice, mineral_injection: &mut impl MineralInjectionTrait, balling_channels: &mut BallingChannels, sql_interface_balling: &mut SqlInterfaceBalling, ) -> bool

Orchestrates the dosing process for a specific peristaltic pump.

This function performs the complete cycle of a dosing event:

  1. Retrieve the pump’s set values (e.g., flow rate, target volume) from the database.
  2. Calculates the required dosing duration.
  3. Invokes the mineral_injection trait method to physically actuate the pump for the calculated duration.
  4. Calculate the actual volume dosed based on the actual run time.
  5. Log the completed Balling dosing event, including the actual volume, back to the database.

The function also monitors for a Quit command from the signal handler during the injection process.

§Arguments
  • pump_id - The unique numerical ID of the peristaltic pump to be actuated (e.g., 1, 2, 3, 4).
  • pump_device - The AquariumDevice enum variant corresponding to the pump_id, representing the physical device.
  • mineral_injection - A mutable reference to an object implementing MineralInjectionTrait, responsible for the physical control of the pump.
  • balling_channels - A mutable reference to BallingChannels struct containing all necessary mpsc
  • sql_interface_balling - A mutable reference to a SqlInterfaceBalling instance, providing the specific SQL interface for Balling dosing operations. This is moved into the struct.
§Returns

A bool which is true if a Quit command was received from the signal handler during the dosing process, indicating that the application should shut down; otherwise false.

Source

pub fn get_pump_from_id(pump_id: i32) -> Option<(u32, AquariumDevice)>

Selects the appropriate peristaltic pump and its corresponding device representation based on a given ID.

This function acts as a mapping from a numerical pump ID to a tuple containing the pump’s u32 ID and its AquariumDevice enum variant. Numerical pump IDs are used in external commands and in the database.

§Arguments
  • pump_id - The numerical ID of the pump (e.g., 1, 2, 3, 4) to be selected.
§Returns

An Option<(u32, AquariumDevice)>:

  • Some((u32, AquariumDevice)): If the pump_id matches one of the known peristaltic pumps, it will return its u32 ID and the corresponding AquariumDevice variant.
  • None: If the provided pump_id does not correspond to a known peristaltic pump.
Source

pub fn execute( &mut self, mutex_device_scheduler_balling: Arc<Mutex<i32>>, balling_channels: &mut BallingChannels, mineral_injection: &mut impl MineralInjectionTrait, sql_interface_balling: SqlInterfaceBalling, )

Executes the main control loop for the Balling dosing module.

This function runs continuously, managing the automatic dosing schedule for multiple peristaltic pumps, processing external commands, and ensuring a graceful shutdown. It periodically checks the dosing countdowns for each pump and, if due, initiates the dosing process, respecting schedule limitations.

The loop continues until a Quit command is received from the signal handler. After exiting the main loop, it sends a confirmation back to the signal handler and then waits for a Terminate command to complete its shutdown sequence.

§Arguments
  • mutex_device_scheduler_balling - An Arc<Mutex<i32>> used for coordinating access to device scheduling, preventing parallel actuation across different control modules. It holds a counter of the completed actuation.
  • balling_channels - A mutable reference to BallingChannels struct containing all necessary mpsc sender and receiver channels for inter-thread communication (e.g., with the signal handler, relay manager, and schedule checker).
  • mineral_injection - A mutable reference to an object implementing the MineralInjectionTrait, responsible for the physical control of the dosing pumps.
  • sql_interface_balling - A SqlInterfaceBalling instance, providing the specific SQL interface for Balling dosing operations.

Trait Implementations§

Source§

impl DatabasePingTrait for Balling

Source§

fn get_ping_interval(&self) -> Duration

Gets the interval at which the resource should be pinged.
Source§

fn get_last_ping_instant(&self) -> Instant

Gets the timestamp of the last successful ping.
Source§

fn update_last_ping_instant(&mut self)

Updates the timestamp of the last successful ping.
Source§

fn check_timing_and_ping_database( &mut self, database_interface: &mut (impl Pingable + ?Sized), )

Pings the database.
Source§

impl Display for Balling

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl ProcessExternalRequestTrait for Balling

Source§

fn process_external_request( &mut self, rx_from_signal_handler: &mut AquaReceiver<InternalCommand>, rx_from_messaging_opt: Option<&mut AquaReceiver<InternalCommand>>, ) -> (bool, bool, bool)

Checks for and processes new commands relevant to the Balling control module from external channels.

This is the specialized implementation of ProcessExternalRequestTrait for the Balling module. It handles standard “Terminate” or “Quit” commands from the signal handler. From the messaging channel, it specifically processes “Start,” “Stop,” and “Execute” commands, updating internal state variables (execute_command_received, pump_id_requested) based on these commands. Inapplicable commands are ignored with warnings.

§Arguments
  • rx_from_signal_handler - A reference to the receiver end of the channel for commands originating from the signal handler.
  • rx_from_messaging_opt - An Option containing a reference to the receiver end of the channel for commands from the messaging system. This channel is optional.
§Returns

A tuple (bool, bool, bool) indicating the status of specific commands received:

  • The first bool is true if a Quit or Terminate command was received from the signal handler; otherwise false.
  • The second bool is true if a Start command was received from messaging; otherwise false.
  • The third bool is true if a Stop command was received from messaging; otherwise false.
Source§

impl WaitForTerminationTrait for Balling

Source§

fn get_warn_lock_mut(&mut self) -> &mut bool

Method connects the default trait implementation with the specific implementation accessing the warn-lock.

Source§

fn get_error_lock_mut(&mut self) -> &mut bool

Method connects the default trait implementation with the specific implementation for accessing the error-lock.

Source§

fn wait_for_termination( &mut self, rx_waiting_thread_from_signal_handler: &mut AquaReceiver<InternalCommand>, sleep_duration: Duration, origin: &str, )

Implements the graceful shutdown wait loop for several threads (default implementation). Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> MaybeSendSync for T