@@ -7,6 +7,25 @@ keybrd version 1.0.0 will be released when the public API is stable. | |||
## [Unreleased][unreleased] | |||
## [0.3.2] - 2016-06-10 | |||
### Changed | |||
* Changed uC from scanning port arrays to scanning Arduino pins. | |||
Thereby added support for Arduino boards, Teensy 3, and Teensy LC micro controllers. | |||
* Changed IOE from scanning port arrays to scanning single ports. | |||
* Moved scanner and debouncer into their own classes. | |||
### Added | |||
* Row_uC | |||
* Row_IOE | |||
* RowScannerInterface | |||
* RowScanner_PinsArray | |||
* RowScanner_PinsBitwise | |||
* DebouncerInterface | |||
* Debouncer_4Samples | |||
### Removed | |||
* Port arrays | |||
## [0.3.1] - 2016-06-02 | |||
### Added | |||
* RowBase class |
@@ -8,8 +8,8 @@ The most common reason for new classes are: | |||
## Who this guide is for | |||
This guide is for the maintainers and developers of the keybrd library and it's extensions. | |||
It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, aggregation, inheritance, polymorphism, and enum. | |||
Some classes use bit manipulation. | |||
It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. | |||
Debouncer and I/O expander use bit manipulation. | |||
## Class inheritance diagrams | |||
@@ -17,9 +17,14 @@ Keybrd library class inheritance diagram | |||
``` | |||
Matrix | |||
RowBase | |||
| | |||
Row | |||
RowBase | |||
/ \ | |||
Row_uC Row_IOE | |||
RowScannerInterface | |||
/ \ | |||
RowScanner_PinsArray RowScanner_PinsBitwise | |||
IOExpanderPort | |||
@@ -36,8 +41,13 @@ Keybrd library class inheritance diagram | |||
LED_AVR LED_MCP23018 LED_PCA9655E (one LED class for each type of IC) | |||
DebouncerInterface | |||
| | |||
Debouncer_4Samples | |||
LayerStateInterface | |||
| | |||
| | |||
LayerState | |||
@@ -66,32 +76,70 @@ Keybrd library class inheritance diagram | |||
## Dependency diagrams | |||
single-layer dependency diagram with LEDs | |||
Example single-layer dependency diagram with LEDs | |||
``` | |||
matrix[1..*] | |||
| | |||
row[1..*]_____________________________ | |||
| \ \ \ | |||
rowPort[1] rowPin[1] colPort[1] keys[1] | |||
| | | |||
colPins[1..*] code[1..*] | |||
| | |||
LED[1] | |||
``` | |||
multi-layer dependency diagram with LEDs and I/O Expander | |||
``` | |||
matrix[1..*] | |||
| layerStates[1..*] | |||
row[1..*]_________________________________________/__ | \ | |||
| \ \ \ / \ | \ | |||
rowPort[1] rowPin[1] colPort[1] keys[1] / code_layer[1..*] LED[0..*] | |||
\ / \ | / / | |||
\ / colPins[1..*] key[1..*] / | |||
\ / | / | |||
\ / code[1..*] / | |||
\ / ______________________________________/ | |||
matrix[1..*] | |||
| | |||
___ row_uC[1..*] ________ | |||
/ \ \ | |||
RowScanner_PinsArray debouncer keys[1..*] | |||
/ \ | | |||
strobePin[1] readPins[1..*] code[1..*] | |||
| | |||
LED[1] | |||
``` | |||
Example single-layer dependency diagram I/O Expander | |||
``` | |||
________ row_uC[1..*] _________ | |||
/ \ \ | |||
RowScanner_PinsArray[1] debouncer[1] keys[1..*] | |||
/ \ | | |||
strobePin[1] readPins[1..*] code[1..*] | |||
___ row_IOE[1..*] _________ | |||
/ \ \ | |||
RowScanner_PinsBitwise[1] debouncer[1] keys[1..*] | |||
/ | \ | | |||
rowPort[1] rowPin[1] colPort[1] code[1..*] | |||
\ / \ | |||
\ / colPins[1..*] | |||
\ / | |||
IOExpanderPort[0..*] | |||
``` | |||
Example multi-layer dependency diagram with layer LEDs | |||
``` | |||
layerStates[1..*] | |||
________ row_uC[1..*] _____________________/__ | \ | |||
/ \ \ / \ | \ | |||
RowScanner_PinsArray[1] debouncer[1] keys[1..*] / code_layer[1..*] LED[0..*] | |||
/ \ | / | |||
strobePin[1] readPins[1..*] code[1..*] | |||
``` | |||
Example multi-layer dependency diagram with I/O Expander | |||
``` | |||
________ row_uC[1..*] ________________________ _______layerStates[1..*] | |||
/ \ \ \ / | | |||
RowScanner_PinsArray[1] debouncer[1] keys[1..*] code_layer[1..*] | | |||
/ \ | ________________________| | |||
strobePin[1] readPins[1..*] code[1..*] | | |||
| | |||
| | |||
___ row_IOE[1..*] _________ __________| | |||
/ \ \ / | | |||
RowScanner_PinsBitwise[1] debouncer[1] keys[1..*] code_layer[1..*] | | |||
/ | \ | _____________________| | |||
rowPort[1] rowPin[1] colPort[1] code[1..*] | |||
\ / \ | |||
\ / colPins[1..*] | |||
\ / | |||
IOExpanderPort[0..*] | |||
``` | |||
@@ -162,29 +210,25 @@ Following the style guide makes it easier for the next programmer to understand | |||
## Trace of keybrd scan | |||
Arduino does not have a debugger. | |||
So here is the next best thing; a list of functions in the order that they are called. | |||
The trace is of a single-layer keybrd scan (no LEDs and no I/O expander). | |||
Refer to it like a table of contents while reading the keybrd library. | |||
``` | |||
Matrix::scan() for each row | |||
Row::process() | |||
Row::wait() | |||
Row::scan() | |||
RowPort_*::setActivePin*() strobe row on | |||
for each col port | |||
ColPort_*::read() read col port | |||
RowPort_*::setActivePin*() strobe row off | |||
Row::getRowState() for each col port | |||
for each connected col pin | |||
if key is pressed | |||
Matrix::scan() for each row | |||
RowBase::process() | |||
RowBase::wait() delay time for debounce | |||
RowScanner_PinsArray::scan() strobe row on | |||
for each readPin | |||
set rowState bit | |||
Row::debounce() debounce | |||
Row::pressRelease() for each key in row | |||
if falling edge | |||
Key_*::release() scanCode->release() | |||
Code_*::release() Keyboard.release(scancode) | |||
if rising edge | |||
Key_*::press() scanCode->press() | |||
Code_*::press() Keyboard.press(scancode) | |||
strobe row off | |||
Debouncer_4Samples::debounce() debounce | |||
RowBase::pressRelease() for each key in row | |||
if falling edge | |||
Key_*::release() scanCode->release() | |||
Code_*::release() Keyboard.release(scancode) | |||
if rising edge | |||
Key_*::press() scanCode->press() | |||
Code_*::press() Keyboard.press(scancode) | |||
``` | |||
## The Arduino libraries |
@@ -2,19 +2,19 @@ planned_features is a view of where the keybrd project is headed. | |||
Top priority | |||
============ | |||
Redesign elements of debouncer. | |||
Add support for shift registers, for compact split keyboards up to 32 keys per matrix. | |||
Med priority | |||
============ | |||
Add support for Teensy LC micro controller | |||
Add 16x16 matrix capability (currently limited to 8x8 matrices) | |||
Low priority | |||
============ | |||
Add matrix-to-layout mapping array (to decouple matrix from layout) | |||
Change tutorial sketches from teensy 2.0 and PCA9655E-D IOE to Teensy LC and MCP23018 IOE | |||
Update tutorials: | |||
* Currently tutorial sketches are obsolete and won't compile | |||
* Change tutorial sketches from teensy 2.0 and PCA9655E-D IOE to Teensy LC and MCP23018 IOE | |||
Add more tutorials: | |||
* tutorial_5_LEDs.md |
@@ -24,7 +24,7 @@ For fastest response time, wait() should be placed before scan() or after pressR | |||
A keyboard with a faster scan rate responds faster. | |||
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT: | |||
Initialize DELAY_MICROSECONDS in your sketch: | |||
const unsigned int Row::DELAY_MICROSECONDS = 1000; | |||
const unsigned int RowBase::DELAY_MICROSECONDS = 1000; | |||
Add this to the sketch's loop() function: | |||
debug.print_microseconds_per_scan(); | |||
Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second. | |||
@@ -42,12 +42,7 @@ Avoid sampling the switch input at a rate synchronous to events in the environme | |||
The largest allowable DELAY_MICROSECONDS is 65535 (.065535 seconds). | |||
Polling I2C may slow the scan rate enough so that no additional delay is needed: | |||
const unsigned int Row::DELAY_MICROSECONDS = 0; | |||
Slow-scan trick for debug messages that print too fast and not aligned, add this to sketch loop(): | |||
delay(500); | |||
Keyboard.println(F("")); | |||
That way debug messages are printed at a managable rate, and each scan starts a new line. | |||
const unsigned int RowBase::DELAY_MICROSECONDS = 0; | |||
*/ | |||
void RowBase::wait() | |||
{ |
@@ -5,9 +5,6 @@ | |||
#include <Key.h> | |||
/* RowBase is an abstract base class. | |||
Define and initilize DELAY_MICROSECONDS in sketch. | |||
const unsigned int RowBase::DELAY_MICROSECONDS = 0; | |||
*/ | |||
class RowBase | |||
{ |
@@ -1,11 +1,6 @@ | |||
#ifndef ROWSCANNERINTERFACE_H | |||
#define ROWSCANNERINTERFACE_H | |||
/* RowScannerInterface is an interface class. | |||
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. | |||
*/ | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
@@ -1,7 +1,7 @@ | |||
#include "RowScanner_PinsBitwise.h" | |||
/* | |||
Strobes the row and reads the columns. | |||
Strobe is on for shortest possible time to preserve IR LED on DodoHand's optic switch. | |||
Sets rowEnd and returns rowState. | |||
*/ | |||
uint8_t RowScanner_PinsBitwise::scan(uint16_t& rowEnd) | |||
{ | |||
@@ -16,13 +16,9 @@ uint8_t RowScanner_PinsBitwise::scan(uint16_t& rowEnd) | |||
} | |||
delayMicroseconds(3); //time to stablize voltage | |||
//read all the port pins | |||
//read the port pins | |||
refColPort.read(); | |||
/* shows strobing pin 1 and 2, but realy stobing 0 and 1 todo | |||
Keyboard.print(F(" strobePin=")); | |||
Keyboard.print(strobePin); | |||
Keyboard.print(F(", ")); | |||
*/ | |||
//strobe row off | |||
if (activeHigh) | |||
{ |
@@ -5,14 +5,29 @@ | |||
#include <RowScanner_PinsBitwise.h> | |||
#include <Debouncer_4Samples.h> | |||
/* | |||
Simlar to Row but using RowScanner_PinsBitwise. | |||
/* Row_DH_IOE is a row connected to an Input/Output Expander. | |||
Configuration | |||
------------- | |||
Define and initilize DELAY_MICROSECONDS in sketch. Detailed how to is in RowBase.cpp. | |||
Instantiation | |||
------------- | |||
Example instantiation of a row: | |||
const uint8_t IOExpanderPort::ADDR = 0x18; | |||
IOExpanderPort port1(1, 0); | |||
RowPort_PCA9655E rowPort1(port1); | |||
IOExpanderPort port0(0, 0); | |||
ColPort_PCA9655E colPort0(port0, 1<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 ); | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | |||
Row_IOE row_0(rowPort1, 1<<0, colPort0, ptrsKeys_0); | |||
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_IOE : public RowBase | |||
{ |
@@ -5,13 +5,24 @@ | |||
#include <RowScanner_PinsArray.h> | |||
#include <Debouncer_4Samples.h> | |||
/* | |||
/* Row_uC is a row connected to a micro controller. | |||
Configuration | |||
------------- | |||
Define and initilize DELAY_MICROSECONDS in sketch. Detailed how to is in RowBase.cpp. | |||
Instantiation | |||
------------- | |||
todo - see RowDH | |||
Example instantiation of a row: | |||
const uint8_t colPins[] = {0,1,2,3,7,8}; | |||
const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins); | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | |||
Row_DH_uC row_0(21, colPins, COL_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 | |||
if a Key pointer is missing, the keyboard will fail in an unprdictable way | |||
*/ | |||
class Row_uC : public RowBase | |||
{ |
@@ -19,7 +19,7 @@ The tutorials assume the reader: | |||
* is new to Arduino, firmware, controllers, and the internal workings of keyboards | |||
<!-- todo --> | |||
> All the tutorial sketches are tested on teensy 2.0 and PCA9655E-D I/O expander | |||
> Most of the tutorial sketches are obsolete and will not compile. Will be updated soon. | |||
> The tutorial sketches will be changed to Teensy LC and MCP23018 I/O expander | |||