This repository has been archived on 2025-04-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ulisp-picocalc/libraries/arduino_picocalc_kbd/src/PCKeyboard.cpp

227 lines
4.8 KiB
C++

#include <Arduino.h>
#include "PCKeyboard.h"
#define _REG_VER 0x01 // fw version
#define _REG_CFG 0x02 // config
#define _REG_INT 0x03 // interrupt status
#define _REG_KEY 0x04 // key status
#define _REG_BKL 0x05 // backlight
#define _REG_DEB 0x06 // debounce cfg
#define _REG_FRQ 0x07 // poll freq cfg
#define _REG_RST 0x08 // reset
#define _REG_FIF 0x09 // fifo
#define _REG_BK2 0x0A // backlight 2
#define _REG_BAT 0x0B // battery
#define _REG_DIR 0x0C // gpio direction
#define _REG_PUE 0x0D // gpio input pull enable
#define _REG_PUD 0x0E // gpio input pull direction
#define _REG_GIO 0x0F // gpio value
#define _REG_GIC 0x10 // gpio interrupt config
#define _REG_GIN 0x11 // gpio interrupt status
#define _WRITE_MASK (1 << 7)
#define CFG_OVERFLOW_ON (1 << 0)
#define CFG_OVERFLOW_INT (1 << 1)
#define CFG_CAPSLOCK_INT (1 << 2)
#define CFG_NUMLOCK_INT (1 << 3)
#define CFG_KEY_INT (1 << 4)
#define CFG_PANIC_INT (1 << 5)
#define INT_OVERFLOW (1 << 0)
#define INT_CAPSLOCK (1 << 1)
#define INT_NUMLOCK (1 << 2)
#define INT_KEY (1 << 3)
#define INT_PANIC (1 << 4)
#define KEY_CAPSLOCK (1 << 5)
#define KEY_NUMLOCK (1 << 6)
#define KEY_COUNT_MASK (0x1F)
#define DIR_OUTPUT 0
#define DIR_INPUT 1
#define PUD_DOWN 0
#define PUD_UP 1
PCKeyboard::PCKeyboard()
: m_wire(nullptr)
{
}
void PCKeyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
/*
m_wire->setSDA(4);//i2c0, GP4
m_wire->setSCL(5);//i2c0 GP5
*/
m_wire->begin();
//m_wire->setClock(10000); // important
reset();
}
void PCKeyboard::reset()
{
m_wire->beginTransmission(m_addr);
m_wire->write(_REG_RST);
m_wire->endTransmission();
delay(100);
}
void PCKeyboard::attachInterrupt(uint8_t pin, void (*func)()) const
{
::pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void PCKeyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
void PCKeyboard::clearInterruptStatus()
{
writeRegister(_REG_INT, 0x00);
}
uint16_t PCKeyboard::status() const
{
return readRegister16(_REG_KEY);
}
uint8_t PCKeyboard::keyCount() const
{
return status() & KEY_COUNT_MASK;
}
PCKeyboard::KeyEvent PCKeyboard::keyEvent() const
{
KeyEvent event = { .key = '\0', .state = StateIdle };
if (keyCount() == 0)
return event;
const uint16_t buf = readRegister16(_REG_FIF);
event.key = buf >> 8;
event.state = KeyState(buf & 0xFF);
return event;
}
float PCKeyboard::backlight() const
{
return readRegister8(_REG_BKL) / 255.0f;
}
void PCKeyboard::setBacklight(float value)
{
writeRegister(_REG_BKL, value * 255);
}
float PCKeyboard::backlight2() const
{
return readRegister8(_REG_BK2) / 255.0f;
}
void PCKeyboard::setBacklight2(float value)
{
writeRegister(_REG_BK2, value * 255);
}
void PCKeyboard::pinMode(uint8_t pin, uint8_t mode)
{
if (pin > 7)
return;
if (mode == INPUT || mode == INPUT_PULLUP) {
updateRegisterBit(_REG_DIR, pin, DIR_INPUT);
} else if (mode == OUTPUT) {
updateRegisterBit(_REG_DIR, pin, DIR_OUTPUT);
}
}
void PCKeyboard::digitalWrite(uint8_t pin, uint8_t val)
{
if (pin > 7)
return;
if (readRegisterBit(_REG_DIR, pin) == DIR_INPUT) {
updateRegisterBit(_REG_PUD, pin, val == LOW ? PUD_DOWN : PUD_UP);
} else {
updateRegisterBit(_REG_GIO, pin, val == HIGH);
}
}
int PCKeyboard::digitalRead(uint8_t pin)
{
if (pin > 7)
return LOW;
if (readRegisterBit(_REG_GIO, pin))
return HIGH;
return LOW;
}
uint8_t PCKeyboard::readRegister8(uint8_t reg) const
{
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, 1);
if (m_wire->available() < 1)
return 0;
return m_wire->read();
}
uint16_t PCKeyboard::readRegister16(uint8_t reg) const
{
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, 2);
if (m_wire->available() < 2)
return 0;
const uint8_t low = m_wire->read();
const uint8_t high = m_wire->read();
return (high << 8) | low;
}
uint8_t PCKeyboard::readRegisterBit(uint8_t reg, uint8_t bit)
{
return bitRead(readRegister8(reg), bit);
}
void PCKeyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg | _WRITE_MASK;
data[1] = value;
m_wire->beginTransmission(m_addr);
m_wire->write(data, sizeof(uint8_t) * 2);
m_wire->endTransmission();
}
void PCKeyboard::updateRegisterBit(uint8_t reg, uint8_t bit, uint8_t value)
{
uint8_t oldValue = readRegister8(reg);
uint8_t newValue = oldValue;
bitWrite(newValue, bit, value);
if (newValue != oldValue)
writeRegister(reg, newValue);
}