pimoroni-pico/drivers/trackball/trackball.cpp

171 lines
4.0 KiB
C++
Raw Normal View History

#include "trackball.hpp"
#include <cstdio>
namespace pimoroni {
enum reg {
LED_RED = 0x00,
LED_GRN = 0x01,
LED_BLU = 0x02,
LED_WHT = 0x03,
LEFT = 0x04,
RIGHT = 0x05,
UP = 0x06,
DOWN = 0x07,
SWITCH = 0x08,
USER_FLASH = 0xD0,
FLASH_PAGE = 0xF0,
INT = 0xF9,
CHIP_ID_L = 0xFA,
CHIP_ID_H = 0xFB,
VERSION = 0xFC,
I2C_ADDR = 0xFD,
CTRL = 0xFE,
};
static const uint8_t MSK_SWITCH_STATE = 0b10000000;
enum int_mask {
MSK_INT_TRIGGERED = 0b00000001,
MSK_INT_OUT_EN = 0b00000010,
};
enum ctrl_mask {
MSK_CTRL_SLEEP = 0b00000001,
MSK_CTRL_RESET = 0b00000010,
MSK_CTRL_FREAD = 0b00000100,
MSK_CTRL_FWRITE = 0b00001000,
};
bool Trackball::init() {
bool succeeded = false;
if(i2c->get_baudrate() > 100000) {
return false;
}
if(interrupt != PIN_UNUSED) {
gpio_set_function(interrupt, GPIO_FUNC_SIO);
gpio_set_dir(interrupt, GPIO_IN);
gpio_pull_up(interrupt);
}
uint16_t chip_id = ((uint16_t)i2c->reg_read_uint8(address, reg::CHIP_ID_H) << 8) | (uint16_t)i2c->reg_read_uint8(address, reg::CHIP_ID_L);
if(chip_id == CHIP_ID) {
enable_interrupt();
succeeded = true;
}
return succeeded;
}
i2c_inst_t* Trackball::get_i2c() const {
return i2c->get_i2c();
}
int Trackball::get_address() const {
return address;
}
int Trackball::get_sda() const {
return i2c->get_sda();
}
int Trackball::get_scl() const {
return i2c->get_scl();
}
int Trackball::get_int() const {
return interrupt;
}
void Trackball::change_address(uint8_t new_address) {
i2c->reg_write_uint8(address, reg::I2C_ADDR, new_address);
wait_for_flash();
}
void Trackball::enable_interrupt(bool use_interrupt) {
uint8_t value = i2c->reg_read_uint8(address, reg::INT);
value &= ~MSK_INT_OUT_EN;
if(use_interrupt)
value |= MSK_INT_OUT_EN;
i2c->reg_write_uint8(address, reg::INT, value);
}
bool Trackball::get_interrupt() {
bool value = false;
if(interrupt != PIN_UNUSED) {
value = !gpio_get(interrupt);
}
else {
value = i2c->reg_read_uint8(address, reg::INT);
value &= MSK_INT_TRIGGERED;
}
return false;
}
void Trackball::set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
i2c->reg_write_uint8(address, reg::LED_RED, r);
i2c->reg_write_uint8(address, reg::LED_GRN, g);
i2c->reg_write_uint8(address, reg::LED_BLU, b);
i2c->reg_write_uint8(address, reg::LED_WHT, w);
}
void Trackball::set_red(uint8_t value) {
i2c->reg_write_uint8(address, reg::LED_RED, value);
}
void Trackball::set_green(uint8_t value) {
i2c->reg_write_uint8(address, reg::LED_GRN, value);
}
void Trackball::set_blue(uint8_t value) {
i2c->reg_write_uint8(address, reg::LED_BLU, value);
}
void Trackball::set_white(uint8_t value) {
i2c->reg_write_uint8(address, reg::LED_WHT, value);
}
Trackball::State Trackball::read() {
State state;
uint8_t sw_state;
state.left = i2c->reg_read_uint8(address, reg::LEFT);
state.right = i2c->reg_read_uint8(address, reg::RIGHT);
state.up = i2c->reg_read_uint8(address, reg::UP);
state.down = i2c->reg_read_uint8(address, reg::DOWN);
sw_state = i2c->reg_read_uint8(address, reg::SWITCH);
state.sw_changed = sw_state & ~MSK_SWITCH_STATE;
state.sw_pressed = (sw_state & MSK_SWITCH_STATE) > 0;
return state;
}
void Trackball::wait_for_flash(void) {
unsigned long start_time = millis();
while(get_interrupt()) {
if(millis() - start_time > timeout) {
printf("Timed out waiting for interrupt!\n");
return;
}
sleep_ms(1);
}
start_time = millis();
while(!get_interrupt()) {
if(millis() - start_time > timeout) {
printf("Timed out waiting for interrupt!\n");
return;
}
sleep_ms(1);
}
}
uint32_t Trackball::millis() {
return to_ms_since_boot(get_absolute_time());
}
}