1#[cfg(feature = "use_serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::io::{ErrorType, Read, Write};
5use crate::utils::io::*;
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
10pub struct Slot {
11 pub label: heapless::String<32>,
12 pub state: SlotState,
13 pub firmware: Option<FirmwareInfo>,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
19pub struct FirmwareInfo {
20 pub version: heapless::String<24>,
21 pub released: heapless::String<24>,
22 pub description: Option<heapless::String<128>>,
23 pub signature: Option<heapless::Vec<u8, 32>>,
24 pub download_id: Option<heapless::String<128>>,
25}
26
27#[derive(Clone, Debug)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
30pub struct UpdateProgress {
31 pub progress: u32,
32 pub operation: &'static str,
33}
34
35#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
38pub enum LoadResult {
39 ReloadMore,
40 LoadMore,
41 Loaded,
42}
43
44#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
47pub enum SlotState {
48 Factory,
49 Valid,
50 Invalid,
51 Unverified,
52 Unknown,
53}
54
55pub trait FirmwareInfoLoader: ErrorType {
56 fn load(&mut self, buf: &[u8]) -> Result<LoadResult, Self::Error>;
57
58 fn is_loaded(&self) -> bool;
59
60 fn get_info(&self) -> Result<FirmwareInfo, Self::Error>;
61}
62
63impl<F> FirmwareInfoLoader for &mut F
64where
65 F: FirmwareInfoLoader,
66{
67 fn load(&mut self, buf: &[u8]) -> Result<LoadResult, Self::Error> {
68 (*self).load(buf)
69 }
70
71 fn is_loaded(&self) -> bool {
72 (**self).is_loaded()
73 }
74
75 fn get_info(&self) -> Result<FirmwareInfo, Self::Error> {
76 (**self).get_info()
77 }
78}
79
80pub trait Ota: ErrorType {
81 type Update<'a>: OtaUpdate<Error = Self::Error>
82 where
83 Self: 'a;
84
85 fn get_boot_slot(&self) -> Result<Slot, Self::Error>;
86
87 fn get_running_slot(&self) -> Result<Slot, Self::Error>;
88
89 fn get_update_slot(&self) -> Result<Slot, Self::Error>;
90
91 fn is_factory_reset_supported(&self) -> Result<bool, Self::Error>;
92
93 fn factory_reset(&mut self) -> Result<(), Self::Error>;
94
95 fn initiate_update(&mut self) -> Result<Self::Update<'_>, Self::Error>;
96
97 fn mark_running_slot_valid(&mut self) -> Result<(), Self::Error>;
98
99 fn mark_running_slot_invalid_and_reboot(&mut self) -> Self::Error;
100}
101
102impl<O> Ota for &mut O
103where
104 O: Ota,
105{
106 type Update<'a>
107 = O::Update<'a>
108 where
109 Self: 'a;
110
111 fn get_boot_slot(&self) -> Result<Slot, Self::Error> {
112 (**self).get_boot_slot()
113 }
114
115 fn get_running_slot(&self) -> Result<Slot, Self::Error> {
116 (**self).get_running_slot()
117 }
118
119 fn get_update_slot(&self) -> Result<Slot, Self::Error> {
120 (**self).get_update_slot()
121 }
122
123 fn is_factory_reset_supported(&self) -> Result<bool, Self::Error> {
124 (**self).is_factory_reset_supported()
125 }
126
127 fn factory_reset(&mut self) -> Result<(), Self::Error> {
128 (*self).factory_reset()
129 }
130
131 fn initiate_update(&mut self) -> Result<Self::Update<'_>, Self::Error> {
132 (*self).initiate_update()
133 }
134
135 fn mark_running_slot_valid(&mut self) -> Result<(), Self::Error> {
136 (*self).mark_running_slot_valid()
137 }
138
139 fn mark_running_slot_invalid_and_reboot(&mut self) -> Self::Error {
140 (*self).mark_running_slot_invalid_and_reboot()
141 }
142}
143
144pub trait OtaUpdate: Write {
145 type OtaUpdateFinished: OtaUpdateFinished;
146
147 fn finish(self) -> Result<Self::OtaUpdateFinished, Self::Error>;
148
149 fn complete(self) -> Result<(), Self::Error>;
150
151 fn abort(self) -> Result<(), Self::Error>;
152
153 fn update<R>(
154 mut self,
155 read: R,
156 progress: impl Fn(u64, u64),
157 ) -> Result<(), CopyError<R::Error, Self::Error>>
158 where
159 R: Read,
160 Self: Sized,
161 {
162 let mut buf = [0_u8; 64];
163
164 match copy_len_with_progress(read, &mut self, &mut buf, u64::MAX, progress) {
165 Ok(_) => self.complete().map_err(CopyError::Write),
166 Err(e) => {
167 self.abort().map_err(CopyError::Write)?;
168
169 Err(e)
170 }
171 }
172 }
173}
174
175pub trait OtaUpdateFinished: ErrorType {
176 fn activate(self) -> Result<(), Self::Error>;
177}
178
179pub mod asynch {
180 use crate::io::asynch::{ErrorType, Read, Write};
181 use crate::utils::io::asynch::*;
182
183 pub use super::{FirmwareInfo, FirmwareInfoLoader, LoadResult, Slot, SlotState};
184
185 pub trait Ota: ErrorType {
186 type Update<'a>: OtaUpdate<Error = Self::Error>
187 where
188 Self: 'a;
189
190 async fn get_boot_slot(&self) -> Result<Slot, Self::Error>;
191
192 async fn get_running_slot(&self) -> Result<Slot, Self::Error>;
193
194 async fn get_update_slot(&self) -> Result<Slot, Self::Error>;
195
196 async fn is_factory_reset_supported(&self) -> Result<bool, Self::Error>;
197
198 async fn factory_reset(&mut self) -> Result<(), Self::Error>;
199
200 async fn initiate_update(&mut self) -> Result<Self::Update<'_>, Self::Error>;
201
202 async fn mark_running_slot_valid(&mut self) -> Result<(), Self::Error>;
203
204 async fn mark_running_slot_invalid_and_reboot(&mut self) -> Self::Error;
205 }
206
207 impl<O> Ota for &mut O
208 where
209 O: Ota,
210 {
211 type Update<'a>
212 = O::Update<'a>
213 where
214 Self: 'a;
215
216 async fn get_boot_slot(&self) -> Result<Slot, Self::Error> {
217 (**self).get_boot_slot().await
218 }
219
220 async fn get_running_slot(&self) -> Result<Slot, Self::Error> {
221 (**self).get_running_slot().await
222 }
223
224 async fn get_update_slot(&self) -> Result<Slot, Self::Error> {
225 (**self).get_update_slot().await
226 }
227
228 async fn is_factory_reset_supported(&self) -> Result<bool, Self::Error> {
229 (**self).is_factory_reset_supported().await
230 }
231
232 async fn factory_reset(&mut self) -> Result<(), Self::Error> {
233 (*self).factory_reset().await
234 }
235
236 async fn initiate_update(&mut self) -> Result<Self::Update<'_>, Self::Error> {
237 (*self).initiate_update().await
238 }
239
240 async fn mark_running_slot_valid(&mut self) -> Result<(), Self::Error> {
241 (*self).mark_running_slot_valid().await
242 }
243
244 async fn mark_running_slot_invalid_and_reboot(&mut self) -> Self::Error {
245 (*self).mark_running_slot_invalid_and_reboot().await
246 }
247 }
248
249 pub trait OtaUpdate: Write {
250 type OtaUpdateFinished: OtaUpdateFinished;
251
252 async fn finish(self) -> Result<Self::OtaUpdateFinished, Self::Error>;
253
254 async fn complete(self) -> Result<(), Self::Error>;
255
256 async fn abort(self) -> Result<(), Self::Error>;
257
258 async fn update<R>(
259 self,
260 read: R,
261 progress: impl Fn(u64, u64),
262 ) -> Result<(), CopyError<R::Error, Self::Error>>
263 where
264 R: Read,
265 Self: Sized;
266 }
267
268 pub trait OtaUpdateFinished: ErrorType {
269 async fn activate(self) -> Result<(), Self::Error>;
270 }
271}