cimdit/cimdithal.cpp

186 lines
5.2 KiB
C++

/**
* \file cimdithal.cpp
* \brief implementation of the CimditHAL class
* \author GrumpyDeveloper (Sascha Nitsch)
* \copyright 2022 Sascha Nitsch
* Licensed under MIT license
*
*/
/// pin for analog mux bit 0
#define ANALOG_MUX0 6
/// pin for analog mux bit 1
#define ANALOG_MUX1 8
/// pin for analog mux bit 2
#define ANALOG_MUX2 9
/// pin for analog mux bit 3
#define ANALOG_MUX3 10
/// analog input pin
#define ANALOG_IN A1
/// rotary encoder interrupt pin
#define ROT_INT 7
/// scan analog every 12 milliseconds
#define ANALOG_INTERVAL 12
/// scan keys every 24 milliseconds
#define KEYSCAN_INTERVAL 24
// 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] = 0;
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);
Serial.println(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;
m_rotaryEncoders[i].begin();
}
for (uint8_t i = 8; i < 15; ++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]) {
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);
}