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    Peripheral,
9    buffered_uarte::{BufferedUarteRx, BufferedUarteTx, InterruptHandler},
10    gpio::{AnyPin, Flex},
11    interrupt,
12    ppi::AnyGroup,
13    uarte::{Baudrate, Instance, Parity},
14};
15use embedded_io_async::{Read as _, Write};
16use rktk::drivers::interface::split::SplitDriver;
17
18#[derive(Debug)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum UartHalfDuplexSplitDriverError {
21    GeneralError(&'static str),
22}
23
24impl rktk::drivers::interface::Error for UartHalfDuplexSplitDriverError {}
25
26pub struct UartHalfDuplexSplitDriver<
27    UARTE: Instance,
28    UARTEP: Peripheral<P = UARTE>,
29    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>>,
30    TIMER: embassy_nrf::timer::Instance,
31    TIMERP: Peripheral<P = TIMER>,
32    CH1: embassy_nrf::ppi::ConfigurableChannel,
33    CH1P: Peripheral<P = CH1>,
34    CH2: embassy_nrf::ppi::ConfigurableChannel,
35    CH2P: Peripheral<P = CH2>,
36> {
37    pin: AnyPin,
38    uarte: UARTEP,
39    irq: IRQ,
40    timer: TIMERP,
41    ppi_ch1: CH1P,
42    ppi_ch2: CH2P,
43    ppi_group: AnyGroup,
44    read_buffer: [u8; 256],
45    write_buffer: [u8; 256],
46}
47
48impl<
49    UARTE: Instance,
50    UARTEP: Peripheral<P = UARTE>,
51    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>> + Clone,
52    TIMER: embassy_nrf::timer::Instance,
53    TIMERP: Peripheral<P = TIMER>,
54    CH1: embassy_nrf::ppi::ConfigurableChannel,
55    CH1P: Peripheral<P = CH1>,
56    CH2: embassy_nrf::ppi::ConfigurableChannel,
57    CH2P: Peripheral<P = CH2>,
58> UartHalfDuplexSplitDriver<UARTE, UARTEP, IRQ, TIMER, TIMERP, CH1, CH1P, CH2, CH2P>
59{
60    pub fn new(
61        mut pin: AnyPin,
62        uarte: UARTEP,
63        irq: IRQ,
64        timer: TIMERP,
65        ppi_ch1: CH1P,
66        ppi_ch2: CH2P,
67        ppi_group: AnyGroup,
68    ) -> Self {
69        {
70            let mut pin = Flex::new(&mut pin);
71            pin.set_as_input_output(
72                embassy_nrf::gpio::Pull::Up,
73                embassy_nrf::gpio::OutputDrive::HighDrive0Disconnect1,
74            );
75        }
76        Self {
77            pin,
78            uarte,
79            irq,
80            timer,
81            ppi_ch1,
82            ppi_ch2,
83            ppi_group,
84            read_buffer: [0; 256],
85            write_buffer: [0; 256],
86        }
87    }
88}
89
90impl<
91    UARTE: Instance,
92    UARTEP: Peripheral<P = UARTE> + 'static,
93    IRQ: interrupt::typelevel::Binding<UARTE::Interrupt, InterruptHandler<UARTE>> + Clone + 'static,
94    TIMER: embassy_nrf::timer::Instance,
95    TIMERP: Peripheral<P = TIMER> + 'static,
96    CH1: embassy_nrf::ppi::ConfigurableChannel,
97    CH1P: Peripheral<P = CH1> + 'static,
98    CH2: embassy_nrf::ppi::ConfigurableChannel,
99    CH2P: Peripheral<P = CH2> + 'static,
100> SplitDriver
101    for UartHalfDuplexSplitDriver<UARTE, UARTEP, IRQ, TIMER, TIMERP, CH1, CH1P, CH2, CH2P>
102{
103    type Error = UartHalfDuplexSplitDriverError;
104
105    async fn recv(&mut self, buf: &mut [u8], _is_master: bool) -> Result<usize, Self::Error> {
106        let mut config = embassy_nrf::uarte::Config::default();
107        config.baudrate = Baudrate::BAUD1M;
108        config.parity = Parity::EXCLUDED;
109        let mut rx = BufferedUarteRx::new(
110            &mut self.uarte,
111            &mut self.timer,
112            &mut self.ppi_ch1,
113            &mut self.ppi_ch2,
114            &mut self.ppi_group,
115            self.irq.clone(),
116            &mut self.pin,
117            config,
118            &mut self.read_buffer,
119        );
120        let mut reader = [0u8];
121        let mut i = 0;
122        loop {
123            rx.read_exact(&mut reader)
124                .await
125                .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("read error"))?;
126            if reader[0] == 0 {
127                buf[i] = reader[0];
128                break;
129            } else {
130                buf[i] = reader[0];
131                i += 1;
132            }
133        }
134        drop(rx);
135
136        Ok(i)
137    }
138
139    async fn send_all(&mut self, buf: &[u8], _is_master: bool) -> Result<(), Self::Error> {
140        let mut config = embassy_nrf::uarte::Config::default();
141        config.baudrate = Baudrate::BAUD1M;
142        config.parity = Parity::EXCLUDED;
143        let mut tx = BufferedUarteTx::new(
144            &mut self.uarte,
145            self.irq.clone(),
146            &mut self.pin,
147            config,
148            &mut self.write_buffer,
149        );
150
151        tx.write_all(buf)
152            .await
153            .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("write error"))?;
154        tx.flush()
155            .await
156            .map_err(|_| UartHalfDuplexSplitDriverError::GeneralError("flush error"))?;
157        drop(tx);
158
159        embassy_time::Timer::after_micros(50).await;
160
161        Ok(())
162    }
163}