Implement everything
This commit is contained in:
parent
ff3e80aacc
commit
1a76174582
3 changed files with 263 additions and 42 deletions
|
@ -3,8 +3,6 @@ name = "qwiic-twist"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bitvec = { version = "1.0.1", default-features = false }
|
||||||
embedded-hal = "0.2.7"
|
embedded-hal = "0.2.7"
|
||||||
embedded-time = "0.12.1"
|
|
||||||
|
|
265
src/lib.rs
265
src/lib.rs
|
@ -2,13 +2,20 @@
|
||||||
|
|
||||||
mod registers;
|
mod registers;
|
||||||
|
|
||||||
|
use bitvec::prelude::*;
|
||||||
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
|
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
|
||||||
use embedded_hal::prelude::*;
|
use registers::*;
|
||||||
use embedded_time::rate::Extensions;
|
|
||||||
|
|
||||||
/// 7-bit unshifted default I2C Address
|
/// 7-bit unshifted default I2C Address
|
||||||
const QWIIC_TWIST_ADDR: u8 = 0x3F;
|
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> {
|
pub struct QwiicTwist<I2C> {
|
||||||
i2c: I2C,
|
i2c: I2C,
|
||||||
address: u8,
|
address: u8,
|
||||||
|
@ -18,31 +25,245 @@ impl<I2C, E> QwiicTwist<I2C>
|
||||||
where
|
where
|
||||||
I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
|
I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
|
||||||
{
|
{
|
||||||
pub fn new(i2c: I2C, address: u8) -> Self {
|
pub fn new(i2c: I2C) -> Result<Self, E> {
|
||||||
Self { i2c, address }
|
let mut device = Self {
|
||||||
|
i2c,
|
||||||
|
address: QWIIC_TWIST_ADDR,
|
||||||
|
};
|
||||||
|
|
||||||
|
device.get_id()?;
|
||||||
|
|
||||||
|
Ok(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_register(address: u8) -> u8 {
|
pub fn new_with_address(i2c: I2C, address: u8) -> Result<Self, E> {
|
||||||
todo!()
|
let mut device = Self { i2c, address };
|
||||||
}
|
|
||||||
fn read_register_16(address: u8) -> u16 {
|
device.get_id()?;
|
||||||
todo!()
|
|
||||||
|
Ok(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_register(address: u8, value: u8) {
|
pub fn get_id(&mut self) -> Result<u8, E> {
|
||||||
todo!()
|
self.read_register(TWIST_ID)
|
||||||
}
|
|
||||||
fn write_register_16(address: u8, value: u16) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn write_register_24(address: u8, value: u32) {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_temperature(&mut self) -> Result<u8, E> {
|
/// Returns the number of indents the user has turned the knob
|
||||||
let mut temp = [0];
|
pub fn get_count(&mut self) -> Result<i16, E> {
|
||||||
self.i2c
|
self.read_register_i16(TWIST_COUNT)
|
||||||
.write_read(self.address, &[0x78], &mut temp)
|
}
|
||||||
.and(Ok(temp[0]))
|
/// 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<i16, E> {
|
||||||
|
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<bool, E> {
|
||||||
|
self.get_status_flag(STATUS_ENCODER_MOVED_BIT)
|
||||||
|
}
|
||||||
|
/// Return true if button is currently pressed.
|
||||||
|
pub fn is_pressed(&mut self) -> Result<bool, E> {
|
||||||
|
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<bool, E> {
|
||||||
|
self.get_status_flag(STATUS_BUTTON_CLICKED_BIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status_flag(&mut self, flag: usize) -> Result<bool, E> {
|
||||||
|
let mut result = self.read_register(TWIST_STATUS)?;
|
||||||
|
let status = result.view_bits_mut::<Lsb0>();
|
||||||
|
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<u16, E> {
|
||||||
|
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<u16, E> {
|
||||||
|
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<u8, E> {
|
||||||
|
self.read_register(TWIST_RED)
|
||||||
|
}
|
||||||
|
/// Get current value
|
||||||
|
pub fn get_green(&mut self) -> Result<u8, E> {
|
||||||
|
self.read_register(TWIST_GREEN)
|
||||||
|
}
|
||||||
|
/// Get current value
|
||||||
|
pub fn get_blue(&mut self) -> Result<u8, E> {
|
||||||
|
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<i16, E> {
|
||||||
|
self.read_register_i16(TWIST_CONNECT_RED)
|
||||||
|
}
|
||||||
|
/// Get the connect value for each color
|
||||||
|
pub fn get_green_connect(&mut self) -> Result<i16, E> {
|
||||||
|
self.read_register_i16(TWIST_CONNECT_GREEN)
|
||||||
|
}
|
||||||
|
/// Get the connect value for each color
|
||||||
|
pub fn get_blue_connect(&mut self) -> Result<i16, E> {
|
||||||
|
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<u16, E> {
|
||||||
|
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::<Lsb0>();
|
||||||
|
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::<Lsb0>();
|
||||||
|
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<u16, E> {
|
||||||
|
self.read_register_u16(TWIST_TURN_INT_TIMEOUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a two byte Major/Minor version number
|
||||||
|
pub fn get_version(&mut self) -> Result<u16, E> {
|
||||||
|
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<u8, E> {
|
||||||
|
// 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<u16, E> {
|
||||||
|
// 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<i16, E> {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,37 @@
|
||||||
/// Map to the various registers on the Twist
|
/// 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
|
/// - 2 - button clicked
|
||||||
/// - 1 - button pressed
|
/// - 1 - button pressed
|
||||||
/// - 0 - encoder moved
|
/// - 0 - encoder moved
|
||||||
const TWIST_STATUS: u8 = 0x01;
|
pub const TWIST_STATUS: Register = Register(0x01);
|
||||||
const TWIST_VERSION: u8 = 0x02;
|
pub const TWIST_VERSION: Register = Register(0x02);
|
||||||
|
|
||||||
/// - 1 - button interrupt
|
/// - 1 - button interrupt
|
||||||
/// - 0 - encoder interrupt
|
/// - 0 - encoder interrupt
|
||||||
const TWIST_ENABLE_INTS: u8 = 0x04;
|
pub const TWIST_ENABLE_INTS: Register = Register(0x04);
|
||||||
|
|
||||||
const TWIST_COUNT: u8 = 0x05;
|
pub const TWIST_COUNT: Register = Register(0x05);
|
||||||
const TWIST_DIFFERENCE: u8 = 0x07;
|
pub const TWIST_DIFFERENCE: Register = Register(0x07);
|
||||||
/// Milliseconds since the last movement of the knob
|
/// 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
|
/// 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;
|
pub const TWIST_RED: Register = Register(0x0D);
|
||||||
const TWIST_GREEN: u8 = 0x0E;
|
pub const TWIST_GREEN: Register = Register(0x0E);
|
||||||
const TWIST_BLUE: u8 = 0x0F;
|
pub const TWIST_BLUE: Register = Register(0x0F);
|
||||||
|
|
||||||
/// Amount to change the red LED for each encoder tick
|
/// 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
|
/// 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
|
/// 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;
|
pub const TWIST_TURN_INT_TIMEOUT: Register = Register(0x16);
|
||||||
const TWIST_CHANGE_ADDRESS: u8 = 0x18;
|
pub const TWIST_CHANGE_ADDRESS: Register = Register(0x18);
|
||||||
const TWIST_LIMIT: u8 = 0x19;
|
pub const TWIST_LIMIT: Register = Register(0x19);
|
||||||
|
|
Loading…
Add table
Reference in a new issue