stm32builder/types/
device_id.rs1use crate::{
4 api::Error,
5 types::{FlashSize, Package, TemperatureRange},
6};
7use serde::ser::{Serialize, Serializer};
8
9#[derive(Debug, Clone, PartialEq)]
21pub struct DeviceId {
22 pub id: String,
23 pub package: Package,
24 pub flash_size: FlashSize,
25 pub temperature: TemperatureRange,
26}
27
28impl Serialize for DeviceId {
29 fn serialize<S>(&self, serialize: S) -> Result<S::Ok, S::Error>
31 where
32 S: Serializer,
33 {
34 serialize.serialize_str(&self.id)
35 }
36}
37
38macro_rules! decode {
42 ( $method:ident (on $pos:tt position) as $function:ident ) => {
43 decode!($method (from $pos to $pos characters) as $function);
44 };
45 ( $method:ident (from $start:tt to $end:tt characters) as $function:ident ) => {
46 pub fn $method(&self) -> &str {
47 Self::$function(&self.id).unwrap()
48 }
49 fn $function(id: &str) -> Option<&str> {
50 id.get($start..=$end)
51 }
52 };
53}
54
55impl DeviceId {
56 const BRAND: &'static str = "stm32";
57
58 decode!( header (from 0 to 4 characters) as header_from_str );
60 decode!( family (on 5 position) as family_from_str );
61 decode!( sub_family (from 6 to 8 characters) as sub_family_from_str );
62 decode!( name (from 0 to 8 characters) as name_from_str );
63 decode!( part (from 9 to 10 characters) as part_from_str );
64 decode!( pin_count (on 9 position) as pin_count_from_str );
65 decode!( flash_size (on 10 position) as flash_size_from_str );
66 decode!( package_type (on 11 position) as package_type_from_str );
67 decode!( temperature_range (on 12 position) as temperature_range_from_str );
68
69 pub fn from_str(id: &str) -> Result<Self, Error> {
79 let is_ascii_digit = |c: u8| c.is_ascii_digit();
80 let is_ascii_alphabetic = |c: u8| c.is_ascii_alphabetic();
81
82 if Self::header_from_str(id).ok_or(Error::NoBrand)? != Self::BRAND {
83 return Err(Error::BadBrand);
84 }
85 if !Self::family_from_str(id)
86 .ok_or(Error::NoFamily)?
87 .bytes()
88 .all(is_ascii_alphabetic)
89 {
90 return Err(Error::BadFamily);
91 }
92 if !Self::sub_family_from_str(id)
93 .ok_or(Error::NoSubFamily)?
94 .bytes()
95 .all(is_ascii_digit)
96 {
97 return Err(Error::BadSubFamily);
98 }
99 let pin_count = Self::pin_count_from_str(id).ok_or(Error::NoPinCount)?;
100 if !pin_count.bytes().all(is_ascii_alphabetic) {
101 return Err(Error::BadPinCount);
102 }
103 let pin_count = pin_count.to_ascii_uppercase();
104 let flash_size = Self::flash_size_from_str(id).ok_or(Error::NoFlashSize)?;
105 if !flash_size.bytes().all(is_ascii_digit) {
106 return Err(Error::BadFlashSize);
107 }
108 let package_type = Self::package_type_from_str(id).ok_or(Error::NoPackageType)?;
109 if !package_type.bytes().all(is_ascii_alphabetic) {
110 return Err(Error::BadPackageType);
111 }
112 let package_type = package_type.to_ascii_uppercase();
113 let temperature_range =
114 Self::temperature_range_from_str(id).ok_or(Error::NoTemperatureRange)?;
115 if !temperature_range.bytes().all(is_ascii_digit) {
116 return Err(Error::BadTemperatureRange);
117 }
118
119 let mut new_id = String::new();
120 new_id.push_str(Self::header_from_str(id).unwrap());
121 new_id.push_str(Self::family_from_str(id).unwrap());
122 new_id.push_str(Self::sub_family_from_str(id).unwrap());
123 new_id.push_str(&pin_count);
124 new_id.push_str(&flash_size);
125 new_id.push_str(&package_type);
126 new_id.push_str(&temperature_range);
127 Ok(DeviceId {
128 id: new_id,
129 package: Package::from_pin_and_package_str(&pin_count, &package_type)?,
130 flash_size: FlashSize::from_flash_size_str(flash_size)?,
131 temperature: TemperatureRange::from_temperature_range_str(temperature_range)?,
132 })
133 }
134
135 pub fn datasheet_url(&self) -> String {
136 format!(
137 "https://www.st.com/resource/en/datasheet/{}{}.pdf",
138 self.name(),
139 self.part()
140 )
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 #[allow(non_snake_case)]
150 fn decoding_stm32f051R8T6() {
151 let id = DeviceId::from_str("stm32f051R8T6").unwrap();
152
153 assert_eq!(id.header(), "stm32");
154 assert_eq!(id.name(), "stm32f051");
155 assert_eq!(id.family(), "f");
156 assert_eq!(id.sub_family(), "051");
157 assert_eq!(id.part(), "R8");
158 assert_eq!(id.pin_count(), "R");
159 assert_eq!(id.flash_size(), "8");
160 assert_eq!(id.package_type(), "T");
161 assert_eq!(id.temperature_range(), "6");
162 assert_eq!(id.package, Package::LQFP64);
163 assert_eq!(id.flash_size, FlashSize(64));
164 assert_eq!(id.temperature.min, -40);
165 assert_eq!(id.temperature.max, 85);
166 }
167
168 macro_rules! decoding_fail {
172 ( $str:tt $error:ident $name:ident) => {
173 #[test]
174 pub fn $name() {
175 match DeviceId::from_str($str).err().unwrap() {
176 Error::$error => {}
177 _ => assert!(false, "expected {} error", stringify!($error)),
178 }
179 }
180 };
181 ( $str:tt $error:ident($with:tt) $name:ident ) => {
182 #[test]
183 pub fn $name() {
184 match DeviceId::from_str($str).err().unwrap() {
185 Error::$error(value) => assert_eq!(value, $with.to_string()),
186 _ => assert!(false, "expected {} error", stringify!($error)),
187 }
188 }
189 };
190 }
191 decoding_fail!( "" NoBrand error_on_empty_str );
192 decoding_fail!( "stm" NoBrand error_on_incomplet_brand ); decoding_fail!( "st_32f051R8T6" BadBrand error_on_invalid_brand );
194 decoding_fail!( "stm32" NoFamily error_without_family );
195 decoding_fail!( "stm32_051R8T6" BadFamily error_on_digit_family );
196 decoding_fail!( "stm32f" NoSubFamily error_without_sub_family );
197 decoding_fail!( "stm32f_51R8T6" BadSubFamily error_on_alphabetical_sub_family );
198 decoding_fail!( "stm32f051" NoPinCount error_without_pin_count );
199 decoding_fail!( "stm32f05108T6" BadPinCount error_on_digit_pin_count );
200 decoding_fail!( "stm32f051O8T6" UnknownPinCount("O") error_on_unknown_pin_count );
201 decoding_fail!( "stm32f051R" NoFlashSize error_without_flash_size );
202 decoding_fail!( "stm32f051RAT6" BadFlashSize error_on_alphabetical_flash_size );
203 decoding_fail!( "stm32f051R0T6" UnknownFlashSize("0") error_on_unknown_flash_size );
204 decoding_fail!( "stm32f051R8" NoPackageType error_without_package_type );
205 decoding_fail!( "stm32f051R886" BadPackageType error_on_digit_package_type );
206 decoding_fail!( "stm32f051R8O6" UnknownPackageType("O") error_on_unknown_package_type );
207 decoding_fail!( "stm32f051R8T" NoTemperatureRange error_without_temperature_range );
208 decoding_fail!( "stm32f051R8TT" BadTemperatureRange error_on_alphabetic_temperature_range );
209 decoding_fail!( "stm32f051R8T0" UnknownTemperatureRange("0") error_on_unknown_temperature_range );
210
211 #[test]
212 fn can_be_compared_against() {
213 assert_eq!(
214 DeviceId::from_str("stm32f051R8T6").unwrap(),
215 DeviceId::from_str("stm32f051R8T6").unwrap()
216 );
217 }
218}