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 crate::partitions::PartitionType::Data(
47 crate::partitions::DataPartitionSubType::Ota,
48 ) => {
49 has_ota_data = true;
50 }
51 _ => {}
52 }
53 }
54
55 if !has_ota_data {
56 return Err(Error::Invalid);
57 }
58
59 if ota_count < 2 {
60 return Err(Error::Invalid);
61 }
62
63 Ok(Self {
64 flash,
65 pt,
66 ota_count,
67 })
68 }
69
70 pub fn ota_data(&mut self) -> Result<crate::ota::Ota<'_, F>, 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 ota_part = ota_part.as_embedded_storage(self.flash);
82 let ota = crate::ota::Ota::new(ota_part, self.ota_count)?;
83 Ok(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.ota_data()?.current_app_partition()
118 }
119
120 pub fn current_ota_state(&mut self) -> Result<OtaImageState, Error> {
125 self.ota_data()?.current_ota_state()
126 }
127
128 pub fn set_current_ota_state(&mut self, state: OtaImageState) -> Result<(), Error> {
133 self.ota_data()?.set_current_ota_state(state)
134 }
135
136 pub fn activate_next_partition(&mut self) -> Result<(), Error> {
141 let next_slot = self.next_ota_part()?;
142 self.ota_data()?.set_current_app_partition(next_slot)
143 }
144
145 pub fn next_partition(&mut self) -> Result<(FlashRegion<'_, F>, AppPartitionSubType), Error> {
148 let next_slot = self.next_ota_part()?;
149
150 let flash_region = self
151 .pt
152 .find_partition(crate::partitions::PartitionType::App(next_slot))?
153 .ok_or(Error::Invalid)?
154 .as_embedded_storage(self.flash);
155
156 Ok((flash_region, next_slot))
157 }
158}