Compare commits
6 commits
9ea123186d
...
95d5a18e99
| Author | SHA1 | Date | |
|---|---|---|---|
| 95d5a18e99 | |||
| 2d11808a91 | |||
| 0e697b48f1 | |||
| 597d2584b1 | |||
| 382a018b22 | |||
| 4967aa362f |
3 changed files with 167 additions and 0 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -2,6 +2,15 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zel-tca8418"
|
name = "zel-tca8418"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"embedded-hal",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
embedded-hal = "1.0.0"
|
||||||
|
|
|
||||||
157
src/lib.rs
157
src/lib.rs
|
|
@ -1,2 +1,159 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
use embedded_hal::i2c::SevenBitAddress;
|
||||||
|
|
||||||
|
pub const I2C_ADDR: SevenBitAddress = 0b0_0110100;
|
||||||
|
|
||||||
|
pub struct TCA8418<I2C> {
|
||||||
|
i2c: I2C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct MatrixConfig {
|
||||||
|
rows: u8,
|
||||||
|
columns: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatrixConfig {
|
||||||
|
/// A new config where the matrix has no rows or columns and all of the pins are
|
||||||
|
/// allocated for GPIO.
|
||||||
|
pub const fn new_empty() -> Self {
|
||||||
|
MatrixConfig {
|
||||||
|
rows: 0,
|
||||||
|
columns: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a row to the keyboard matrix, meaning its pin will not be available for GPIO.
|
||||||
|
///
|
||||||
|
/// `row_number` must be in the range `0..=7`
|
||||||
|
pub const fn with_row(self, row_number: u8) -> Self {
|
||||||
|
if row_number >= 8 {
|
||||||
|
panic!("row_number out of bounds");
|
||||||
|
}
|
||||||
|
MatrixConfig {
|
||||||
|
rows: self.rows | (1 << row_number),
|
||||||
|
columns: self.columns,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a column to the keyboard matrix, meaning its pin will not be available for GPIO.
|
||||||
|
///
|
||||||
|
/// `column_number` must be in the range `0..=9`
|
||||||
|
pub const fn with_column(self, column_number: u8) -> Self {
|
||||||
|
if column_number >= 10 {
|
||||||
|
panic!("column_number out of bounds");
|
||||||
|
}
|
||||||
|
MatrixConfig {
|
||||||
|
rows: self.rows,
|
||||||
|
columns: self.columns | (1 << column_number),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct InterruptConfig(u8);
|
||||||
|
|
||||||
|
impl InterruptConfig {
|
||||||
|
/// A new interrupt with the following configuration:
|
||||||
|
/// - GPI events are tracked when keypad is locked
|
||||||
|
/// - Overflow data is lost
|
||||||
|
/// - Processor interrupt remains asserted (or low) if host tries to clear
|
||||||
|
/// interrupt while there is still a pending key press, key release or
|
||||||
|
/// GPI interrupt
|
||||||
|
/// - ~INT is not asserted if the FIFO overflows
|
||||||
|
/// - ~INT is not asserted after a correct unlock key sequence
|
||||||
|
/// - ~INT is not asserted for a change on a GPI
|
||||||
|
/// - ~INT is not asserted when a key event occurs
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn without_gpi_event_tracking_when_locked(self) -> Self {
|
||||||
|
InterruptConfig(self.0 | 0b0100_0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_overflow_data_shifting(self) -> Self {
|
||||||
|
InterruptConfig(self.0 | 0b0010_0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_temporary_interrupt_deassertion(self) -> Self {
|
||||||
|
InterruptConfig(self.0 | 0b0001_0000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct KeySet(u128);
|
||||||
|
|
||||||
|
impl KeySet {
|
||||||
|
fn contains(&self, key_number: u8) -> bool {
|
||||||
|
(self.0 & (1 << key_number)) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::Not for KeySet {
|
||||||
|
type Output = KeySet;
|
||||||
|
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
KeySet(!self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KeySetIter {
|
||||||
|
key_set: KeySet,
|
||||||
|
shift: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Iterator for KeySetIter {
|
||||||
|
type Item = u8;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let next_shift = self.key_set.0.trailing_zeros() as u8 + 1;
|
||||||
|
if next_shift >= 128 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.key_set.0 >>= next_shift;
|
||||||
|
self.shift += next_shift;
|
||||||
|
|
||||||
|
Some(self.shift - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::IntoIterator for KeySet {
|
||||||
|
type Item = u8;
|
||||||
|
|
||||||
|
type IntoIter = KeySetIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
KeySetIter {
|
||||||
|
key_set: self,
|
||||||
|
shift: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2C: embedded_hal::i2c::I2c> TCA8418<I2C> {
|
||||||
|
pub fn new(
|
||||||
|
i2c: I2C,
|
||||||
|
matrix_config: MatrixConfig,
|
||||||
|
interrupt_config: InterruptConfig,
|
||||||
|
) -> Self {
|
||||||
|
let mut self_ = Self { i2c };
|
||||||
|
self_.init(matrix_config, interrupt_config);
|
||||||
|
self_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self, matrix_config: MatrixConfig, interrupt_config: InterruptConfig) {
|
||||||
|
self.i2c.write(I2C_ADDR, &[0x1D, matrix_config.rows]);
|
||||||
|
self.i2c
|
||||||
|
.write(I2C_ADDR, &[0x1E, matrix_config.columns as u8]);
|
||||||
|
self.i2c
|
||||||
|
.write(I2C_ADDR, &[0x1F, (matrix_config.columns >> 8) as u8]);
|
||||||
|
self.i2c.write(I2C_ADDR, &[0x01, interrupt_config.0]);
|
||||||
|
self.i2c.write(I2C_ADDR, &[0x0F, 0]);
|
||||||
|
self.i2c.write(I2C_ADDR, &[0x10, 0]);
|
||||||
|
self.i2c.write(I2C_ADDR, &[0x0E, 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue