esp_bootloader_esp_idf/
ota_updater.rs1use crate::{
4 ota::OtaImageState,
5 partitions::{AppPartitionSubType, Error, FlashRegion, PartitionTable},
6};
7
8#[derive(Debug)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OtaUpdater<'a, F>
14where
15 F: embedded_storage::Storage,
16{
17 flash: &'a mut F,
18 pt: PartitionTable<'a>,
19 ota_count: usize,
20}
21
22impl<'a, F> OtaUpdater<'a, F>
23where
24 F: embedded_storage::Storage,
25{
26 pub fn new(
31 flash: &'a mut F,
32 buffer: &'a mut [u8; crate::partitions::PARTITION_TABLE_MAX_LEN],
33 ) -> Result<Self, Error> {
34 let pt = crate::partitions::read_partition_table(flash, buffer)?;
35
36 let mut ota_count = 0;
37 let mut has_ota_data = false;
38 for part in pt.iter() {
39 match part.partition_type() {
40 crate::partitions::PartitionType::App(subtype) => {
41 if subtype != crate::partitions::AppPartitionSubType::Factory
42 && subtype != crate::partitions::AppPartitionSubType::Test
43 {
44 ota_count += 1;
45 }
46 }
47 crate::partitions::PartitionType::Data(
48 crate::partitions::DataPartitionSubType::Ota,
49 ) => {
50 has_ota_data = true;
51 }
52 _ => (),
53 }
54 }
55
56 if !has_ota_data {
57 return Err(Error::Invalid);
58 }
59
60 if ota_count < 2 {
61 return Err(Error::Invalid);
62 }
63
64 Ok(Self {
65 flash,
66 pt,
67 ota_count,
68 })
69 }
70
71 fn with_ota<R>(
72 &mut self,
73 f: impl FnOnce(crate::ota::Ota<'_, F>) -> Result<R, Error>,
74 ) -> Result<R, Error> {
75 let ota_part = self
76 .pt
77 .find_partition(crate::partitions::PartitionType::Data(
78 crate::partitions::DataPartitionSubType::Ota,
79 ))?;
80 if let Some(ota_part) = ota_part {
81 let mut ota_part = ota_part.as_embedded_storage(self.flash);
82 let ota = crate::ota::Ota::new(&mut ota_part, self.ota_count)?;
83 f(ota)
84 } else {
85 Err(Error::Invalid)
86 }
87 }
88
89 fn next_ota_part(&mut self) -> Result<crate::partitions::AppPartitionSubType, Error> {
90 let current = self.selected_partition()?;
91 let next = match current {
92 AppPartitionSubType::Factory => AppPartitionSubType::Ota0,
93 _ => AppPartitionSubType::from_ota_app_number(
94 (current.ota_app_number() + 1) % self.ota_count as u8,
95 )?,
96 };
97
98 let booted = self.pt.booted_partition()?;
100 let next = if let Some(booted) = booted {
101 if booted.partition_type() == crate::partitions::PartitionType::App(next) {
102 AppPartitionSubType::from_ota_app_number(
103 (current.ota_app_number() + 2) % self.ota_count as u8,
104 )?
105 } else {
106 next
107 }
108 } else {
109 next
110 };
111
112 Ok(next)
113 }
114
115 pub fn selected_partition(&mut self) -> Result<crate::partitions::AppPartitionSubType, Error> {
117 self.with_ota(|mut ota| ota.current_app_partition())
118 }
119
120 pub fn current_ota_state(&mut self) -> Result<OtaImageState, Error> {
125 self.with_ota(|mut ota| ota.current_ota_state())
126 }
127
128 pub fn set_current_ota_state(&mut self, state: OtaImageState) -> Result<(), Error> {
133 self.with_ota(|mut ota| ota.set_current_ota_state(state))
134 }
135
136 pub fn activate_next_partition(&mut self) -> Result<(), Error> {
143 let next_slot = self.next_ota_part()?;
144 self.with_ota(|mut ota| ota.set_current_app_partition(next_slot))
145 }
146
147 pub fn with_next_partition<R>(
152 &mut self,
153 f: impl FnOnce(FlashRegion<'_, F>, AppPartitionSubType) -> R,
154 ) -> Result<R, Error> {
155 let next_slot = self.next_ota_part()?;
156
157 if let Some(flash_region) = self
158 .pt
159 .find_partition(crate::partitions::PartitionType::App(next_slot))?
160 {
161 Ok(f(flash_region.as_embedded_storage(self.flash), next_slot))
162 } else {
163 Err(Error::Invalid)
164 }
165 }
166}