protocol4_example/
protocol4_example.rs

1use std::time::SystemTime;
2use std::env;
3use std::process;
4use chrono::{TimeZone, Utc};
5use timex_datalink::PacketGenerator;
6use timex_datalink::NotebookAdapter;
7use timex_datalink::protocol_4::{
8    Protocol4,
9    alarm::Alarm,
10    eeprom::{
11        Anniversary,
12        Appointment,
13        List,
14        PhoneNumber,
15        Eeprom,
16        phone_number::PhoneType,
17        list::Priority,
18        NotificationMinutes,
19    },
20    time::{Time, DateFormat},
21    sound_options::SoundOptions,
22    sound_theme::SoundTheme,
23    wrist_app::WristApp,
24    start::Start,
25    sync::Sync,
26    end::End,
27};
28use timex_datalink::char_encoders::{CharString, EepromString, PhoneString};
29
30fn main() {
31    // Get the serial port from command line arguments
32    let args: Vec<String> = env::args().collect();
33    let serial_port = match args.len() {
34        1 => {
35            println!("Usage: {} <serial_port_path>", args[0]);
36            println!("  Example: {} /dev/ttyUSB0", args[0]);
37            process::exit(1);
38        },
39        _ => args[1].clone(),
40    };
41    // Create appointments
42    let appointments = vec![
43        Appointment {
44            time: system_time_from_date(2022, 10, 31, 19, 0, 0),
45            message: EepromString::new("Scare the neighbors"),
46        },
47        Appointment {
48            time: system_time_from_date(2022, 11, 24, 17, 0, 0),
49            message: EepromString::new("Feed the neighbors"),
50        },
51        Appointment {
52            time: system_time_from_date(2022, 12, 25, 14, 0, 0),
53            message: EepromString::new("Spoil the neighbors"),
54        },
55    ];
56
57    // Create anniversaries
58    let anniversaries = vec![
59        Anniversary {
60            time: system_time_from_date(1985, 7, 3, 0, 0, 0),
61            anniversary: EepromString::new("Release of Back to the Future"),
62        },
63        Anniversary {
64            time: system_time_from_date(1968, 4, 6, 0, 0, 0),
65            anniversary: EepromString::new("Release of 2001"),
66        },
67    ];
68
69    // Create phone numbers
70    let phone_numbers = vec![
71        PhoneNumber {
72            name: EepromString::new("Marty McFly"),
73            number: PhoneString::new("1112223333"),
74            phone_type: PhoneType::Home,
75        },
76        PhoneNumber {
77            name: EepromString::new("Doc Brown"),
78            number: PhoneString::new("4445556666"),
79            phone_type: PhoneType::Cell,
80        },
81    ];
82
83    // Create lists
84    let lists = vec![
85        List {
86            list_entry: EepromString::new("Muffler bearings"),
87            priority: Some(Priority::Two),
88        },
89        List {
90            list_entry: EepromString::new("Headlight fluid"),
91            priority: Some(Priority::Four),
92        },
93    ];
94
95    // Current time
96    let time1 = SystemTime::now();
97
98    // Create the Protocol4 structure with all components
99    let mut protocol = Protocol4::new();
100    
101    // Add mandatory components
102    protocol.add(Sync { length: 100 });
103    protocol.add(Start {});
104    
105    // Add multiple time zones
106    protocol.add(Time {
107        zone: 1,
108        is_24h: false,
109        date_format: DateFormat::MonthDashDayDashYear,
110        time: time1,
111        name: CharString::new("PDT", true),
112    });
113    
114    protocol.add(Time {
115        zone: 2,
116        is_24h: true,
117        date_format: DateFormat::MonthDashDayDashYear,
118        time: time1,
119        name: CharString::new("GMT", true),
120    });
121    
122    // Add multiple alarms
123    protocol.add(Alarm {
124        number: 1,
125        audible: true,
126        time: system_time_from_time(9, 0),
127        message: CharString::new("Wake up", false),
128    });
129    
130    protocol.add(Alarm {
131        number: 2,
132        audible: true,
133        time: system_time_from_time(9, 5),
134        message: CharString::new("For real", false),
135    });
136    
137    protocol.add(Alarm {
138        number: 3,
139        audible: false,
140        time: system_time_from_time(9, 10),
141        message: CharString::new("Get up", false),
142    });
143    
144    protocol.add(Alarm {
145        number: 4,
146        audible: true,
147        time: system_time_from_time(18, 0), // 6 PM
148        message: CharString::new("Or not", false),
149    });
150    
151    protocol.add(Alarm {
152        number: 5,
153        audible: false,
154        time: system_time_from_time(14, 0), // 2 PM
155        message: CharString::new("Told you", false),
156    });
157    
158    // Add optional components
159    protocol.add(SoundOptions {
160        hourly_chime: true,
161        button_beep: true,
162    });
163    
164    protocol.add(SoundTheme {
165        // Data from DEFHIGH.SPC
166        sound_theme_data: vec![0x00, 0x01, 0x02, 0x03],
167    });
168    
169    // Create and add EEPROM
170    let eeprom = Eeprom {
171        appointments,
172        anniversaries,
173        lists,
174        phone_numbers,
175        appointment_notification_minutes: Some(NotificationMinutes::FifteenMinutes),
176    };
177    protocol.add(eeprom);
178    
179    protocol.add(WristApp {
180        // Data from TIMER13.ZAP
181        wrist_app_data: vec![0x00, 0x01, 0x02, 0x03],
182    });
183    
184    // Add End component (mandatory)
185    protocol.add(End {});
186
187    // Generate all packets
188    let all_packets = protocol.packets();
189    
190    // Display results
191    println!("Created Protocol4 structure with all components");
192    println!("- Generated {} packet groups", all_packets.len());
193    
194    // Print packet summary
195    for (i, packet) in all_packets.iter().enumerate() {
196        // Only print the first few bytes of each packet to avoid overwhelming output
197        let preview: Vec<u8> = packet.iter().take(6).cloned().collect();
198        println!("Packet group {}: {} bytes, starts with {:02X?}...", i, packet.len(), preview);
199    }
200    
201    println!("\nTransmitting data to the watch on port: {}", serial_port);
202    
203    // Create the notebook adapter and send the packets
204    let adapter = NotebookAdapter::new(
205        serial_port,
206        None, // Use default byte sleep time
207        None, // Use default packet sleep time
208        true, // Enable verbose output
209    );
210    
211    match adapter.write(&all_packets) {
212        Ok(_) => println!("\nSuccessfully transmitted data to the watch!"),
213        Err(e) => {
214            eprintln!("\nError transmitting data: {}", e);
215            process::exit(1);
216        }
217    }
218}
219
220// Helper function to create a SystemTime from date components
221fn system_time_from_date(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> SystemTime {
222    // Create a DateTime with chrono
223    let naive_dt = chrono::NaiveDate::from_ymd_opt(year, month, day)
224        .unwrap()
225        .and_hms_opt(hour, min, sec)
226        .unwrap();
227    
228    let dt = Utc.from_utc_datetime(&naive_dt);
229    
230    // Convert to system time - handle negative timestamps properly
231    if dt.timestamp() >= 0 {
232        SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(dt.timestamp() as u64)
233    } else {
234        SystemTime::UNIX_EPOCH - std::time::Duration::from_secs((-dt.timestamp()) as u64)
235    }
236}
237
238// Helper function to create a SystemTime with just hour and minute
239fn system_time_from_time(hour: u32, min: u32) -> SystemTime {
240    // For alarms, we only care about hour and minute, so use a fixed date
241    // Using 2000-01-01 as the base date
242    let naive_dt = chrono::NaiveDate::from_ymd_opt(2000, 1, 1)
243        .unwrap()
244        .and_hms_opt(hour, min, 0)
245        .unwrap();
246    
247    let dt = Utc.from_utc_datetime(&naive_dt);
248    
249    // Convert to system time
250    SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(dt.timestamp() as u64)
251}