timex_datalink/protocol_3/
alarm.rs

1//! Alarm implementation for Protocol 3
2//!
3//! This module handles alarm functionality for Timex Datalink watches.
4
5use crate::PacketGenerator;
6use crate::helpers::crc_packets_wrapper;
7use crate::char_encoders::CharString;
8
9/// Alarm structure for Protocol 3
10///
11/// This structure handles alarms with a message and configurable sound.
12pub struct Alarm {
13    /// Alarm number (1-5)
14    pub number: u8,
15    
16    /// Whether the alarm makes sound when triggered
17    pub audible: bool,
18    
19    /// Hour of the alarm (0-23)
20    pub hour: u8,
21    
22    /// Minute of the alarm (0-59)
23    pub minute: u8,
24    
25    /// Message to display (8 chars max)
26    pub message: CharString<8>,
27}
28
29impl PacketGenerator for Alarm {
30    fn packets(&self) -> Vec<Vec<u8>> {
31        // Define constants from Ruby implementation
32        const CPACKET_ALARM: u8 = 0x50;
33
34        // Create the raw packet
35        let mut raw_packet = Vec::with_capacity(16);
36        raw_packet.push(CPACKET_ALARM);   // Alarm command
37        raw_packet.push(self.number);      // Alarm number (1-5)
38        raw_packet.push(self.hour);        // Hour
39        raw_packet.push(self.minute);      // Minute
40        raw_packet.push(0);                // Unused bytes in protocol 3
41        raw_packet.push(0);                // Unused bytes in protocol 3
42        
43        // Add message characters (8 chars)
44        for &byte in self.message.as_bytes() {
45            raw_packet.push(byte);
46        }
47        
48        // Audible flag
49        raw_packet.push(if self.audible { 1 } else { 0 });
50        
51        // Apply CRC wrapping
52        crc_packets_wrapper::wrap_packets_with_crc(vec![raw_packet])
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_alarm_basic() {
62        let alarm = Alarm {
63            number: 1,
64            audible: true,
65            hour: 9,
66            minute: 0,
67            message: CharString::new("Wake up", true),
68        };
69
70        // From golden fixture: alarm_basic.jsonl
71        #[rustfmt::skip]
72        let expected = vec![vec![
73            18, 80, 1, 9, 0, 0, 0, 32, 10, 20, 14, 36, 30, 25, 36, 1, 32, 240
74        ]];
75
76        assert_eq!(alarm.packets(), expected);
77    }
78
79    #[test]
80    fn test_alarm_silent() {
81        let alarm = Alarm {
82            number: 3,
83            audible: false,
84            hour: 9,
85            minute: 10,
86            message: CharString::new("Get up", true),
87        };
88
89        // From golden fixture: alarm_silent.jsonl
90        #[rustfmt::skip]
91        let expected = vec![vec![
92            18, 80, 3, 9, 10, 0, 0, 16, 14, 29, 36, 30, 25, 36, 36, 0, 191, 169
93        ]];
94
95        assert_eq!(alarm.packets(), expected);
96    }
97}