Skip to content
Snippets Groups Projects
keyboard.rs 2.7 KiB
Newer Older
Stephen D's avatar
Stephen D committed
use core::convert::Infallible;
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
use embedded_hal::{
    blocking::delay::{DelayMs, DelayUs},
    digital::v2::{InputPin, OutputPin},
};
use rp2040_hal::Timer;
Stephen D's avatar
Stephen D committed
use rtt_target::rprintln;
Stephen D's avatar
Stephen D committed

pub struct Keyboard<
    // col
    CCLK: OutputPin<Error = Infallible>,
    CSER: OutputPin<Error = Infallible>,
    CRCLK: OutputPin<Error = Infallible>,
    // row
    RCLK: OutputPin<Error = Infallible>,
    RSER: InputPin,
    RLD: OutputPin<Error = Infallible>,
> {
    timer: Timer,
    col_clk: CCLK,
    col_ser: CSER,
    col_rclk: CRCLK,
    row_clk: RCLK,
    row_ser: RSER,
    row_ld: RLD,
Stephen D's avatar
Stephen D committed
}

Stephen D's avatar
Stephen D committed
impl<
        CCLK: OutputPin<Error = Infallible>,
        CSER: OutputPin<Error = Infallible>,
        CRCLK: OutputPin<Error = Infallible>,
        RCLK: OutputPin<Error = Infallible>,
        RSER: InputPin<Error = Infallible>,
        RLD: OutputPin<Error = Infallible>,
    > Keyboard<CCLK, CSER, CRCLK, RCLK, RSER, RLD>
{
Stephen D's avatar
Stephen D committed
    pub fn new(
Stephen D's avatar
Stephen D committed
        timer: Timer,
        col_clk: CCLK,
        col_ser: CSER,
        col_rclk: CRCLK,
        row_clk: RCLK,
        row_ser: RSER,
        row_ld: RLD,
Stephen D's avatar
Stephen D committed
    ) -> Self {
Stephen D's avatar
Stephen D committed
        Self {
            timer,
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
            col_clk,
            col_ser,
            col_rclk,

            row_clk,
            row_ser,
            row_ld,
        }
Stephen D's avatar
Stephen D committed
    }

    pub fn read_state(&mut self) -> u64 {
        let mut out = 0;

Stephen D's avatar
Stephen D committed
        for x in 0..6 {
Stephen D's avatar
Stephen D committed
            // +2 gets us to QF (col 6)
            self.write_cols(1 << (x + 2));
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
            self.timer.delay_ms(1);
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
            out |= u64::from(read_rows(
                &mut self.timer,
                &mut self.row_clk,
                &mut self.row_ser,
                &mut self.row_ld,
            )) << (x * 8);
Stephen D's avatar
Stephen D committed
        }

        out
    }
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
    // 1s in val are low
    // 0s are high
    // indexes from furthest pin (QH on second shift register)
    fn write_cols(&mut self, val: u16) {
        for i in 0..16 {
Stephen D's avatar
Stephen D committed
            self.col_ser
Stephen D's avatar
Stephen D committed
                .set_state(((val & (1 << i)) == 0).into())
Stephen D's avatar
Stephen D committed
                .unwrap();
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
            self.col_clk.set_low().unwrap();
            self.col_clk.set_high().unwrap();
        }

        self.col_rclk.set_low().unwrap();
        self.col_rclk.set_high().unwrap();
    }
}

fn read_rows<
    RCLK: OutputPin<Error = Infallible>,
    RSER: InputPin<Error = Infallible>,
    RLD: OutputPin<Error = Infallible>,
>(
    timer: &mut Timer,
    row_clk: &mut RCLK,
    row_ser: &mut RSER,
    row_ld: &mut RLD,
) -> u8 {
    row_ld.set_low().unwrap();
    row_ld.set_high().unwrap();

    let mut out = 0;
    for i in 0..8 {
        timer.delay_us(10);

        if row_ser.is_low().unwrap() {
            out |= 1 << i;
        }

        row_clk.set_low().unwrap();
        row_clk.set_high().unwrap();
    }

    out
Stephen D's avatar
Stephen D committed
}