#driver #channel #async-networking #embassy-net #high-level #packet

无需std embassy-net-driver-channel

embassy-net异步TCP/IP网络栈提供基于通道的高级驱动程序

4个版本 (破坏性)

0.3.0 2024年8月5日
0.2.0 2023年10月18日
0.1.0 2023年6月29日
0.0.0 2023年1月3日

676嵌入式开发

Download history 1233/week @ 2024-04-29 1002/week @ 2024-05-06 1306/week @ 2024-05-13 2230/week @ 2024-05-20 2069/week @ 2024-05-27 1248/week @ 2024-06-03 1130/week @ 2024-06-10 975/week @ 2024-06-17 1569/week @ 2024-06-24 1461/week @ 2024-07-01 1084/week @ 2024-07-08 2207/week @ 2024-07-15 1578/week @ 2024-07-22 1440/week @ 2024-07-29 1837/week @ 2024-08-05 1979/week @ 2024-08-12

每月7,055次下载
用于 20 个crate(6个直接使用)

MIT/Apache

255KB
5.5K SLoC

embassy-net-driver-channel

该crate提供了一组工具,用于以比直接实现embassy-net-driver特质更高级的方式实现embassy-net驱动程序。

embassy-net-driver特质是基于轮询的。要实现它,你必须手动编写数据包接收/发送状态机,并将embassy-net提供的Waker连接到正确的中断处理程序,以便embassy-net知道何时再次轮询你的驱动程序以取得更多进展。

使用embassy-net-driver-channel,你将获得一个“通道式”接口,你可以将数据包从embassy-net发送到/接收自embassy-net。预期的使用方式是在后台启动一个“驱动程序任务”,该任务执行此操作,在硬件和通道之间传递数据包。

关于死锁的说明

当使用此crate实现驱动程序时,可能会诱使你以最直接的方式编写它

loop {
    // Wait for either..
    match select(
        // ... the chip signaling an interrupt, indicating a packet is available to receive, or
        irq_pin.wait_for_low(),
        // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
        tx_chan.tx_buf(),
    ).await {
        Either::First(_) => {
            // a packet is ready to be received!
            let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
            let n = receive_packet_over_spi(buf).await;
            rx_chan.rx_done(n);
        }
        Either::Second(buf) => {
            // a packet is ready to be sent!
            send_packet_over_spi(buf).await;
            tx_chan.tx_done();
        }
    }
}

然而,这段代码存在潜在的死锁错误。症状是它在负载下可能会在rx_chan.rx_buf().await处挂起。

原因是在负载下,TX和RX队列可能会同时满。当这种情况发生时,由于TX队列已满,embassy-net任务会暂停尝试发送,因此它停止处理RX队列中的数据包。由于RX队列已满,你的驱动程序任务也会暂停,因此它停止处理TX队列中的数据包。

修复方法是确保在等待RX队列中的空间可用时,始终维护TX队列。例如,选择“tx_chan.tx_buf()可用”或“INT低且rx_chan.rx_buf()可用”。

loop {
    // Wait for either..
    match select(
        async {
            // ... the chip signaling an interrupt, indicating a packet is available to receive
            irq_pin.wait_for_low().await;
            // *AND* the buffer is ready...
            rx_chan.rx_buf().await
        },
        // ... or a TX buffer becoming available, i.e. embassy-net wants to send a packet
        tx_chan.tx_buf(),
    ).await {
        Either::First(buf) => {
            // a packet is ready to be received!
            let n = receive_packet_over_spi(buf).await;
            rx_chan.rx_done(n);
        }
        Either::Second(buf) => {
            // a packet is ready to be sent!
            send_packet_over_spi(buf).await;
            tx_chan.tx_done();
        }
    }
}

示例

这些embassy-net驱动程序使用此crate实现。您可以从中获取灵感。

互操作性

此crate可以在任何executor上运行。

依赖项

~1–1.4MB
~28K SLoC