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

Dependents:   KeyboardTest

KeyboardManager.cpp

Committer:
osmeest
Date:
2011-01-19
Revision:
0:f813c207f78f
Child:
1:a74ffceb67e5

File content as of revision 0:f813c207f78f:

#include "KeyboardManager.h"

enum {
    InPortShift = 15,
    OutPortShift = 6
};

KeyboardManager::KeyboardManager(
        PortName inPort, int inLowestBit, PortName outPort, int outLowestBit, 
        KeyEventHandler handler) :
    handler(handler),
    in(inPort, 0x0f << inLowestBit), inBitShift(inLowestBit),
    out(outPort, 0x0f << outLowestBit), outBitShift(outLowestBit),
    ticker(), scanRow(0), currentState(0), lastState(0), lastReportedState(0)
{
}

void KeyboardManager::start()
{
    printf("Starting KeyboardManager...\r\n");
    this->in.mode(PullDown); 
    this->ticker.attach(this, &KeyboardManager::timerHandler, 0.01);
}

void KeyboardManager::stop()
{
    printf("Stopping KeyboardManager...\r\n");
    this->ticker.detach();
    this->in.mode(OpenDrain); 
}
   
namespace {
    bool isSingleKey(int state) {
        if (state == 0) {
            return false;
        }
        
        return (state == (state & (-state)));
    }
    
    int getKeyId(int state) {
        if (state == 0) {
            return 0;
        }
        
        int key = 1;
        while ((state & 1) == 0) {
            key++;
            state >>= 1;
        }
        return key;
    }
}

void KeyboardManager::timerHandler()
{
    unsigned r = 1 << (this->scanRow + this->outBitShift);
    out.write(r);
    wait_us(10);
    unsigned v = in.read() >> this->inBitShift;
    this->currentState |= (v & 0x0f) << (4 * this->scanRow);
    this->scanRow = (this->scanRow + 1) & 3;

    if (this->scanRow == 0) {
        if (this->currentState != this->lastState) {
            if (isSingleKey(this->currentState) && this->lastReportedState == 0) 
            {
                int key = getKeyId(this->currentState);
                
                printf("Key pressed: %d (%04x)\r\n", key, this->currentState);
                
                if (this->handler) {
                    this->handler(key, true);
                }
                this->lastReportedState = this->currentState;
            }
            else if (this->lastReportedState != 0 &&
                     (this->currentState & this->lastReportedState) == 0)
            {
                int key = getKeyId(this->lastReportedState);
                
                printf("Key released: %d (%04x | %04x)\r\n", 
                    key, this->currentState, this->lastReportedState); 
                               
                if (this->handler) {
                    this->handler(key, false);
                }
                this->lastReportedState = 0;
            }
            
            this->lastState = this->currentState;
        }
        
        this->currentState = 0;
    }
}