1use std::collections::HashMap;
11
12#[derive(Debug)]
13pub enum Error {
14 TooMuchPaddingRequired(usize),
15 NonWordPaddingSize(usize),
16 InvalidDataSize(usize),
17}
18
19pub fn convert_from_uf2(buf: &[u8]) -> Result<(Vec<u8>, HashMap<u32, u64>), Error> {
32 let mut curr_addr: Option<usize> = None;
33 let mut curr_family_id: Option<u32> = None;
34 let mut families_found: HashMap<u32, u64> = HashMap::new();
35 let mut outp: Vec<u8> = Vec::new();
36
37 for (index, block) in buf.chunks_exact(512).enumerate() {
38 let hd: [u32; 8] = block[0..32]
39 .chunks_exact(4)
40 .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
41 .collect::<Vec<u32>>()
42 .try_into()
43 .unwrap();
44 if (hd[0], hd[1]) != (0x0A32_4655, 0x9E5D_5157) || (hd[2] & 1) != 0 {
46 continue;
47 }
48 let data_len = hd[4] as usize;
49 if data_len > 476 {
50 return Err(Error::InvalidDataSize(index));
51 }
52 let new_addr = hd[3] as usize;
53 if (hd[2] & 0x2000) != 0 && curr_family_id.is_none() {
54 curr_family_id = Some(hd[7]);
55 }
56
57 if curr_addr.is_none() || ((hd[2] & 0x2000) != 0 && Some(hd[7]) != curr_family_id) {
58 curr_family_id = Some(hd[7]);
59 curr_addr = Some(new_addr);
60 }
61 let mut padding = new_addr - curr_addr.unwrap();
62 if padding > 10 * 1024 * 1024 {
63 return Err(Error::TooMuchPaddingRequired(index));
64 }
65 if padding % 4 != 0 {
66 return Err(Error::NonWordPaddingSize(index));
67 }
68 while padding > 0 {
69 padding -= 4;
70 outp.extend_from_slice(&[0x0, 0x0, 0x0, 0x0]);
71 }
72
73 if (hd[2] & 0x2000) != 0 {
74 outp.extend_from_slice(&block[32..(32 + data_len)]);
75 }
76 curr_addr = Some(new_addr + data_len);
77 if (hd[2] & 0x2000) != 0 {
78 match families_found.get(&hd[7]) {
79 Some(v) if *v > new_addr.try_into().unwrap() => {
80 families_found.insert(hd[7], new_addr.try_into().unwrap());
81 }
82 None => {
83 families_found.insert(hd[7], new_addr.try_into().unwrap());
84 }
85 _ => (),
86 }
87 }
88 }
89
90 Ok((outp, families_found))
91}