Browse Source

change class and variable names

tags/v0.5.0
wolfv6 7 years ago
parent
commit
a5d6fb8d9e

+ 43
- 43
doc/keybrd_library_developer_guide.md View File

@@ -13,14 +13,14 @@ Debouncer and I/O expander use bit manipulation.
## Custom Row classes
The keybrd library is flexible for designing custom Rows
* RowBase functions can be overridden in a derived class
* Row functions can be overridden in a derived class
* choice of Debouncers
* choice of Scanners
this example illustrates the custom Row classes for a fictional keybrd_Ext extension library
the keybrd_Ext library is for a split keyboard with a matrix on each hand
Row_Ext::keyWasPressed() overrides RowBase::keyWasPressed()
Row_Ext::keyWasPressed() overrides Row::keyWasPressed()
Row_Ext::keyWasPressed() is used to unstick sticky keys
Row_Ext_uC scans the primary matrix
@@ -30,14 +30,14 @@ Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock key
Class inheritance diagram
```
RowBase
Row
|
Row_Ext (override RowBase::keyWasPressed() )
Row_Ext (override Row::keyWasPressed() )
/ \
Row_Ext_uC Row_Ext_ShiftRegisters (inherit Row_Ext::keyWasPressed() )
RowScanner_PinsArray RowScanner_SPIShiftRegisters
Scanner_uC Scanner_ShiftRegs74HC165
```
@@ -46,16 +46,16 @@ Dependency diagram
________ Row_Ext_uC[1] _______________
/ \ \
RowScanner_PinsArray[1] Debouncer_Samples[1] Key[1..*]
Scanner_uC[1] Debouncer_Samples[1] Key[1..*]
/ \ |
strobePin[1] readPins[1..*] Code[1..*]
_____ Row_Ext_ShiftRegisters[1] ___________
/ \ \
RowScanner_SPIShiftRegisters[1] Debouncer_Samples[1] Key[1..*]
/ \ |
strobePin[1] ROW_END[1] Code[1..*]
_____ Row_Ext_ShiftRegisters[1] ________
/ \ \
Scanner_ShiftRegs74HC165[1] Debouncer_Samples[1] Key[1..*]
/ \ |
strobePin[1] ROW_END[1] Code[1..*]
```
@@ -63,23 +63,23 @@ Dependency diagram
Keybrd library class inheritance diagram
```
_______ RowBase ________
________ Row ___________
/ | \
Row_uC Row_ShiftRegisters Row_IOE
Row_uC Row_ShiftRegisters Row_IOE (to be added)
RowScanner_PinsArray RowScanner_PinsBitwise RowScanner_SPIShiftRegisters
Scanner_uC Scanner_Port Scanner_ShiftRegs74HC165
IOExpanderPort
IOEPort
RowPort
StrobePort
|
RowPort_PCA9655E (one RowPort class for each IOE type)
StrobePort_PCA9655E (one StrobePort class for each IOE type)
ColPort
ReadPort
|
ColPort_PCA9655E (one ColPort class for each IOE type)
ReadPort_PCA9655E (one ReadPort class for each IOE type)
____ LED ____
/ \
@@ -124,30 +124,30 @@ Keybrd library class inheritance diagram
Example single-layer dependency diagram with LEDs
```
___ Row_uC[1..*] ________
/ \ \
RowScanner_PinsArray Debouncer Keys[1..*] __
| \
Code[1..*] Code_LEDLock[1..*]
|
LED_PinNumber[1]
_ Row_uC[1..*] _
/ | \
Scanner_uC Debouncer Keys[1..*] __
| \
Code[1..*] Code_LEDLock[1..*]
|
LED_PinNumber[1]
```
Example multi-layer dependency diagram with layer LEDs
```
LayerStates[1..*]
________ Row_uC[1..*] _____________________/__ | \
/ \ \ / \ | \
RowScanner_PinsArray[1] Debouncer[1] Keys[1..*] / Code_Layer[1..*] LED_PinNumber[0..*]
| /
Code[1..*]
LayerStates[1..*]
________ Row_uC[1..*] ___________/__ | \
/ | \ / \ | \
Scanner_uC[1] Debouncer[1] Keys[1..*] / Code_Layer[1..*] LED_PinNumber[0..*]
| /
Code[1..*]
```
Example secondary matrix with shift registers dependency diagram
```
Row_ShiftRegisters[1..*]
Row_ShiftRegisters[1..*]
/ \ \
RowScanner_ShiftRegisters Debouncer Keys[1..*]
|
@@ -159,13 +159,13 @@ Example secondary matrix with I/O Expander dependency diagram with LEDs
```
___ Row_IOE[1..*] _________
/ \ \
RowScanner_PinsBitwise[1] Debouncer[1] Keys[1..*] __
/ | \ | \
RowPort[1] RowPin[1] ColPort[1] Code[1..*] Code_LEDLock[1..*]
\ / \ |
\ / ColPins[1..*] LED[1]
\ /
IOExpanderPort[0..*]
__ Scanner_Port[1] _ Debouncer[1] Keys[1..*] __
/ | \ | \
StrobePort[1] RowPin[1] ReadPort[1] Code[1..*] Code_LEDLock[1..*]
\ / \ |
\ / ColPins[1..*] LED[1]
\ /
IOEPort[0..*]
```
@@ -240,13 +240,13 @@ Refer to it like a table of contents while reading the keybrd library.
```
loop() for each row
RowBase::process()
RowScanner_PinsArray::scan() strobe row on
Row::process()
Scanner_uC::scan() strobe row on
for each readPin
set rowState bit
strobe row off
Debouncer_4Samples::debounce() debounce
RowBase::pressRelease() for each key in row
Row::pressRelease() for each key in row
if falling edge
Key_*::release() scanCode->release()
Code_*::release() Keyboard.release(scancode)

+ 25
- 25
examples/keybrd_shift_register/keybrd_shift_register.ino View File

@@ -3,11 +3,11 @@ Tested on Teensy LC and daisy chained 74HC165 shift registers

The keyboard hardware for this sketch has 4 shift registers,
with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key.
Unused input pins are not grounded, so add this line to RowScanner_SPIShiftRegisters::scan():
Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan():
//clear unpowered pins (for testing on breadboard)
rowState &= 0b11110001000100010001000100010001; //todo

Layout
Layout Layout
| Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**|
|:-----:|------|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|-----|-----|
| **0** |capLck| a | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
@@ -32,20 +32,20 @@ Layout
ScanDelay scanDelay(9000);

//active state of left matrix
const bool RowScanner_PinsArray::STROBE_ON = LOW;
const bool RowScanner_PinsArray::STROBE_OFF = HIGH;
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;

const uint8_t RowScanner_SPIShiftRegisters::SHIFT_LOAD = 10;
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;

//active state of right matrix
const bool RowScanner_SPIShiftRegisters::STROBE_ON = LOW;
const bool RowScanner_SPIShiftRegisters::STROBE_OFF = HIGH;
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;

Debug debug;

// ================= LEFT PINS =================
uint8_t readPins[] = {14, 15};
uint8_t KEY_COUNT = sizeof(readPins)/sizeof(*readPins);
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);

// ==================== LEDs ===================
LED_PinNumber LED1(16);
@@ -98,48 +98,48 @@ Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED1);

// ================= LEFT ROWS =================
Key* ptrsKeys_L0[] = { &o_capsLock, &s_a };
Row_uC row_L0(0, readPins, ptrsKeys_L0, KEY_COUNT);
Row_uC row_L0(0, readPins, ptrsKeys_L0, READ_PIN_COUNT);

Key* ptrsKeys_L1[] = { &s_b, &s_c };
Row_uC row_L1(1, readPins, ptrsKeys_L1, KEY_COUNT);
Row_uC row_L1(1, readPins, ptrsKeys_L1, READ_PIN_COUNT);

// ================= RIGHT ROWS ================
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h
//Row_ShiftRegisters(STROBE_PIN, ptrsKeys[], KEY_COUNT)
//Row_ShiftRegisters(STROBE_PIN, ptrsKeys[], READ_PIN_COUNT)
//the s_z are place holders and should not print

/*
//prints 0 1
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z };
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT);
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, READ_PIN_COUNT_R0);

//prints a b
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z };
const uint8_t KEY_R1_COUNT = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row_ShiftRegisters row_R1(9, ptrsKeys_R1, KEY_R1_COUNT);
const uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row_ShiftRegisters row_R1(9, ptrsKeys_R1, READ_PIN_COUNT_R1);
*/
/*
//prints 0 1 2
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
&s_2, &s_z, &s_z, &s_z };
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT);
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, READ_PIN_COUNT_R0);
*/
/*
//prints 0 1 2 3
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z };
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT);
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, READ_PIN_COUNT_R0);
*/
/*
//prints 0 1 2 3 4 5
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z };
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT);
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, READ_PIN_COUNT_R0);
*/

//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4
@@ -147,16 +147,16 @@ Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z,
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 };
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(0, ptrsKeys_R0, KEY_R0_COUNT);
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_ShiftRegisters row_R0(0, ptrsKeys_R0, READ_PIN_COUNT_R0);

//prints a b c d u v w x
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z,
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z,
&s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z,
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x };
const uint8_t KEY_R1_COUNT = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row_ShiftRegisters row_R1(1, ptrsKeys_R1, KEY_R1_COUNT);
const uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row_ShiftRegisters row_R1(1, ptrsKeys_R1, READ_PIN_COUNT_R1);

// ################### MAIN ####################
void setup()

+ 0
- 13
src/ColPort.cpp View File

@@ -1,13 +0,0 @@
#include "ColPort.h"
uint8_t ColPort::getColPins()
{
return colPins;
}
uint8_t ColPort::getPortState()
{
//todo Keyboard.print(" portState=");
//Keyboard.print(portState);
return portState;
}

src/IOExpanderPort.h → src/IOEPort.h View File

@@ -2,19 +2,19 @@
#define IOEXPANDERPORT_H
#include <inttypes.h>
/* The pins of an IC's port can be split between RowPort, ColPort, and LED.
/* The pins of an IC's port can be split between StrobePort, ReadPort, and LED.
IOExpanderPort contains outputVal, the value of a port's output register.
outputVal is used for port manipulation by classes RowPort and LED.
One port's outputVal can be shared by one RowPort object and multiple LED objects.
IOEPort contains outputVal, the value of a port's output register.
outputVal is used for port manipulation by classes StrobePort and LED.
One port's outputVal can be shared by one StrobePort object and multiple LED objects.
IOExpanderPort is only used by I/O expander port classes.
IOEPort is only used by I/O expander port classes.
AVR port classes do not need a similar class because PORTx is global in the Arduino library.
Instantiation
------------
Example IOExpanderPort::ADDR initilization:
const uint8_t IOExpanderPort::ADDR = 0x18;
Example IOEPort::ADDR initilization:
const uint8_t IOEPort::ADDR = 0x18;
Be careful with the ADDR.
Table 6 in PCA9655E datasheet lists 8-bit versions of I2C addresses.
The Arduino Wire library uses 7-bit addresses throughout, so drop the low bit.
@@ -29,21 +29,21 @@ outputVal: For pins that are connected to active low rows, set outputVal bit to
Set all other outputVal bits to 0.
Example instantiation for port0 with active low rows on all pins:
IOExpanderPort port0(0, ~0);
IOEPort port0(0, ~0);
Example instantiation for portA with active low rows on pins 0,1,2:
IOExpanderPort portA(0, 1<<0 | 1<<1 | 1<<2 );
IOEPort portA(0, 1<<0 | 1<<1 | 1<<2 );
Example instantiation for portB with active high rows on pins 0,1,2:
IOExpanderPort portB(1, 0);
IOEPort portB(1, 0);
*/
struct IOExpanderPort
struct IOEPort
{
static const uint8_t ADDR; //I2C address
const uint8_t num; //port number
uint8_t outputVal; //bitwise value of output register
IOExpanderPort(const uint8_t portNumber, uint8_t outputVal)
IOEPort(const uint8_t portNumber, uint8_t outputVal)
: num(portNumber), outputVal(outputVal) {}
};
#endif

+ 3
- 3
src/LED_PCA9655E.h View File

@@ -4,7 +4,7 @@
#include <inttypes.h>
#include <Wire.h>
#include <LED.h>
#include "IOExpanderPort.h"
#include "IOEPort.h"
/* A LED_PCA9655E object is an PCA9655E pin that is connected to an LED indicator light.
Input/Ouput Direction configuration is set to ouput in row_Port_PCA9655E.begin() and col_Port_PCA9655E.begin().
@@ -12,12 +12,12 @@ Input/Ouput Direction configuration is set to ouput in row_Port_PCA9655E.begin()
class LED_PCA9655E: public LED
{
private:
IOExpanderPort& port;
IOEPort& port;
const uint8_t outputByteCommand; //General Purpose Input/Ouput register address
const uint8_t pin; //bitwise pin to LED
public:
LED_PCA9655E(IOExpanderPort& port, const uint8_t pin)
LED_PCA9655E(IOEPort& port, const uint8_t pin)
: port(port), outputByteCommand(port.num + 2), pin(pin) {}
virtual void on();

+ 13
- 0
src/ReadPort.cpp View File

@@ -0,0 +1,13 @@
#include "ReadPort.h"
uint8_t ReadPort::getColPins()
{
return readPins;
}
uint8_t ReadPort::getPortState()
{
//todo Keyboard.print(" portState=");
//Keyboard.print(portState);
return portState;
}

src/ColPort.h → src/ReadPort.h View File

@@ -1,19 +1,19 @@
#ifndef COLPORT_H
#define COLPORT_H
#ifndef READPORT_H
#define READPORT_H
#include <Arduino.h>
#include <inttypes.h>
/*
ColPort is an abstract base class.
ReadPort is an abstract base class.
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
*/
class ColPort
class ReadPort
{
protected:
const uint8_t colPins; //bitwise pin configuration, 1 means read column
const uint8_t readPins; //bitwise pin configuration, 1 means read column
uint8_t portState; //bitwise pin values, which is set in read()
public:
ColPort(const uint8_t colPins): colPins(colPins), portState(0) {}
ReadPort(const uint8_t readPins): readPins(readPins), portState(0) {}
//read port and store it's pins values in portState
virtual void read()=0;

src/ColPort_PCA9655E.cpp → src/ReadPort_PCA9655E.cpp View File

@@ -1,24 +1,24 @@
#include "ColPort_PCA9655E.h"
#include "ReadPort_PCA9655E.h"
/*
configures column port's configuration, input, and pins.
*/
ColPort_PCA9655E::ColPort_PCA9655E (IOExpanderPort& port, const uint8_t colPins)
: ColPort(colPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
ReadPort_PCA9655E::ReadPort_PCA9655E (IOEPort& port, const uint8_t readPins)
: ReadPort(readPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
{}
void ColPort_PCA9655E::begin()
void ReadPort_PCA9655E::begin()
{
Wire.beginTransmission(port.ADDR);
Wire.write(configurationByteCommand);
Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read)
Wire.write(readPins); //0=configure as output (for LED), 1=configure as input (for read)
Wire.endTransmission();
}
/*
Saves all port-pin values to portState.
*/
void ColPort_PCA9655E::read()
void ReadPort_PCA9655E::read()
{
Wire.beginTransmission(port.ADDR);
Wire.write(inputByteCommand); //input immediately before requestFrom

src/ColPort_PCA9655E.h → src/ReadPort_PCA9655E.h View File

@@ -1,42 +1,42 @@
#ifndef COLPORT_PCA9655E_H
#define COLPORT_PCA9655E_H
#ifndef READPORT_PCA9655E_H
#define READPORT_PCA9655E_H
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <ColPort.h>
#include "IOExpanderPort.h"
#include <ReadPort.h>
#include "IOEPort.h"
/* One PCA9655E I/O expander port connected to matrix columns.
PCA9655E does not have internal pull-up resistors (PCA9535E does).
Instantiation
------------
colPins parameter is port's bitwise pin configuration
readPins parameter is port's bitwise pin configuration
1=configure as input (for pins connected to column)
0=configure as output (for LED or not connected to a column)
Example instantiation for column port 0, with pins 2 and 3 connected to columns:
IOExpanderPort port0(0, 0);
ColPort_PCA9655E colPort0(port0, 2<<0 | 1<<3 );
IOEPort port0(0, 0);
ReadPort_PCA9655E colPort0(port0, 2<<0 | 1<<3 );
Example instantiation for column port 1, with pins 2 and 3 connected to columns:
IOExpanderPort port1(1, 0);
ColPort_PCA9655E colPort1(port1, 2<<0 | 1<<3 );
IOEPort port1(1, 0);
ReadPort_PCA9655E colPort1(port1, 2<<0 | 1<<3 );
colPins are read from pin 0 on up.
readPins are read from pin 0 on up.
Diode orientation
----------------
Rows, columns, and diode orientation are explained in Matrix.h
*/
class ColPort_PCA9655E : public ColPort
class ReadPort_PCA9655E : public ReadPort
{
private:
IOExpanderPort& port;
IOEPort& port;
const uint8_t configurationByteCommand;
const uint8_t inputByteCommand;
public:
//The constructor initialization list is in .cpp
ColPort_PCA9655E(IOExpanderPort& port, const uint8_t colPins);
ReadPort_PCA9655E(IOEPort& port, const uint8_t readPins);
void begin();
//read port and store result in portState

+ 38
- 0
src/Row.cpp View File

@@ -0,0 +1,38 @@
#include "Row.h"
/*
pressRelease() calls key's press() or release() function if it was pressed or released.
Both parameters are bitwise.
*/
void Row::pressRelease(const uint8_t READ_PIN_COUNT, const read_pins_t debouncedChanged)
{
read_pins_t isFallingEdge; //bitwise, 1 means falling edge
read_pins_t isRisingEdge; //bitwise, 1 means rising edge
read_pins_t readMask; //bitwise, active read bit is 1
uint8_t i; //index for ptrsKeys[i] array
//bit=1 if last debounced changed from 1 to 0, else bit=0
isFallingEdge = debouncedChanged & ~debounced;
//bit=1 if last debounced changed from 0 to 1, else bit=0
isRisingEdge = debouncedChanged & debounced;
for (readMask=1, i=0; i < READ_PIN_COUNT; readMask<<=1, i++) //for each key in row
{
//release before press avoids impossible key sequence
if (readMask & isFallingEdge) //if key was released
{
ptrsKeys[i]->release();
}
if (readMask & isRisingEdge) //if key was pressed
{
ptrsKeys[i]->press();
keyWasPressed();
}
}
}
void Row::keyWasPressed()
{
//empty in Row class. To unstick sticky keys, override keyWasPressed() in derived class.
}

src/RowBase.h → src/Row.h View File

@@ -1,22 +1,22 @@
#ifndef ROWBASE_H
#define ROWBASE_H
#ifndef ROW_H
#define ROW_H
#include <Arduino.h>
#include <inttypes.h>
#include <config_keybrd.h>
#include <Key.h>
/* RowBase is an abstract base class.
/* Row is an abstract base class.
*/
class RowBase
class Row
{
private:
Key *const *const ptrsKeys; //array of Key pointers
virtual void keyWasPressed();
protected:
read_pins_t debounced; //bitwise, 1 means pressed, 0 means released
void pressRelease(const uint8_t KEY_COUNT, const read_pins_t debouncedChanged);
void pressRelease(const uint8_t READ_PIN_COUNT, const read_pins_t debouncedChanged);
public:
RowBase(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { }
Row(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { }
virtual void process()=0;
};
#endif

+ 0
- 38
src/RowBase.cpp View File

@@ -1,38 +0,0 @@
#include "RowBase.h"
/*
pressRelease() calls key's press() or release() function if it was pressed or released.
Both parameters are bitwise.
*/
void RowBase::pressRelease(const uint8_t KEY_COUNT, const read_pins_t debouncedChanged)
{
read_pins_t isFallingEdge; //bitwise, 1 means falling edge
read_pins_t isRisingEdge; //bitwise, 1 means rising edge
read_pins_t rowMask; //bitwise, active col bit is 1
uint8_t col; //index for ptrsKeys[col] array
//bit=1 if last debounced changed from 1 to 0, else bit=0
isFallingEdge = debouncedChanged & ~debounced;
//bit=1 if last debounced changed from 0 to 1, else bit=0
isRisingEdge = debouncedChanged & debounced;
for (rowMask=1, col=0; col < KEY_COUNT; rowMask<<=1, col++) //for each key in row
{
//release before press avoids impossible key sequence
if (rowMask & isFallingEdge) //if key was released
{
ptrsKeys[col]->release();
}
if (rowMask & isRisingEdge) //if key was pressed
{
ptrsKeys[col]->press();
keyWasPressed();
}
}
}
void RowBase::keyWasPressed()
{
//empty in RowBase class. To unstick sticky keys, override keyWasPressed() in derived class.
}

+ 0
- 25
src/RowScanner_PinsBitwise.h View File

@@ -1,25 +0,0 @@
#ifndef ROWSCANNER_PINSBITWISE_H
#define ROWSCANNER_PINSBITWISE_H
#include <Arduino.h>
#include <inttypes.h>
#include <RowPort.h>
#include <ColPort.h>

/* RowScanner_PinsBitwise uses bit manipulation to read all pins of one port.
The maximum keys per row is 8, because ports have a maximum of 8 pins each.
*/
class RowScanner_PinsBitwise
{
private:
RowPort& refRowPort; //this row's IC port
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
ColPort& refColPort;
public:
RowScanner_PinsBitwise(RowPort &refRowPort, const uint8_t strobePin,
ColPort& refColPort)
: refRowPort(refRowPort), strobePin(strobePin),
refColPort(refColPort) {}
static const bool STROBE_ON; //logic level of strobe on, active state, HIGH or LOW
virtual ColPort* const scan();
};
#endif

+ 3
- 3
src/Row_ShiftRegisters.cpp View File

@@ -4,12 +4,12 @@ void Row_ShiftRegisters::process()
{
//these variables are all bitwise, one bit per key
read_pins_t rowState; //1 means pressed, 0 means released
uint8_t keyCount;
uint8_t readPinCount;
read_pins_t debouncedChanged; //1 means debounced changed

rowState = scanner.scan(keyCount);
rowState = scanner.scan(readPinCount);
debouncedChanged = debouncer.debounce(rowState, debounced);
pressRelease(keyCount, debouncedChanged);
pressRelease(readPinCount, debouncedChanged);
}

void Row_ShiftRegisters::begin()

+ 8
- 8
src/Row_ShiftRegisters.h View File

@@ -1,8 +1,8 @@
#ifndef ROW_SHIFTREGISTERS_H
#define ROW_SHIFTREGISTERS_H

#include <RowBase.h>
#include <RowScanner_SPIShiftRegisters.h>
#include <Row.h>
#include <Scanner_ShiftRegs74HC165.h>
#include <Debouncer_4Samples.h>
//#include <Debouncer_Not.h>

@@ -10,10 +10,10 @@

Instantiation
-------------
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
Example instantiation of a row:

const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
const unsigned int Row::DELAY_MICROSECONDS = 1000;

todo

@@ -24,15 +24,15 @@ Number of pins in colPort0 should equal number of keys in ptrsKeys_0[] array.
if a pin is missing, a key will be unresposive
if a Key pointer is missing, the keyboard will fail in an unprdictable way
*/
class Row_ShiftRegisters : public RowBase
class Row_ShiftRegisters : public Row
{
private:
RowScanner_SPIShiftRegisters scanner;
Scanner_ShiftRegs74HC165 scanner;
Debouncer_4Samples debouncer;
//Debouncer_Not debouncer; //passed test
public:
Row_ShiftRegisters(const uint8_t STROBE_PIN, Key *const ptrsKeys[], uint8_t KEY_COUNT)
: RowBase(ptrsKeys), scanner(STROBE_PIN, KEY_COUNT) { }
Row_ShiftRegisters(const uint8_t STROBE_PIN, Key *const ptrsKeys[], uint8_t READ_PIN_COUNT)
: Row(ptrsKeys), scanner(STROBE_PIN, READ_PIN_COUNT) { }
void begin();
void process();
};

+ 3
- 13
src/Row_uC.cpp View File

@@ -7,20 +7,10 @@ void Row_uC::process()
{
//these variables are all bitwise, one bit per key
read_pins_t rowState; //1 means pressed, 0 means released
uint8_t keyCount;
uint8_t readPinCount;
read_pins_t debouncedChanged; //1 means debounced changed

rowState = scanner.scan(keyCount);
/*
Keyboard.print(" keyCount=");
Keyboard.print(keyCount);
Keyboard.print(" rowState=");
Keyboard.print(rowState);
*/
rowState = scanner.scan(readPinCount);
debouncedChanged = debouncer.debounce(rowState, debounced);
/*
Keyboard.print(" debounced=");
Keyboard.print(debounced);
*/
pressRelease(keyCount, debouncedChanged);
pressRelease(readPinCount, debouncedChanged);
}

+ 18
- 18
src/Row_uC.h View File

@@ -1,40 +1,40 @@
#ifndef ROW_H
#define ROW_H
#ifndef ROW_UC_H
#define ROW_UC_H

#include <RowBase.h>
#include <RowScanner_PinsArray.h>
#include <Row.h>
#include <Scanner_uC.h>
#include <Debouncer_4Samples.h>

/* Row_uC is a row connected to a micro controller.

Instantiation
-------------
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
Example instantiation of a row:

const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
const bool RowScanner_PinsArray::STROBE_ON = LOW; //logic level of strobe on
const bool RowScanner_PinsArray::STROBE_OFF = HIGH; //logic level of strobe off
const unsigned int Row::DELAY_MICROSECONDS = 1000;
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on
const bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off

const uint8_t colPins[] = {0,1,2,3,7,8};
const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins);
const uint8_t readPins[] = {0,1,2,3,7,8};
const uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);

Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
Row_uC row_0(21, colPins, COL_PIN_COUNT, ptrsKeys_0);
Row_uC row_0(21, readPins, READ_PIN_COUNT, ptrsKeys_0);

Number of colPins should equal number of keys in ptrsKeys_0[] array.
if a colPin is missing, a key will be unresposive
Number of readPins should equal number of keys in ptrsKeys_0[] array.
if a readPins is missing, a key will be unresposive
if a Key pointer is missing, the keyboard will fail in an unprdictable way
*/
class Row_uC : public RowBase
class Row_uC : public Row
{
private:
RowScanner_PinsArray scanner;
Scanner_uC scanner;
Debouncer_4Samples debouncer;
public:
Row_uC(const uint8_t strobePin, const uint8_t readPins[],
Key *const ptrsKeys[], const uint8_t KEY_COUNT)
: RowBase(ptrsKeys), scanner(strobePin, readPins, KEY_COUNT) { }
Row_uC(const uint8_t strobePin, const uint8_t READ_PINS[],
Key *const ptrsKeys[], const uint8_t READ_PIN_COUNT)
: Row(ptrsKeys), scanner(strobePin, READ_PINS, READ_PIN_COUNT) { }
void process();
};
#endif

src/RowScanner_PinsBitwise.cpp → src/Scanner_Port.cpp View File

@@ -1,32 +1,32 @@
#include "RowScanner_PinsBitwise.h"
#include "Scanner_Port.h"
/*
Strobes the row and reads the columns.
*/
ColPort* const RowScanner_PinsBitwise::scan()
ReadPort* const Scanner_Port::scan()
{
//strobe row on
if (STROBE_ON == LOW)
{
refRowPort.setActivePinLow(strobePin);
refStrobePort.setActivePinLow(strobePin);
}
else //activeLow
{
refRowPort.setActivePinHigh(strobePin);
refStrobePort.setActivePinHigh(strobePin);
}
delayMicroseconds(3); //time to stablize voltage

//read the port pins
refColPort.read();
refReadPort.read();

//strobe row off
if (STROBE_ON == LOW)
{
refRowPort.setActivePinHigh(strobePin);
refStrobePort.setActivePinHigh(strobePin);
}
else //activeLow
{
refRowPort.setActivePinLow(strobePin);
refStrobePort.setActivePinLow(strobePin);
}
return &refColPort;
return &refReadPort;
}

+ 25
- 0
src/Scanner_Port.h View File

@@ -0,0 +1,25 @@
#ifndef SCANNER_PORT_H
#define SCANNER_PORT_H
#include <Arduino.h>
#include <inttypes.h>
#include <StrobePort.h>
#include <ReadPort.h>

/* Scanner_Port uses bit manipulation to read all pins of one port.
The maximum keys per row is 8, because ports have a maximum of 8 pins each.
*/
class Scanner_Port
{
private:
StrobePort& refStrobePort; //this row's IC port
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
ReadPort& refReadPort;
public:
Scanner_Port(StrobePort &refStrobePort, const uint8_t strobePin,
ReadPort& refReadPort)
: refStrobePort(refStrobePort), strobePin(strobePin),
refReadPort(refReadPort) {}
static const bool STROBE_ON; //logic level of strobe on, active state, HIGH or LOW
virtual ReadPort* const scan();
};
#endif

src/RowScanner_SPIShiftRegisters.cpp → src/Scanner_ShiftRegs74HC165.cpp View File

@@ -1,24 +1,24 @@
#include "RowScanner_SPIShiftRegisters.h"
#include "Scanner_ShiftRegs74HC165.h"

//constructor
RowScanner_SPIShiftRegisters::RowScanner_SPIShiftRegisters(const uint8_t STROBE_PIN, uint8_t KEY_COUNT)
: STROBE_PIN(STROBE_PIN), BYTE_COUNT(ceil (float(KEY_COUNT)/8)), KEY_COUNT(KEY_COUNT)
Scanner_ShiftRegs74HC165::Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT)
: STROBE_PIN(STROBE_PIN), BYTE_COUNT(ceil (float(READ_PIN_COUNT)/8)), READ_PIN_COUNT(READ_PIN_COUNT)
{
//configure controller to communicate with shift register matrix
pinMode(STROBE_PIN, OUTPUT);
pinMode(SHIFT_LOAD, OUTPUT);
}

void RowScanner_SPIShiftRegisters::begin()
void Scanner_ShiftRegs74HC165::begin()
{
//initialize shift register's shift/load pin
digitalWrite(SHIFT_LOAD, HIGH);
}

/*
Sets keyCount and returns rowState.
Sets readPinCount and returns rowState.
*/
read_pins_t RowScanner_SPIShiftRegisters::scan(uint8_t& keyCount)
read_pins_t Scanner_ShiftRegs74HC165::scan(uint8_t& readPinCount)
{
read_pins_t rowState = 0;

@@ -34,7 +34,7 @@ read_pins_t RowScanner_SPIShiftRegisters::scan(uint8_t& keyCount)
//strobe row off
digitalWrite(STROBE_PIN, STROBE_OFF);

keyCount = KEY_COUNT;
readPinCount = READ_PIN_COUNT;

//for testing on breadboard, clear unpowered pins
rowState &= 0b11110001000100010001000100010001; //todo

src/RowScanner_SPIShiftRegisters.h → src/Scanner_ShiftRegs74HC165.h View File

@@ -1,29 +1,29 @@
#ifndef ROWSCANNER_SPI_SHIFTREGISTERS_H
#define ROWSCANNER_SPI_SHIFTREGISTERS_H
#ifndef ROWSCANNER_SHIFTREGS74HC165_H
#define ROWSCANNER_SHIFTREGS74HC165_H
#include <Arduino.h>
#include <inttypes.h>
#include <config_keybrd.h>
#include <SPI.h>
#include <RowPort.h>
#include <ColPort.h>
#include <StrobePort.h>
#include <ReadPort.h>

/* RowScanner_SPIShiftRegisters reads shift registers.
/* Scanner_ShiftRegs74HC165 reads shift registers.
shift registers 74HC165 is Parallel-In-Serial-Out (PISO)
Upto 4 shift registers can be in a daisy chained.

In sketch:
const uint8_t RowScanner_SPIShiftRegisters::SHIFT_LOAD = 10;
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
call begin() from setup()

For active low:
const bool RowScanner_SPIShiftRegisters::STROBE_ON = LOW;
const bool RowScanner_SPIShiftRegisters::STROBE_OFF = HIGH;
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
//shift register parallel input pins have 10k pull-down resistors powered
//controller's MISO pin is connected to shift register's complementary serial output (/QH) pin

For active high:
const bool RowScanner_SPIShiftRegisters::STROBE_ON = HIGH;
const bool RowScanner_SPIShiftRegisters::STROBE_OFF = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_ON = HIGH;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = LOW;
//shift register parallel input pins have 10k pull-down resistors grounded
//controller's MISO pin is connected to shift register's serial output (QH) pin

@@ -36,7 +36,7 @@ The two parts of a split keyboard can be connected by one of:
* Ethernet cable (has 8 wires, good for 3 rows)

*/
class RowScanner_SPIShiftRegisters
class Scanner_ShiftRegs74HC165
{
private:
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin
@@ -44,10 +44,10 @@ class RowScanner_SPIShiftRegisters
static const bool STROBE_OFF; //logic level of strobe off, complement of active state
const uint8_t STROBE_PIN; //Arduino pin number connected to this row
const uint8_t BYTE_COUNT; //number of bytes to read from shift registers
uint8_t KEY_COUNT;
uint8_t READ_PIN_COUNT;
public:
RowScanner_SPIShiftRegisters(const uint8_t STROBE_PIN, uint8_t KEY_COUNT);
virtual read_pins_t scan(uint8_t& KEY_COUNT);
Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT);
virtual read_pins_t scan(uint8_t& READ_PIN_COUNT);
void begin();
};
#endif

src/RowScanner_PinsArray.cpp → src/Scanner_uC.cpp View File

@@ -1,8 +1,8 @@
#include "RowScanner_PinsArray.h"
#include "Scanner_uC.h"

/* constructor
*/
RowScanner_PinsArray::RowScanner_PinsArray(const uint8_t STROBE_PIN,
Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN,
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT)
: STROBE_PIN(STROBE_PIN), READ_PINS(READ_PINS), READ_PIN_COUNT(READ_PIN_COUNT)
{
@@ -20,7 +20,7 @@ RowScanner_PinsArray::RowScanner_PinsArray(const uint8_t STROBE_PIN,
mode = INPUT; //requires external pull-down resistor
}

//configure cols
//configure read pins
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
{
pinMode(READ_PINS[i], mode);
@@ -28,7 +28,7 @@ RowScanner_PinsArray::RowScanner_PinsArray(const uint8_t STROBE_PIN,
}

/* scan() Strobes the row and reads the columns.
Sets KEY_COUNT and returns rowState.
Sets READ_PIN_COUNT and returns rowState.

https://www.arduino.cc/en/Tutorial/DigitalPins
https://www.arduino.cc/en/Reference/PinMode
@@ -36,26 +36,28 @@ https://www.arduino.cc/en/Reference/DigitalWrite
https://www.arduino.cc/en/Reference/DigitalRead
https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT_PULLUP, and OUTPUT
*/
read_pins_t RowScanner_PinsArray::scan(uint8_t& keyCount)
read_pins_t Scanner_uC::scan(uint8_t& readPinCount)
{
read_pins_t rowState = 0; //bitwise, one col per bit, 1 means key is pressed
read_pins_t rowMask = 1; //bitwise, one col per bit, active col bit is 1
read_pins_t readMask = 1; //bitwise, one col per bit, active col bit is 1

//strobe row on
digitalWrite(STROBE_PIN, STROBE_ON);
delayMicroseconds(3); //time to stablize voltage

//read all the column pins
//read all the read pins
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
{
if ( digitalRead(READ_PINS[i]) == STROBE_ON )
{
rowState |= rowMask;
rowState |= readMask;
}
rowMask <<= 1;
readMask <<= 1;
}

//strobe row off
digitalWrite(STROBE_PIN, STROBE_OFF);

keyCount = READ_PIN_COUNT;
readPinCount = READ_PIN_COUNT;
return rowState;
}

src/RowScanner_PinsArray.h → src/Scanner_uC.h View File

@@ -1,15 +1,15 @@
#ifndef ROWSCANNER_PINSARRAY_H
#define ROWSCANNER_PINSARRAY_H
#ifndef SCANNER_UC_H
#define SCANNER_UC_H
#include <Arduino.h>
#include <inttypes.h>
#include <config_keybrd.h>
#include <RowPort.h>
#include <ColPort.h>
#include <StrobePort.h>
#include <ReadPort.h>

/* RowScanner_PinsArray class uses Arduino pin numbers (not port pin numbers).
Constructor is in RowScanner_PinsArray.cpp
/* Scanner_uC class uses Arduino pin numbers (not port pin numbers).
Constructor is in Scanner_uC.cpp
*/
class RowScanner_PinsArray
class Scanner_uC
{
private:
static const bool STROBE_ON; //logic level of strobe on, HIGH or LOW
@@ -18,9 +18,9 @@ class RowScanner_PinsArray
const uint8_t* const READ_PINS; //array of read pin numbers
const uint8_t READ_PIN_COUNT; //number of read pins
public:
RowScanner_PinsArray(const uint8_t STROBE_PIN,
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT); //todo rename READ_PIN_COUNT to KEY_COUNT ??
virtual read_pins_t scan(uint8_t& KEY_COUNT);
Scanner_uC(const uint8_t STROBE_PIN,
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT); //todo rename READ_PIN_COUNT to READ_PIN_COUNT ??
virtual read_pins_t scan(uint8_t& READ_PIN_COUNT);
};
#endif


src/RowPort.h → src/StrobePort.h View File

@@ -1,13 +1,13 @@
#ifndef ROWPORT_H
#define ROWPORT_H
#ifndef STROBEPORT_H
#define STROBEPORT_H
#include <Arduino.h>
#include <inttypes.h>
/*
RowPort is an abstract base class.
StrobePort is an abstract base class.
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
*/
class RowPort
class StrobePort
{
public:
virtual void setActivePinHigh(const uint8_t activePin)=0;

src/RowPort_PCA9655E.cpp → src/StrobePort_PCA9655E.cpp View File

@@ -1,12 +1,12 @@
#include "RowPort_PCA9655E.h"
#include "StrobePort_PCA9655E.h"
/*
configures column port's configuration and output.
*/
RowPort_PCA9655E::RowPort_PCA9655E(IOExpanderPort& port)
StrobePort_PCA9655E::StrobePort_PCA9655E(IOEPort& port)
: port(port), configurationByteCommand(port.num + 6), outputByteCommand(port.num + 2) {}
void RowPort_PCA9655E::begin()
void StrobePort_PCA9655E::begin()
{
Wire.beginTransmission(port.ADDR);
Wire.write(configurationByteCommand);
@@ -18,7 +18,7 @@ void RowPort_PCA9655E::begin()
sets activePin pin output to low, does not reset the other pins because they might be used by LEDs.
activePin is port mask, where active pin is 1.
*/
void RowPort_PCA9655E::setActivePinLow(const uint8_t activePin)
void StrobePort_PCA9655E::setActivePinLow(const uint8_t activePin)
{
Wire.beginTransmission(port.ADDR);
Wire.write(outputByteCommand);
@@ -30,7 +30,7 @@ void RowPort_PCA9655E::setActivePinLow(const uint8_t activePin)
sets activePin pin output to high.
activePin is port mask, where active pin is 1.
*/
void RowPort_PCA9655E::setActivePinHigh(const uint8_t activePin)
void StrobePort_PCA9655E::setActivePinHigh(const uint8_t activePin)
{
Wire.beginTransmission(port.ADDR);
Wire.write(outputByteCommand);

src/RowPort_PCA9655E.h → src/StrobePort_PCA9655E.h View File

@@ -1,10 +1,10 @@
#ifndef ROWPORT_PCA9655E_H
#define ROWPORT_PCA9655E_H
#ifndef STROBEPORT_PCA9655E_H
#define STROBEPORT_PCA9655E_H
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <RowPort.h>
#include "IOExpanderPort.h"
#include <StrobePort.h>
#include "IOEPort.h"
/* One PCA9655E I/O expander port connected to matrix rows.
@@ -14,12 +14,12 @@ This should normally be called only once.
Instantiation
------------
Example instantiation for row port 0:
IOExpanderPort port0(0, 0);
RowPort_PCA9655E rowPort0(port0);
IOEPort port0(0, 0);
StrobePort_PCA9655E rowPort0(port0);
Example instantiation for row port 1:
IOExpanderPort port1(1, 0);
RowPort_PCA9655E rowPort1(port1);
IOEPort port1(1, 0);
StrobePort_PCA9655E rowPort1(port1);
Diode orientation
----------------
@@ -32,16 +32,16 @@ PCA9655E data sheet
http://www.onsemi.com/pub_link/Collateral/PCA9655E-D.PDF
*/
class RowPort_PCA9655E : public RowPort
class StrobePort_PCA9655E : public StrobePort
{
private:
IOExpanderPort& port;
IOEPort& port;
const uint8_t configurationByteCommand;
const uint8_t outputByteCommand;
public:
//The constructor initialization list is in .cpp
RowPort_PCA9655E(IOExpanderPort& port);
StrobePort_PCA9655E(IOEPort& port);
void begin();
virtual void setActivePinLow(const uint8_t activePin); //activePin is a port mask

+ 3
- 3
src/config_keybrd.h View File

@@ -9,9 +9,9 @@ Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
*/

/* Uncomment a typedef read_pins_t size that covers all col pins of all RowScanner objects i.e.
For RowScanner_PinsArray, RowScanner_PinsArray::READ_PIN_COUNT
For RowScanner_SPIShiftRegisters, RowScanner_SPIShiftRegisters::KEY_COUNT
For RowScanner_PinsBitwise, cover the last 1 bit in RowScanner_PinsBitwise::strobePin
For Scanner_uC, Scanner_uC::READ_PIN_COUNT
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::READ_PIN_COUNT
For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin
*/
//typedef uint8_t read_pins_t;
//typedef uint16_t read_pins_t;