esp_bootloader_esp_idf/
ota_updater.rs1use crate::{
4 ota::OtaImageState,
5 partitions::{AppPartitionSubType, Error, FlashRegion, FlashStorage, PartitionTable},
6};
7
8#[derive(Debug)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OtaUpdater<'a, 'd> {
14 flash: &'a mut FlashStorage<'d>,
15 pt: PartitionTable<'a>,
16 ota_count: usize,
17}
18
19impl<'a, 'd> OtaUpdater<'a, 'd> {
20 pub fn new(
25 flash: &'a mut FlashStorage<'d>,
26 buffer: &'a mut [u8; crate::partitions::PARTITION_TABLE_MAX_LEN],
27 ) -> Result<Self, Error> {
28 let pt = crate::partitions::read_partition_table(flash, buffer)?;
29
30 let mut ota_count = 0;
31 let mut has_ota_data = false;
32 for part in pt.iter() {
33 match part.partition_type() {
34 crate::partitions::PartitionType::App(subtype)
35 if subtype != crate::partitions::AppPartitionSubType::Factory
36 && subtype != crate::partitions::AppPartitionSubType::Test =>
37 {
38 ota_count += 1;
39 }
40 crate::partitions::PartitionType::Data(
41 crate::partitions::DataPartitionSubType::Ota,
42 ) => {
43 has_ota_data = true;
44 }
45 _ => {}
46 }
47 }
48
49 if !has_ota_data {
50 return Err(Error::Invalid);
51 }
52
53 if ota_count < 2 {
54 return Err(Error::Invalid);
55 }
56
57 Ok(Self {
58 flash,
59 pt,
60 ota_count,
61 })
62 }
63
64 pub fn ota_data(&mut self) -> Result<crate::ota::Ota<'_, 'd>, Error> {
69 let ota_part = self
70 .pt
71 .find_partition(crate::partitions::PartitionType::Data(
72 crate::partitions::DataPartitionSubType::Ota,
73 ))?;
74 if let Some(ota_part) = ota_part {
75 let ota_part = ota_part.as_flash_region(self.flash);
76 let ota = crate::ota::Ota::new(ota_part, self.ota_count)?;
77 Ok(ota)
78 } else {
79 Err(Error::Invalid)
80 }
81 }
82
83 fn next_ota_part(&mut self) -> Result<crate::partitions::AppPartitionSubType, Error> {
84 let current = self.selected_partition()?;
85 let next = match current {
86 AppPartitionSubType::Factory => AppPartitionSubType::Ota0,
87 _ => AppPartitionSubType::from_ota_app_number(
88 (current.ota_app_number() + 1) % self.ota_count as u8,
89 )?,
90 };
91
92 let booted = self.pt.booted_partition()?;
94 let next = if let Some(booted) = booted {
95 if booted.partition_type() == crate::partitions::PartitionType::App(next) {
96 AppPartitionSubType::from_ota_app_number(
97 (current.ota_app_number() + 2) % self.ota_count as u8,
98 )?
99 } else {
100 next
101 }
102 } else {
103 next
104 };
105
106 Ok(next)
107 }
108
109 pub fn selected_partition(&mut self) -> Result<crate::partitions::AppPartitionSubType, Error> {
111 self.ota_data()?.current_app_partition()
112 }
113
114 pub fn current_ota_state(&mut self) -> Result<OtaImageState, Error> {
119 self.ota_data()?.current_ota_state()
120 }
121
122 pub fn set_current_ota_state(&mut self, state: OtaImageState) -> Result<(), Error> {
127 self.ota_data()?.set_current_ota_state(state)
128 }
129
130 pub fn activate_next_partition(&mut self) -> Result<(), Error> {
135 let next_slot = self.next_ota_part()?;
136 self.ota_data()?.set_current_app_partition(next_slot)
137 }
138
139 pub fn next_partition(&mut self) -> Result<(FlashRegion<'_, 'd>, AppPartitionSubType), Error> {
142 let next_slot = self.next_ota_part()?;
143
144 let flash_region = self
145 .pt
146 .find_partition(crate::partitions::PartitionType::App(next_slot))?
147 .ok_or(Error::Invalid)?
148 .as_flash_region(self.flash);
149
150 Ok((flash_region, next_slot))
151 }
152
153 pub fn reset_data(&mut self) -> Result<(), Error> {
157 self.ota_data()?
161 .set_current_app_partition(AppPartitionSubType::Factory)
162 }
163}