1//! Interface traits for the BrewMaster Pro 3000 Coffee Machine
  2//!
  3//! This module contains trait definitions corresponding to the interface
  4//! specifications defined in the sphinx-needs documentation.
  5//! Each trait represents a communication contract between architectural
  6//! components as specified in docs/coffee-machine/index.rst
  7
[docs]  8// @ BrewStrength enum, IMPL_BREW_STRENGTH, impl, [SWREQ_BREW_STRENGTH]
  9/// Brew strength selection for coffee brewing
 10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 11pub enum BrewStrength {
 12    /// Weak: 180ml water, 3 minutes
 13    Weak,
 14    /// Medium: 180ml water, 4 minutes
 15    Medium,
 16    /// Strong: 180ml water, 5 minutes
 17    Strong,
 18}
 19
[docs] 20// @ SafetyCommand enum, IMPL_SAFETY_CMD_ENUM, impl, [INTF_SAFETY_CMD]
 21/// Safety command types for emergency control
 22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 23pub enum SafetyCommand {
 24    /// Immediate shutdown (<100ms response required)
 25    EmergencyStop,
 26    /// Clear emergency state after fault resolved
 27    ResumeNormal,
 28}
 29
[docs] 30// @ UserCommand enum, IMPL_USER_CMD_ENUM, impl, [INTF_USER_CMD]
 31/// User command types for UI interaction
 32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 33pub enum UserCommand {
 34    /// Start brewing with specified strength
 35    StartBrew(BrewStrength),
 36    /// Stop/cancel current brewing operation
 37    StopBrew,
 38    /// Select brew strength (without starting)
 39    SelectStrength(BrewStrength),
 40}
 41
 42/// Temperature Status Interface (INTF_TEMP_STATUS)
 43///
 44/// **Provider**: Temperature Controller Module
 45///
 46/// **Consumer**: Brew Controller Module
 47///
 48/// **Description**: Provides current temperature readings and heating
 49/// status to the brew controller.
 50///
 51/// **Protocol**: Shared memory with atomic updates, 100ms refresh rate
[docs] 52// @ TemperatureStatus struct, IMPL_TEMP_STATUS, impl, [INTF_TEMP_STATUS]
 53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 54pub struct TemperatureStatus {
 55    /// Current temperature in °C × 10 for 0.1°C resolution
 56    pub current_temp: i16,
 57    /// Target temperature in °C × 10
 58    pub target_temp: i16,
 59    /// True when within target range
 60    pub is_ready: bool,
 61    /// True when heating element is active
 62    pub heating_active: bool,
 63}
 64
 65impl TemperatureStatus {
 66    /// Create a new temperature status
 67    pub fn new(current_temp: i16, target_temp: i16, is_ready: bool, heating_active: bool) -> Self {
 68        Self {
 69            current_temp,
 70            target_temp,
 71            is_ready,
 72            heating_active,
 73        }
 74    }
 75
 76    /// Get current temperature in °C (floating point)
 77    pub fn current_temp_celsius(&self) -> f32 {
 78        self.current_temp as f32 / 10.0
 79    }
 80
 81    /// Get target temperature in °C (floating point)
 82    pub fn target_temp_celsius(&self) -> f32 {
 83        self.target_temp as f32 / 10.0
 84    }
 85}
 86
[docs] 87// @ TemperatureStatusProvider trait, IMPL_TEMP_STATUS_PROVIDER, impl, [INTF_TEMP_STATUS, COMP_TEMP_CTRL]
 88/// Trait for components that provide temperature status
 89///
 90/// Implements: Temperature Controller Module (COMP_TEMP_CTRL)
 91pub trait TemperatureStatusProvider {
 92    /// Get the current temperature status
 93    fn get_temperature_status(&self) -> TemperatureStatus;
 94}
 95
[docs] 96// @ TemperatureStatusConsumer trait, IMPL_TEMP_STATUS_CONSUMER, impl, [INTF_TEMP_STATUS, COMP_BREW_CTRL]
 97/// Trait for components that consume temperature status
 98///
 99/// Implements: Brew Controller Module (COMP_BREW_CTRL)
100pub trait TemperatureStatusConsumer {
101    /// Update with new temperature status
102    fn update_temperature_status(&mut self, status: TemperatureStatus);
103}
104
105/// Temperature Controller Status Interface (INTF_TEMP_CTRL_STATUS)
106///
107/// **Provider**: Temperature Controller Module (COMP_TEMP_CTRL)
108///
109/// **Consumer**: Safety Monitor Module (COMP_SAFETY_MON)
110///
111/// **Description**: Continuous status reporting from the Temperature Controller
112/// to the Safety Monitor, including temperature readings and fault flags.
113///
114/// **Protocol**: Polled by safety monitor at 10Hz
[docs]115// @ TempCtrlStatus struct, IMPL_TEMP_CTRL_STATUS, impl, [INTF_TEMP_CTRL_STATUS]
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub struct TempCtrlStatus {
118    /// Module identifier (fixed value for Temperature Controller)
119    pub module_id: u8,
120    /// Heartbeat counter (incremented each control cycle)
121    pub heartbeat_counter: u32,
122    /// Bitfield of detected faults (0 = no fault)
123    pub fault_flags: u16,
124    /// Current measured temperature (°C × 10 for 0.1°C resolution)
125    pub temperature_value: i16,
126}
127
128impl TempCtrlStatus {
129    /// Create a new temperature controller status
130    pub fn new(
131        module_id: u8,
132        heartbeat_counter: u32,
133        fault_flags: u16,
134        temperature_value: i16,
135    ) -> Self {
136        Self {
137            module_id,
138            heartbeat_counter,
139            fault_flags,
140            temperature_value,
141        }
142    }
143
144    /// Check if any faults are present
145    pub fn has_faults(&self) -> bool {
146        self.fault_flags != 0
147    }
148
149    /// Get temperature in °C (floating point)
150    pub fn temperature_celsius(&self) -> f32 {
151        self.temperature_value as f32 / 10.0
152    }
153}
154
[docs]155// @ TempCtrlStatusProvider trait, IMPL_TEMP_CTRL_STATUS_PROVIDER, impl, [INTF_TEMP_CTRL_STATUS, COMP_TEMP_CTRL]
156/// Trait for the Temperature Controller to expose its status to the Safety Monitor
157///
158/// Implements: Temperature Controller Module (COMP_TEMP_CTRL)
159pub trait TempCtrlStatusProvider {
160    /// Get the current temperature controller status
161    fn get_temp_ctrl_status(&self) -> TempCtrlStatus;
162}
163
[docs]164// @ TempCtrlStatusConsumer trait, IMPL_TEMP_CTRL_STATUS_CONSUMER, impl, [INTF_TEMP_CTRL_STATUS, COMP_SAFETY_MON]
165/// Trait for the Safety Monitor to consume temperature controller status
166///
167/// Implements: Safety Monitor Module (COMP_SAFETY_MON)
168pub trait TempCtrlStatusConsumer {
169    /// Process a temperature controller status update
170    fn process_temp_ctrl_status(&mut self, status: TempCtrlStatus);
171}
172
173/// Brew Controller Status Interface (INTF_BREW_CTRL_STATUS)
174///
175/// **Provider**: Brew Controller Module (COMP_BREW_CTRL)
176///
177/// **Consumer**: Safety Monitor Module (COMP_SAFETY_MON)
178///
179/// **Description**: Continuous status reporting from the Brew Controller
180/// to the Safety Monitor, including water level readings and fault flags.
181///
182/// **Protocol**: Polled by safety monitor at 10Hz
[docs]183// @ BrewCtrlStatus struct, IMPL_BREW_CTRL_STATUS, impl, [INTF_BREW_CTRL_STATUS]
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185pub struct BrewCtrlStatus {
186    /// Module identifier (fixed value for Brew Controller)
187    pub module_id: u8,
188    /// Heartbeat counter (incremented each control cycle)
189    pub heartbeat_counter: u32,
190    /// Bitfield of detected faults (0 = no fault)
191    pub fault_flags: u16,
192    /// Current water level (0–100%)
193    pub water_level: u8,
194}
195
196impl BrewCtrlStatus {
197    /// Create a new brew controller status
198    pub fn new(
199        module_id: u8,
200        heartbeat_counter: u32,
201        fault_flags: u16,
202        water_level: u8,
203    ) -> Self {
204        Self {
205            module_id,
206            heartbeat_counter,
207            fault_flags,
208            water_level,
209        }
210    }
211
212    /// Check if any faults are present
213    pub fn has_faults(&self) -> bool {
214        self.fault_flags != 0
215    }
216}
217
[docs]218// @ BrewCtrlStatusProvider trait, IMPL_BREW_CTRL_STATUS_PROVIDER, impl, [INTF_BREW_CTRL_STATUS, COMP_BREW_CTRL]
219/// Trait for the Brew Controller to expose its status to the Safety Monitor
220///
221/// Implements: Brew Controller Module (COMP_BREW_CTRL)
222pub trait BrewCtrlStatusProvider {
223    /// Get the current brew controller status
224    fn get_brew_ctrl_status(&self) -> BrewCtrlStatus;
225}
226
[docs]227// @ BrewCtrlStatusConsumer trait, IMPL_BREW_CTRL_STATUS_CONSUMER, impl, [INTF_BREW_CTRL_STATUS, COMP_SAFETY_MON]
228/// Trait for the Safety Monitor to consume brew controller status
229///
230/// Implements: Safety Monitor Module (COMP_SAFETY_MON)
231pub trait BrewCtrlStatusConsumer {
232    /// Process a brew controller status update
233    fn process_brew_ctrl_status(&mut self, status: BrewCtrlStatus);
234}
235
236/// Safety Command Interface (INTF_SAFETY_CMD)
237///
238/// **Provider**: Safety Monitor Module
239///
240/// **Consumers**: Temperature Controller, Brew Controller
241///
242/// **Description**: Emergency shutdown commands from safety monitor to
243/// all controlled subsystems.
244///
245/// **Protocol**: Interrupt-driven with hardware watchdog backup, highest priority
[docs]246// @ SafetyCommandProvider trait, IMPL_SAFETY_CMD_PROVIDER, impl, [INTF_SAFETY_CMD, COMP_SAFETY_MON]
247pub trait SafetyCommandProvider {
248    /// Send a safety command to subsystems
249    fn send_safety_command(&self, command: SafetyCommand);
250}
251
[docs]252// @ SafetyCommandConsumer trait, IMPL_SAFETY_CMD_CONSUMER, impl, [INTF_SAFETY_CMD, COMP_TEMP_CTRL, COMP_BREW_CTRL]
253/// Trait for components that receive safety commands
254///
255/// Implements: Temperature Controller (COMP_TEMP_CTRL), Brew Controller (COMP_BREW_CTRL)
256pub trait SafetyCommandConsumer {
257    /// Handle a safety command (must respond within 100ms for EMERGENCY_STOP)
258    fn handle_safety_command(&mut self, command: SafetyCommand);
259}
260
261/// User Command Interface (INTF_USER_CMD)
262///
263/// **Provider**: User Interface Module
264///
265/// **Consumer**: Brew Controller Module
266///
267/// **Description**: User commands and settings passed from UI to the
268/// brewing state machine.
269///
270/// **Protocol**: Message queue with event-driven processing, debounced at UI layer
[docs]271// @ UserCommandProvider trait, IMPL_USER_CMD_PROVIDER, impl, [INTF_USER_CMD, COMP_UI_MODULE]
272pub trait UserCommandProvider {
273    /// Send a user command to the brew controller
274    fn send_user_command(&self, command: UserCommand);
275}
276
[docs]277// @ UserCommandConsumer trait, IMPL_USER_CMD_CONSUMER, impl, [INTF_USER_CMD, COMP_BREW_CTRL]
278/// Trait for components that consume user commands
279///
280/// Implements: Brew Controller Module (COMP_BREW_CTRL)
281pub trait UserCommandConsumer {
282    /// Handle a user command
283    fn handle_user_command(&mut self, command: UserCommand);
284}
285
286/// Sensor Data Interface (INTF_SENSOR_DATA)
287///
288/// **Provider**: Hardware sensors (temperature, water level)
289///
290/// **Consumers**: Temperature Controller, Safety Monitor
291///
292/// **Description**: Raw sensor readings from hardware via ADC.
293///
294/// **Protocol**: ADC DMA with double buffering, 100Hz sampling rate
[docs]295// @ SensorData struct, IMPL_SENSOR_DATA, impl, [INTF_SENSOR_DATA]
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
297pub struct SensorData {
298    /// Temperature sensor ADC value (0-4095)
299    pub temp_sensor_raw: u16,
300    /// Water level sensor ADC value (0-4095)
301    pub water_level_raw: u16,
302    /// Timestamp in milliseconds
303    pub sensor_timestamp: u32,
304}
305
306impl SensorData {
307    /// Create new sensor data
308    pub fn new(temp_sensor_raw: u16, water_level_raw: u16, sensor_timestamp: u32) -> Self {
309        Self {
310            temp_sensor_raw,
311            water_level_raw,
312            sensor_timestamp,
313        }
314    }
315}
316
[docs]317// @ SensorDataProvider trait, IMPL_SENSOR_DATA_PROVIDER, impl, [INTF_SENSOR_DATA, COMP_HAL]
318/// Trait for components that provide sensor data
319///
320/// Implements: Hardware Abstraction Layer (COMP_HAL)
321pub trait SensorDataProvider {
322    /// Get the latest sensor readings
323    fn get_sensor_data(&self) -> SensorData;
324}
325
[docs]326// @ SensorDataConsumer trait, IMPL_SENSOR_DATA_CONSUMER, impl, [INTF_SENSOR_DATA, COMP_TEMP_CTRL, COMP_SAFETY_MON]
327/// Trait for components that consume sensor data
328///
329/// Implements: Temperature Controller (COMP_TEMP_CTRL), Safety Monitor (COMP_SAFETY_MON)
330pub trait SensorDataConsumer {
331    /// Process new sensor data
332    fn process_sensor_data(&mut self, data: SensorData);
333}
334
335#[cfg(test)]
336mod tests {
337    use super::*;
338
339    #[test]
340    fn test_temperature_status_conversions() {
341        let status = TemperatureStatus::new(900, 950, true, false);
342        assert_eq!(status.current_temp_celsius(), 90.0);
343        assert_eq!(status.target_temp_celsius(), 95.0);
344        assert_eq!(status.is_ready, true);
345        assert_eq!(status.heating_active, false);
346    }
347
348    #[test]
349    fn test_temp_ctrl_status_fault_detection() {
350        let status_no_fault = TempCtrlStatus::new(1, 100, 0, 900);
351        assert_eq!(status_no_fault.has_faults(), false);
352        assert_eq!(status_no_fault.temperature_celsius(), 90.0);
353
354        let status_with_fault = TempCtrlStatus::new(1, 101, 0x0001, 900);
355        assert_eq!(status_with_fault.has_faults(), true);
356    }
357
358    #[test]
359    fn test_brew_ctrl_status_fault_detection() {
360        let status_no_fault = BrewCtrlStatus::new(2, 100, 0, 80);
361        assert_eq!(status_no_fault.has_faults(), false);
362        assert_eq!(status_no_fault.water_level, 80);
363
364        let status_with_fault = BrewCtrlStatus::new(2, 101, 0x0001, 80);
365        assert_eq!(status_with_fault.has_faults(), true);
366    }
367
368    #[test]
369    fn test_brew_strength_enum() {
370        let strength = BrewStrength::Medium;
371        assert_eq!(strength, BrewStrength::Medium);
372        assert_ne!(strength, BrewStrength::Weak);
373    }
374
375    #[test]
376    fn test_user_command_variants() {
377        let cmd1 = UserCommand::StartBrew(BrewStrength::Strong);
378        let cmd2 = UserCommand::StopBrew;
379        let cmd3 = UserCommand::SelectStrength(BrewStrength::Weak);
380
381        match cmd1 {
382            UserCommand::StartBrew(BrewStrength::Strong) => (),
383            _ => panic!("Wrong command variant"),
384        }
385
386        match cmd2 {
387            UserCommand::StopBrew => (),
388            _ => panic!("Wrong command variant"),
389        }
390
391        match cmd3 {
392            UserCommand::SelectStrength(BrewStrength::Weak) => (),
393            _ => panic!("Wrong command variant"),
394        }
395    }
396
397    #[test]
398    fn test_sensor_data_creation() {
399        let data = SensorData::new(2048, 3000, 12345);
400        assert_eq!(data.temp_sensor_raw, 2048);
401        assert_eq!(data.water_level_raw, 3000);
402        assert_eq!(data.sensor_timestamp, 12345);
403    }
404}