Struct AtlasScientific

Source
pub struct AtlasScientific {
    config: AtlasScientificConfig,
    pub(crate) lock_error_channel_receive_termination: bool,
    pub(crate) lock_warn_inapplicable_command_signal_handler: bool,
    lock_error_channel_send_i2c_interface: bool,
    pub lock_warn_max_mutex_access_duration_temperature: bool,
    pub lock_warn_max_mutex_access_duration_ph: bool,
    pub lock_warn_max_mutex_access_duration_conductivity: bool,
    pub last_measurement_instant: Instant,
    pub measurement_interval: Duration,
    pub max_mutex_access_duration_millis: Duration,
}
Expand description

Contains the communication Atlas Scientific sensors via I2C. Alternatively, TCP communication is used when configured to run with the simulator. The struct holds attributes for the results and for error flags indicating unsuccessful communication. Sensor data is read periodically and stored. Requests from data logger, ventilation, and heating control are answered with last measured data. Creates the channels and sets up threads. Thread communication of this component is as follows:

graph LR atlas_scientific --> signal_handler[SignalHandler] signal_handler --> atlas_scientific atlas_scientific -.-> data_logger[DataLogger]

Fields§

§config: AtlasScientificConfig

configuration data for AtlasScientific

§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

§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 from the signal handler thread

§lock_error_channel_send_i2c_interface: bool

inhibition flag to avoid flooding the log file with repeated messages about to send request via the channel to I2cInterface thread

§lock_warn_max_mutex_access_duration_temperature: bool

inhibition flag to avoid flooding the log file with repeated messages about excessive access time to mutex for water temperature

§lock_warn_max_mutex_access_duration_ph: bool

inhibition flag to avoid flooding the log file with repeated messages about excessive access time to mutex for pH

§lock_warn_max_mutex_access_duration_conductivity: bool

inhibition flag to avoid flooding the log file with repeated messages about excessive access time to mutex for conductivity

§last_measurement_instant: Instant

instant when the last measurement took place

§measurement_interval: Duration

duration of the measurement interval calculated from the configuration data

§max_mutex_access_duration_millis: Duration

maximum allowed duration for access to mutex

Implementations§

Source§

impl AtlasScientific

Source

pub fn new(config: AtlasScientificConfig) -> AtlasScientific

Creates a new AtlasScientific control instance.

This constructor initializes the Atlas Scientific sensor module. It takes the configuration, calculates the measurement interval, and sets up internal state, including lock flags used to prevent log flooding from recurring errors or warnings.

§Arguments
  • config - Configuration data for the Atlas Scientific module, specifying I2C addresses, sleep times, and the measurement interval.
§Returns

A new AtlasScientific struct, ready to manage sensor data acquisition.

Source

fn is_numeric(character: u8, negative_allowed: bool) -> bool

Checks if a given character is a valid part of a numeric string, considering optional negative signs.

This private helper function is used during the parsing of sensor responses to validate that each character in the data section is either a digit (0-9), a decimal point (.), or, if negative_allowed is true, a negative sign (-).

§Arguments
  • character - The u8 byte value of the character to be checked (typically an ASCII representation).
  • negative_allowed - A bool flag. If true, a negative sign character (-) will be considered valid; otherwise, it will be considered invalid.
§Returns

true if the character is a valid numeric component based on the rules; false otherwise.

Source

fn check_response( buffer: [u8; 8], is_ph: bool, ) -> Result<f32, AtlasScientificError>

Evaluates a raw byte array response from an Atlas Scientific sensor unit, validating its format and converting it to f32.

This private helper function performs several critical steps to parse sensor data:

  1. Magic Number Check: Verifies the protocol’s start and end “magic” bytes.
  2. Numeric Content Validation: Ensures all characters within the data section are valid numeric components.
  3. UTF-8 Conversion & Float Parsing: Converts the validated byte sequence into a string and parses it into an f32 value.

The is_ph flag specifically controls whether a negative sign is allowed, as pH values are non-negative by definition.

§Arguments
  • buffer - A fixed-size array of u8 bytes representing the complete message received from the sensor.
  • is_ph - A bool flag indicating if the response is from a pH sensor (true) or another type (false).
§Returns

A Result containing the successfully parsed f32 sensor reading.

§Errors

Returns an AtlasScientificError variant if any validation or parsing step fails:

  • FirstCharacterNotMagic: If the message’s first byte is incorrect.
  • LastCharacterNotMagic: If the message’s last byte is incorrect.
  • ContainsInvalidCharacter: If the data section contains non-numeric characters.
  • InvalidUtf8Sequence: If the numeric byte sequence is not valid UTF-8.
  • ConversionFailure: If the valid numeric string cannot be parsed into an f32.
Source

fn send_request_to_i2c_interface( &mut self, signal: &AquariumSignal, atlas_scientific_channels: &mut AtlasScientificChannels, ) -> Result<(), AtlasScientificError>

Constructs and sends a measurement request to the I2C interface thread.

This function creates an I2cRequest based on the specified signal. It retrieves the correct I2C address and sleep time from the configuration for the given sensor. The request is then sent over the provided channel to the I2C thread for execution.

§Arguments
  • signal - The AquariumSignal identifying which sensor to request a reading from.
  • atlas_scientific_channels - A mutable reference to the struct containing the channels.
§Returns

An empty Result (Ok(())) if the measurement request was successfully created and sent.

§Errors

Returns an AtlasScientificError if any step fails:

  • InvalidSignal: If an unsupported AquariumSignal is provided.
  • SignalRequestCreationFailure: If the underlying I2cRequest::new call fails (e.g., command too long).
  • SendingRequestToI2cInterfaceFailed: If sending the request over the channel fails, which typically means the receiver (the I2C thread) has been dropped.
Source

fn write_result_to_mutex( &self, signal: &AquariumSignal, result: AtlasScientificResultData, mutex_water_temperature: &Arc<Mutex<AtlasScientificResultData>>, mutex_ph: &Arc<Mutex<AtlasScientificResultData>>, mutex_conductivity: &Arc<Mutex<AtlasScientificResultData>>, ) -> Result<Instant, AtlasScientificError>

Atomically writes a sensor measurement result to the appropriate shared mutex.

This helper function directs an AtlasScientificResultData to its corresponding shared Mutex based on the provided signal. It centralizes the mutex selection and locking logic.

§Arguments
  • signal - The AquariumSignal that determines which mutex to update.
  • result - The AtlasScientificResultData to be written.
  • mutex_water_temperature - The shared mutex for the water temperature result.
  • mutex_ph - The shared mutex for the pH sensor result.
  • mutex_conductivity - The shared mutex for the conductivity sensor result.
§Returns

A Result containing the Instant at which the lock was released on success.

§Errors

Returns Err(AtlasScientificError::CouldNotLockMutex) if the target mutex is poisoned and cannot be locked.

Source

fn receive_response_from_i2c_interface( &mut self, signal: &AquariumSignal, atlas_scientific_channels: &mut AtlasScientificChannels, mutex_water_temperature: &Arc<Mutex<AtlasScientificResultData>>, mutex_ph: &Arc<Mutex<AtlasScientificResultData>>, mutex_conductivity: &Arc<Mutex<AtlasScientificResultData>>, ) -> Result<AtlasScientificResultData, AtlasScientificError>

Receives and processes a measurement response from the I2C interface thread.

This function orchestrates the full cycle of handling a sensor reading. It performs a non-blocking receive on the I2C channel. If a message is available, it processes the result, which can be either a successful data payload or an I2C-level error.

For a successful payload, the function:

  1. Parses the raw byte buffer using check_response.
  2. Converts the valid data into an AtlasScientificResultData struct.
  3. Atomically writes this result to the correct shared Mutex using write_result_to_mutex.
  4. Monitors the duration of the mutex lock, issuing a warning if it exceeds the threshold.
§Arguments
  • signal - The AquariumSignal indicating which sensor’s data is expected.
  • atlas_scientific_channels - A mutable reference to the struct containing the channels.
  • mutex_water_temperature - The shared Mutex for the water temperature result.
  • mutex_ph - The shared Mutex for the pH result.
  • mutex_conductivity - The shared Mutex for the conductivity result.
§Returns

An AtlasScientificResult containing the AtlasScientificResultData if a valid sensor reading was successfully received, parsed, and stored.

§Errors

Returns an AtlasScientificError variant if any error occurred:

  • ChannelIsEmpty: A recoverable error indicating no message was available.
  • ChannelIsDisconnected: A critical error indicating the I2C thread has terminated.
  • I2cCommunicationFailure: The I2C thread reported a hardware-level communication error.
  • ResponseCheckFailed / IncorrectBufferLength: The received data payload was malformed.
  • CouldNotLockMutex: The target mutex was poisoned and could not be updated.
Source

pub fn execute( &mut self, atlas_scientific_channels: &mut AtlasScientificChannels, mutex_atlas_scientific_water_temperature: Arc<Mutex<AtlasScientificResultData>>, mutex_atlas_scientific_ph: Arc<Mutex<AtlasScientificResultData>>, mutex_atlas_scientific_conductivity: Arc<Mutex<AtlasScientificResultData>>, )

Executes the main control loop for the Atlas Scientific sensor module.

This function runs continuously, managing the periodic and sequential measurement of water temperature, pH, and conductivity. It interacts with an I2C interface thread by sending requests for one sensor at a time and then processing the response.

The collected data (or any resulting error) is written to a shared Mutex, making it available to other application threads. The loop respects the configured measurement_interval between cycles and remains responsive to Quit and Terminate commands from the signal handler for a graceful shutdown.

§Arguments
  • atlas_scientific_channels - A mutable reference to the struct containing all mpsc channels necessary for inter-thread communication with the I2CInterface and the SignalHandler.
  • mutex_atlas_scientific_water_temperature - The shared Mutex for storing the water temperature result.
  • mutex_atlas_scientific_ph - The shared Mutex for storing the pH result.
  • mutex_atlas_scientific_conductivity - The shared Mutex for storing the conductivity result.

Trait Implementations§

Source§

impl CheckMutexAccessDurationTrait for AtlasScientific

Source§

fn get_max_mutex_access_duration(&self) -> Duration

Method connects the default trait implementation with the specific implementation for getting maximum permissible access duration

Source§

fn get_location(&self) -> &str

inform the location of the warning for logging purposes

Source§

fn get_warn_lock(&self, key_opt: &Option<&AquariumSignal>) -> bool

Reads the warn-lock. This flag is used to prevent log-flooding
Source§

fn set_warn_lock(&mut self, key_opt: &Option<&AquariumSignal>, value: bool)

Sets the warn-lock. This flag is used to prevent log-flooding
Source§

fn check_mutex_access_duration( &mut self, key_opt: Option<&AquariumSignal>, instant_after_locking_mutex: Instant, instant_before_locking_mutex: Instant, )

Source§

impl GetResponseFromSimulatorTrait for AtlasScientific

Source§

fn get_response_from_simulator( requester: String, tx_to_tcp: &mut AquaSender<InternalCommand>, rx_from_tcp: &mut AquaReceiver<Result<f32, TcpCommunicationError>>, internal_command: InternalCommand, ) -> Result<f32, TcpCommunicationError>

Sends a request to a simulator via a channel and blocks until a response is received. Read more
Source§

impl ProcessExternalRequestTrait for AtlasScientific

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 received from the signal handler and an optional messaging channel. Read more
Source§

impl WaitForTerminationTrait for AtlasScientific

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, 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