172 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			172 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);
 | 
						|
}
 |