diff --git a/Cargo.toml b/Cargo.toml index e32a617..81382aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,6 @@ name = "qwiic-twist" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +bitvec = { version = "1.0.1", default-features = false } embedded-hal = "0.2.7" -embedded-time = "0.12.1" diff --git a/src/lib.rs b/src/lib.rs index ae1f2d9..1036858 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,20 @@ mod registers; +use bitvec::prelude::*; use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; -use embedded_hal::prelude::*; -use embedded_time::rate::Extensions; +use registers::*; /// 7-bit unshifted default I2C Address const QWIIC_TWIST_ADDR: u8 = 0x3F; +const STATUS_BUTTON_CLICKED_BIT: usize = 2; +const STATUS_BUTTON_PRESSED_BIT: usize = 1; +const STATUS_ENCODER_MOVED_BIT: usize = 0; + +const ENABLE_INTERRUPT_BUTTON_BIT: usize = 1; +const ENABLE_INTERRUPT_ENCODER_BIT: usize = 0; + pub struct QwiicTwist { i2c: I2C, address: u8, @@ -18,31 +25,245 @@ impl QwiicTwist where I2C: Read + Write + WriteRead, { - pub fn new(i2c: I2C, address: u8) -> Self { - Self { i2c, address } + pub fn new(i2c: I2C) -> Result { + let mut device = Self { + i2c, + address: QWIIC_TWIST_ADDR, + }; + + device.get_id()?; + + Ok(device) } - fn read_register(address: u8) -> u8 { - todo!() - } - fn read_register_16(address: u8) -> u16 { - todo!() + pub fn new_with_address(i2c: I2C, address: u8) -> Result { + let mut device = Self { i2c, address }; + + device.get_id()?; + + Ok(device) } - fn write_register(address: u8, value: u8) { - todo!() - } - fn write_register_16(address: u8, value: u16) { - todo!() - } - fn write_register_24(address: u8, value: u32) { - todo!() + pub fn get_id(&mut self) -> Result { + self.read_register(TWIST_ID) } - pub fn read_temperature(&mut self) -> Result { - let mut temp = [0]; - self.i2c - .write_read(self.address, &[0x78], &mut temp) - .and(Ok(temp[0])) + /// Returns the number of indents the user has turned the knob + pub fn get_count(&mut self) -> Result { + self.read_register_i16(TWIST_COUNT) + } + /// Set the number of indents to a given amount + pub fn set_count(&mut self, amount: i16) -> Result<(), E> { + self.write_register_i16(TWIST_COUNT, amount) + } + /// Returns the number of ticks since last check + pub fn get_diff(&mut self, clear_value: bool) -> Result { + let result = self.read_register_i16(TWIST_DIFFERENCE)?; + if clear_value { + self.write_register_i16(TWIST_DIFFERENCE, 0)?; + } + Ok(result) + } + /// Returns true if knob has been twisted + pub fn is_moved(&mut self) -> Result { + self.get_status_flag(STATUS_ENCODER_MOVED_BIT) + } + /// Return true if button is currently pressed. + pub fn is_pressed(&mut self) -> Result { + self.get_status_flag(STATUS_BUTTON_PRESSED_BIT) + } + /// Returns true if a click event has occurred. Event flag is then reset. + pub fn is_clicked(&mut self) -> Result { + self.get_status_flag(STATUS_BUTTON_CLICKED_BIT) + } + + fn get_status_flag(&mut self, flag: usize) -> Result { + let mut result = self.read_register(TWIST_STATUS)?; + let status = result.view_bits_mut::(); + let moved = status.get(flag).map_or(false, |b| *b); + + // Reset flag to 0 + status.set(flag, false); + self.write_register(TWIST_STATUS, result)?; + + Ok(moved) + } + + /// Returns the number of milliseconds since the last encoder movement + pub fn time_since_last_movement(&mut self, clear_value: bool) -> Result { + let time_elapsed = self.read_register_u16(TWIST_LAST_ENCODER_EVENT)?; + + if clear_value { + self.write_register_u16(TWIST_LAST_ENCODER_EVENT, 0)?; + } + + Ok(time_elapsed) + } + /// Returns the number of milliseconds since the last button event (press and release) + pub fn time_since_last_press(&mut self, clear_value: bool) -> Result { + let time_elapsed = self.read_register_u16(TWIST_LAST_BUTTON_EVENT)?; + + if clear_value { + self.write_register_u16(TWIST_LAST_BUTTON_EVENT, 0)?; + } + + Ok(time_elapsed) + } + /// Clears the moved, clicked, and pressed bits + pub fn clear_interrupts(&mut self) -> Result<(), E> { + self.write_register(TWIST_STATUS, 0) + } + + /// Sets the color of the encoder LEDs, 0-255 + pub fn set_color(&mut self, red: u8, green: u8, blue: u8) -> Result<(), E> { + self.write_register_24(TWIST_RED, [red, green, blue]) + } + /// Set the red LED, 0-255 + pub fn set_red(&mut self, red: u8) -> Result<(), E> { + self.write_register(TWIST_RED, red) + } + /// Set the green LED, 0-255 + pub fn set_green(&mut self, green: u8) -> Result<(), E> { + self.write_register(TWIST_GREEN, green) + } + /// Set the blue LED, 0-255 + pub fn set_blue(&mut self, blue: u8) -> Result<(), E> { + self.write_register(TWIST_BLUE, blue) + } + /// Get current value + pub fn get_red(&mut self) -> Result { + self.read_register(TWIST_RED) + } + /// Get current value + pub fn get_green(&mut self) -> Result { + self.read_register(TWIST_GREEN) + } + /// Get current value + pub fn get_blue(&mut self) -> Result { + self.read_register(TWIST_BLUE) + } + + //'Connect' commands Set the relation between each color and the twisting of the knob + //This will connect the LED so it changes [amount] with each encoder tick + //Negative numbers are allowed (so LED gets brighter the more you turn the encoder down) + + /// Connect all colors in one command + pub fn connect_color(&mut self, red: i16, green: i16, blue: i16) -> Result<(), E> { + let (red, green, blue) = (red.to_be_bytes(), green.to_be_bytes(), blue.to_be_bytes()); + let bytes = [ + TWIST_CONNECT_RED.0, + red[0], + red[1], + green[0], + green[1], + blue[0], + blue[1], + ]; + self.i2c.write(self.address, &bytes) + } + /// Connect individual colors + pub fn connect_red(&mut self, red: i16) -> Result<(), E> { + self.write_register_i16(TWIST_CONNECT_RED, red) + } + /// Connect individual colors + pub fn connect_green(&mut self, green: i16) -> Result<(), E> { + self.write_register_i16(TWIST_CONNECT_GREEN, green) + } + /// Connect individual colors + pub fn connect_blue(&mut self, blue: i16) -> Result<(), E> { + self.write_register_i16(TWIST_CONNECT_BLUE, blue) + } + /// Get the connect value for each color + pub fn get_red_connect(&mut self) -> Result { + self.read_register_i16(TWIST_CONNECT_RED) + } + /// Get the connect value for each color + pub fn get_green_connect(&mut self) -> Result { + self.read_register_i16(TWIST_CONNECT_GREEN) + } + /// Get the connect value for each color + pub fn get_blue_connect(&mut self) -> Result { + self.read_register_i16(TWIST_CONNECT_BLUE) + } + + /// Set the limit of what the encoder will go to, then wrap to 0. Set to 0 to disable. + pub fn set_limit(&mut self, limit: u16) -> Result<(), E> { + self.write_register_u16(TWIST_LIMIT, limit) + } + pub fn get_limit(&mut self) -> Result { + self.read_register_u16(TWIST_LIMIT) + } + + pub fn set_encoder_interrupt_enabled(&mut self, enabled: bool) -> Result<(), E> { + let mut result = self.read_register(TWIST_ENABLE_INTS)?; + let status = result.view_bits_mut::(); + status.set(ENABLE_INTERRUPT_ENCODER_BIT, enabled); + self.write_register(TWIST_ENABLE_INTS, result) + } + + pub fn set_button_interrupt_enabled(&mut self, enabled: bool) -> Result<(), E> { + let mut result = self.read_register(TWIST_ENABLE_INTS)?; + let status = result.view_bits_mut::(); + status.set(ENABLE_INTERRUPT_BUTTON_BIT, enabled); + self.write_register(TWIST_ENABLE_INTS, result) + } + + /// Set number of milliseconds that elapse between end of knob turning and interrupt firing + pub fn set_interrupt_timeout(&mut self, timeout: u16) -> Result<(), E> { + self.write_register_u16(TWIST_TURN_INT_TIMEOUT, timeout) + } + /// Get number of milliseconds that must elapse between end of knob turning and interrupt firing + pub fn get_interrupt_timeout(&mut self) -> Result { + self.read_register_u16(TWIST_TURN_INT_TIMEOUT) + } + + /// Returns a two byte Major/Minor version number + pub fn get_version(&mut self) -> Result { + self.read_register_u16(TWIST_VERSION) + } + + /// Change the I²C address to `new_address` + pub fn change_address(&mut self, new_address: u8) -> Result<(), E> { + self.write_register(TWIST_CHANGE_ADDRESS, new_address)?; + self.address = new_address; + Ok(()) + } + + /// Reads from a given location from the Twist + fn read_register(&mut self, address: Register) -> Result { + // TODO: See if write_read() will work here + self.i2c.write(self.address, &[address.0])?; + let mut buffer: [u8; 1] = [0; 1]; + self.i2c.read(self.address, &mut buffer)?; + Ok(u8::from_le_bytes(buffer)) + } + fn read_register_u16(&mut self, address: Register) -> Result { + // TODO: See if write_read() will work here + self.i2c.write(self.address, &[address.0])?; + let mut buffer: [u8; 2] = [0; 2]; + self.i2c.read(self.address, &mut buffer)?; + Ok(u16::from_le_bytes(buffer)) + } + fn read_register_i16(&mut self, address: Register) -> Result { + let result = self.read_register_u16(address)?; + Ok(i16::from_ne_bytes(result.to_ne_bytes())) + } + + /// Write a byte value to a spot in the Twist + fn write_register(&mut self, address: Register, value: u8) -> Result<(), E> { + self.i2c.write(self.address, &[address.0, value]) + } + fn write_register_u16(&mut self, address: Register, value: u16) -> Result<(), E> { + let value = value.to_le_bytes(); + let bytes = [address.0, value[0], value[1]]; + self.i2c.write(self.address, &bytes) + } + fn write_register_i16(&mut self, address: Register, value: i16) -> Result<(), E> { + let value = u16::from_ne_bytes(value.to_ne_bytes()); + self.write_register_u16(address, value) + } + fn write_register_24(&mut self, address: Register, value: [u8; 3]) -> Result<(), E> { + let bytes = [address.0, value[0], value[1], value[2]]; + self.i2c.write(self.address, &bytes) } } diff --git a/src/registers.rs b/src/registers.rs index 5aad5f6..0568c31 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,35 +1,37 @@ /// Map to the various registers on the Twist -const TWIST_ID: u8 = 0x00; +pub struct Register(pub u8); + +pub const TWIST_ID: Register = Register(0x00); /// - 2 - button clicked /// - 1 - button pressed /// - 0 - encoder moved -const TWIST_STATUS: u8 = 0x01; -const TWIST_VERSION: u8 = 0x02; +pub const TWIST_STATUS: Register = Register(0x01); +pub const TWIST_VERSION: Register = Register(0x02); /// - 1 - button interrupt /// - 0 - encoder interrupt -const TWIST_ENABLE_INTS: u8 = 0x04; +pub const TWIST_ENABLE_INTS: Register = Register(0x04); -const TWIST_COUNT: u8 = 0x05; -const TWIST_DIFFERENCE: u8 = 0x07; +pub const TWIST_COUNT: Register = Register(0x05); +pub const TWIST_DIFFERENCE: Register = Register(0x07); /// Milliseconds since the last movement of the knob -const TWIST_LAST_ENCODER_EVENT: u8 = 0x09; +pub const TWIST_LAST_ENCODER_EVENT: Register = Register(0x09); /// Milliseconds since the last press/release -const TWIST_LAST_BUTTON_EVENT: u8 = 0x0B; +pub const TWIST_LAST_BUTTON_EVENT: Register = Register(0x0B); -const TWIST_RED: u8 = 0x0D; -const TWIST_GREEN: u8 = 0x0E; -const TWIST_BLUE: u8 = 0x0F; +pub const TWIST_RED: Register = Register(0x0D); +pub const TWIST_GREEN: Register = Register(0x0E); +pub const TWIST_BLUE: Register = Register(0x0F); /// Amount to change the red LED for each encoder tick -const TWIST_CONNECT_RED: u8 = 0x10; +pub const TWIST_CONNECT_RED: Register = Register(0x10); /// Amount to change the green LED for each encoder tick -const TWIST_CONNECT_GREEN: u8 = 0x12; +pub const TWIST_CONNECT_GREEN: Register = Register(0x12); /// Amount to change the blue LED for each encoder tick -const TWIST_CONNECT_BLUE: u8 = 0x14; +pub const TWIST_CONNECT_BLUE: Register = Register(0x14); -const TWIST_TURN_INT_TIMEOUT: u8 = 0x16; -const TWIST_CHANGE_ADDRESS: u8 = 0x18; -const TWIST_LIMIT: u8 = 0x19; +pub const TWIST_TURN_INT_TIMEOUT: Register = Register(0x16); +pub const TWIST_CHANGE_ADDRESS: Register = Register(0x18); +pub const TWIST_LIMIT: Register = Register(0x19);