RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/split/
uart_half_duplex.rs

1//! Uart half duplex split driver
2//!
3//! This module includes a half-duplex communication driver for split keyboard-to-keyboard communication using UART.
4//! Since this driver is a half-duplex communication where the transmitter and receiver share pins, a TRRS cable is not required for connection; a TRS cable is sufficient.
5//! However, due to its nature, it is relatively prone to transmission and reception errors. I checked on the receiving side and confirmed that reception failed at a rate of about 0.3%. This is a relatively high figure for a keyboard.
6
7use embassy_nrf::{
8    Peri,
9    buffered_uarte::{BufferedUarteRx, BufferedUarteTx, InterruptHandler},
10    gpio::{Flex, Pin},
11    interrupt,
12    uarte::{Baudrate, Instance, Parity},
13};
14use embedded_io_async::{Read as _, Write};
15use rktk::drivers::interface::split::SplitDriver;
16
17#[derive(Debug)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum UartHalfDuplexSplitDriverError {
20    GeneralError(&'static str),
21}
22
23impl rktk::drivers::interface::Error for UartHalfDuplexSplitDriverError {}
24
25pub struct UartHalfDuplexSplitDriver<
26    PIN: Pin,
27    UARTE: Instance,
28    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>>,
29    TIMER: embassy_nrf::timer::Instance,
30    CH1: embassy_nrf::ppi::ConfigurableChannel,
31    CH2: embassy_nrf::ppi::ConfigurableChannel,
32    GROUP: embassy_nrf::ppi::Group,
33> {
34    pin: Peri<'static, PIN>,
35    uarte: Peri<'static, UARTE>,
36    irq: IRQ,
37    timer: Peri<'static, TIMER>,
38    ppi_ch1: Peri<'static, CH1>,
39    ppi_ch2: Peri<'static, CH2>,
40    ppi_group: Peri<'static, GROUP>,
41    read_buffer: [u8; 256],
42    write_buffer: [u8; 256],
43}
44
45impl<
46    PIN: Pin,
47    UARTE: Instance,
48    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>> + Clone,
49    TIMER: embassy_nrf::timer::Instance,
50    CH1: embassy_nrf::ppi::ConfigurableChannel,
51    CH2: embassy_nrf::ppi::ConfigurableChannel,
52    GROUP: embassy_nrf::ppi::Group,
53> UartHalfDuplexSplitDriver<PIN, UARTE, IRQ, TIMER, CH1, CH2, GROUP>
54{
55    pub fn new(
56        mut pin: Peri<'static, PIN>,
57        uarte: Peri<'static, UARTE>,
58        irq: IRQ,
59        timer: Peri<'static, TIMER>,
60        ppi_ch1: Peri<'static, CH1>,
61        ppi_ch2: Peri<'static, CH2>,
62        ppi_group: Peri<'static, GROUP>,
63    ) -> Self {
64        {
65            let mut pin = Flex::new(pin.reborrow());
66            pin.set_as_input_output(
67                embassy_nrf::gpio::Pull::Up,
68                embassy_nrf::gpio::OutputDrive::HighDrive0Disconnect1,
69            );
70        }
71        Self {
72            pin,
73            uarte,
74            irq,
75            timer,
76            ppi_ch1,
77            ppi_ch2,
78            ppi_group,
79            read_buffer: [0; 256],
80            write_buffer: [0; 256],
81        }
82    }
83}
84
85impl<
86    PIN: Pin,
87    UARTE: Instance,
88    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>> + Clone + 'static,
89    TIMER: embassy_nrf::timer::Instance,
90    CH1: embassy_nrf::ppi::ConfigurableChannel,
91    CH2: embassy_nrf::ppi::ConfigurableChannel,
92    GROUP: embassy_nrf::ppi::Group,
93> SplitDriver for UartHalfDuplexSplitDriver<PIN, UARTE, IRQ, TIMER, CH1, CH2, GROUP>
94{
95    type Error = UartHalfDuplexSplitDriverError;
96
97    async fn recv(&mut self, buf: &mut [u8], _is_master: bool) -> Result<usize, Self::Error> {
98        let mut config = embassy_nrf::uarte::Config::default();
99        config.baudrate = Baudrate::BAUD1M;
100        config.parity = Parity::EXCLUDED;
101        let mut rx = BufferedUarteRx::new(
102            self.uarte.reborrow(),
103            self.timer.reborrow(),
104            self.ppi_ch1.reborrow(),
105            self.ppi_ch2.reborrow(),
106            self.ppi_group.reborrow(),
107            self.irq.clone(),
108            self.pin.reborrow(),
109            config,
110            &mut self.read_buffer,
111        );
112        let mut reader = [0u8];
113        let mut i = 0;
114        loop {
115            rx.read_exact(&mut reader)
116                .await
117                .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("read error"))?;
118            if reader[0] == 0 {
119                buf[i] = reader[0];
120                break;
121            } else {
122                buf[i] = reader[0];
123                i += 1;
124            }
125        }
126        drop(rx);
127
128        Ok(i)
129    }
130
131    async fn send_all(&mut self, buf: &[u8], _is_master: bool) -> Result<(), Self::Error> {
132        let mut config = embassy_nrf::uarte::Config::default();
133        config.baudrate = Baudrate::BAUD1M;
134        config.parity = Parity::EXCLUDED;
135        let mut tx = BufferedUarteTx::new(
136            self.uarte.reborrow(),
137            self.pin.reborrow(),
138            self.irq.clone(),
139            config,
140            &mut self.write_buffer,
141        );
142
143        tx.write_all(buf)
144            .await
145            .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("write error"))?;
146        tx.flush()
147            .await
148            .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("flush error"))?;
149        drop(tx);
150
151        embassy_time::Timer::after_micros(50).await;
152
153        Ok(())
154    }
155}