1#![no_std]
18
19pub mod arm;
20pub mod rp;
21pub mod stm;
22
23extern crate alloc;
24use core::fmt;
25use core::ops::RangeInclusive;
26use static_assertions::const_assert;
27
28use crate::arm::ap::Idr;
29use crate::arm::dp::IdCode;
30
31#[derive(Debug, Clone, Copy)]
36pub enum Mcu {
37 Stm32(stm::StmDetails),
39
40 Rp(rp::RpDetails),
42
43 Unknown(IdCode),
45}
46
47impl Mcu {
48 pub fn flash_base(&self) -> Option<u32> {
50 match self {
51 Mcu::Stm32(details) => details.flash_base(),
52 Mcu::Rp(details) => details.flash_base(),
53 Mcu::Unknown(_) => None,
54 }
55 }
56
57 pub fn ram_base(&self) -> Option<u32> {
59 match self {
60 Mcu::Stm32(details) => details.ram_base(),
61 Mcu::Rp(details) => details.ram_base(),
62 Mcu::Unknown(_) => None,
63 }
64 }
65
66 pub fn flash_size_bytes(&self) -> Option<u32> {
68 self.flash_size_kb().map(|size| size * 1024)
69 }
70
71 pub fn flash_size_kb(&self) -> Option<u32> {
73 match self {
74 Mcu::Stm32(details) => details.flash_size_kb().map(|size| size.raw() as u32),
75 Mcu::Rp(_) => None,
76 Mcu::Unknown(_) => None,
77 }
78 }
79
80 pub fn ram_size_bytes(&self) -> Option<u32> {
82 self.ram_size_kb().map(|size| size * 1024)
83 }
84
85 pub fn ram_size_kb(&self) -> Option<u32> {
87 match self {
88 Mcu::Stm32(details) => details.mcu().line().ram_size_kb(),
89 Mcu::Rp(details) => details.line().ram_size_kb(),
90 Mcu::Unknown(_) => None,
91 }
92 }
93
94 pub fn is_stm32(&self) -> bool {
96 matches!(self, Mcu::Stm32(_))
97 }
98
99 pub fn is_stm32f4(&self) -> bool {
101 match self {
102 Mcu::Stm32(stm) => stm.is_stm32f4(),
103 Mcu::Rp(_) => false,
104 Mcu::Unknown(_) => false,
105 }
106 }
107
108 pub fn is_rp(&self) -> bool {
110 matches!(self, Mcu::Rp(_))
111 }
112
113 pub fn get_sector_size_bytes(&self, sector: u8) -> Option<u32> {
115 match self {
116 Mcu::Stm32(details) => details.get_sector_size_bytes(sector),
117 Mcu::Rp(_) => None,
118 Mcu::Unknown(_) => None,
119 }
120 }
121
122 pub fn get_sector_size_words(&self, sector: u8) -> Option<u32> {
124 self.get_sector_size_bytes(sector).map(|size| size / 4)
125 }
126
127 pub fn get_sector_size_kb(&self, sector: u8) -> Option<u32> {
129 self.get_sector_size_bytes(sector).map(|size| size / 1024)
130 }
131
132 pub const MAX_SECTORS: u8 = 12;
134
135 pub fn get_sectors_from_word_range(
139 &self,
140 range: RangeInclusive<u32>,
141 sectors: &mut [u8; Self::MAX_SECTORS as usize],
142 ) -> Option<usize> {
143 const_assert!(Mcu::MAX_SECTORS <= stm::StmDetails::MAX_SECTORS);
144 match self {
145 Mcu::Stm32(details) => details.get_sectors_from_word_range(range, sectors),
146 Mcu::Rp(_) => None,
147 Mcu::Unknown(_) => None,
148 }
149 }
150
151 pub fn expected_idr(&self) -> Option<Idr> {
154 match self {
155 Mcu::Stm32(details) => details.expected_idr(),
156 Mcu::Rp(details) => details.expected_idr(),
157 Mcu::Unknown(_) => None,
158 }
159 }
160}
161
162impl fmt::Display for Mcu {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 Mcu::Stm32(details) => {
166 if f.alternate() {
167 write!(f, "STM32 MCU: {details:#}")
168 } else {
169 write!(f, "{details}")
170 }
171 }
172 Mcu::Rp(details) => {
173 if f.alternate() {
174 write!(f, "RP MCU: {details:#}")
175 } else {
176 write!(f, "{details}")
177 }
178 }
179 Mcu::Unknown(idcode) => {
180 if f.alternate() {
181 write!(f, "Unknown MCU (IDCODE: {idcode:#})")
182 } else {
183 write!(f, "Unknown MCU (IDCODE: {idcode})")
184 }
185 }
186 }
187 }
188}