tinyboot_core/
protocol.rs1use crate::ringbuf::RingBuf;
2use crate::traits::boot::{BootCtl, BootMetaStore, Platform, Storage, Transport};
3use crate::traits::{BootMode, BootState};
4use tinyboot_protocol::crc::{CRC_INIT, crc16};
5use tinyboot_protocol::frame::{Frame, InfoData, VerifyData};
6use tinyboot_protocol::{Cmd, ReadError, Status};
7
8pub struct Dispatcher<'a, T: Transport, S: Storage, B: BootMetaStore, C: BootCtl, const BUF: usize>
15{
16 pub platform: &'a mut Platform<T, S, B, C>,
18 pub frame: Frame,
20 buf: RingBuf<BUF>,
22 next_addr: Option<u32>,
24}
25
26impl<'a, T: Transport, S: Storage, B: BootMetaStore, C: BootCtl, const BUF: usize>
27 Dispatcher<'a, T, S, B, C, BUF>
28{
29 pub fn new(platform: &'a mut Platform<T, S, B, C>) -> Self {
31 Self {
32 platform,
33 frame: Frame::default(),
34 buf: RingBuf::default(),
35 next_addr: None,
36 }
37 }
38
39 fn write_buf(&mut self, next: u32, n: usize) {
41 let addr = next - self.buf.len() as u32;
42 let data = self.buf.peek(n);
43 if self.platform.storage.write(addr, data).is_err() {
44 self.frame.status = Status::WriteError;
45 }
46 self.buf.consume(n);
47 }
48
49 pub fn dispatch(&mut self) -> Result<(), ReadError> {
53 let status = self.frame.read(&mut self.platform.transport)?;
54
55 if status != Status::Ok {
56 self.frame.len = 0;
57 self.frame.status = status;
58 return self
59 .frame
60 .send(&mut self.platform.transport)
61 .map_err(|_| ReadError);
62 }
63
64 let data_len = self.frame.len as usize;
65 let capacity = self.platform.storage.capacity() as u32;
66 let erase_size = S::ERASE_SIZE as u32;
67 let write_size = S::WRITE_SIZE as u32;
68 let state = self.platform.boot_meta.boot_state();
69 self.frame.len = 0;
70 self.frame.status = Status::Ok;
71
72 match self.frame.cmd {
73 Cmd::Info => {
74 self.frame.len = 12;
75 let app_sz = self.platform.boot_meta.app_size();
76 let app_ver = if app_sz != 0xFFFF_FFFF {
77 let base = self.platform.storage.as_slice().as_ptr();
80 unsafe { base.add(app_sz as usize - 2).cast::<u16>().read_volatile() }
81 } else {
82 0xFFFF
83 };
84 let boot_version = crate::tinyboot_version();
85 self.frame.data.info = InfoData {
86 capacity,
87 erase_size: erase_size as u16,
88 boot_version,
89 app_version: app_ver,
90 mode: 0,
91 };
92 }
93 Cmd::Erase => {
94 let addr = self.frame.addr;
95 let byte_count = unsafe { self.frame.data.erase }.byte_count as u32;
96 if !addr.is_multiple_of(erase_size)
97 || !byte_count.is_multiple_of(erase_size)
98 || byte_count == 0
99 || addr + byte_count > capacity
100 {
101 self.frame.status = Status::AddrOutOfBounds;
102 } else {
103 match state {
105 BootState::Idle => {
107 if self.platform.boot_meta.advance().is_err() {
108 self.frame.status = Status::WriteError;
109 }
110 }
111 BootState::Validating => {
113 if self
114 .platform
115 .boot_meta
116 .refresh(0xFFFF, BootState::Updating, 0xFFFF_FFFF)
117 .is_err()
118 {
119 self.frame.status = Status::WriteError;
120 }
121 }
122 BootState::Updating => {}
124 }
125 if self.frame.status == Status::Ok
126 && self
127 .platform
128 .storage
129 .erase(addr, addr + byte_count)
130 .is_err()
131 {
132 self.frame.status = Status::WriteError;
133 }
134 }
135 }
136 Cmd::Write => {
137 if state != BootState::Updating {
138 self.frame.status = Status::Unsupported;
139 } else {
140 let addr = self.frame.addr;
141 if addr + data_len as u32 > capacity
142 || (self.next_addr.is_none() && !addr.is_multiple_of(write_size))
143 || self.next_addr.is_some_and(|n| n != addr)
144 {
145 self.frame.status = Status::AddrOutOfBounds;
146 } else {
147 self.buf
149 .push(unsafe { self.frame.data.raw.get_unchecked(..data_len) });
150 let next = addr + data_len as u32;
151 self.next_addr = Some(next);
152 if self.buf.len() >= S::WRITE_SIZE {
154 self.write_buf(next, S::WRITE_SIZE);
155 }
156 }
157 }
158 }
159 Cmd::Verify => {
160 if state != BootState::Updating {
161 self.frame.status = Status::Unsupported;
162 } else {
163 let app_size = self.frame.addr;
164 let sz = app_size as usize;
165 if sz == 0 || sz > capacity as usize {
166 self.frame.status = Status::AddrOutOfBounds;
167 } else {
168 let crc = crc16(CRC_INIT, unsafe {
170 self.platform.storage.as_slice().get_unchecked(..sz)
171 });
172 self.frame.len = 2;
173 self.frame.data.verify = VerifyData { crc };
174 if self
175 .platform
176 .boot_meta
177 .refresh(crc, BootState::Validating, app_size)
178 .is_err()
179 {
180 self.frame.status = Status::WriteError;
181 }
182 }
183 }
184 }
185 Cmd::Reset => {
186 let _ = self.frame.send(&mut self.platform.transport);
187 let mode = if self.frame.addr == 1 {
188 BootMode::Bootloader
189 } else {
190 BootMode::App
191 };
192 self.platform.ctl.system_reset(mode);
193 }
194 Cmd::Flush => {
195 if let Some(next) = self.next_addr {
196 if !self.buf.is_empty() {
197 self.write_buf(next, self.buf.len());
198 }
199 self.next_addr = None;
200 }
201 }
202 }
203
204 self.frame
205 .send(&mut self.platform.transport)
206 .map_err(|_| ReadError)
207 }
208}