parent
8118e696cf
commit
c6e4d17ffb
|
@ -0,0 +1,2 @@
|
||||||
|
filter=-build/include_subdir,-whitespace/line_length
|
||||||
|
root=./
|
|
@ -0,0 +1,158 @@
|
||||||
|
/**
|
||||||
|
* \file cimdit.ino
|
||||||
|
* \brief main functions
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// use a custom keyboard layout
|
||||||
|
#define HID_CUSTOM_LAYOUT
|
||||||
|
/// use german keyboard layout
|
||||||
|
#define LAYOUT_GERMAN
|
||||||
|
#define HAVE_DISPLAY
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
/// no splash screen on OLED
|
||||||
|
#define SSD1306_NO_SPLASH
|
||||||
|
/// OLED display width, in pixels
|
||||||
|
#define SCREEN_WIDTH 128
|
||||||
|
/// OLED display height, in pixels
|
||||||
|
#define SCREEN_HEIGHT 32
|
||||||
|
/// OLED screen address
|
||||||
|
#define SCREEN_ADDRESS 0x3C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// library includes
|
||||||
|
#include <HID-Project.h>
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "cimdithal.h"
|
||||||
|
|
||||||
|
/// update usb devices every x ms if needed
|
||||||
|
#define UPDATE_INTERVAL 100
|
||||||
|
|
||||||
|
/// our hardware abstraction layer
|
||||||
|
CimditHAL hal;
|
||||||
|
|
||||||
|
/// flag if the rotary interrupt has been triggered
|
||||||
|
volatile bool outstandingRotInterrupt = false;
|
||||||
|
|
||||||
|
/// interrupt service routine for rotatry change interrupt
|
||||||
|
void rotInt() {
|
||||||
|
outstandingRotInterrupt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// next update time in ms
|
||||||
|
uint32_t nextUpdate = 0;
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
/// our display
|
||||||
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
|
||||||
|
#endif
|
||||||
|
/// display
|
||||||
|
///
|
||||||
|
/// initial setup
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
hal.begin();
|
||||||
|
attachInterrupt(digitalPinToInterrupt(7), rotInt, RISING);
|
||||||
|
// initialize USB related things
|
||||||
|
Keyboard.begin();
|
||||||
|
Mouse.begin();
|
||||||
|
Gamepad.begin();
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
// init display
|
||||||
|
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
|
||||||
|
display.clearDisplay();
|
||||||
|
display.display();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// main loop
|
||||||
|
void loop() {
|
||||||
|
hal.readFromHardware(outstandingRotInterrupt);
|
||||||
|
if (outstandingRotInterrupt) {
|
||||||
|
outstandingRotInterrupt = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hal.m_millis < nextUpdate && hal.m_millis > ROLLOVER_INTERVAL) return;
|
||||||
|
nextUpdate = hal.m_millis + UPDATE_INTERVAL;
|
||||||
|
uint8_t rotaryChanged = hal.rotaryChanged();
|
||||||
|
if (rotaryChanged) {
|
||||||
|
for (uint8_t i = 0; i < 7; ++i) {
|
||||||
|
if (rotaryChanged & 1) {
|
||||||
|
// temporary debug output
|
||||||
|
Serial.print(F("rot "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(" => "));
|
||||||
|
Serial.println(hal.getEncoder(i));
|
||||||
|
// end of temporary debug output
|
||||||
|
}
|
||||||
|
rotaryChanged >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint16_t analogChanged = hal.analogChanged();
|
||||||
|
if (analogChanged) {
|
||||||
|
for (uint8_t i = 0; i < 4; ++i) {
|
||||||
|
if (analogChanged & 1) {
|
||||||
|
uint16_t analog = hal.getAnalog(i);
|
||||||
|
// temporary debug output
|
||||||
|
int16_t analogMapped16 = map(analog, 0, 1024, -32767, 32768);
|
||||||
|
int8_t analogMapped8 = map(analog, 0, 1024, -127, 127);
|
||||||
|
switch(i) {
|
||||||
|
case 0:
|
||||||
|
Gamepad.xAxis(analogMapped16);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Gamepad.yAxis(analogMapped16);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Gamepad.zAxis(analogMapped8);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Gamepad.rxAxis(analogMapped16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(F("analog "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(": "));
|
||||||
|
Serial.println(analogMapped16);
|
||||||
|
// end of temporary debug output
|
||||||
|
}
|
||||||
|
analogChanged >>= 1;
|
||||||
|
}
|
||||||
|
Gamepad.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t buttonsChanged = hal.buttonsChanged();
|
||||||
|
if (buttonsChanged) {
|
||||||
|
for (uint8_t i = 0; i < 64; ++i) {
|
||||||
|
if (buttonsChanged & 0xFF) { // quickcheck for 8 bits at a time
|
||||||
|
if (buttonsChanged & 1) {
|
||||||
|
// temporary debug output
|
||||||
|
Serial.print(F("button "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(" "));
|
||||||
|
bool pressed = hal.getButton(i);
|
||||||
|
Serial.println(pressed);
|
||||||
|
if (i<32) {
|
||||||
|
if (pressed)
|
||||||
|
Gamepad.press(i+1);
|
||||||
|
else
|
||||||
|
Gamepad.release(i+1);
|
||||||
|
}
|
||||||
|
// end of temporary debug output
|
||||||
|
}
|
||||||
|
buttonsChanged >>= 1;
|
||||||
|
} else {
|
||||||
|
buttonsChanged >>= 8;
|
||||||
|
i += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
/**
|
||||||
|
* \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);
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* \file cimdithal.h
|
||||||
|
* \brief declaration of the CimditHAL class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CIMDITHAL_H_
|
||||||
|
#define CIMDITHAL_H_
|
||||||
|
|
||||||
|
/// rollover time (when 32 bit millis rolls over)
|
||||||
|
#define ROLLOVER_INTERVAL 200
|
||||||
|
|
||||||
|
// external libraries
|
||||||
|
#include <Adafruit_MCP23X17.h>
|
||||||
|
|
||||||
|
// own libraries
|
||||||
|
#include "cimditrotary.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CimditHAL
|
||||||
|
* \brief basic hardware abstraction layer
|
||||||
|
*/
|
||||||
|
class CimditHAL {
|
||||||
|
public:
|
||||||
|
/// constructor
|
||||||
|
CimditHAL();
|
||||||
|
|
||||||
|
/// initialize
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/// \brief read current state from hardware
|
||||||
|
/// \param interrupt true if called from an interrupt
|
||||||
|
void readFromHardware(bool interrupt);
|
||||||
|
|
||||||
|
/// \brief has a rotary input changed
|
||||||
|
uint8_t rotaryChanged();
|
||||||
|
|
||||||
|
/// \brief has an analog value changed
|
||||||
|
uint16_t analogChanged();
|
||||||
|
|
||||||
|
/// \brief has a button changed
|
||||||
|
uint64_t buttonsChanged();
|
||||||
|
|
||||||
|
/// \brief get single rotary value
|
||||||
|
/// \param num number of encoder
|
||||||
|
/// \retval delta value for the given encoder
|
||||||
|
int8_t getEncoder(uint8_t num);
|
||||||
|
|
||||||
|
/// \brief get analog value
|
||||||
|
/// \param num number of analog values
|
||||||
|
/// \retval analog values
|
||||||
|
uint16_t getAnalog(uint8_t num) const;
|
||||||
|
|
||||||
|
/// \brief get state of a single button
|
||||||
|
/// \param num button number
|
||||||
|
/// \retval buttons status
|
||||||
|
bool getButton(uint8_t num) const;
|
||||||
|
|
||||||
|
/// global millis value
|
||||||
|
static uint32_t m_millis;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CimditRotary m_rotaryEncoders[8];
|
||||||
|
|
||||||
|
/// rotary encoder change flags
|
||||||
|
uint8_t m_rotChanged;
|
||||||
|
|
||||||
|
/// current button values
|
||||||
|
uint8_t m_currentButtons[8];
|
||||||
|
|
||||||
|
/// changed values since last hardware read
|
||||||
|
uint8_t m_buttonsChanged[8];
|
||||||
|
|
||||||
|
/// current analag values
|
||||||
|
int16_t m_currentAnalogValues[16];
|
||||||
|
|
||||||
|
/// changed analog values flags
|
||||||
|
uint16_t m_analogChanged;
|
||||||
|
|
||||||
|
/// our key matrix
|
||||||
|
Adafruit_MCP23X17 m_keyMatrix;
|
||||||
|
|
||||||
|
/// our rotary encoders
|
||||||
|
Adafruit_MCP23X17 m_rotEncoders;
|
||||||
|
|
||||||
|
/// next time we do an analog read
|
||||||
|
uint32_t m_nextAnalogRead;
|
||||||
|
|
||||||
|
/// next time we do an key row scan
|
||||||
|
uint32_t m_nextKeyScan;
|
||||||
|
|
||||||
|
/// current analog number
|
||||||
|
uint8_t m_analogNum;
|
||||||
|
|
||||||
|
/// current key matrix row
|
||||||
|
uint8_t m_keyRow;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIMDITHAL_H_
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* \file cimditrotary.cpp
|
||||||
|
* \brief implementiton of the CimditRotary class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "cimditrotary.h"
|
||||||
|
|
||||||
|
CimditRotary::CimditRotary() {
|
||||||
|
m_a = false;
|
||||||
|
m_delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditRotary::begin() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CimditRotary::update(bool a, bool b) {
|
||||||
|
if (a == m_a) return false; // no change
|
||||||
|
if (a && !m_a) { // rising bit a
|
||||||
|
if (b) {
|
||||||
|
++m_delta;
|
||||||
|
} else {
|
||||||
|
--m_delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_a = a;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t CimditRotary::getDelta() {
|
||||||
|
int8_t ret = m_delta;
|
||||||
|
m_delta = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* \file cimditrotary.h
|
||||||
|
* \brief declaration of the CimditRotary class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef CIMDITROTARY_H_
|
||||||
|
#define CIMDITROTARY_H_
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CimditRotary
|
||||||
|
* \brief rotary encocer class
|
||||||
|
*/
|
||||||
|
class CimditRotary {
|
||||||
|
public:
|
||||||
|
/// constructor
|
||||||
|
CimditRotary();
|
||||||
|
|
||||||
|
/// initialize
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/// update internal state with new inputs
|
||||||
|
/// \param a first pin
|
||||||
|
/// \param b second pin
|
||||||
|
/// \return true on position change
|
||||||
|
bool update(bool a, bool b);
|
||||||
|
|
||||||
|
/// get delta value since last read
|
||||||
|
/// \returns number of ticks in positive - negative direction
|
||||||
|
/// \note resets internal counters
|
||||||
|
int8_t getDelta();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// delta position since last read
|
||||||
|
int8_t m_delta;
|
||||||
|
|
||||||
|
/// old a value
|
||||||
|
bool m_a;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIMDITROTARY_H_
|
Loading…
Reference in New Issue