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}