pico_cdc/
lib.rs

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
14// 绑定中断处理程序
15bind_interrupts!(struct Irqs {
16    USBCTRL_IRQ => InterruptHandler<USB>;
17});
18
19#[embassy_executor::task]
20pub async fn init() {
21    // 初始化RP2040外围设备
22    let p = embassy_rp::init(Default::default());
23
24    // 从HAL创建USB驱动程序
25    let driver = Driver::new(p.USB, Irqs);
26
27    // 创建embassy-usb配置
28    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    // 为了兼容Windows,需要设置如下配置
36    // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
37    config.device_class = 0xEF;
38    config.device_sub_class = 0x02;
39    config.device_protocol = 0x01;
40    config.composite_with_iads = true;
41
42    // 使用驱动程序和配置创建embassy-usb DeviceBuilder
43    // 需要一些缓冲区来构建描述符
44    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 [], // 没有msos描述符
56        &mut control_buf,
57    );
58
59    // 在构建器上创建类
60    let class = CdcAcmClass::new(&mut builder, &mut state, 64);
61
62    // 构建USB设备
63    let mut usb = builder.build();
64
65    // 将CDC-ACM类分成独立的TX和RX端点
66    let (mut usb_tx, mut usb_rx) = class.split();
67
68    // 运行USB设备
69    let usb_fut = usb.run();
70
71    // 处理USB接收并回显数据的Future
72    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            // 读取接收到的数据
79            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            // 回显接收到的每个字节
86            for &byte in &buf[..n] {
87                usb_tx.write_packet(&[byte]).await.ok();
88
89                // 如果接收到换行符,则附加 "Hi"
90                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                    // 存储接收到的字符
124                    if idx < message.len() {
125                        message[idx] = byte;
126                        idx += 1;
127                    }
128                }
129            }
130        }
131    };
132
133    // 并发运行所有任务
134    embassy_futures::join::join(usb_fut, usb_echo_fut).await;
135}