1#![no_std]
2#![no_main]
3
4use embassy_rp::bind_interrupts;
5use embassy_rp::peripherals::USB;
6use embassy_rp::usb::{Driver, InterruptHandler};
7use embassy_time::Timer;
8use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
9use embassy_usb::driver::EndpointError;
10use embassy_usb::{Builder, Config};
11use rp2040_hal::rom_data::reset_to_usb_boot;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
16 USBCTRL_IRQ => InterruptHandler<USB>;
17});
18
19#[embassy_executor::task]
20pub async fn init() {
21 let p = embassy_rp::init(Default::default());
23
24 let driver = Driver::new(p.USB, Irqs);
26
27 let mut config = Config::new(65535u16, 65535u16);
29 config.manufacturer = Some("Jaydar");
30 config.product = Some("RP2040 Debug");
31 config.serial_number = Some("RP2040");
32 config.max_power = 100;
33 config.max_packet_size_0 = 64;
34
35 config.device_class = 0xEF;
38 config.device_sub_class = 0x02;
39 config.device_protocol = 0x01;
40 config.composite_with_iads = true;
41
42 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256];
46 let mut control_buf = [0; 64];
47
48 let mut state = State::new();
49
50 let mut builder = Builder::new(
51 driver,
52 config,
53 &mut config_descriptor,
54 &mut bos_descriptor,
55 &mut [], &mut control_buf,
57 );
58
59 let class = CdcAcmClass::new(&mut builder, &mut state, 64);
61
62 let mut usb = builder.build();
64
65 let (mut usb_tx, mut usb_rx) = class.split();
67
68 let usb_fut = usb.run();
70
71 let usb_echo_fut = async {
73 let mut buf = [0; 64];
74 let mut message = [0; 128];
75 let mut idx = 0;
76
77 loop {
78 let n = match usb_rx.read_packet(&mut buf).await {
80 Ok(n) => n,
81 Err(EndpointError::Disabled) => break,
82 Err(_) => continue,
83 };
84
85 for &byte in &buf[..n] {
87 usb_tx.write_packet(&[byte]).await.ok();
88
89 if byte == b'\r' || byte == b'\n' {
91 if idx > 0 {
92 usb_tx.write_packet(b"\r\n").await.ok();
93
94 let is_boot = idx == 6
95 && message[0] == b'r'
96 && message[1] == b'e'
97 && message[2] == b'b'
98 && message[3] == b'o'
99 && message[4] == b'o'
100 && message[5] == b't';
101
102 let is_clear = idx == 5
103 && message[0] == b'c'
104 && message[1] == b'l'
105 && message[2] == b'e'
106 && message[3] == b'a'
107 && message[4] == b'r';
108
109 if is_boot {
110 usb_tx.write_packet(b"Booting\r\n").await.ok();
111 Timer::after_secs(1).await;
112 reset_to_usb_boot(0, 0)
113 } else if is_clear {
114 usb_tx.write_packet(b"\x1b[2J\x1b[H").await.ok();
115 } else {
116 usb_tx.write_packet(&message[..idx]).await.ok();
117 usb_tx.write_packet(b" Hi\r\n").await.ok();
118 }
119
120 idx = 0;
121 }
122 } else {
123 if idx < message.len() {
125 message[idx] = byte;
126 idx += 1;
127 }
128 }
129 }
130 }
131 };
132
133 embassy_futures::join::join(usb_fut, usb_echo_fut).await;
135}