1use std::path::PathBuf;
6use crate::PacketGenerator;
7use crate::helpers::crc_packets_wrapper;
8use crate::helpers::cpacket_paginator;
9
10pub struct WristApp {
14 pub wrist_app_data: Vec<u8>,
16}
17
18impl WristApp {
19 pub fn new(wrist_app_data: Vec<u8>) -> Self {
21 Self {
22 wrist_app_data,
23 }
24 }
25
26 pub fn from_zap_file(file_path: PathBuf) -> std::io::Result<Self> {
31 let file_data = std::fs::read(file_path)?;
33
34 let wrist_app_data = Self::parse_zap_file(&file_data)?;
36
37 Ok(Self {
38 wrist_app_data,
39 })
40 }
41
42 pub fn parse_zap_file(zap_data: &[u8]) -> std::io::Result<Vec<u8>> {
49 const WRIST_APP_CODE_INDEX: usize = 8; let mut sections = Vec::new();
54 let mut current_section = Vec::new();
55 let mut i = 0;
56
57 while i < zap_data.len() {
58 if zap_data[i] == 0xAC {
59 if !current_section.is_empty() {
61 sections.push(current_section);
62 current_section = Vec::new();
63 }
64
65 i += 1;
67 while i < zap_data.len() && !(zap_data[i] == b'\r' && i + 1 < zap_data.len() && zap_data[i + 1] == b'\n') {
68 i += 1;
69 }
70
71 if i < zap_data.len() && zap_data[i] == b'\r' && i + 1 < zap_data.len() && zap_data[i + 1] == b'\n' {
73 i += 2; }
75 } else {
76 current_section.push(zap_data[i]);
78 i += 1;
79 }
80 }
81
82 if !current_section.is_empty() {
84 sections.push(current_section);
85 }
86
87 if sections.len() <= WRIST_APP_CODE_INDEX {
89 return Err(std::io::Error::new(
90 std::io::ErrorKind::InvalidData,
91 format!("ZAP file does not contain enough sections, expected at least {}", WRIST_APP_CODE_INDEX + 1)
92 ));
93 }
94
95 let target_section = §ions[WRIST_APP_CODE_INDEX];
97
98 let mut result = Vec::new();
101
102 let mut i = 0;
104 while i + 1 < target_section.len() {
105 let high = Self::hex_digit_to_value(target_section[i]);
106 let low = Self::hex_digit_to_value(target_section[i + 1]);
107
108 if let (Some(high), Some(low)) = (high, low) {
109 result.push((high << 4) | low);
110 } else {
111 if high.is_none() {
113 i += 1;
114 }
115 }
117
118 i += 2;
119 }
120
121 Ok(result)
122 }
123
124 fn hex_digit_to_value(digit: u8) -> Option<u8> {
126 match digit {
127 b'0'..=b'9' => Some(digit - b'0'),
128 b'A'..=b'F' => Some(digit - b'A' + 10),
129 b'a'..=b'f' => Some(digit - b'a' + 10),
130 _ => None,
131 }
132 }
133}
134
135impl PacketGenerator for WristApp {
136 fn packets(&self) -> Vec<Vec<u8>> {
137 const CPACKET_CLEAR: [u8; 2] = [0x93, 0x02];
139 const CPACKET_SECT: [u8; 2] = [0x90, 0x02];
140 const CPACKET_DATA: [u8; 2] = [0x91, 0x02];
141 const CPACKET_END: [u8; 2] = [0x92, 0x02];
142 const CPACKET_DATA_LENGTH: usize = 32;
143
144 let payloads = cpacket_paginator::paginate_cpackets(
146 &CPACKET_DATA,
147 CPACKET_DATA_LENGTH,
148 &self.wrist_app_data
149 );
150
151 let mut sect_packet = Vec::new();
153 sect_packet.extend_from_slice(&CPACKET_SECT);
154 sect_packet.push(payloads.len() as u8);
155 sect_packet.push(1); let mut all_packets = Vec::with_capacity(payloads.len() + 3);
160 all_packets.push(CPACKET_CLEAR.to_vec());
161 all_packets.push(sect_packet);
162 all_packets.extend(payloads);
163 all_packets.push(CPACKET_END.to_vec());
164
165 crc_packets_wrapper::wrap_packets_with_crc(all_packets)
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use std::path::PathBuf;
174
175 #[test]
176 fn test_wrist_app() {
177 let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
179 .join("fixtures")
180 .join("EXAMPLE.ZAP");
181
182 let wrist_app = WristApp::from_zap_file(fixture_path).unwrap();
183
184 #[rustfmt::skip]
186 let expected = vec![
187 vec![ 5, 147, 2, 48, 253 ],
188 vec![ 7, 144, 2, 5, 1, 144, 251 ],
189 vec![ 38, 145, 2, 1, 49, 53, 48, 32, 100, 97, 116, 97, 58, 32, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 211, 127 ],
190 vec![ 38, 145, 2, 2, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 114, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 101, 108, 105, 63, 42 ],
191 vec![ 38, 145, 2, 3, 116, 44, 32, 115, 101, 100, 32, 100, 111, 32, 101, 105, 117, 115, 109, 111, 100, 32, 116, 101, 109, 112, 111, 114, 32, 105, 110, 99, 105, 100, 105, 100, 140, 40 ],
192 vec![ 38, 145, 2, 4, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 111, 114, 101, 32, 101, 116, 32, 100, 111, 108, 111, 114, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 167, 146 ],
193 vec![ 11, 145, 2, 5, 105, 113, 117, 97, 46, 102, 103 ],
194 vec![ 5, 146, 2, 160, 252 ]
195 ];
196
197 assert_eq!(wrist_app.packets(), expected);
198 }
199}