KeyboardManager: a class to manage the polling of a switch-matrix keyboard

Dependents:   KeyboardTest

Committer:
osmeest
Date:
Wed Jan 19 23:05:30 2011 +0000
Revision:
1:a74ffceb67e5
Parent:
0:f813c207f78f
Child:
2:eb4cc53ff33d
Remove debug messages from lib. Make polling frequency configurable.
Add parameter checking (constructor).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
osmeest 0:f813c207f78f 1 #include "KeyboardManager.h"
osmeest 1:a74ffceb67e5 2 #include <algorithm>
osmeest 1:a74ffceb67e5 3 #include <stdexcept>
osmeest 0:f813c207f78f 4
osmeest 0:f813c207f78f 5 enum {
osmeest 0:f813c207f78f 6 InPortShift = 15,
osmeest 0:f813c207f78f 7 OutPortShift = 6
osmeest 0:f813c207f78f 8 };
osmeest 0:f813c207f78f 9
osmeest 0:f813c207f78f 10 KeyboardManager::KeyboardManager(
osmeest 0:f813c207f78f 11 PortName inPort, int inLowestBit, PortName outPort, int outLowestBit,
osmeest 1:a74ffceb67e5 12 KeyEventHandler handler, float pollingPeriod) :
osmeest 0:f813c207f78f 13 handler(handler),
osmeest 0:f813c207f78f 14 in(inPort, 0x0f << inLowestBit), inBitShift(inLowestBit),
osmeest 0:f813c207f78f 15 out(outPort, 0x0f << outLowestBit), outBitShift(outLowestBit),
osmeest 1:a74ffceb67e5 16 ticker(), pollingPeriod(std::max<float>(pollingPeriod, 0.000020)),
osmeest 1:a74ffceb67e5 17 scanRow(0), currentState(0), lastState(0), lastReportedState(0)
osmeest 0:f813c207f78f 18 {
osmeest 1:a74ffceb67e5 19 if (inPort == outPort) {
osmeest 1:a74ffceb67e5 20 int inMask = 0x0f << inLowestBit,
osmeest 1:a74ffceb67e5 21 outMask = 0x0f << outLowestBit;
osmeest 1:a74ffceb67e5 22 if (inMask & outMask) {
osmeest 1:a74ffceb67e5 23 printf("KeyboardManager: ERROR: Input and output bits are overlapping.");
osmeest 1:a74ffceb67e5 24 }
osmeest 1:a74ffceb67e5 25 }
osmeest 0:f813c207f78f 26 }
osmeest 0:f813c207f78f 27
osmeest 0:f813c207f78f 28 void KeyboardManager::start()
osmeest 0:f813c207f78f 29 {
osmeest 0:f813c207f78f 30 this->in.mode(PullDown);
osmeest 1:a74ffceb67e5 31 this->ticker.attach(this, &KeyboardManager::timerHandler, this->pollingPeriod);
osmeest 0:f813c207f78f 32 }
osmeest 0:f813c207f78f 33
osmeest 0:f813c207f78f 34 void KeyboardManager::stop()
osmeest 0:f813c207f78f 35 {
osmeest 0:f813c207f78f 36 this->ticker.detach();
osmeest 0:f813c207f78f 37 this->in.mode(OpenDrain);
osmeest 0:f813c207f78f 38 }
osmeest 0:f813c207f78f 39
osmeest 0:f813c207f78f 40 namespace {
osmeest 0:f813c207f78f 41 bool isSingleKey(int state) {
osmeest 0:f813c207f78f 42 if (state == 0) {
osmeest 0:f813c207f78f 43 return false;
osmeest 0:f813c207f78f 44 }
osmeest 0:f813c207f78f 45
osmeest 0:f813c207f78f 46 return (state == (state & (-state)));
osmeest 0:f813c207f78f 47 }
osmeest 0:f813c207f78f 48
osmeest 0:f813c207f78f 49 int getKeyId(int state) {
osmeest 0:f813c207f78f 50 if (state == 0) {
osmeest 0:f813c207f78f 51 return 0;
osmeest 0:f813c207f78f 52 }
osmeest 0:f813c207f78f 53
osmeest 0:f813c207f78f 54 int key = 1;
osmeest 0:f813c207f78f 55 while ((state & 1) == 0) {
osmeest 0:f813c207f78f 56 key++;
osmeest 0:f813c207f78f 57 state >>= 1;
osmeest 0:f813c207f78f 58 }
osmeest 0:f813c207f78f 59 return key;
osmeest 0:f813c207f78f 60 }
osmeest 0:f813c207f78f 61 }
osmeest 0:f813c207f78f 62
osmeest 0:f813c207f78f 63 void KeyboardManager::timerHandler()
osmeest 0:f813c207f78f 64 {
osmeest 0:f813c207f78f 65 unsigned r = 1 << (this->scanRow + this->outBitShift);
osmeest 0:f813c207f78f 66 out.write(r);
osmeest 0:f813c207f78f 67 wait_us(10);
osmeest 0:f813c207f78f 68 unsigned v = in.read() >> this->inBitShift;
osmeest 1:a74ffceb67e5 69 this->currentState |= v << (4 * this->scanRow);
osmeest 0:f813c207f78f 70 this->scanRow = (this->scanRow + 1) & 3;
osmeest 0:f813c207f78f 71
osmeest 0:f813c207f78f 72 if (this->scanRow == 0) {
osmeest 0:f813c207f78f 73 if (this->currentState != this->lastState) {
osmeest 0:f813c207f78f 74 if (isSingleKey(this->currentState) && this->lastReportedState == 0)
osmeest 0:f813c207f78f 75 {
osmeest 0:f813c207f78f 76 int key = getKeyId(this->currentState);
osmeest 0:f813c207f78f 77
osmeest 0:f813c207f78f 78 if (this->handler) {
osmeest 0:f813c207f78f 79 this->handler(key, true);
osmeest 0:f813c207f78f 80 }
osmeest 1:a74ffceb67e5 81
osmeest 0:f813c207f78f 82 this->lastReportedState = this->currentState;
osmeest 0:f813c207f78f 83 }
osmeest 0:f813c207f78f 84 else if (this->lastReportedState != 0 &&
osmeest 0:f813c207f78f 85 (this->currentState & this->lastReportedState) == 0)
osmeest 0:f813c207f78f 86 {
osmeest 0:f813c207f78f 87 int key = getKeyId(this->lastReportedState);
osmeest 0:f813c207f78f 88
osmeest 0:f813c207f78f 89 if (this->handler) {
osmeest 0:f813c207f78f 90 this->handler(key, false);
osmeest 0:f813c207f78f 91 }
osmeest 1:a74ffceb67e5 92
osmeest 0:f813c207f78f 93 this->lastReportedState = 0;
osmeest 0:f813c207f78f 94 }
osmeest 0:f813c207f78f 95
osmeest 0:f813c207f78f 96 this->lastState = this->currentState;
osmeest 0:f813c207f78f 97 }
osmeest 0:f813c207f78f 98
osmeest 0:f813c207f78f 99 this->currentState = 0;
osmeest 0:f813c207f78f 100 }
osmeest 0:f813c207f78f 101 }