Skip to main content

embedded_svc/
ota.rs

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}