diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-09-05 15:29:20 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-05 15:29:20 +0200 |
| commit | 704c2941621d1541519c54859acd0f3001039f31 (patch) | |
| tree | df888264f127db68ac53a42c2917c299d77fe63a /examples | |
| parent | a548d7efe3ad963b95183d92c2841fde744cc373 (diff) | |
| parent | f6414d8cd22d18eb1adc5dfa2780bc94a150be30 (diff) | |
Merge branch 'main' into adc_with_clock
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf-rtos-trace/Cargo.toml | 4 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/nfct.rs | 274 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/sai.rs | 52 | ||||
| -rw-r--r-- | examples/stm32l0/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/usb_serial.rs | 95 |
5 files changed, 410 insertions, 17 deletions
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index a2dc0c7ad..c9eeaaac7 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml | |||
| @@ -25,8 +25,8 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 25 | cortex-m-rt = "0.7.0" | 25 | cortex-m-rt = "0.7.0" |
| 26 | panic-probe = "1.0.0" | 26 | panic-probe = "1.0.0" |
| 27 | serde = { version = "1.0.136", default-features = false } | 27 | serde = { version = "1.0.136", default-features = false } |
| 28 | rtos-trace = "0.1.3" | 28 | rtos-trace = "0.2" |
| 29 | systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] } | 29 | systemview-target = { version = "0.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] } |
| 30 | log = { version = "0.4.17", optional = true } | 30 | log = { version = "0.4.17", optional = true } |
| 31 | 31 | ||
| 32 | [[bin]] | 32 | [[bin]] |
diff --git a/examples/nrf52840/src/bin/nfct.rs b/examples/nrf52840/src/bin/nfct.rs index d559d006a..fafa37f48 100644 --- a/examples/nrf52840/src/bin/nfct.rs +++ b/examples/nrf52840/src/bin/nfct.rs | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::{todo, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::config::HfclkSource; | 6 | use embassy_nrf::config::HfclkSource; |
| 7 | use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; | 7 | use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; |
| 8 | use embassy_nrf::{bind_interrupts, nfct}; | 8 | use embassy_nrf::{bind_interrupts, nfct}; |
| 9 | use iso14443_4::{Card, IsoDep}; | ||
| 9 | use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; | 10 | use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | bind_interrupts!(struct Irqs { | 12 | bind_interrupts!(struct Irqs { |
| @@ -30,12 +31,28 @@ async fn main(_spawner: Spawner) { | |||
| 30 | 31 | ||
| 31 | let mut buf = [0u8; 256]; | 32 | let mut buf = [0u8; 256]; |
| 32 | 33 | ||
| 34 | let cc = &[ | ||
| 35 | 0x00, 0x0f, /* CCEN_HI, CCEN_LOW */ | ||
| 36 | 0x20, /* VERSION */ | ||
| 37 | 0x00, 0x7f, /* MLe_HI, MLe_LOW */ | ||
| 38 | 0x00, 0x7f, /* MLc_HI, MLc_LOW */ | ||
| 39 | /* TLV */ | ||
| 40 | 0x04, 0x06, 0xe1, 0x04, 0x00, 0x7f, 0x00, 0x00, | ||
| 41 | ]; | ||
| 42 | |||
| 43 | let ndef = &[ | ||
| 44 | 0x00, 0x10, 0xd1, 0x1, 0xc, 0x55, 0x4, 0x65, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x79, 0x2e, 0x64, 0x65, 0x76, | ||
| 45 | ]; | ||
| 46 | let mut selected: &[u8] = cc; | ||
| 47 | |||
| 33 | loop { | 48 | loop { |
| 34 | info!("activating"); | 49 | info!("activating"); |
| 35 | nfc.activate().await; | 50 | nfc.activate().await; |
| 51 | info!("activated!"); | ||
| 52 | |||
| 53 | let mut nfc = IsoDep::new(iso14443_3::Logger(&mut nfc)); | ||
| 36 | 54 | ||
| 37 | loop { | 55 | loop { |
| 38 | info!("rxing"); | ||
| 39 | let n = match nfc.receive(&mut buf).await { | 56 | let n = match nfc.receive(&mut buf).await { |
| 40 | Ok(n) => n, | 57 | Ok(n) => n, |
| 41 | Err(e) => { | 58 | Err(e) => { |
| @@ -44,25 +61,51 @@ async fn main(_spawner: Spawner) { | |||
| 44 | } | 61 | } |
| 45 | }; | 62 | }; |
| 46 | let req = &buf[..n]; | 63 | let req = &buf[..n]; |
| 47 | info!("received frame {:02x}", req); | 64 | info!("iso-dep rx {:02x}", req); |
| 48 | 65 | ||
| 49 | let mut deselect = false; | 66 | let Ok(apdu) = Apdu::parse(req) else { |
| 50 | let resp = match req { | 67 | error!("apdu parse error"); |
| 51 | [0xe0, ..] => { | 68 | break; |
| 52 | info!("Got RATS, tx'ing ATS"); | 69 | }; |
| 53 | &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80][..] | 70 | |
| 71 | info!("apdu: {:?}", apdu); | ||
| 72 | |||
| 73 | let resp = match (apdu.cla, apdu.ins, apdu.p1, apdu.p2) { | ||
| 74 | (0, 0xa4, 4, 0) => { | ||
| 75 | info!("select app"); | ||
| 76 | &[0x90, 0x00][..] | ||
| 54 | } | 77 | } |
| 55 | [0xc2] => { | 78 | (0, 0xa4, 0, 12) => { |
| 56 | info!("Got deselect!"); | 79 | info!("select df"); |
| 57 | deselect = true; | 80 | match apdu.data { |
| 58 | &[0xc2] | 81 | [0xe1, 0x03] => { |
| 82 | selected = cc; | ||
| 83 | &[0x90, 0x00][..] | ||
| 84 | } | ||
| 85 | [0xe1, 0x04] => { | ||
| 86 | selected = ndef; | ||
| 87 | &[0x90, 0x00][..] | ||
| 88 | } | ||
| 89 | _ => todo!(), // return NOT FOUND | ||
| 90 | } | ||
| 91 | } | ||
| 92 | (0, 0xb0, p1, p2) => { | ||
| 93 | info!("read"); | ||
| 94 | let offs = u16::from_be_bytes([p1 & 0x7f, p2]) as usize; | ||
| 95 | let len = if apdu.le == 0 { usize::MAX } else { apdu.le as usize }; | ||
| 96 | let n = len.min(selected.len() - offs); | ||
| 97 | buf[..n].copy_from_slice(&selected[offs..][..n]); | ||
| 98 | buf[n..][..2].copy_from_slice(&[0x90, 0x00]); | ||
| 99 | &buf[..n + 2] | ||
| 59 | } | 100 | } |
| 60 | _ => { | 101 | _ => { |
| 61 | info!("Got unknown command!"); | 102 | info!("Got unknown command!"); |
| 62 | &[0xFF] | 103 | &[0xFF, 0xFF] |
| 63 | } | 104 | } |
| 64 | }; | 105 | }; |
| 65 | 106 | ||
| 107 | info!("iso-dep tx {:02x}", resp); | ||
| 108 | |||
| 66 | match nfc.transmit(resp).await { | 109 | match nfc.transmit(resp).await { |
| 67 | Ok(()) => {} | 110 | Ok(()) => {} |
| 68 | Err(e) => { | 111 | Err(e) => { |
| @@ -70,10 +113,211 @@ async fn main(_spawner: Spawner) { | |||
| 70 | break; | 113 | break; |
| 71 | } | 114 | } |
| 72 | } | 115 | } |
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 73 | 119 | ||
| 74 | if deselect { | 120 | #[derive(Debug, Clone, defmt::Format)] |
| 75 | break; | 121 | struct Apdu<'a> { |
| 122 | pub cla: u8, | ||
| 123 | pub ins: u8, | ||
| 124 | pub p1: u8, | ||
| 125 | pub p2: u8, | ||
| 126 | pub data: &'a [u8], | ||
| 127 | pub le: u16, | ||
| 128 | } | ||
| 129 | |||
| 130 | #[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)] | ||
| 131 | struct ApduParseError; | ||
| 132 | |||
| 133 | impl<'a> Apdu<'a> { | ||
| 134 | pub fn parse(apdu: &'a [u8]) -> Result<Self, ApduParseError> { | ||
| 135 | if apdu.len() < 4 { | ||
| 136 | return Err(ApduParseError); | ||
| 137 | } | ||
| 138 | |||
| 139 | let (data, le) = match apdu.len() - 4 { | ||
| 140 | 0 => (&[][..], 0), | ||
| 141 | 1 => (&[][..], apdu[4]), | ||
| 142 | n if n == 1 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], 0), | ||
| 143 | n if n == 2 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], apdu[apdu.len() - 1]), | ||
| 144 | _ => return Err(ApduParseError), | ||
| 145 | }; | ||
| 146 | |||
| 147 | Ok(Apdu { | ||
| 148 | cla: apdu[0], | ||
| 149 | ins: apdu[1], | ||
| 150 | p1: apdu[2], | ||
| 151 | p2: apdu[3], | ||
| 152 | data, | ||
| 153 | le: le as _, | ||
| 154 | }) | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | mod iso14443_3 { | ||
| 159 | use core::future::Future; | ||
| 160 | |||
| 161 | use defmt::info; | ||
| 162 | use embassy_nrf::nfct::{Error, NfcT}; | ||
| 163 | |||
| 164 | pub trait Card { | ||
| 165 | type Error; | ||
| 166 | async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>; | ||
| 167 | async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>; | ||
| 168 | } | ||
| 169 | |||
| 170 | impl<'a, T: Card> Card for &'a mut T { | ||
| 171 | type Error = T::Error; | ||
| 172 | |||
| 173 | fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> { | ||
| 174 | T::receive(self, buf) | ||
| 175 | } | ||
| 176 | |||
| 177 | fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> { | ||
| 178 | T::transmit(self, buf) | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | impl<'a> Card for NfcT<'a> { | ||
| 183 | type Error = Error; | ||
| 184 | |||
| 185 | fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> { | ||
| 186 | self.receive(buf) | ||
| 187 | } | ||
| 188 | |||
| 189 | fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> { | ||
| 190 | self.transmit(buf) | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | pub struct Logger<T: Card>(pub T); | ||
| 195 | |||
| 196 | impl<T: Card> Card for Logger<T> { | ||
| 197 | type Error = T::Error; | ||
| 198 | |||
| 199 | async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | ||
| 200 | let n = T::receive(&mut self.0, buf).await?; | ||
| 201 | info!("<- {:02x}", &buf[..n]); | ||
| 202 | Ok(n) | ||
| 203 | } | ||
| 204 | |||
| 205 | fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> { | ||
| 206 | info!("-> {:02x}", buf); | ||
| 207 | T::transmit(&mut self.0, buf) | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | mod iso14443_4 { | ||
| 213 | use defmt::info; | ||
| 214 | |||
| 215 | use crate::iso14443_3; | ||
| 216 | |||
| 217 | #[derive(defmt::Format)] | ||
| 218 | pub enum Error<T> { | ||
| 219 | Deselected, | ||
| 220 | Protocol, | ||
| 221 | Lower(T), | ||
| 222 | } | ||
| 223 | |||
| 224 | pub trait Card { | ||
| 225 | type Error; | ||
| 226 | async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>; | ||
| 227 | async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>; | ||
| 228 | } | ||
| 229 | |||
| 230 | pub struct IsoDep<T: iso14443_3::Card> { | ||
| 231 | nfc: T, | ||
| 232 | |||
| 233 | /// Block count spin bit: 0 or 1 | ||
| 234 | block_num: u8, | ||
| 235 | |||
| 236 | /// true if deselected. This is permanent, you must create another IsoDep | ||
| 237 | /// instance if we get selected again. | ||
| 238 | deselected: bool, | ||
| 239 | |||
| 240 | /// last response, in case we need to retransmit. | ||
| 241 | resp: [u8; 256], | ||
| 242 | resp_len: usize, | ||
| 243 | } | ||
| 244 | |||
| 245 | impl<T: iso14443_3::Card> IsoDep<T> { | ||
| 246 | pub fn new(nfc: T) -> Self { | ||
| 247 | Self { | ||
| 248 | nfc, | ||
| 249 | block_num: 1, | ||
| 250 | deselected: false, | ||
| 251 | resp: [0u8; 256], | ||
| 252 | resp_len: 0, | ||
| 76 | } | 253 | } |
| 77 | } | 254 | } |
| 78 | } | 255 | } |
| 256 | |||
| 257 | impl<T: iso14443_3::Card> Card for IsoDep<T> { | ||
| 258 | type Error = Error<T::Error>; | ||
| 259 | |||
| 260 | async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | ||
| 261 | if self.deselected { | ||
| 262 | return Err(Error::Deselected); | ||
| 263 | } | ||
| 264 | |||
| 265 | let mut temp = [0u8; 256]; | ||
| 266 | |||
| 267 | loop { | ||
| 268 | let n = self.nfc.receive(&mut temp).await.map_err(Error::Lower)?; | ||
| 269 | assert!(n != 0); | ||
| 270 | match temp[0] { | ||
| 271 | 0x02 | 0x03 => { | ||
| 272 | self.block_num ^= 0x01; | ||
| 273 | assert!(temp[0] == 0x02 | self.block_num); | ||
| 274 | buf[..n - 1].copy_from_slice(&temp[1..n]); | ||
| 275 | return Ok(n - 1); | ||
| 276 | } | ||
| 277 | 0xb2 | 0xb3 => { | ||
| 278 | if temp[0] & 0x01 != self.block_num { | ||
| 279 | info!("Got NAK, transmitting ACK."); | ||
| 280 | let resp = &[0xA2 | self.block_num]; | ||
| 281 | self.nfc.transmit(resp).await.map_err(Error::Lower)?; | ||
| 282 | } else { | ||
| 283 | info!("Got NAK, retransmitting."); | ||
| 284 | let resp: &[u8] = &self.resp[..self.resp_len]; | ||
| 285 | self.nfc.transmit(resp).await.map_err(Error::Lower)?; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | 0xe0 => { | ||
| 289 | info!("Got RATS, tx'ing ATS"); | ||
| 290 | let resp = &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80]; | ||
| 291 | self.nfc.transmit(resp).await.map_err(Error::Lower)?; | ||
| 292 | } | ||
| 293 | 0xc2 => { | ||
| 294 | info!("Got deselect!"); | ||
| 295 | self.deselected = true; | ||
| 296 | let resp = &[0xC2]; | ||
| 297 | self.nfc.transmit(resp).await.map_err(Error::Lower)?; | ||
| 298 | return Err(Error::Deselected); | ||
| 299 | } | ||
| 300 | _ => { | ||
| 301 | info!("Got unknown command {:02x}!", temp[0]); | ||
| 302 | return Err(Error::Protocol); | ||
| 303 | } | ||
| 304 | }; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error> { | ||
| 309 | if self.deselected { | ||
| 310 | return Err(Error::Deselected); | ||
| 311 | } | ||
| 312 | |||
| 313 | self.resp[0] = 0x02 | self.block_num; | ||
| 314 | self.resp[1..][..buf.len()].copy_from_slice(buf); | ||
| 315 | self.resp_len = 1 + buf.len(); | ||
| 316 | |||
| 317 | let resp: &[u8] = &self.resp[..self.resp_len]; | ||
| 318 | self.nfc.transmit(resp).await.map_err(Error::Lower)?; | ||
| 319 | |||
| 320 | Ok(()) | ||
| 321 | } | ||
| 322 | } | ||
| 79 | } | 323 | } |
diff --git a/examples/stm32h5/src/bin/sai.rs b/examples/stm32h5/src/bin/sai.rs new file mode 100644 index 000000000..0e182f9cf --- /dev/null +++ b/examples/stm32h5/src/bin/sai.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::{sai, Config}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | info!("Hello world."); | ||
| 12 | |||
| 13 | let mut config = Config::default(); | ||
| 14 | { | ||
| 15 | use embassy_stm32::rcc::*; | ||
| 16 | |||
| 17 | config.rcc.pll2 = Some(Pll { | ||
| 18 | source: PllSource::HSI, | ||
| 19 | prediv: PllPreDiv::DIV16, | ||
| 20 | mul: PllMul::MUL32, | ||
| 21 | divp: Some(PllDiv::DIV16), // 8 MHz SAI clock | ||
| 22 | divq: None, | ||
| 23 | divr: None, | ||
| 24 | }); | ||
| 25 | |||
| 26 | config.rcc.mux.sai1sel = mux::Saisel::PLL2_P; | ||
| 27 | } | ||
| 28 | let p = embassy_stm32::init(config); | ||
| 29 | |||
| 30 | let mut write_buffer = [0u16; 1024]; | ||
| 31 | let (_, sai_b) = sai::split_subblocks(p.SAI1); | ||
| 32 | |||
| 33 | let mut sai_b = sai::Sai::new_asynchronous( | ||
| 34 | sai_b, | ||
| 35 | p.PF8, | ||
| 36 | p.PE3, | ||
| 37 | p.PF9, | ||
| 38 | p.GPDMA1_CH0, | ||
| 39 | &mut write_buffer, | ||
| 40 | Default::default(), | ||
| 41 | ); | ||
| 42 | |||
| 43 | // Populate arbitrary data. | ||
| 44 | let mut data = [0u16; 256]; | ||
| 45 | for (index, sample) in data.iter_mut().enumerate() { | ||
| 46 | *sample = index as u16; | ||
| 47 | } | ||
| 48 | |||
| 49 | loop { | ||
| 50 | sai_b.write(&data).await.unwrap(); | ||
| 51 | } | ||
| 52 | } | ||
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 90f57a2d8..d42cdac15 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -11,6 +11,8 @@ embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [" | |||
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | ||
| 15 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | ||
| 14 | 16 | ||
| 15 | defmt = "1.0.1" | 17 | defmt = "1.0.1" |
| 16 | defmt-rtt = "1.0.0" | 18 | defmt-rtt = "1.0.0" |
diff --git a/examples/stm32l0/src/bin/usb_serial.rs b/examples/stm32l0/src/bin/usb_serial.rs new file mode 100644 index 000000000..fdb1aeb59 --- /dev/null +++ b/examples/stm32l0/src/bin/usb_serial.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{panic, *}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_futures::join::join; | ||
| 7 | use embassy_stm32::usb::{self, Driver, Instance}; | ||
| 8 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 10 | use embassy_usb::driver::EndpointError; | ||
| 11 | use embassy_usb::Builder; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | USB => usb::InterruptHandler<peripherals::USB>; | ||
| 16 | }); | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) { | ||
| 20 | let mut config = embassy_stm32::Config::default(); | ||
| 21 | { | ||
| 22 | use embassy_stm32::rcc::*; | ||
| 23 | config.rcc.hsi = true; | ||
| 24 | config.rcc.pll = Some(Pll { | ||
| 25 | source: PllSource::HSI, | ||
| 26 | mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz | ||
| 27 | div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) | ||
| 28 | }); | ||
| 29 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 30 | } | ||
| 31 | |||
| 32 | let p = embassy_stm32::init(config); | ||
| 33 | |||
| 34 | info!("Hello World!"); | ||
| 35 | |||
| 36 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||
| 37 | |||
| 38 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 39 | config.manufacturer = Some("Embassy"); | ||
| 40 | config.product = Some("USB-Serial Example"); | ||
| 41 | config.serial_number = Some("123456"); | ||
| 42 | |||
| 43 | let mut config_descriptor = [0; 256]; | ||
| 44 | let mut bos_descriptor = [0; 256]; | ||
| 45 | let mut control_buf = [0; 64]; | ||
| 46 | |||
| 47 | let mut state = State::new(); | ||
| 48 | |||
| 49 | let mut builder = Builder::new( | ||
| 50 | driver, | ||
| 51 | config, | ||
| 52 | &mut config_descriptor, | ||
| 53 | &mut bos_descriptor, | ||
| 54 | &mut [], // no msos descriptors | ||
| 55 | &mut control_buf, | ||
| 56 | ); | ||
| 57 | |||
| 58 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||
| 59 | |||
| 60 | let mut usb = builder.build(); | ||
| 61 | |||
| 62 | let usb_fut = usb.run(); | ||
| 63 | |||
| 64 | let echo_fut = async { | ||
| 65 | loop { | ||
| 66 | class.wait_connection().await; | ||
| 67 | info!("Connected"); | ||
| 68 | let _ = echo(&mut class).await; | ||
| 69 | info!("Disconnected"); | ||
| 70 | } | ||
| 71 | }; | ||
| 72 | |||
| 73 | join(usb_fut, echo_fut).await; | ||
| 74 | } | ||
| 75 | |||
| 76 | struct Disconnected {} | ||
| 77 | |||
| 78 | impl From<EndpointError> for Disconnected { | ||
| 79 | fn from(val: EndpointError) -> Self { | ||
| 80 | match val { | ||
| 81 | EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||
| 82 | EndpointError::Disabled => Disconnected {}, | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||
| 88 | let mut buf = [0; 64]; | ||
| 89 | loop { | ||
| 90 | let n = class.read_packet(&mut buf).await?; | ||
| 91 | let data = &buf[..n]; | ||
| 92 | info!("data: {:x}", data); | ||
| 93 | class.write_packet(data).await?; | ||
| 94 | } | ||
| 95 | } | ||
