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_ADC_DRV]
318/// Trait for components that provide sensor data
319///
320/// Implements: ADC Driver (COMP_ADC_DRV)
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/// PWM Control Interface (INTF_PWM_CTRL)
336///
337/// **Provider**: PWM Driver (COMP_PWM_DRV)
338///
339/// **Consumer**: Temperature Controller Module (COMP_TEMP_CTRL)
340///
341/// **Description**: Controls PWM output channels for heating element regulation.
342///
343/// **Protocol**: Direct register-mapped API, immediate effect
344
[docs]345// @ PwmChannel enum, IMPL_PWM_CHANNEL, impl, [INTF_PWM_CTRL]
346/// PWM output channel identifier
347#[derive(Debug, Clone, Copy, PartialEq, Eq)]
348pub enum PwmChannel {
349    /// Heating element control channel
350    Heater,
351}
352
[docs]353// @ PwmControl trait, IMPL_PWM_CTRL, impl, [INTF_PWM_CTRL, COMP_PWM_DRV]
354/// Trait for PWM output control
355///
356/// Implements: PWM Driver (COMP_PWM_DRV)
357pub trait PwmControl {
358    /// Set duty cycle for a channel (0–10000 for 0.01% resolution)
359    fn set_duty_cycle(&mut self, channel: PwmChannel, duty: u16);
360    /// Enable a PWM channel
361    fn enable(&mut self, channel: PwmChannel);
362    /// Disable a PWM channel
363    fn disable(&mut self, channel: PwmChannel);
364}
365
366/// GPIO Interface (INTF_GPIO)
367///
368/// **Provider**: GPIO Driver (COMP_GPIO_DRV)
369///
370/// **Consumers**: User Interface Module (COMP_UI_MODULE), Brew Controller Module (COMP_BREW_CTRL)
371///
372/// **Description**: Digital I/O abstraction for discrete signals —
373/// pump motor, brew valve, buttons, and LED indicators.
374///
375/// **Protocol**: Direct register-mapped API with interrupt support
376
[docs]377// @ GpioPin enum, IMPL_GPIO_PIN, impl, [INTF_GPIO]
378/// GPIO pin identifiers for the BrewMaster Pro 3000
379#[derive(Debug, Clone, Copy, PartialEq, Eq)]
380pub enum GpioPin {
381    /// Pump motor control (output)
382    PumpMotor,
383    /// Brew valve solenoid (output)
384    BrewValve,
385    /// Start button (input)
386    ButtonStart,
387    /// Strength select button (input)
388    ButtonStrength,
389    /// Ready LED (output)
390    LedReady,
391    /// Error LED (output)
392    LedError,
393}
394
[docs]395// @ Edge enum, IMPL_GPIO_EDGE, impl, [INTF_GPIO]
396/// GPIO interrupt edge trigger type
397#[derive(Debug, Clone, Copy, PartialEq, Eq)]
398pub enum Edge {
399    /// Trigger on rising edge
400    Rising,
401    /// Trigger on falling edge
402    Falling,
403}
404
[docs]405// @ GpioControl trait, IMPL_GPIO_CTRL, impl, [INTF_GPIO, COMP_GPIO_DRV]
406/// Trait for GPIO pin control
407///
408/// Implements: GPIO Driver (COMP_GPIO_DRV)
409pub trait GpioControl {
410    /// Set a pin output state
411    fn set_pin(&mut self, pin: GpioPin, state: bool);
412    /// Read a pin input state
413    fn read_pin(&self, pin: GpioPin) -> bool;
414}
415
416/// SPI Bus Interface (INTF_SPI_BUS)
417///
418/// **Provider**: SPI Driver (COMP_SPI_DRV)
419///
420/// **Consumer**: User Interface Module (COMP_UI_MODULE)
421///
422/// **Description**: SPI bus access for communication with the
423/// front-panel OLED display controller.
424///
425/// **Protocol**: Full-duplex SPI Mode 0, 4 MHz clock, DMA-capable
426
[docs]427// @ SpiBus trait, IMPL_SPI_BUS, impl, [INTF_SPI_BUS, COMP_SPI_DRV]
428/// Trait for SPI bus communication
429///
430/// Implements: SPI Driver (COMP_SPI_DRV)
431pub trait SpiBus {
432    /// Full-duplex SPI transfer
433    fn transfer(&mut self, tx_buf: &[u8], rx_buf: &mut [u8]);
434    /// Non-blocking DMA write
435    fn write_dma(&mut self, buf: &[u8]);
436    /// Check if a DMA transfer is still in progress
437    fn busy(&self) -> bool;
438}
439
440#[cfg(test)]
441mod tests {
442    use super::*;
443
[docs]444    // @ test_temperature_status_conversions, IMPL_TEST_TEMP_STATUS, impl, [TEST_TEMP_CONTROL]
445    #[test]
446    fn test_temperature_status_conversions() {
447        let status = TemperatureStatus::new(900, 950, true, false);
448        assert_eq!(status.current_temp_celsius(), 90.0);
449        assert_eq!(status.target_temp_celsius(), 95.0);
450        assert_eq!(status.is_ready, true);
451        assert_eq!(status.heating_active, false);
452    }
453
[docs]454    // @ test_temp_ctrl_status_fault_detection, IMPL_TEST_TEMP_FAULT, impl, [TEST_SAFETY_SHUTDOWN]
455    #[test]
456    fn test_temp_ctrl_status_fault_detection() {
457        let status_no_fault = TempCtrlStatus::new(1, 100, 0, 900);
458        assert_eq!(status_no_fault.has_faults(), false);
459        assert_eq!(status_no_fault.temperature_celsius(), 90.0);
460
461        let status_with_fault = TempCtrlStatus::new(1, 101, 0x0001, 900);
462        assert_eq!(status_with_fault.has_faults(), true);
463    }
464
[docs]465    // @ test_brew_ctrl_status_fault_detection, IMPL_TEST_BREW_FAULT, impl, [TEST_SAFETY_SHUTDOWN]
466    #[test]
467    fn test_brew_ctrl_status_fault_detection() {
468        let status_no_fault = BrewCtrlStatus::new(2, 100, 0, 80);
469        assert_eq!(status_no_fault.has_faults(), false);
470        assert_eq!(status_no_fault.water_level, 80);
471
472        let status_with_fault = BrewCtrlStatus::new(2, 101, 0x0001, 80);
473        assert_eq!(status_with_fault.has_faults(), true);
474    }
475
[docs]476    // @ test_brew_strength_enum, IMPL_TEST_BREW_STRENGTH, impl, [TEST_BREW_STRENGTH]
477    #[test]
478    fn test_brew_strength_enum() {
479        let strength = BrewStrength::Medium;
480        assert_eq!(strength, BrewStrength::Medium);
481        assert_ne!(strength, BrewStrength::Weak);
482    }
483
[docs]484    // @ test_user_command_variants, IMPL_TEST_USER_CMD, impl, [TEST_BUTTON_DEBOUNCE]
485    #[test]
486    fn test_user_command_variants() {
487        let cmd1 = UserCommand::StartBrew(BrewStrength::Strong);
488        let cmd2 = UserCommand::StopBrew;
489        let cmd3 = UserCommand::SelectStrength(BrewStrength::Weak);
490
491        match cmd1 {
492            UserCommand::StartBrew(BrewStrength::Strong) => (),
493            _ => panic!("Wrong command variant"),
494        }
495
496        match cmd2 {
497            UserCommand::StopBrew => (),
498            _ => panic!("Wrong command variant"),
499        }
500
501        match cmd3 {
502            UserCommand::SelectStrength(BrewStrength::Weak) => (),
503            _ => panic!("Wrong command variant"),
504        }
505    }
506
[docs]507    // @ test_sensor_data_creation, IMPL_TEST_SENSOR_DATA, impl, [TEST_TEMP_CONTROL]
508    #[test]
509    fn test_sensor_data_creation() {
510        let data = SensorData::new(2048, 3000, 12345);
511        assert_eq!(data.temp_sensor_raw, 2048);
512        assert_eq!(data.water_level_raw, 3000);
513        assert_eq!(data.sensor_timestamp, 12345);
514    }
515}