diff --git a/doc/keybrd_library_developer_guide.md b/doc/keybrd_library_developer_guide.md index 2f90823..1706c05 100644 --- a/doc/keybrd_library_developer_guide.md +++ b/doc/keybrd_library_developer_guide.md @@ -17,7 +17,9 @@ Keybrd library class inheritance diagram ``` Matrix - Row + RowBase + | + Row IOExpanderPort diff --git a/src/Matrix.h b/src/Matrix.h index 2906aa9..d1474e5 100644 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -2,7 +2,7 @@ #define MATRIX_H #include #include -#include "Row.h" +#include "RowBase.h" /* Diode orientation @@ -28,12 +28,12 @@ External pull-down resistors should have a value between 10k Ohms and 2.2k Ohms. class Matrix { private: - Row *const *const ptrsRows; //array of row pointers + RowBase *const *const ptrsRows; //array of row pointers const uint8_t rowCount; const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh public: - Matrix( Row *const ptrsRows[], const uint8_t rowCount, const bool activeHigh) + Matrix( RowBase *const ptrsRows[], const uint8_t rowCount, const bool activeHigh) : ptrsRows(ptrsRows), rowCount(rowCount), activeHigh(activeHigh) {} void scan(); diff --git a/src/Row.cpp b/src/RowBase.cpp similarity index 55% rename from src/Row.cpp rename to src/RowBase.cpp index a70a72e..0eb840e 100644 --- a/src/Row.cpp +++ b/src/RowBase.cpp @@ -1,8 +1,8 @@ -#include "Row.h" +#include "RowBase.h" /* scans the row and calls any newly pressed or released keys. */ -void Row::process(const bool activeHigh) +void RowBase::process(const bool activeHigh) { //these variables are all bitwise, one bit per key uint8_t rowState; //1 means pressed, 0 means released @@ -22,7 +22,7 @@ void Row::process(const bool activeHigh) Strobes the row and reads the columns. Strobe is on for shortest possible time to preserve IR LED on DodoHand's optic switch. */ -void Row::scan(const bool activeHigh) +void RowBase::scan(const bool activeHigh) { //strobe row on if (activeHigh) @@ -57,7 +57,7 @@ Sets rowEnd and returns rowState. rowEnd is bitwise, where 1 bit corrsiponds to place immediatly after last key of row. rowEnd and rowMask are larger type than portMask so that they can not overflow. */ -uint8_t Row::getRowState(uint16_t& rowEnd, const bool activeHigh) +uint8_t RowBase::getRowState(uint16_t& rowEnd, const bool activeHigh) { uint16_t rowMask = 1; //bitwise, one col per bit, active col bit is 1 uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed @@ -94,71 +94,11 @@ uint8_t Row::getRowState(uint16_t& rowEnd, const bool activeHigh) return rowState; } -/* -Parameter rowState is bitwise, 1 means pressed, 0 means released. -Returns debounced rowState. - -Debounce uses multiple samples to debounces switch states, -where each sample contains the switch states for a row of keys, one bit per switch. - -Debounce uses Marty's debounce algorithm from - http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html -I2C and TWI protocals do not include any Packet Error Checking (PEC). -The goal of Marty's debounce routine is to reject spurious signals, -which is useful when conecting split keyboards with a cable using I2C or TWI. -Was tested on split keyboard with 3-meter long telephone wire to I/O expander - -Marty's debounce algorithm: - Periodically read samples and update the state when a number consecutive sample bits are equal. - -samples[SAMPLE_COUNT] is a ring buffer and samplesIndex is it's current write index. -SAMPLE_COUNT is #defined in Row.h -SAMPLE_COUNT is the number of consecutive equal samples needed to debounce. -It is a macro because it is used to define array size of samples[SAMPLE_COUNT] in Row. -SAMPLE_COUNT should be at lease 2. - -Multiple samples are for error correction on I2C I/O expander and shorten response time. -On keyboards without I/O expander, multiple samples only shorten response time. -Larger SAMPLE_COUNTs are more reliable but consume more memory, where - SAMPLE_COUNT*ROW_COUNT = bytes of memory consumed by keyboard -So don't make SAMPLE_COUNT too large, SAMPLE_COUNT = 4 is very reliable for I2C error correction. - -big SAMPLE_COUNT for fast response, small SAMPLE_COUNT to save memory -there is a way to define SAMPLE_COUNT in the sketch, but it's ugly - see http://forum.arduino.cc/index.php?topic=364843.0 > rely #2 -*/ -uint8_t Row::debounce(const uint8_t rowState) -{ - uint8_t all_1 = ~0; //bitwise - uint8_t all_0 = 0; //bitwise - - delayMicroseconds(DELAY_MICROSECONDS); //delay between Row scans to debounce key - - samples[samplesIndex] = rowState; //insert rowState into samples[] ring buffer - - if (++samplesIndex >= SAMPLE_COUNT) - { - samplesIndex = 0; //wrap samplesIndex to beginning of ring buffer - } - - for (uint8_t j = 0; j < SAMPLE_COUNT; j++) //traverse the sample[] ring buffer - { - all_1 &= samples[j]; //1 if all samples are 1 - all_0 |= samples[j]; //0 if all samples are 0 - } - - // update newDebounce if all the samples agree with one another - // if all samples=1 then newDebounced=1 - // elseif all samples=0 then newDebounced=0 - // else newDebounced=debounced i.e. no change - return all_1 | (all_0 & debounced); -} - /* Computes isFallingEdge and isRisingEdge. All 3 parameters are bitwise. */ -void Row::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge) +void RowBase::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge) { uint8_t debouncedChanged; //bitwise @@ -176,7 +116,7 @@ void Row::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRi calls key's press() or release() function if it was pressed or released. All 3 parameters are bitwise. */ -void Row::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge, +void RowBase::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge, const uint8_t isRisingEdge) { uint8_t rowMask; //bitwise, active col bit is 1 @@ -198,7 +138,7 @@ void Row::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge, } } -void Row::keyWasPressed() +void RowBase::keyWasPressed() { - //empty in Row class. To unstick sticky keys, override keyWasPressed() in derived class. + //empty in RowBase class. To unstick sticky keys, override keyWasPressed() in derived class. } diff --git a/src/Row.h b/src/RowBase.h similarity index 81% rename from src/Row.h rename to src/RowBase.h index 3f3817c..b0ce263 100644 --- a/src/Row.h +++ b/src/RowBase.h @@ -1,5 +1,5 @@ -#ifndef ROW_H -#define ROW_H +#ifndef ROWBASE_H +#define ROWBASE_H #include #include #include @@ -46,7 +46,7 @@ Slow-scan trick for debug message that print too fast Change DELAY_MICROSECONDS to a large number like 10000 That way printing debug messages is slowed to a managable rate */ -class Row +class RowBase { private: Key *const *const ptrsKeys; //array of Key pointers @@ -57,25 +57,23 @@ class Row ColPort *const *const ptrsColPorts; //array of column ports const uint8_t colPortCount; - static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing - uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most resent readings - uint8_t samplesIndex; //samples[] current write index - uint8_t debounced; //bitwise, one bit per key, debounced value of readings + void scan(const bool activeHigh); + uint8_t getRowState(uint16_t& rowEnd, const bool activeHigh); + virtual uint8_t debounce(const uint8_t rowState)=0; //debouncer and I2C error correction + void detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge); + void pressRelease(const uint16_t rowEnd, + const uint8_t isFallingEdge, const uint8_t isRisingEdge); virtual void keyWasPressed(); + protected: + uint8_t debounced; //bitwise, one bit per key, debounced value of readings public: - Row( RowPort &refRowPort, const uint8_t rowPin, + RowBase( RowPort &refRowPort, const uint8_t rowPin, ColPort *const ptrsColPorts[], const uint8_t colPortCount, Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), refRowPort(refRowPort), rowPin(rowPin), ptrsColPorts(ptrsColPorts), colPortCount(colPortCount), - samplesIndex(0), debounced(0) { } - - Key* getPtrKey(uint8_t col) const; + debounced(0) { } + //Key* getPtrKey(uint8_t col) const; todo delete, no longer needed 5/31/16 void process(const bool activeHigh); - void scan(const bool activeHigh); - uint8_t getRowState(uint16_t& rowEnd, const bool activeHigh); - uint8_t debounce(const uint8_t rowState); //switch debouncer and I2C error correction - void detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge); - void pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge, const uint8_t isRisingEdge); }; #endif