173 lines
4.9 KiB
C++
173 lines
4.9 KiB
C++
/**
|
|
* \file cimdithal.cpp
|
|
* \brief implementation of the CimditHAL class
|
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
|
* \copyright 2022 Sascha Nitsch
|
|
* Licensed under MIT license
|
|
*
|
|
*/
|
|
// our defines
|
|
#include "defines.h"
|
|
|
|
// library includes
|
|
#include <Adafruit_MCP23X17.h>
|
|
|
|
// own includes
|
|
#include "cimdithal.h"
|
|
|
|
uint32_t CimditHAL::m_millis = 0;
|
|
|
|
CimditHAL::CimditHAL() {
|
|
m_nextKeyScan = 0;
|
|
m_nextAnalogRead = 0;
|
|
m_keyRow = 0;
|
|
m_analogNum = 0;
|
|
m_analogChanged = 0;
|
|
for (uint8_t i = 0; i < 8; ++i) {
|
|
m_currentButtons[i] = 0xff;
|
|
m_buttonsChanged[i] = 0;
|
|
}
|
|
m_rotChanged = 0;
|
|
}
|
|
|
|
void CimditHAL::begin() {
|
|
pinMode(ROT_INT, INPUT);
|
|
pinMode(ANALOG_MUX0, OUTPUT);
|
|
pinMode(ANALOG_MUX1, OUTPUT);
|
|
pinMode(ANALOG_MUX2, OUTPUT);
|
|
pinMode(ANALOG_MUX3, OUTPUT);
|
|
m_keyMatrix.begin_I2C(0x20);
|
|
m_rotEncoders.begin_I2C(0x21);
|
|
// combine the inputs to a single interrupt pin
|
|
m_rotEncoders.setupInterrupts(true, false, HIGH);
|
|
for (uint8_t i = 0; i < 8; ++i) {
|
|
// set key matrix row to output
|
|
m_keyMatrix.pinMode(i, OUTPUT);
|
|
// set encoders to input and setup interrupt to fire on change
|
|
m_rotEncoders.pinMode(i, INPUT_PULLUP);
|
|
m_rotEncoders.setupInterruptPin(i, CHANGE);
|
|
m_currentButtons[i] = 0xff;
|
|
}
|
|
for (uint8_t i = 8; i < 16; ++i) {
|
|
// set key matrix rows to input
|
|
m_keyMatrix.pinMode(i, INPUT_PULLUP);
|
|
// set encoders to input and setup interrupt to fire on change
|
|
m_rotEncoders.pinMode(i, INPUT_PULLUP);
|
|
m_rotEncoders.setupInterruptPin(i, CHANGE);
|
|
}
|
|
m_keyMatrix.writeGPIO(0xff, 0);
|
|
|
|
// read in encoder values
|
|
uint16_t rot = m_rotEncoders.readGPIOAB();
|
|
for (uint8_t i = 0; i < 8; ++i) {
|
|
m_rotaryEncoders[i].update((rot & 1) != 0, (rot & 2) != 0);
|
|
rot >>= 2;
|
|
}
|
|
|
|
// read in key matrix values
|
|
for (uint8_t i = 0 ; i < 8; ++i) {
|
|
m_keyMatrix.writeGPIO(0xff ^ (1 << i), 0);
|
|
delay(10);
|
|
m_currentButtons[i] = m_keyMatrix.readGPIO(1);
|
|
}
|
|
|
|
// read in analog values
|
|
for (uint8_t i = 0 ; i < 16; ++i) {
|
|
digitalWrite(ANALOG_MUX3, i & 8);
|
|
digitalWrite(ANALOG_MUX2, i & 4);
|
|
digitalWrite(ANALOG_MUX1, i & 2);
|
|
digitalWrite(ANALOG_MUX0, i & 1);
|
|
delay(10); // give the muxer a chance
|
|
m_currentAnalogValues[i] = analogRead(ANALOG_IN);
|
|
}
|
|
m_millis = millis();
|
|
}
|
|
|
|
void CimditHAL::readFromHardware(bool interrupt) {
|
|
bool rotChanged = interrupt; // if true, we return after doing the rotary steps
|
|
while (interrupt || digitalRead(ROT_INT)) {
|
|
rotChanged = true;
|
|
interrupt = false;
|
|
uint16_t rot = m_rotEncoders.readGPIOAB();
|
|
for (uint8_t i = 0; i < 8; ++i) {
|
|
m_rotChanged |= m_rotaryEncoders[i].update((rot & 1) != 0, (rot & 2) != 0) << i;
|
|
rot = rot >> 2;
|
|
}
|
|
}
|
|
// quick return if rotary encoder changed
|
|
if (rotChanged) return;
|
|
|
|
m_millis = millis();
|
|
// uint32_t rollover every 92 days
|
|
if (m_millis < ROLLOVER_INTERVAL) {
|
|
m_nextAnalogRead = 0;
|
|
m_nextKeyScan = 0;
|
|
}
|
|
if (m_millis > m_nextAnalogRead) { // only scan analog every ANALOG_INTERVAL ms
|
|
m_nextAnalogRead = m_millis + ANALOG_INTERVAL;
|
|
// save old state
|
|
int16_t lastAnalogValue = m_currentAnalogValues[m_analogNum];
|
|
// scan analog value
|
|
m_currentAnalogValues[m_analogNum] = analogRead(ANALOG_IN);
|
|
// set changed bits
|
|
if (lastAnalogValue != m_currentAnalogValues[m_analogNum]) {
|
|
//if (abs(lastAnalogValue - m_currentAnalogValues[m_analogNum]) > 1) {
|
|
m_analogChanged |= 1 << m_analogNum;
|
|
}
|
|
// set mux value for next round, wrap to 0 at 16
|
|
m_analogNum = (m_analogNum + 1) & 15;
|
|
// set output
|
|
digitalWrite(ANALOG_MUX3, m_analogNum & 8);
|
|
digitalWrite(ANALOG_MUX2, m_analogNum & 4);
|
|
digitalWrite(ANALOG_MUX1, m_analogNum & 2);
|
|
digitalWrite(ANALOG_MUX0, m_analogNum & 1);
|
|
}
|
|
|
|
// scan key matrix
|
|
if (m_millis > m_nextKeyScan) { // only scan analog every KEYSCAN_INTERVAL ms
|
|
m_nextKeyScan = m_millis + KEYSCAN_INTERVAL;
|
|
// save old state
|
|
uint8_t lastButtons = m_currentButtons[m_keyRow];
|
|
// read column bits
|
|
m_currentButtons[m_keyRow] = m_keyMatrix.readGPIO(1);
|
|
// set changed bits
|
|
m_buttonsChanged[m_keyRow] |= lastButtons ^ m_currentButtons[m_keyRow];
|
|
// set row bit wrap 8 to 0
|
|
m_keyRow = (m_keyRow + 1) & 7;
|
|
m_keyMatrix.writeGPIO(0xff ^ (1 << m_keyRow), 0);
|
|
}
|
|
}
|
|
|
|
uint8_t CimditHAL::rotaryChanged() {
|
|
uint8_t ret = m_rotChanged;
|
|
m_rotChanged = 0;
|
|
return ret;
|
|
}
|
|
|
|
uint16_t CimditHAL::analogChanged() {
|
|
uint16_t ret = m_analogChanged;
|
|
m_analogChanged = 0;
|
|
return ret;
|
|
}
|
|
|
|
uint64_t CimditHAL::buttonsChanged() {
|
|
uint64_t ret = 0;
|
|
for (int8_t i = 7; i >= 0; --i) {
|
|
ret = (ret << 8) + m_buttonsChanged[i];
|
|
m_buttonsChanged[i] = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int8_t CimditHAL::getEncoder(uint8_t num) {
|
|
return m_rotaryEncoders[num].getDelta();
|
|
}
|
|
|
|
uint16_t CimditHAL::getAnalog(uint8_t num) const {
|
|
return m_currentAnalogValues[num];
|
|
}
|
|
|
|
bool CimditHAL::getButton(uint8_t num) const {
|
|
return !((m_currentButtons[num >> 3] >> (num & 7)) & 1);
|
|
}
|