#![no_std]
#![forbid(unsafe_code)]
#![forbid(missing_docs)]
use embedded_hal::blocking::i2c::{Write, WriteRead};
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
enum Register {
DeviceId = 0x00,
FirmwareMinor = 0x01,
ButtonStatus = 0x03,
InterruptConfig = 0x04,
ButtonDebounceTime = 0x05,
PressedQueueStatus = 0x07,
PressedQueueFront = 0x08,
PressedQueueBack = 0x0C,
ClickedQueueStatus = 0x10,
ClickedQueueFront = 0x11,
ClickedQueueBack = 0x15,
LedBrightness = 0x19,
LedPulseGranularity = 0x1A,
LedPulseCycleTime = 0x1B,
LedPulseOffTime = 0x1D,
I2CAddress = 0x1F,
}
#[derive(Debug)]
pub enum Error {
I2C,
QwiicButton(QwiicButtonError),
}
#[derive(Debug)]
pub enum QwiicButtonError {
AddressError,
}
#[derive(Debug)]
pub struct ButtonLED<I2C> {
i2c: I2C,
address: u8,
}
#[derive(Debug)]
pub struct ButtonStatus {
pub event_available: bool,
pub clicked: bool,
pub pressed: bool,
}
impl From<u8> for ButtonStatus {
fn from(val: u8) -> Self {
ButtonStatus {
event_available: 0b1 & val == 1,
clicked: 0b10 & val == 2,
pressed: 0b100 & val == 4,
}
}
}
impl From<ButtonStatus> for u8 {
fn from(val: ButtonStatus) -> u8 {
(val.event_available as u8 & 0b1)
| (val.clicked as u8 & 0b1) << 1
| (val.pressed as u8 & 0b1) << 2
}
}
#[derive(Debug)]
pub struct InterruptConfig {
pub pressed: bool,
pub clicked: bool,
}
impl From<u8> for InterruptConfig {
fn from(val: u8) -> Self {
InterruptConfig {
pressed: 0b01 & val == 1,
clicked: 0b10 & val == 2,
}
}
}
impl From<InterruptConfig> for u8 {
fn from(val: InterruptConfig) -> u8 {
(val.clicked as u8 & 0b1) << 1 | (val.pressed as u8 & 0b1)
}
}
#[derive(Debug)]
pub struct PressedQueueStatus {
pub buffer_empty: bool,
pub buffer_full: bool,
}
impl From<u8> for PressedQueueStatus {
fn from(val: u8) -> Self {
PressedQueueStatus {
buffer_empty: 0b010 & val == 2,
buffer_full: 0b100 & val == 4,
}
}
}
#[derive(Debug)]
pub struct ClickedQueueStatus {
pub buffer_empty: bool,
pub buffer_full: bool,
}
impl From<u8> for ClickedQueueStatus {
fn from(val: u8) -> Self {
ClickedQueueStatus {
buffer_empty: 0b010 & val == 2,
buffer_full: 0b100 & val == 4,
}
}
}
const ADDRESS_MIN: u8 = 0x08;
const ADDRESS_MAX: u8 = 0x77;
impl<I2C> ButtonLED<I2C>
where
I2C: Write + WriteRead,
{
fn write_u8(&mut self, op: Register, payload: u8) -> Result<(), Error> {
self.i2c
.write(self.address, &[op as u8, payload])
.map_err(|_| Error::I2C)
}
fn read_u8(&mut self, op: Register) -> Result<u8, Error> {
let mut buf: [u8; 1] = [0u8; 1];
match self.i2c.write_read(self.address, &[op as u8], &mut buf) {
Ok(_) => Ok(buf[0]),
Err(_) => Err(Error::I2C),
}
}
fn write_u16(&mut self, op: Register, payload: u16) -> Result<(), Error> {
let mut cmd: [u8; 3] = [0u8; 3];
cmd[0] = op as u8;
cmd[1..].copy_from_slice(&payload.to_le_bytes());
self.i2c.write(self.address, &cmd).map_err(|_| Error::I2C)
}
fn read_u16(&mut self, op: Register) -> Result<u16, Error> {
let mut buf: [u8; 2] = [0u8; 2];
match self.i2c.write_read(self.address, &[op as u8], &mut buf) {
Ok(_) => Ok(u16::from_le_bytes(buf)),
Err(_) => Err(Error::I2C),
}
}
fn read_u32(&mut self, op: Register) -> Result<u32, Error> {
let mut buf: [u8; 4] = [0u8; 4];
match self.i2c.write_read(self.address, &[op as u8], &mut buf) {
Ok(_) => Ok(u32::from_le_bytes(buf)),
Err(_) => Err(Error::I2C),
}
}
pub fn init(i2c: I2C, address: u8) -> Self {
Self { i2c, address }
}
pub fn button_id(&mut self) -> Result<u8, Error> {
self.read_u8(Register::DeviceId)
}
pub fn firmware_version(&mut self) -> Result<u16, Error> {
self.read_u16(Register::FirmwareMinor)
}
pub fn button_status(&mut self) -> Result<ButtonStatus, Error> {
self.read_u8(Register::ButtonStatus).map(|r| r.into())
}
pub fn set_button_status(&mut self, new_status: ButtonStatus) -> Result<(), Error> {
self.write_u8(Register::ButtonStatus, new_status.into())
}
pub fn interrupt_config(&mut self) -> Result<InterruptConfig, Error> {
self.read_u8(Register::InterruptConfig).map(|r| r.into())
}
pub fn set_interrupt_config(&mut self, config: InterruptConfig) -> Result<(), Error> {
self.write_u8(Register::InterruptConfig, config.into())
}
pub fn button_debounce_time(&mut self) -> Result<u16, Error> {
self.read_u16(Register::ButtonDebounceTime)
}
pub fn set_button_debounce_time(&mut self, time: u16) -> Result<(), Error> {
self.write_u16(Register::ButtonDebounceTime, time)
}
pub fn pressed_queue_full(&mut self) -> Result<bool, Error> {
self.read_u8(Register::PressedQueueStatus)
.map(|r| r & 0b100 == 4)
}
pub fn pressed_queue_empty(&mut self) -> Result<bool, Error> {
self.read_u8(Register::PressedQueueStatus)
.map(|r| r & 0b010 == 2)
}
pub fn pressed_queue_status(&mut self) -> Result<PressedQueueStatus, Error> {
self.read_u8(Register::PressedQueueStatus).map(|r| r.into())
}
pub fn newest_press_timestamp(&mut self) -> Result<u32, Error> {
let stamp = self.read_u32(Register::PressedQueueFront)?;
let mut current_status = self.read_u8(Register::PressedQueueStatus)?;
current_status |= 1;
self.write_u8(Register::PressedQueueStatus, current_status)?;
Ok(stamp)
}
pub fn oldest_press_timestamp(&mut self) -> Result<u32, Error> {
let stamp = self.read_u32(Register::PressedQueueBack)?;
let mut current_status = self.read_u8(Register::PressedQueueStatus)?;
current_status |= 1;
self.write_u8(Register::PressedQueueStatus, current_status)?;
Ok(stamp)
}
pub fn clicked_queue_full(&mut self) -> Result<bool, Error> {
self.read_u8(Register::ClickedQueueStatus)
.map(|r| r & 0b100 == 4)
}
pub fn clicked_queue_empty(&mut self) -> Result<bool, Error> {
self.read_u8(Register::ClickedQueueStatus)
.map(|r| r & 0b010 == 2)
}
pub fn clicked_queue_status(&mut self) -> Result<ClickedQueueStatus, Error> {
self.read_u8(Register::ClickedQueueStatus).map(|r| r.into())
}
pub fn newest_click_timestamp(&mut self) -> Result<u32, Error> {
let stamp = self.read_u32(Register::ClickedQueueFront)?;
let mut current_status = self.read_u8(Register::ClickedQueueStatus)?;
current_status |= 1;
self.write_u8(Register::ClickedQueueStatus, current_status)?;
Ok(stamp)
}
pub fn oldest_click_timestamp(&mut self) -> Result<u32, Error> {
let stamp = self.read_u32(Register::ClickedQueueBack)?;
let mut current_status = self.read_u8(Register::ClickedQueueStatus)?;
current_status |= 1;
self.write_u8(Register::ClickedQueueStatus, current_status)?;
Ok(stamp)
}
pub fn led_brightness(&mut self) -> Result<u8, Error> {
self.read_u8(Register::LedBrightness)
}
pub fn set_led_brightness(&mut self, brightness: u8) -> Result<(), Error> {
self.write_u8(Register::LedBrightness, brightness)
}
pub fn led_pulse_granularity(&mut self) -> Result<u8, Error> {
self.read_u8(Register::LedPulseGranularity)
}
pub fn set_led_pulse_granularity(&mut self, brightness: u8) -> Result<(), Error> {
self.write_u8(Register::LedPulseGranularity, brightness)
}
pub fn led_pulse_cycle_time(&mut self) -> Result<u16, Error> {
self.read_u16(Register::LedPulseCycleTime)
}
pub fn set_led_pulse_cycle_time(&mut self, cycle_time: u16) -> Result<(), Error> {
self.write_u16(Register::LedPulseCycleTime, cycle_time)
}
pub fn led_pulse_off_time(&mut self) -> Result<u16, Error> {
self.read_u16(Register::LedPulseOffTime)
}
pub fn set_led_pulse_off_time(&mut self, off_time: u16) -> Result<(), Error> {
self.write_u16(Register::LedPulseOffTime, off_time)
}
pub fn device_address(&mut self) -> Result<u8, Error> {
self.read_u8(Register::I2CAddress)
}
pub fn set_device_address(&mut self, new_address: u8) -> Result<(), Error> {
if !(ADDRESS_MIN..=ADDRESS_MAX).contains(&new_address) {
return Err(Error::QwiicButton(QwiicButtonError::AddressError));
}
match self.write_u8(Register::I2CAddress, new_address) {
Ok(_) => {
self.address = new_address;
Ok(())
}
Err(e) => Err(e),
}
}
}