A DTMF sequence editor and player for HAM radio equipment command & control.

Dependencies:   mbed ExtTextLCD

Files at this revision

API Documentation at this revision

Comitter:
osmeest
Date:
Mon Mar 07 22:51:19 2011 +0000
Commit message:

Changed in this revision

ExtTextLCD.lib Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/KeyMapper.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/KeyboardMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/KeyboardState.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/KeyboardStateChangeMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/LongKeyPressMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/SingleKeyPressMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyMapper.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyPressEventHandler.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyPressEventServer.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardEventServer.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardManager.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardMonitor.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardState.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardStateChangeMonitor.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardStateEventServer.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/KeyboardStateHandler.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/LongKeyPressMonitor.h Show annotated file Show diff for this revision Revisions of this file
KeyboardManager/kbd_mgr/SingleKeyPressMonitor.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/SineWave.cpp Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/SoundWaveGenerator.cpp Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/TriangleWave.cpp Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/WaveBuffer.cpp Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/WaveCombo.cpp Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/BufferedWave.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/SineWave.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/SoundWaveGenerator.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/TriangleWave.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/Wave.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/WaveBuffer.h Show annotated file Show diff for this revision Revisions of this file
SoundWaveGenerator/snd_wave_generator/WaveCombo.h Show annotated file Show diff for this revision Revisions of this file
command_state.cpp Show annotated file Show diff for this revision Revisions of this file
display_manager.hpp Show annotated file Show diff for this revision Revisions of this file
dtmf_generator.hpp Show annotated file Show diff for this revision Revisions of this file
edit_state.cpp Show annotated file Show diff for this revision Revisions of this file
init_state.cpp Show annotated file Show diff for this revision Revisions of this file
interactive_state.cpp Show annotated file Show diff for this revision Revisions of this file
key_handler.hpp Show annotated file Show diff for this revision Revisions of this file
keyboard_manager.hpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbed_display_manager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed_display_manager.hpp Show annotated file Show diff for this revision Revisions of this file
mbed_dtmf_generator.cpp Show annotated file Show diff for this revision Revisions of this file
mbed_dtmf_generator.hpp Show annotated file Show diff for this revision Revisions of this file
mbed_keyboard_manager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed_keyboard_manager.hpp Show annotated file Show diff for this revision Revisions of this file
sending_state.cpp Show annotated file Show diff for this revision Revisions of this file
state.hpp Show annotated file Show diff for this revision Revisions of this file
state_base.cpp Show annotated file Show diff for this revision Revisions of this file
system.cpp Show annotated file Show diff for this revision Revisions of this file
system.hpp Show annotated file Show diff for this revision Revisions of this file
system_states.hpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ExtTextLCD.lib	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/osmeest/code/ExtTextLCD/#2773889d6143
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/KeyMapper.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,57 @@
+#include "kbd_mgr/KeyMapper.h"
+#include <algorithm>
+#include <functional>
+
+namespace kbd_mgr {
+
+void KeyMap::addMapping(KeyEvent::EventType event, int key, char ch)
+{
+    const KeyMapping *mapping = getMapping(event, key);
+    if (mapping) {
+        KeyMapping *updatable = const_cast<KeyMapping*>(mapping);
+        updatable->ch = ch;
+    }
+    else {
+        KeyMapping o(event, key, ch);
+        this->map_.push_back(o);
+    }
+}
+
+void KeyMap::addMappings(KeyEvent::EventType event, const std::string &str)
+{
+    for(int key = 0; key < str.size(); ++key) {
+        addMapping(event, key, str[key]);
+    }
+}
+
+char KeyMap::map(KeyEvent::EventType event, int key) const
+{
+    const KeyMapping *mapping = getMapping(event, key);
+    if (!mapping) {
+        mapping = getMapping(KeyEvent::NoEvent, key);
+    }
+    return (mapping ? mapping->ch : '\0');
+}
+
+const KeyMap::KeyMapping * KeyMap::getMapping(KeyEvent::EventType event, int key) const
+{
+    std::pair<KeyEvent::EventType, int> criteria = std::make_pair(event, key);
+    Map::const_iterator p = this->map_.begin();
+    while (p != this->map_.end() && !p->matches(criteria)) {
+        ++p;
+    }
+    
+    if (p == this->map_.end()) {
+        return NULL;
+    }
+    return &(*p);
+}
+
+void KeyMapper::handleKeyPress(const KeyEvent &keypress)
+{
+    char ch = map(keypress.event, keypress.keyCode);
+    KeyEvent mapped(keypress, ch);
+    invokeHandler(mapped);
+}
+
+} // kbd_mgr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/KeyboardMonitor.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,55 @@
+#include "kbd_mgr/KeyboardMonitor.h"
+
+namespace kbd_mgr {
+
+KeyboardMonitor::KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, 
+            const KeyboardMonitor::OutPinsSet &outPins) :
+    in(inPort, ((1 << numKeysPerRow)-1) << inLowestBit), inBitShift(inLowestBit), outPins(outPins),
+    ticker(), scanRow(0), currentState(outPins.size(), numKeysPerRow)
+{ }
+
+KeyboardMonitor::~KeyboardMonitor()
+{
+    stop();
+}
+    
+void KeyboardMonitor::start(float pollingPeriod)
+{   
+    if (this->outPins.empty()) {
+        return;
+    }
+    
+    if (pollingPeriod < 20e-6) {
+        pollingPeriod = 20e-6;
+    }
+    
+    for(OutPinsSet::const_iterator p = this->outPins.begin(); p != this->outPins.end(); ++p) {
+        DigitalOut out(*p);
+        out.write( p == this->outPins.begin() ? 1 : 0 );
+    }
+    this->in.mode(PullDown);
+    this->scanRow = 0; 
+    this->ticker.attach(this, &KeyboardMonitor::timerHandler, pollingPeriod);
+}
+
+void KeyboardMonitor::stop()
+{
+    this->ticker.detach();
+    this->in.mode(OpenDrain);
+}
+
+void KeyboardMonitor::timerHandler()
+{
+    DigitalOut out(this->outPins[this->scanRow]);
+    out.write(1);
+    wait_us(10);
+    int v = (this->in.read() >> this->inBitShift);
+    out.write(0);
+    this->currentState.setRowState(this->scanRow, v);
+    this->scanRow = (this->scanRow + 1) % this->currentState.getNumRows();
+    if (this->scanRow == 0) {
+        invokeHandler(this->currentState);
+    }    
+}
+
+} // kbd_mgr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/KeyboardState.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,170 @@
+#include "kbd_mgr/KeyboardState.h"
+
+#include <algorithm>
+#include <iomanip>
+
+namespace kbd_mgr {
+
+KeyboardState::KeyboardState() :
+    numRows(0), numKeysPerRow(0), rowMask(0), numRowsPerWord(0), numKeysPerWord(0), numWords(0), data(0)
+{ }
+
+KeyboardState::KeyboardState(std::size_t numRows, std::size_t numKeysPerRow) :
+    numRows(numRows), numKeysPerRow(numKeysPerRow), rowMask((1 << numKeysPerRow) -1),
+    numRowsPerWord((sizeof(int) * 8) / numKeysPerRow), numKeysPerWord(numRowsPerWord * numKeysPerRow),
+    numWords((numRows + (numRowsPerWord-1)) / numRowsPerWord),
+    data(numWords, 0)
+{ }
+
+void KeyboardState::clear() {
+    std::fill(this->data.begin(), this->data.end(), 0);
+}
+
+int KeyboardState::getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const
+{
+    std::size_t rowInWord = row % numRowsPerWord;
+    wordIndex = row / numRowsPerWord;
+    rowShift = numKeysPerRow * rowInWord;
+    rowMask = this->rowMask << rowShift;
+    
+    return this->data[wordIndex];
+}
+
+void KeyboardState::setRowState(std::size_t row, int rowState) {
+    std::size_t wordIndex;
+    std::size_t rowShift;
+    int rowMask;
+    int v = getRowInfo(row, wordIndex, rowShift, rowMask);
+    v = (v & ~rowMask) | ((rowState & this->rowMask) << rowShift);
+    this->data[wordIndex] = v;
+}
+
+int KeyboardState::getRowState(std::size_t row) const {
+    std::size_t wordIndex;
+    std::size_t rowShift;
+    int rowMask;
+    int v = getRowInfo(row, wordIndex, rowShift, rowMask);
+    return (v & rowMask) >> rowShift;
+}
+    
+bool KeyboardState::getKeyState(std::size_t key) const {
+    std::size_t row = key / this->numKeysPerRow;
+    std::size_t keyInRow = key % this->numKeysPerRow;
+    int keyMask = 1 << keyInRow;
+
+    return (getRowState(row) & keyMask) != 0;
+}
+
+KeyboardState KeyboardState::operator&(const KeyboardState &other) const {
+    KeyboardState result(this->numRows, this->numKeysPerRow);
+    
+    typedef Data::const_iterator SourceIterator;
+    typedef Data::iterator TargetIterator;
+    
+    SourceIterator a = this->data.begin();
+    SourceIterator b = other.data.begin();
+    TargetIterator t = result.data.begin();
+    while (a != this->data.end() && b != other.data.end() && t != result.data.end()) 
+    {
+        *t = *a & *b;
+        ++a; ++b; ++t;
+    }
+    
+    return result;
+}
+
+bool KeyboardState::operator==(const KeyboardState &other) const { 
+    if (this == &other) {
+        return true;
+    }
+    
+    if (this->numRows != other.numRows || this->numKeysPerRow != other.numKeysPerRow)
+        return false;
+    
+    Data::const_iterator p = this->data.begin();
+    Data::const_iterator q = other.data.begin();
+    while (p != this->data.end() && q != other.data.end()) {
+        if (*p != *q) {
+            return false;
+        }
+        ++p; ++q;
+    }
+    
+    return true; 
+}
+
+bool KeyboardState::empty() const {
+    for(Data::const_iterator p = this->data.begin(); p != this->data.end(); ++p) {
+        if (*p != 0) {
+            return false;
+        }
+    }
+    
+    return true;
+}
+
+namespace {
+    int getBitNumber(int v)
+    {
+        if (v == 0) {
+            return -1;
+        }
+        
+        int key = 0;
+        while (v != 1) {
+            key++;
+            v >>= 1;
+        }
+        
+        return key;
+    }
+}
+
+KeyboardState::KeyPressType KeyboardState::getKeyPressType(int *key) const
+{
+    if (key) {
+        *key = -1;
+    }
+
+    Data::const_iterator p = this->data.begin();
+    std::size_t wordIndex = 0;
+    while (p != this->data.end() && *p == 0) {
+        ++p;
+        ++wordIndex;
+    }
+    if (p != this->data.end()) {
+        int v = *p;
+        if (v != (v & -v)) {
+            return MultiKeyPress;
+        }
+        int k = getBitNumber(v) + wordIndex * this->numKeysPerWord;
+        ++p;
+        while (p != this->data.end() && *p == 0) {
+            ++p;
+        }
+        if (p == this->data.end()) {
+            if (key) {
+                *key = k;
+            }
+            return SingleKeyPress;
+        }
+        else {
+            return MultiKeyPress;
+        }
+    }
+    else {
+        return Idle;
+    }
+}
+
+void KeyboardState::streamTo(std::ostream &out) const {
+    using namespace std;
+    std::size_t width = (this->numKeysPerWord + 3) / 4;
+    ios_base::fmtflags f = out.flags();
+    for(Data::const_reverse_iterator p = this->data.rbegin(); p != this->data.rend(); ++p) {
+        out << hex << setw(width) << setfill('0') << *p;
+    }
+    out.flags(f);
+}
+
+} // kbd_mgr
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/KeyboardStateChangeMonitor.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,13 @@
+#include "kbd_mgr/KeyboardStateChangeMonitor.h"
+
+namespace kbd_mgr {
+
+void KeyboardStateChangeMonitor::handleState(const KeyboardState &newState)
+{
+    if (newState != this->lastState) {
+        invokeHandler(newState);
+        this->lastState = newState;
+    }
+}
+
+} // kbd_mgr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/LongKeyPressMonitor.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,132 @@
+#include <kbd_mgr/LongKeyPressMonitor.h>
+
+namespace kbd_mgr {
+
+LongKeyPressMonitor::AutoRepeatSetupProxy LongKeyPressMonitor::autoRepeat(float initTime, float delay)
+{
+    this->repeatInitTime_ = initTime;
+    this->repeatDelay_ = delay;
+    
+    return AutoRepeatSetupProxy(this);
+} 
+    
+void LongKeyPressMonitor::addAutoRepeatKey(int firstKey, int lastKey)
+{
+    for(int key = firstKey; key <= lastKey; ++key) {
+        this->repeatKeys_.insert(key);
+        this->longPressKeys_.erase(key);
+    }
+}
+
+LongKeyPressMonitor::LongPressSetupProxy LongKeyPressMonitor::longKeyPress(float longPressTime)
+{
+    this->longPressTime_ = longPressTime;
+    return LongPressSetupProxy(this);
+}
+    
+void LongKeyPressMonitor::addLongPressKey(int firstKey, int lastKey)
+{
+    for(int key = firstKey; key <= lastKey; ++key) {
+        this->longPressKeys_.insert(key);
+        this->repeatKeys_.erase(key);
+    }
+}
+
+void LongKeyPressMonitor::handleKeyPress(const KeyEvent &keypress)
+{
+    if (keypress.event == KeyEvent::KeyDown) {
+        invokeHandler(keypress);
+        handleKeyDown(keypress);
+    }
+    else if (keypress.event == KeyEvent::KeyUp) {
+        handleKeyUp(keypress);
+        invokeHandler(keypress);
+    }
+    else {
+        invokeHandler(keypress);
+    }
+}
+
+void LongKeyPressMonitor::handleKeyDown(const KeyEvent &keypress)
+{
+    this->keyDownCount++;
+    if (this->keyDownCount == 1) {
+        handleFirstKeyDown(keypress);
+    }
+    else {
+        handleOtherKeyDown(keypress);
+    }
+}
+
+void LongKeyPressMonitor::handleFirstKeyDown(const KeyEvent &keypress)
+{
+    this->keypress = keypress;
+    
+    if (isAutoRepeatKey(keypress.keyCode)) {
+        this->state = RepeatInitWait;
+        this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->repeatInitTime_);
+    }
+    else if (isLongPressKey(keypress.keyCode)) {
+        this->state = LongPressWait;
+        this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->longPressTime_);
+    }
+}
+
+void LongKeyPressMonitor::handleOtherKeyDown(const KeyEvent &keypress)
+{
+    this->state = Invalid;
+    this->timer.detach();
+}
+
+void LongKeyPressMonitor::handleKeyUp(const KeyEvent &keypress)
+{
+    this->keyDownCount--;
+
+    if (this->state == Invalid || this->state == RepeatInitWait || this->state == LongPressWait) {
+        KeyEvent pressed(keypress, KeyEvent::KeyPress);
+        invokeHandler(pressed);
+    }
+    
+    if (this->keyDownCount == 0) {
+        handleLastKeyUp(keypress);
+    }
+}
+    
+void LongKeyPressMonitor::handleLastKeyUp(const KeyEvent &keypress)
+{
+    this->state = Idle;
+}
+    
+void LongKeyPressMonitor::handleTimer()
+{
+    switch(this->state) {
+    case RepeatInitWait:
+    case Repeating:
+        handleRepeatTimer();
+        break;
+    case LongPressWait:
+        handleLongPressTimer();
+        break;
+    default:
+        break;
+    }
+}
+
+void LongKeyPressMonitor::handleRepeatTimer()
+{
+    KeyEvent repeated(this->keypress, 
+        (this->state == RepeatInitWait ? KeyEvent::KeyPress : KeyEvent::RepeatedKeyPress));
+    invokeHandler(repeated);
+    
+    this->state = Repeating;
+    this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->repeatDelay_);
+}
+
+void LongKeyPressMonitor::handleLongPressTimer()
+{
+    KeyEvent longPressed(keypress, KeyEvent::LongKeyPress);
+    invokeHandler(longPressed);
+    this->state = LongPressReported;
+}
+
+} // kbd_mgr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/SingleKeyPressMonitor.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,28 @@
+#include "kbd_mgr/SingleKeyPressMonitor.h"
+
+namespace kbd_mgr {
+
+void SingleKeyPressMonitor::handleState(const KeyboardState &newState)
+{
+    int key;
+    if (newState.getKeyPressType(key) == KeyboardState::SingleKeyPress && this->lastReportedState.empty()) 
+    {
+        KeyEvent keyDown(key, KeyEvent::KeyDown);
+        invokeHandler(keyDown);
+        
+        this->lastReportedState = newState;
+        this->lastReportedKey = key;
+    }
+    else if (!this->lastReportedState.empty() &&
+             (newState & this->lastReportedState).empty())
+    {
+        KeyEvent keyUp(this->lastReportedKey, KeyEvent::KeyUp);
+        invokeHandler(keyUp);
+                
+        this->lastReportedState.clear();
+        this->lastReportedKey = KeyEvent::NoKey;
+    }
+
+}
+
+} // kbd_mgr
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyMapper.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,123 @@
+#ifndef KEY_MAPPER_H_
+#define KEY_MAPPER_H_
+
+#include "kbd_mgr/KeyPressEventServer.h"
+
+#include <vector>
+#include <string>
+#include <utility>
+
+namespace kbd_mgr {
+
+/**
+ * @brief A class used to store a set of key mappings.
+ * It associates a key event and a key code to a mapped character.
+ * It also allows to specify a mapping for any unmatched key event of a key.
+ * The KeyMap can be set at construction time with a string and an optional key event.
+ * Additional mappings can be specified by using the () operator. This way, both individual mappings and string mappings are possible.
+ * Eg. keymap(KeyEvent::LongKeyPress, 1, '@')(1, '*')
+ *      maps the key 1 to '*' for all key presses but to '@' when a long key press occurs.
+ */
+class KeyMap {
+public:
+    /**
+     * @brief Creates an empty keymap.
+     */
+    KeyMap() : map_() { }
+    
+    /**
+     * @brief Creates a keymap based on a string.
+     * Each character is mapped to the key at that position (key 1 maps to str[1]).
+     */
+    KeyMap(const std::string &str) : map_() {
+        addMappings(KeyEvent::NoEvent, str);
+    }
+    /**
+     * @brief Creates a keymap based on a string for a certain key event.
+     * Each character is mapped to the key at that position (key 1 maps to str[1]).
+     */
+    KeyMap(KeyEvent::EventType event, const std::string &str) : map_() {
+        addMappings(event, str);
+    }
+    
+    /**
+     * @brief Adds key mappings based on the given string.
+     */
+    KeyMap& operator()(const std::string &str) {
+        addMappings(KeyEvent::NoEvent, str);
+        return *this;
+    }
+    
+    /**
+     * @brief Adds key mappings based on the given string for a given event.
+     */
+    KeyMap& operator()(KeyEvent::EventType event, const std::string &str) {
+        addMappings(event, str);
+        return *this;
+    }
+    
+    /**
+     * @brief Adds a key mapping for a key.
+     */
+    KeyMap& operator()(int key, char ch) { 
+        addMapping(KeyEvent::NoEvent, key, ch); 
+        return *this; 
+    }
+    
+    /**
+     * @brief Adds a key mapping for a key event & code combo.
+     */
+    KeyMap& operator()(KeyEvent::EventType event, int key, char ch) { 
+        addMapping(event, key, ch); 
+        return *this; 
+    }
+
+    /**
+     * @brief Gets the mapped character for a key press event.
+     */    
+    char map(KeyEvent::EventType event, int key) const;
+
+private:
+    struct KeyMapping {
+        KeyEvent::EventType event;
+        int key;
+        char ch;
+        
+        KeyMapping(KeyEvent::EventType event, int key, char ch) : event(event), key(key), ch(ch) { }
+        
+        bool matches(const std::pair<KeyEvent::EventType, int> &arg) const {
+            return this->event == arg.first && this->key == arg.second;
+        }
+    };
+    
+    void addMapping(KeyEvent::EventType event, int key, char ch);
+    void addMappings(KeyEvent::EventType event, const std::string &str);
+    const KeyMapping * getMapping(KeyEvent::EventType event, int key) const;
+    
+    typedef std::vector<KeyMapping> Map;
+    Map map_;
+};
+
+/**
+ * @brief A key press event handler that adds a mapped key char to key events.
+ * Mappings can be specified for any key press event or for some specific key press event.
+ */
+class KeyMapper : public KeyPressEventServer, public KeyPressEventHandler {
+public:
+    
+    KeyMapper(const KeyMap &keymap = KeyMap()) :
+        keymap_(keymap)
+    { }
+    
+    const KeyMap & keymap() const { return this->keymap_; }
+    char map(KeyEvent::EventType event, int key) const { return this->keymap_.map(event, key); }
+
+    virtual void handleKeyPress(const KeyEvent &keypress);
+
+private:
+    KeyMap keymap_;
+};
+
+} // kbd_mgr
+
+#endif // KEY_MAPPER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyPressEventHandler.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,82 @@
+#ifndef KEY_PRESS_EVENT_HANDLER_H_
+#define KEY_PRESS_EVENT_HANDLER_H_
+
+namespace kbd_mgr {
+
+struct KeyEvent {
+    enum KeyId {
+        NoKey = -1
+    };
+    
+    enum EventType {
+        NoEvent, KeyDown, KeyPress, RepeatedKeyPress, LongKeyPress, KeyUp
+    };
+    
+    int keyCode;
+    char keyChar;
+    EventType event;
+    
+    KeyEvent() : keyCode(NoKey), keyChar(0), event(NoEvent) { }
+    
+    /**
+     * @brief Creates a raw key event (no char).
+     */
+    KeyEvent(int key, EventType event) : keyCode(key), keyChar(0), event(event) { }    
+    
+    /**
+     * @brief Converts a raw key event into a mapped key.
+     */
+    KeyEvent(const KeyEvent &raw, char ch) : keyCode(raw.keyCode), keyChar(ch), event(raw.event) { }    
+    
+    /**
+     * @brief Creates a key event with a different event code.
+     */
+    KeyEvent(const KeyEvent &other, EventType event) : keyCode(other.keyCode), keyChar(other.keyChar), event(event) { }    
+};
+
+/**
+ * @brief Interface used to report key presses and releases.
+ */
+class KeyPressEventHandler {
+public:
+    virtual void handleKeyPress(const KeyEvent &keypress) = 0;
+    virtual ~KeyPressEventHandler() { }
+};
+
+template <class T>
+class MemberKeyPressEventHandler : public KeyPressEventHandler {
+public:
+    typedef void (T::*MemberFunction)(const KeyEvent &keypress);
+    
+    MemberKeyPressEventHandler(T *obj, MemberFunction fn) :
+        object(obj), func(fn)
+    { }
+    
+    virtual void handleKeyPress(const KeyEvent &keypress) {
+        (object->*func)(keypress);
+    }
+    
+private:
+    T *object;
+    MemberFunction func;
+};
+
+class FunctionKeyPressEventHandler : public KeyPressEventHandler {
+public:
+    typedef void (*HandlerFunction)(const KeyEvent &keypress);
+
+    FunctionKeyPressEventHandler(HandlerFunction fn) :
+        func(fn)
+    { }
+
+    virtual void handleKeyPress(const KeyEvent &keypress) {
+        func(keypress);
+    }
+        
+private:
+    HandlerFunction func;
+};
+    
+} // kbd_mgr
+
+#endif // KEY_PRESS_EVENT_HANDLER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyPressEventServer.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,43 @@
+#ifndef KEYPRESS_EVENT_SERVER_H_
+#define KEYPRESS_EVENT_SERVER_H_
+
+#include "kbd_mgr/KeyboardEventServer.h"
+#include "kbd_mgr/KeyPressEventHandler.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief A base class for monitors that report keypresses.
+ */ 
+class KeyPressEventServer : public KeyboardEventServer<KeyPressEventHandler> {
+public:
+    /**
+     * @brief Attaches the monitor to a function.
+     * @param fn       Event handler called to report keyboard state change.
+     */
+    void attach(FunctionKeyPressEventHandler::HandlerFunction fn) {
+        setHandler(new FunctionKeyPressEventHandler(fn));
+    }
+    
+    /**
+     * @brief Attaches the monitor to a method of an object.
+     * @param obj      Event handler object
+     * @param fn       Event handler method called to report keyboard state after each complete scan.
+     */
+    template <class T>
+    void attach(T *obj, typename MemberKeyPressEventHandler<T>::MemberFunction fn) {
+        setHandler(new MemberKeyPressEventHandler<T>(obj, fn));
+    }
+    
+    using KeyboardEventServer<KeyPressEventHandler>::attach;
+    
+    void invokeHandler(const KeyEvent &keypress) {
+        if (this->hasHandler()) {
+            this->handler()->handleKeyPress(keypress);
+        }
+    }
+};
+
+} // kbd_mgr
+
+#endif // KEYPRESS_EVENT_SERVER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardEventServer.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,54 @@
+#ifndef KEYBOARD_EVENT_SERVER_H_
+#define KEYBOARD_EVENT_SERVER_H_
+
+#include <cstdlib>
+
+namespace kbd_mgr {
+
+template <class HandlerClass>
+class KeyboardEventServer {
+protected:
+    KeyboardEventServer() : handler_(NULL), ownHandler_(false) { }
+
+    ~KeyboardEventServer()
+    {
+        clearHandler();
+    }
+    
+    void setHandler(HandlerClass *h, bool owner = true) {
+        this->handler_ = h;
+        this->ownHandler_ = owner;
+    }
+    
+    void clearHandler() {
+        if (this->ownHandler_) {
+            delete this->handler_;
+        }
+        this->handler_ = NULL;
+        this->ownHandler_ = false;
+    }
+
+    HandlerClass *handler() const { return this->handler_; }
+
+    bool hasHandler() const { return this->handler_ != NULL; }
+    
+public:
+    void attach(HandlerClass *handler) {
+        setHandler(handler, false);
+    }
+    void attach(HandlerClass &handler) {
+        setHandler(&handler, false);
+    }
+    
+    void detach() {
+        clearHandler();
+    }
+
+private:
+    HandlerClass *handler_;
+    bool ownHandler_;
+};
+
+} // kbd_mgr
+
+#endif // KEYBOARD_EVENT_SERVER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardManager.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,5 @@
+#include "kbd_mgr/KeyboardMonitor.h"
+#include "kbd_mgr/KeyboardStateChangeMonitor.h"
+#include "kbd_mgr/SingleKeyPressMonitor.h"
+#include "kbd_mgr/LongKeyPressMonitor.h"
+#include "kbd_mgr/KeyMapper.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardMonitor.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,57 @@
+#ifndef KEYBOARD_MONITOR_H_
+#define KEYBOARD_MONITOR_H_
+
+#include "kbd_mgr/KeyboardStateEventServer.h"
+#include "kbd_mgr/KeyboardState.h"
+
+#include "mbed.h"
+#include <vector>
+
+namespace kbd_mgr {
+
+/**
+ * @brief A class that polls the state of a switch-matrix keyboard.
+ * For efficiency reasons, this class uses contiguous bits in a GPIO ports for reading the state of the keys in a row.
+ * Key rows are activated one by one using a set of digital outputs.
+ * When a full keyboard scan has been done, it is provided to the registered handler.
+ */
+class KeyboardMonitor : public KeyboardStateEventServer {
+public:
+    typedef std::vector<PinName> OutPinsSet;
+    
+    /**
+     * @param inPort        Port to be used for reading the key state.
+     * @param numKeysPerRow Number of keys in a row (N)
+     * @param inLowestBit   Index of the lowest bit of inPort (using inLowestBit to inLowestBit+N).
+     * @param outPins       Pins to be used for powering each key row.
+     */
+    KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, 
+            const OutPinsSet &outPins);
+    
+    ~KeyboardMonitor();
+    
+    /**
+     * @brief Starts the polling of the keyboard state.
+     */
+    void start(float pollingPeriod = 0.001);
+    
+    /**
+     * @brief Disables the polling of the keyboard state.
+     */
+    void stop();
+    
+private:
+    void timerHandler();
+
+    PortIn in;
+    int inBitShift;
+    OutPinsSet outPins;
+
+    Ticker ticker;
+    std::size_t scanRow;            /*!< next key row to be scanned */
+    KeyboardState currentState;     /*!< currently being built keyboard state */
+};
+
+} // kbd_mgr
+
+#endif // KEYBOARD_MONITOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardState.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,94 @@
+#ifndef KEYBOARD_STATE_H_
+#define KEYBOARD_STATE_H_
+
+#include <vector>
+#include <iostream>
+
+namespace kbd_mgr {
+
+/**
+ * @brief A class to hold the state of a keyboard.
+ * A keyboard is handled as a set of key rows. Each row can have as many keys as there are bits in integers.
+ * The class maintains an array of integers to handle the number of rows.
+ * If possible, multiple rows are combined in a single integer to reduce memory footprint.
+ */
+class KeyboardState {
+public:
+    /**
+     * @brief Constructor for a 0x0 keyboard state.
+     */
+    KeyboardState();
+    
+    /**
+     * @brief Constructor for a NxM keyboard state.
+     * @param numRows       Number of key rows (unlimited)
+     * @param numKeysPerRow Number of keys per row (limited to the number of bits in an integer).
+     */
+    KeyboardState(std::size_t numRows, std::size_t numKeysPerRow);
+
+    std::size_t getNumRows() const { return this->numRows; }
+    std::size_t getNumKeysPerRow() const { return this->numKeysPerRow; }
+    std::size_t getNumKeys() const { return this->numRows * this->numKeysPerRow; }
+    
+    void clear();
+    void setRowState(std::size_t row, int rowState);
+    int getRowState(std::size_t row) const;
+    bool getKeyState(std::size_t key) const;
+    
+    /**
+     * @brief Executes a XOR between two states.
+     * @return a state that represents the keys that changed of state.
+     */
+    KeyboardState operator^(const KeyboardState &other) const;
+    
+    /**
+     * @brief Executes an AND between two states.
+     */
+    KeyboardState operator&(const KeyboardState &mask) const;
+    
+    bool operator==(const KeyboardState &other) const;
+    bool operator!=(const KeyboardState &other) const { return !(*this == other); }
+    
+    /**
+     * @brief Checks if a keyboard state is full of 0.
+     */
+    bool empty() const;
+    
+    enum KeyPressType {
+        Idle, SingleKeyPress, MultiKeyPress
+    };
+    
+    /**
+     * @brief Determines the kind of key press present in the state.
+     * The keyboard state can represent an idle keyboard, a single key pressed
+     * or a key combination. This method determines which type of state this is.
+     * If a single key is represented, the key index can be retrieved.
+     * @param key   An integer where the single key pressed should be stored.
+     */
+    KeyPressType getKeyPressType(int *key = NULL) const;
+    KeyPressType getKeyPressType(int &key) const { return getKeyPressType(&key); }
+    
+    void streamTo(std::ostream &out) const;
+    
+private:
+    int getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const;
+
+    std::size_t numRows;
+    std::size_t numKeysPerRow;
+    int rowMask;
+    std::size_t numRowsPerWord;
+    std::size_t numKeysPerWord;
+    std::size_t numWords;
+    
+    typedef std::vector<int> Data;
+    Data data;
+};
+
+inline std::ostream & operator<<(std::ostream &out, const KeyboardState &s) {
+    s.streamTo(out);
+    return out;
+}
+
+} // kbd_mgr
+
+#endif // KEYBOARD_STATE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardStateChangeMonitor.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,22 @@
+#ifndef KEYBOARD_STATE_CHANGE_MONITOR_H_
+#define KEYBOARD_STATE_CHANGE_MONITOR_H_
+
+#include "kbd_mgr/KeyboardStateEventServer.h"
+#include "kbd_mgr/KeyboardState.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief A keyboard state handler that reports only state changes.
+ */    
+class KeyboardStateChangeMonitor : public KeyboardStateEventServer, public KeyboardStateHandler {
+public:
+    virtual void handleState(const KeyboardState &newState);
+    
+private:
+    KeyboardState lastState;
+};
+
+} // kbd_mgr
+
+#endif // KEYBOARD_STATE_CHANGE_MONITOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardStateEventServer.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,43 @@
+#ifndef KEYBOARD_STATE_EVENT_SERVER_H_
+#define KEYBOARD_STATE_EVENT_SERVER_H_
+
+#include "kbd_mgr/KeyboardEventServer.h"
+#include "kbd_mgr/KeyboardStateHandler.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief A keyboard state handler that reports only state changes.
+ */    
+class KeyboardStateEventServer : public KeyboardEventServer<KeyboardStateHandler> {
+public:
+    /**
+     * @brief Attaches the monitor to a function.
+     * @param fn       Event handler called to report keyboard state change.
+     */
+    void attach(FunctionKeyboardStateHandler::HandlerFunction fn) {
+        setHandler(new FunctionKeyboardStateHandler(fn));
+    }
+    
+    /**
+     * @brief Attaches the monitor to a method of an object.
+     * @param obj      Event handler object
+     * @param fn       Event handler method called to report keyboard state after each complete scan.
+     */
+    template <class T>
+    void attach(T *obj, typename MemberKeyboardStateHandler<T>::MemberFunction fn) {
+        setHandler(new MemberKeyboardStateHandler<T>(obj, fn));
+    }
+    
+    using  KeyboardEventServer<KeyboardStateHandler>::attach;
+    
+    void invokeHandler(const KeyboardState &state) {
+        if (this->hasHandler()) {
+            this->handler()->handleState(state);
+        }
+    }
+};
+
+} // kbd_mgr
+
+#endif // KEYBOARD_STATE_EVENT_SERVER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/KeyboardStateHandler.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,53 @@
+#ifndef KEYBOARD_STATE_HANDLER_H_
+#define KEYBOARD_STATE_HANDLER_H_
+
+#include "kbd_mgr/KeyboardState.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief Interface used to report a keyboard state.
+ */
+class KeyboardStateHandler {
+public:
+    virtual void handleState(const KeyboardState &newState) = 0;
+    virtual ~KeyboardStateHandler() { }
+};
+
+template <class T>
+class MemberKeyboardStateHandler : public KeyboardStateHandler {
+public:
+    typedef void (T::*MemberFunction)(const KeyboardState &);
+    
+    MemberKeyboardStateHandler(T *obj, MemberFunction fn) :
+        object(obj), func(fn)
+    { }
+    
+    virtual void handleState(const KeyboardState &newState) {
+        (object->*func)(newState);
+    }
+    
+private:
+    T *object;
+    MemberFunction func;
+};
+
+class FunctionKeyboardStateHandler : public KeyboardStateHandler {
+public:
+    typedef void (*HandlerFunction)(const KeyboardState &);
+
+    FunctionKeyboardStateHandler(HandlerFunction fn) :
+        func(fn)
+    { }
+
+    virtual void handleState(const KeyboardState &newState) {
+        func(newState);
+    }
+        
+private:
+    HandlerFunction func;
+};
+
+} // kbd_mgr
+
+#endif // KEYBOARD_STATE_HANDLER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/LongKeyPressMonitor.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,115 @@
+#ifndef LONG_KEY_PRESS_MONITOR_H_
+#define LONG_KEY_PRESS_MONITOR_H_
+
+#include <kbd_mgr/KeyPressEventServer.h>
+#include <set>
+
+#include "mbed.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief A key press event handler that detects long key presses and report them as specified.
+ * This class offers two specific reactions for long key presses. Either a specific long key press is reported
+ * or the key press event is auto repeated. The timing for both kind of reactions can be specified independently.
+ * The monitor reacts on key code, not on mapped key char. If a mapped key char is present in the event, it is retained
+ * in the generated key press events.
+ */
+class LongKeyPressMonitor : public KeyPressEventServer, public KeyPressEventHandler {
+public:
+    LongKeyPressMonitor() : 
+        repeatKeys_(), repeatInitTime_(0), repeatDelay_(0), longPressKeys_(), longPressTime_(0),
+        state(Idle), keyDownCount(0), timer()
+    { }
+    
+    class AutoRepeatSetupProxy {
+    public:
+        AutoRepeatSetupProxy(LongKeyPressMonitor *monitor) : monitor_(monitor) { }
+        AutoRepeatSetupProxy& operator()(int key) { this->monitor_->addAutoRepeatKey(key, key); return *this; }
+        AutoRepeatSetupProxy& operator()(int firstKey, int lastKey) { this->monitor_->addAutoRepeatKey(firstKey, lastKey); return *this; }
+        
+    private:
+        LongKeyPressMonitor *monitor_;
+    };
+    
+    friend class AutoRepeatSetupProxy;
+    
+    /**
+     * @brief Sets up auto-repeat keys.
+     * This method takes the timing parameters. It returns a special class that allows specifying the keys
+     * between brackets. Eg: 
+     *  - monitor.autoRepeat(0.3, 0.1)(1)(2)(4,8)
+     *    Sets up auto repeat after 300ms, every 100ms for keys 1, 2 and 4 to 8.
+     */
+    AutoRepeatSetupProxy autoRepeat(float initTime, float delay); 
+    
+    
+    class LongPressSetupProxy {
+    public:
+        LongPressSetupProxy(LongKeyPressMonitor *monitor) : monitor_(monitor) { }
+        LongPressSetupProxy& operator()(int key) { this->monitor_->addLongPressKey(key, key); return *this; }
+        LongPressSetupProxy& operator()(int firstKey, int lastKey) { this->monitor_->addLongPressKey(firstKey, lastKey); return *this; }
+        
+    private:
+        LongKeyPressMonitor *monitor_;
+    };
+    
+    friend class LongPressSetupProxy;
+    
+    /**
+     * @brief Sets up long key press keys.
+     * This method takes the timing parameters. It returns a special class that allows specifying the keys
+     * between brackets. Eg: 
+     *  - monitor.longKeyPress(0.5)(3)(12,14)
+     *    Sets up report of long key press after 500ms for keys 3 and 12 to 14.
+     */
+    LongPressSetupProxy longKeyPress(float longPressTime);
+    
+    /**
+     * @brief KeyPressEventHandler interface
+     */
+    virtual void handleKeyPress(const KeyEvent &keypress);
+    
+private:
+    void addAutoRepeatKey(int firstKey, int lastKey);
+    bool isAutoRepeatKey(int key) const { return this->repeatKeys_.find(key) != this->repeatKeys_.end(); }
+    void addLongPressKey(int firstKey, int lastKey);
+    bool isLongPressKey(int key) const { return this->longPressKeys_.find(key) != this->longPressKeys_.end(); }
+    
+    void handleKeyDown(const KeyEvent &keypress);
+    void handleFirstKeyDown(const KeyEvent &keypress);
+    void handleOtherKeyDown(const KeyEvent &keypress);
+    void handleKeyUp(const KeyEvent &keypress);
+    void handleLastKeyUp(const KeyEvent &keypress);
+
+    void handleTimer();
+    void handleRepeatTimer();
+    void handleLongPressTimer();
+    
+    typedef std::set<int> KeySet;
+    
+    KeySet repeatKeys_;
+    float repeatInitTime_;
+    float repeatDelay_;
+    
+    KeySet longPressKeys_;
+    float longPressTime_;
+    
+    enum State {
+        Idle,
+        RepeatInitWait,
+        Repeating,
+        LongPressWait,
+        LongPressReported,
+        Invalid
+    };
+    
+    State state;
+    KeyEvent keypress;
+    int keyDownCount;
+    Timeout timer;
+};
+
+} // kbd_mgr
+
+#endif // LONG_KEY_PRESS_MONITOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardManager/kbd_mgr/SingleKeyPressMonitor.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,28 @@
+#ifndef SINGLE_KEY_PRESS_MONITOR_H_
+#define SINGLE_KEY_PRESS_MONITOR_H_
+
+#include "kbd_mgr/KeyPressEventServer.h"
+#include "kbd_mgr/KeyboardStateHandler.h"
+
+namespace kbd_mgr {
+
+/**
+ * @brief A keyboard state change handler that reports on single keypresses.
+ * It voluntarily ignores key combinations (only the first key pressed in a combo is reported).
+ */ 
+class SingleKeyPressMonitor : public KeyPressEventServer, public KeyboardStateHandler {
+public:
+    SingleKeyPressMonitor() : 
+        lastReportedState(), lastReportedKey(KeyEvent::NoKey) 
+    { }
+    
+    virtual void handleState(const KeyboardState &newState);
+    
+private:
+    KeyboardState lastReportedState;
+    int lastReportedKey;
+};
+
+} // kbd_mgr
+
+#endif // SINGLE_KEY_PRESS_MONITOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/SineWave.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,36 @@
+#include "snd_wave_generator/SineWave.h"
+#include <cmath>
+
+namespace snd_wave_generator {
+
+void SineWave::prepare(std::size_t sampleRate)
+{
+    std::size_t cycleLength = sampleRate / this->frequency;
+    this->buffer.resize(cycleLength);
+
+    std::size_t middle = cycleLength / 2;
+    std::size_t quarter = middle / 2;
+    
+    float delta = 6.28 / (float(sampleRate) / float(this->frequency));
+    for(std::size_t i = 0; i < quarter; ++i) {
+        float dt = delta * i;
+        float dv = std::sin(dt) / 2.0;
+        float posValue = 0.5 + dv;
+        float negValue = 0.5 - dv;
+        this->buffer.write(i, posValue);
+        this->buffer.write(middle - i, posValue);
+        this->buffer.write(middle + i, negValue);
+        this->buffer.write(cycleLength - i, negValue);
+    }
+    
+    this->buffer.write(quarter, 1.0);
+    if (middle - quarter != quarter) {
+        this->buffer.write(middle - quarter, 1.0);
+    }
+    this->buffer.write(cycleLength - quarter, 0.0);
+    if (middle + quarter != cycleLength - quarter) {
+        this->buffer.write(middle + quarter, 0.0);
+    }
+}
+
+} // snd_wave_generator
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/SoundWaveGenerator.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,28 @@
+#include "snd_wave_generator/SoundWaveGenerator.h"
+
+namespace snd_wave_generator {
+
+void SoundWaveGenerator::play(Wave *wave)
+{
+    wave->prepare(this->sampleRate);
+
+    this->wave = wave;
+    
+    this->pos = 0;
+    this->ticker.attach(this, &SoundWaveGenerator::tickerHandler, 1.0 / this->sampleRate);
+}
+
+void SoundWaveGenerator::stop()
+{
+    this->ticker.detach();
+    this->output.write(0.0);
+    this->wave = NULL;
+}
+    
+void SoundWaveGenerator::tickerHandler()
+{
+    float v = this->wave ? this->wave->read(this->pos++) : 0.0;
+    this->output.write(v);
+}
+
+} // snd_wave_generator
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/TriangleWave.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,34 @@
+#include "snd_wave_generator/TriangleWave.h"
+
+namespace snd_wave_generator {
+
+void TriangleWave::prepare(std::size_t sampleRate)
+{
+    std::size_t cycleLength = sampleRate / this->frequency;
+    this->buffer.resize(cycleLength);
+
+    std::size_t middle = cycleLength / 2;
+    std::size_t quarter = middle / 2;
+    
+    float delta = 2.0 / (float(sampleRate) / float(this->frequency));
+    for(std::size_t i = 0; i < quarter; ++i) {
+        float dt = delta * i;
+        float posValue = 0.5 + dt;
+        float negValue = 0.5 - dt;
+        this->buffer.write(i, posValue);
+        this->buffer.write(middle - i, posValue);
+        this->buffer.write(middle + i, negValue);
+        this->buffer.write(cycleLength - i, negValue);
+    }
+    
+    this->buffer.write(quarter, 1.0);
+    if (middle - quarter != quarter) {
+        this->buffer.write(middle - quarter, 1.0);
+    }
+    this->buffer.write(cycleLength - quarter, 0.0);
+    if (middle + quarter != cycleLength - quarter) {
+        this->buffer.write(middle + quarter, 0.0);
+    }
+}
+
+} // snd_wave_generator
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/WaveBuffer.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,21 @@
+#include "snd_wave_generator/WaveBuffer.h"
+
+namespace snd_wave_generator {
+
+void WaveBuffer::resize(std::size_t size)
+{
+    if (this->capacity_ > 0 && size > this->capacity_) {
+        delete[] this->data_;
+        this->data_ = NULL;
+        this->capacity_ = 0;
+    }
+    
+    if (size > this->capacity_) {
+        this->data_ = new float[size];
+        this->capacity_ = size;
+    }
+    
+    this->size_ = size;
+}
+
+} // snd_wave_generator
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/WaveCombo.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,40 @@
+#include "snd_wave_generator/WaveCombo.h"
+
+#include <algorithm>
+#include <functional>
+#include <numeric>
+
+namespace snd_wave_generator {
+
+WaveCombo & WaveCombo::add(Wave *wave) { 
+    if (wave) { 
+        this->waves.push_back(wave);
+        this->numWaves = this->waves.size(); 
+    }
+    
+    return *this;
+}
+
+void WaveCombo::prepare(std::size_t sampleRate)
+{
+    std::for_each(this->waves.begin(), this->waves.end(),
+        std::bind2nd(std::mem_fun(&Wave::prepare), sampleRate));
+}
+
+struct AccumulateWaveValueAt {
+    AccumulateWaveValueAt(std::size_t pos) : pos(pos) { }
+    float operator()(float acc, const Wave *wave) const {
+        return acc + wave->read(this->pos);
+    }
+    
+    std::size_t pos;
+};
+
+float WaveCombo::read(std::size_t pos) const {
+    float v = std::accumulate(this->waves.begin(), this->waves.end(), 0.0f,
+        AccumulateWaveValueAt(pos));
+                
+    return v / this->numWaves;
+}
+
+} // snd_wave_generator
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/BufferedWave.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,23 @@
+#ifndef BUFFERED_WAVE_H_
+#define BUFFERED_WAVE_H_
+
+#include "snd_wave_generator/Wave.h"
+#include "snd_wave_generator/WaveBuffer.h"
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A base class for Waves which pre-computes their values in a buffer during preparation and play from that buffer.
+ */
+class BufferedWave : public Wave {
+public:
+    BufferedWave() : buffer() { }
+    virtual float read(std::size_t pos) const { return this->buffer.read(pos); }
+    
+protected:
+    WaveBuffer buffer;
+};
+
+} // snd_wave_generator
+
+#endif // BUFFERED_WAVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/SineWave.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,23 @@
+#ifndef SINE_WAVE_H_
+#define SINE_WAVE_H_
+
+#include "snd_wave_generator/BufferedWave.h"
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A class producing a sine wave of a given frequency.
+ */
+class SineWave : public BufferedWave {
+public:
+    SineWave(unsigned freq) : BufferedWave(), frequency(freq) { }
+
+    virtual void prepare(std::size_t sampleRate);
+    
+private:
+    unsigned frequency;
+};
+
+} // snd_wave_generator
+
+#endif // SINE_WAVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/SoundWaveGenerator.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,45 @@
+#ifndef SOUND_WAVE_GENERATOR_H_
+#define SOUND_WAVE_GENERATOR_H_
+
+#include "snd_wave_generator/Wave.h"
+#include "mbed.h"
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A class to handle computed sound wave generation.
+ * The generator is bound to an AnalogOut pin (p18 on LPC1768).
+ * It has a fixed sample rate.
+ */
+class SoundWaveGenerator {
+public:
+    SoundWaveGenerator(std::size_t sampleRate, PinName pin = p18) : 
+        sampleRate(sampleRate), wave(NULL), pos(0), output(pin), ticker()
+    { }
+    
+    /**
+     * @brief Starts playing a given wave.
+     * The wave will be prepared for the generator's sample rate and then played back
+     * on the bound analog output.
+     */
+    void play(Wave *wave);
+    
+    /**
+     * @brief Stops playing.
+     */
+    void stop();
+    
+private:
+    void tickerHandler();
+    
+    std::size_t sampleRate;
+    
+    Wave *wave;    
+    std::size_t pos;
+    AnalogOut output;
+    Ticker ticker;
+};
+  
+} // snd_wave_generator
+  
+#endif // SOUND_WAVE_GENERATOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/TriangleWave.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,23 @@
+#ifndef TRIANGLE_WAVE_H_
+#define TRIANGLE_WAVE_H_
+
+#include "snd_wave_generator/BufferedWave.h"
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A class producing a triangle wave of a given frequency.
+ */
+class TriangleWave : public BufferedWave {
+public:
+    TriangleWave(unsigned freq) : BufferedWave(), frequency(freq) { }
+
+    virtual void prepare(std::size_t sampleRate);
+    
+private:
+    unsigned frequency;
+};
+
+} // snd_wave_generator
+
+#endif // TRIANGLE_WAVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/Wave.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,23 @@
+#ifndef WAVE_H_
+#define WAVE_H_
+
+#include <cstddef>
+
+namespace snd_wave_generator {
+
+/**
+ * @brief Interface of a playable sound wave.
+ * Waves are processed in two phases.
+ * Before sending out signal, the wave is "prepared" for the generator sample rate.
+ * Once the preparation is done, the generator will repeatedly "read" the wave samples.
+ * The sample position is measured in samples.
+ */
+class Wave {
+public:
+    virtual void prepare(std::size_t sampleRate) = 0;
+    virtual float read(std::size_t pos) const = 0;
+};
+
+} // snd_wave_generator
+
+#endif // WAVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/WaveBuffer.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,37 @@
+#ifndef WAVE_BUFFER_H_
+#define WAVE_BUFFER_H_
+
+#include <cstddef>
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A class used to hold buffered sound wave data.
+ * It's basically a vector of floats which can be read in a cyclic way.
+ */
+class WaveBuffer {
+public:
+    WaveBuffer() : size_(0), capacity_(0), data_(NULL) { }
+    ~WaveBuffer() { delete[] this->data_; }
+    
+    void resize(std::size_t size);
+    
+    void write(std::size_t pos, float v) { 
+        if (pos < this->size_) {
+            this->data_[pos] = v; 
+        }
+    }
+    
+    float read(std::size_t pos) const { 
+        return this->data_[pos % this->size_]; 
+    }
+
+private:
+    std::size_t size_;
+    std::size_t capacity_;
+    float *data_;
+};
+
+} // snd_wave_generator
+
+#endif // WAVE_BUFFER_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SoundWaveGenerator/snd_wave_generator/WaveCombo.h	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,33 @@
+#ifndef WAVE_COMBO_H_
+#define WAVE_COMBO_H_
+
+#include "snd_wave_generator/Wave.h"
+#include <vector>
+
+namespace snd_wave_generator {
+
+/**
+ * @brief A class that produces a wave that results of the combination of multiple waves.
+ * The combined wave does not buffer itself (as it does not know the length of the combined cycle.
+ * During preparation phase, it invokes the prepare() method of its contained waves.
+ */
+class WaveCombo : public Wave {
+public:
+    WaveCombo(Wave *wave = NULL) : waves(), numWaves(0)
+    {
+        add(wave); 
+    }
+    
+    WaveCombo & add(Wave *wave);
+    
+    virtual void prepare(std::size_t sampleRate);
+    virtual float read(std::size_t pos) const;
+    
+private:
+    std::vector<Wave*> waves;
+    float numWaves;
+};
+
+} // snd_wave_generator
+
+#endif // WAVE_COMBO_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/command_state.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,120 @@
+#include "system_states.hpp"
+#include "system.hpp"
+#include "display_manager.hpp"
+
+const char *statusMsg[] = {
+    //234567890123456
+    "Cmd: [5]Help",
+    "Cmd: [0]Send",
+    "Cmd: 1<-4-+-6->3",
+    "Cmd: [7]BS[8]Del",
+    "Cmd: [9]Clear",
+    "Cmd: <*>Edit",
+    NULL
+};
+
+enum {
+    HelpTimeout = 2
+};
+
+void CommandState::enterState() {
+    DisplayManager *display = system()->display();
+    display->hideCursor();
+    showStatusMsg(0);
+    updateText();
+}
+
+void CommandState::exitState() {
+    this->statusMsgTimeout.detach();
+}
+
+void CommandState::handleKey(char key)
+{
+    switch(key) {
+    case '5':
+        handleHelp(); break;
+    case '1':
+        handleHome(); break;
+    case '3':
+        handleEnd(); break;
+    case '4':
+        handleLeft(); break;
+    case '6':
+        handleRight(); break;
+    case '7':
+        handleBackSpace(); break;
+    case '8':
+        handleDelete(); break;
+    case '9':
+        handleClear(); break;
+    case '0':
+        handleSend(); break;
+    case '@':
+        system()->setState(System::Edit);
+        break;
+    default:
+        break;
+    }
+}
+
+void CommandState::handleHome() const {
+    system()->moveCursorTo(0);
+    updateCursor();
+}
+
+void CommandState::handleEnd() const {
+    system()->moveCursorTo(-1);
+    updateCursor();
+}
+
+void CommandState::handleLeft() const {
+    system()->moveCursorBy(-1);
+    updateCursor();
+}
+
+void CommandState::handleRight() const {
+    system()->moveCursorBy(+1);
+    updateCursor();
+}
+
+void CommandState::handleDelete() const {
+    system()->deleteCurrentSymbol();
+    updateText();
+}
+
+void CommandState::handleBackSpace() const {
+    system()->moveCursorBy(-1);
+    system()->deleteCurrentSymbol();
+    updateText();
+}
+
+void CommandState::handleClear() const {
+    system()->clearText();
+    updateText();
+}
+
+void CommandState::handleSend() const {
+    if (system()->text_size() > 0) {
+        system()->setState(System::Sending);
+    }
+}
+
+void CommandState::handleHelp() {
+    this->statusMsgTimeout.detach();
+    showNextStatusMsg();
+}
+
+void CommandState::showNextStatusMsg() {
+    int msg = this->statusMsgIndex+1;
+    if (statusMsg[msg] == NULL) {
+        msg = 0;
+    }
+    showStatusMsg(msg);
+}
+
+void CommandState::showStatusMsg(int index) {
+    this->statusMsgIndex = index;
+    DisplayManager *display = system()->display();
+    display->writeStatus(statusMsg[index]);
+    this->statusMsgTimeout.attach(this, &CommandState::showNextStatusMsg, HelpTimeout * 1.0);    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/display_manager.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,18 @@
+#ifndef _DISPLAY_INTERFACE_HPP
+#define _DISPLAY_INTERFACE_HPP
+
+#include <string>
+
+class DisplayManager {
+public:
+    virtual void moveTo(std::size_t pos) = 0;
+    virtual void writeStatus(const std::string &text) = 0;
+    virtual void writeText(const std::string &text) = 0;
+    virtual void showCursor() = 0;
+    virtual void hideCursor() = 0;
+    virtual void clear() = 0;
+    
+    virtual ~DisplayManager() {}
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dtmf_generator.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,14 @@
+#ifndef _DTMF_GENERATOR_HPP
+#define _DTMF_GENERATOR_HPP
+
+#include <string>
+
+class DtmfGenerator {
+public:
+    virtual void play(char ch) = 0;
+    virtual void stop() = 0;
+    
+    virtual ~DtmfGenerator() {}
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/edit_state.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,29 @@
+#include "system_states.hpp"
+#include "system.hpp"
+#include "display_manager.hpp"
+
+void EditState::enterState() {
+    DisplayManager *display = system()->display();
+    display->hideCursor();
+    display->writeStatus("Edit: <*>Cmd");
+    updateText();
+}
+
+void EditState::handleKey(char key)
+{
+    if (key == '@') {
+        system()->setState(System::Command);
+    }
+    else if (key == '$') {
+        // ignored for the time being
+    }
+    else {
+        handleSymbol(key);
+    }
+}
+
+void EditState::handleSymbol(char ch) const {
+    system()->insertSymbol(ch);
+    updateText();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/init_state.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,17 @@
+#include "system_states.hpp"
+#include "display_manager.hpp"
+
+void InitState::enterState() {
+    DisplayManager *display = system()->display();
+    display->clear();
+    display->hideCursor();
+    display->writeStatus("DTMF-Kit v1.0");
+    display->writeText(__DATE__ " / " __TIME__);
+    wait(2);
+}
+
+void InitState::exitState() {
+    DisplayManager *display = system()->display();
+    display->clear();
+    display->hideCursor();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interactive_state.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,17 @@
+#include "system_states.hpp"
+#include "system.hpp"
+#include "display_manager.hpp"
+
+void InteractiveState::updateText() const {
+    DisplayManager *display = system()->display();
+    display->hideCursor();
+    display->writeText(system()->text());
+    
+    updateCursor();
+}
+
+void InteractiveState::updateCursor() const {
+    DisplayManager *display = system()->display();
+    display->moveTo(system()->cursor());
+    display->showCursor();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/key_handler.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,10 @@
+#ifndef _KEY_HANDLER_HPP
+#define _KEY_HANDLER_HPP
+
+class KeyHandler {
+public:
+    virtual void handleKey(char ch) = 0;
+    virtual ~KeyHandler() { }
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyboard_manager.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,14 @@
+#ifndef _KEYBOARD_MANAGER_HPP
+#define _KEYBOARD_MANAGER_HPP
+
+#include "key_handler.hpp"
+
+class KeyboardManager {
+public:
+    virtual void attach(KeyHandler *handler) = 0;    
+    virtual void detach() = 0;
+        
+    virtual ~KeyboardManager() {}
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,28 @@
+#include "mbed_display_manager.hpp"
+#include "mbed_keyboard_manager.hpp"
+#include "mbed_dtmf_generator.hpp"
+#include "system.hpp"
+#include "system_states.hpp"
+#include <iostream>
+
+int main() {
+    std::cout << "\r\n\nDTMF-Kit " __DATE__ " / " __TIME__ "\r" << std::endl;
+    
+    MbedDisplayManager display;
+    MbedKeyboardManager keyboard;
+    MbedDtmfGenerator dtmf;
+
+    System system(&display, &keyboard, &dtmf);
+    InitState initState(&system);
+    EditState editState(&system);
+    CommandState commandState(&system);
+    SendingState sendingState(&system);
+    
+    keyboard.attach(&system);
+    
+    system.setState(System::Edit);
+    
+    while (true) {
+        wait(10);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/9a9732ce53a1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_display_manager.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,61 @@
+#include "mbed_display_manager.hpp"
+#include <iostream>
+
+using namespace ext_text_lcd;
+
+MbedDisplayManager::MbedDisplayManager() :
+    lcd(p28, p27, Port2, 0, TextLCD::LCD16x2), pos(0)
+{
+    std::cout << "Init Display" << "\r" << std::endl;     
+}
+
+void MbedDisplayManager::moveTo(std::size_t pos) 
+{
+    std::cout << "Display moveTo " << pos << "\r" << std::endl;
+    this->pos = pos;
+    updateCursor();
+}
+
+void MbedDisplayManager::writeStatus(const std::string &text)
+{
+    std::cout << "Display write status '" << text << "'\r" << std::endl;
+    writeAt(0, text);
+}
+
+void MbedDisplayManager::writeText(const std::string &text)
+{
+    std::cout << "Display write text '" << text << "'\r" << std::endl;
+    writeAt(1, text);
+}
+
+void MbedDisplayManager::writeAt(std::size_t row, const std::string &text)
+{
+    std::size_t len = text.size();
+    std::string str = (text + std::string(20 - len, ' '));
+    lcd.locate(0, row);
+    lcd.printf(str.c_str());
+    updateCursor();
+}
+    
+void MbedDisplayManager::updateCursor()
+{
+    lcd.locate(pos, 1);
+}
+
+void MbedDisplayManager:: showCursor()
+{
+    std::cout << "Display showCursor" << "\r" << std::endl;     
+    lcd.setDisplayControl(TextLCD::DisplayOn, TextLCD::CursorOn, TextLCD::BlinkingCursor);
+}
+
+void MbedDisplayManager:: hideCursor()
+{
+    std::cout << "Display hideCursor" << "\r" << std::endl;     
+    lcd.setDisplayControl(TextLCD::DisplayOn, TextLCD::CursorOff);
+}
+
+void MbedDisplayManager:: clear()
+{
+    std::cout << "Display clear" << "\r" << std::endl;     
+    lcd.cls();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_display_manager.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,26 @@
+#ifndef _MBED_DISPLAY_INTERFACE_HPP
+#define _MBED_DISPLAY_INTERFACE_HPP
+
+#include "display_manager.hpp"
+#include "ext_text_lcd/TextLCD.h"
+
+class MbedDisplayManager : public DisplayManager {
+public:
+    MbedDisplayManager();
+    
+    virtual void moveTo(std::size_t pos);
+    virtual void writeStatus(const std::string &text);
+    virtual void writeText(const std::string &text);
+    virtual void showCursor();
+    virtual void hideCursor();
+    virtual void clear();
+    
+private:
+    void writeAt(std::size_t row, const std::string &text);
+    void updateCursor();
+
+    ext_text_lcd::TextLCD lcd;
+    std::size_t pos;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_dtmf_generator.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,88 @@
+#include "mbed_dtmf_generator.hpp"
+#include "snd_wave_generator/SineWave.h"
+#include "snd_wave_generator/WaveCombo.h"
+#include <iostream>
+#include <sstream>
+#include <string>
+
+using namespace snd_wave_generator;
+
+MbedDtmfGenerator::MbedDtmfGenerator() :
+    generator(16000)
+{
+    std::cout << "Init Wave" << "\r" << std::endl;     
+    makeWaves();
+}
+
+void MbedDtmfGenerator::makeKeyWave(int pos, int row, int col)
+{
+    std::cout << "Init Key Wave #" << pos << " R" << row << "C" << col << "\r" << std::endl;     
+    std::auto_ptr<WaveCombo> wave(new WaveCombo());
+    wave->add(colWaves[col].get());
+    wave->add(rowWaves[row].get());
+    
+    waves[pos] = wave;
+}
+
+void MbedDtmfGenerator::makeWaves()
+{
+    static int colFreq[4] = { 1209, 1336, 1477, 1633 };
+    static int rowFreq[4] = { 697, 770, 852, 941 };
+    
+    for(int i = 0; i < 4; ++i) {
+        std::cout << "Init ColWave " << i << " hz=" << colFreq[i] << "\r" << std::endl;     
+        colWaves[i].reset(new SineWave(colFreq[i]));
+        
+        std::cout << "Init RowWave " << i << " hz=" << rowFreq[i] << "\r" << std::endl;     
+        rowWaves[i].reset(new SineWave(rowFreq[i]));
+    }
+
+    makeKeyWave(0, 3, 1);    
+    for(int row = 0; row < 3; ++row) {
+        for(int col = 0; col < 3; ++col) {
+            makeKeyWave(row * 3 + col + 1, row, col);
+        }
+    }
+    for(int ltr=0; ltr < 4; ++ltr) {
+        makeKeyWave(ltr+10, ltr, 3);
+    }
+    makeKeyWave(14, 3, 0);
+    makeKeyWave(15, 3, 2);
+}
+
+Wave * MbedDtmfGenerator::getWaveFor(char ch)
+{
+    int index = -1;
+    if (ch >= '0' && ch <= '9') {
+        index = ch - '0';
+    }
+    else if (ch >= 'A' && ch <= 'D') {
+        index = ch - 'A' + 10;
+    }
+    else if (ch == '*') {
+        index = 14;
+    }
+    else if (ch == '#') {
+        index = 15;
+    }
+    std::cout << "Wave for '" << ch << "' => " << index << "\r" << std::endl;
+    return this->waves[index].get();
+}
+
+void MbedDtmfGenerator::play(char ch) 
+{
+    Wave *wave = getWaveFor(ch);
+    std::cout << "Play Wave '" << ch << "'" << "\r" << std::endl; 
+    if (wave) {    
+        generator.play(getWaveFor(ch));
+    }
+    else {
+        std::cout << "No wave !\r" << std::endl;
+    }
+}
+
+void MbedDtmfGenerator::stop() 
+{
+    std::cout << "Stop Wave" << "\r" << std::endl;     
+    generator.stop();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_dtmf_generator.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,29 @@
+#ifndef _MBED_DTMF_GENERATOR_HPP
+#define _MBED_DTMF_GENERATOR_HPP
+
+#include "dtmf_generator.hpp"
+
+#include "snd_wave_generator/SoundWaveGenerator.h"
+#include "snd_wave_generator/Wave.h"
+
+#include <memory>
+
+class MbedDtmfGenerator : public DtmfGenerator {
+public:
+    MbedDtmfGenerator();
+    
+    virtual void play(char ch);
+    virtual void stop();
+    
+private:
+    void makeWaves();
+    void makeKeyWave(int pos, int row, int col);
+    snd_wave_generator::Wave * getWaveFor(char ch);
+    
+    snd_wave_generator::SoundWaveGenerator generator;
+    std::auto_ptr<snd_wave_generator::Wave> rowWaves[4];
+    std::auto_ptr<snd_wave_generator::Wave> colWaves[4];
+    std::auto_ptr<snd_wave_generator::Wave> waves[16];
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_keyboard_manager.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,67 @@
+#include "mbed_keyboard_manager.hpp"
+#include <iostream>
+
+using namespace kbd_mgr;
+
+namespace {
+    PinName outPinsArray[4] = { p8, p7, p6, p5 };
+    KeyboardMonitor::OutPinsSet outPins(&outPinsArray[0], &outPinsArray[4]);
+
+    
+    KeyMap makeKeymap()
+    {
+        KeyMap keymap("123A456B789C*0#D");
+        keymap(kbd_mgr::KeyEvent::LongKeyPress, 12, '@')
+            (kbd_mgr::KeyEvent::LongKeyPress, 14, '$');
+        return keymap;
+    }
+
+}
+
+MbedKeyboardManager::MbedKeyboardManager() :
+    keyMonitor(Port0, 4, 15, outPins), changeMonitor(), keyPressMonitor(),
+    longKeyPressMonitor(), keyMapper(makeKeymap())
+{
+    std::cout << "Init Keyboard" << "\r" << std::endl;     
+    longKeyPressMonitor.autoRepeat(0.500,0.250)(0,15);
+    longKeyPressMonitor.longKeyPress(0.500)(12)(14);
+}
+
+void MbedKeyboardManager::attach(KeyHandler *handler)
+{
+    std::cout << "Attach Keyboard" << "\r" << std::endl;     
+
+    this->handler = handler;
+    
+    keyMapper.attach(this);
+    longKeyPressMonitor.attach(keyMapper);
+    keyPressMonitor.attach(longKeyPressMonitor);
+    changeMonitor.attach(keyPressMonitor);
+    keyMonitor.attach(changeMonitor);
+
+    keyMonitor.start();
+}
+    
+void MbedKeyboardManager::detach()
+{
+    std::cout << "Detach Keyboard" << "\r" << std::endl;     
+    
+    keyMonitor.stop();
+    
+    keyMapper.detach();
+    longKeyPressMonitor.detach();
+    changeMonitor.detach();
+    keyMonitor.detach();
+}
+
+void MbedKeyboardManager::handleKeyPress(const KeyEvent &keypress)
+{
+    if (keypress.event != KeyEvent::KeyPress && keypress.event != KeyEvent::RepeatedKeyPress && keypress.event != KeyEvent::LongKeyPress) {
+        return;
+    }
+    
+    if (keypress.keyChar != 0) {
+        std::cout << "Handle Key '" << keypress.keyChar << "'\r" << std::endl;     
+        this->handler->handleKey(keypress.keyChar);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_keyboard_manager.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,26 @@
+#ifndef _MBED_KEYBOARD_MANAGER_HPP
+#define _MBED_KEYBOARD_MANAGER_HPP
+
+#include "keyboard_manager.hpp"
+#include "kbd_mgr/KeyboardManager.h"
+
+class MbedKeyboardManager : public KeyboardManager, public kbd_mgr::KeyPressEventHandler {
+public:
+    MbedKeyboardManager();
+    
+    virtual void attach(KeyHandler *handler);    
+    virtual void detach();
+    
+private:
+    virtual void handleKeyPress(const kbd_mgr::KeyEvent &event);
+    
+    kbd_mgr::KeyboardMonitor keyMonitor;
+    kbd_mgr::KeyboardStateChangeMonitor changeMonitor;
+    kbd_mgr::SingleKeyPressMonitor keyPressMonitor;
+    kbd_mgr::LongKeyPressMonitor longKeyPressMonitor;
+    kbd_mgr::KeyMapper keyMapper;
+    
+    KeyHandler *handler;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sending_state.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,80 @@
+#include "system_states.hpp"
+#include "system.hpp"
+#include "display_manager.hpp"
+#include "dtmf_generator.hpp"
+#include <iostream>
+
+float SendingState::ToneTime = 1.0;
+float SendingState::PauseTime = 0.25;
+
+namespace {
+    DigitalOut toneLed(LED3);
+    DigitalOut pauseLed(LED4);
+}
+
+void SendingState::enterState() {
+    system()->moveCursorTo(0);
+    
+    DisplayManager *display = system()->display();
+    display->hideCursor();
+    display->writeStatus("Sending...");
+
+    toneLed = 0;
+    pauseLed = 0;
+    
+    playSymbol();
+}
+
+void SendingState::handleKey(char key) {
+    this->timer.detach();
+    pauseLed = 0;
+
+    system()->dtmf()->stop();
+    toneLed = 0;
+
+    system()->setState(System::Edit);
+}
+
+void SendingState::playSymbol() {
+    std::cout << "Sending: Play @" << system()->cursor() << "/" << system()->text_size() << "\r" << std::endl;
+    DisplayManager *display = system()->display();
+    display->moveTo(system()->cursor());
+    display->showCursor();
+
+    char symbol = system()->text().at(system()->cursor());
+    system()->dtmf()->play(symbol);
+    
+    toneLed = 1;
+    
+    this->timer.attach(this, &SendingState::endSymbol, ToneTime);
+}
+
+void SendingState::endSymbol() {
+    std::cout << "Sending: End @" << system()->cursor() << "/" << system()->text_size() << "\r" << std::endl;
+    system()->dtmf()->stop();
+    
+    toneLed = 0;
+    
+    if (system()->cursor() < system()->text_size()-1) {
+        this->timer.attach(this, &SendingState::nextSymbol, PauseTime);
+        pauseLed = 1;
+    }
+    else {
+        DisplayManager *display = system()->display();
+        display->hideCursor();
+
+        system()->moveCursorBy(1);
+
+        //                    1234567890123456
+        display->writeStatus("Done sending...");
+    }
+}
+
+void SendingState::nextSymbol() {
+    std::cout << "Sending: Next @" << system()->cursor() << "/" << system()->text_size() << "\r" << std::endl;
+    
+    pauseLed = 0;
+    
+    system()->moveCursorBy(1);
+    playSymbol();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/state.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,16 @@
+#ifndef _STATE_HPP
+#define _STATE_HPP
+
+#include "keyboard_manager.hpp"
+
+class State {
+public:
+    virtual void enterState() {}
+    virtual void exitState() {}
+
+    virtual void handleKey(char key) {}
+    
+    virtual ~State() {}
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/state_base.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,10 @@
+#include "system_states.hpp"
+#include "system.hpp"
+
+StateBase::StateBase(System::StateId id, System *system) : system_(system) {
+    this->system_->registerState(id, this);
+}
+    
+StateBase::~StateBase() {
+    this->system_->unregisterState(this);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system.cpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,141 @@
+#include "system.hpp"
+#include "state.hpp"
+
+#include "mbed.h"
+
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+
+BusOut stateLeds(LED1, LED2);
+
+System::System(DisplayManager *display, KeyboardManager *keyboard, DtmfGenerator *dtmf) : 
+    display_(display), keyboard_(keyboard), dtmf_(dtmf), state_(NULL), text_(), len_(0), pos_(0)
+{
+    std::cout << "Init System" << "\r" << std::endl;     
+
+    std::memset(this->states_, 0, sizeof(this->states_));
+}
+
+void System::registerState(StateId id, State *state)
+{
+    std::cout << "Register System State " << id << "\r" << std::endl;     
+    this->states_[id] = state;
+    if (this->state_ == NULL) {
+        setState(id);
+    }
+}
+
+void System::unregisterState(State *state)
+{
+    State **begin = &this->states_[0];
+    State **end = begin + NumStates;
+    State **p = std::find(begin, end, state);
+    if (p != end) {
+        *p = NULL;
+    }
+    
+    if (this->state_ == state) {
+        this->state_ = NULL;
+    }
+}
+
+void System::setState(StateId newState)
+{
+    std::cout << "Set System state " << newState << "\r" << std::endl;     
+    State *s = this->states_[newState];
+    if (!s) {
+        std::cout << "Target state not found !\r" << std::endl;
+        return;
+    }
+    
+    if (s != this->state_) {
+        if (this->state_ != NULL) {
+            std::cout << "Exit current state\r" << std::endl;
+            this->state_->exitState();
+        }
+        
+        stateLeds = 0;
+        
+        if (s != NULL) {
+            std::cout << "Enter new state\r" << std::endl;
+            s->enterState();
+        }
+        
+        stateLeds = newState+1;
+        
+        this->state_ = s;
+        std::cout << "State change complete\r" << std::endl;
+    }
+}
+
+void System::insertSymbol(char ch)
+{
+    std::cout << "System Insert '" << ch << "'\r" << std::endl;     
+
+    if (this->len_ == 19) {
+        return;
+    }
+    
+    if (this->pos_ == this->len_) {
+        this->text_.append(1, ch);
+    }
+    else {
+        this->text_.insert(this->pos_, 1, ch);
+    }
+    this->pos_++;
+    this->len_++;
+}
+
+void System::deleteCurrentSymbol()
+{
+    std::cout << "System Delete" << "\r" << std::endl;     
+    if (this->pos_ < this->len_) {
+        this->text_.erase(this->pos_, 1);
+        this->len_--;
+        if (this->pos_ > this->len_) {
+            this->pos_ = len_;
+        }
+    }
+}
+
+void System::clearText()
+{
+    std::cout << "System Clear" << "\r" << std::endl;     
+    this->text_.clear();
+    this->len_ = 0;
+    this->pos_ = 0;
+}
+
+void System::moveCursorTo(int pos)
+{
+    std::cout << "System MoveTo " << pos << "/" << this->len_ << "\r" << std::endl;     
+    if (pos < 0) {
+        pos = this->len_+1 + pos;
+    }
+    setCursorPosition(pos);
+}
+
+void System::moveCursorBy(int delta)
+{
+    std::cout << "System MoveBy " << delta << "\r" << std::endl;     
+    int pos = this->pos_ + delta;
+    setCursorPosition(pos);
+}
+
+void System::setCursorPosition(int pos) 
+{    
+    std::cout << "System SetPos " << pos << "/" << this->len_ << "\r" << std::endl;     
+    if (pos < 0) {
+        pos = 0;
+    }
+    else if (pos > this->len_) {
+        pos = this->len_;
+    }
+    this->pos_ = pos;
+}
+
+void System::handleKey(char ch)
+{
+    this->state()->handleKey(ch);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,60 @@
+#ifndef _SYSTEM_HPP
+#define _SYSTEM_HPP
+
+#include "key_handler.hpp"
+#include <string>
+
+class State;
+class DisplayManager;
+class KeyboardManager;
+class DtmfGenerator;
+
+
+class System : public KeyHandler {
+public:
+    enum StateId { 
+        Init, Edit, Command, Sending,
+        NumStates
+    };
+
+    System(DisplayManager *display, KeyboardManager *keyboard, DtmfGenerator *dtmf);
+
+    DisplayManager *display() { return this->display_; }
+    KeyboardManager *keyboard() { return this->keyboard_; }
+    DtmfGenerator *dtmf() { return this->dtmf_; }
+        
+    void registerState(StateId id, State *state);
+    void unregisterState(State *state);
+    
+    void setState(StateId newState);
+    State * state() const { return this->state_; }
+
+    void insertSymbol(char ch);
+    void deleteCurrentSymbol();
+    void clearText();
+    const std::string &text() const { return this->text_; }
+    std::size_t text_size() const { return this->len_; }
+    
+    void moveCursorTo(int pos);
+    void moveCursorBy(int delta);
+    std::size_t cursor() const { return this->pos_; }
+    
+    // KeyHandler implementation
+    virtual void handleKey(char ch);
+     
+private:
+    void setCursorPosition(int pos);
+    
+    DisplayManager *display_;
+    KeyboardManager *keyboard_;
+    DtmfGenerator *dtmf_;
+
+    State *state_;
+    State *states_[NumStates];
+
+    std::string text_;
+    std::size_t len_;
+    std::size_t pos_;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system_states.hpp	Mon Mar 07 22:51:19 2011 +0000
@@ -0,0 +1,96 @@
+#ifndef _SYSTEM_STATES_HPP
+#define _SYSTEM_STATES_HPP
+
+#include "state.hpp"
+#include "system.hpp" // for System::StateId
+
+#include "mbed.h" // for Timeout
+
+class StateBase : public State {
+protected:
+    StateBase(System::StateId id, System *system);
+    virtual ~StateBase();
+    
+public:
+    System * system() const { return this->system_; }
+    
+private:
+    System *system_;
+};
+
+class InitState : public StateBase {
+public:
+    InitState(System *system) : StateBase(System::Init, system) { }
+    
+    virtual void enterState();
+    virtual void exitState();
+};
+
+class InteractiveState : public StateBase {
+public:
+    InteractiveState(System::StateId id, System *system) : StateBase(id, system) { }
+
+protected:
+    void updateText() const;
+    void updateCursor() const;
+};
+
+class EditState : public InteractiveState {
+public:
+    EditState(System *system) : InteractiveState(System::Edit, system) { }
+
+    virtual void enterState();
+
+    virtual void handleKey(char key);
+
+private:
+    void handleSymbol(char ch) const;
+};
+
+class CommandState : public InteractiveState {
+public:
+    CommandState(System *system) : InteractiveState(System::Command, system) { }
+
+    virtual void enterState();
+    virtual void exitState();
+
+    virtual void handleKey(char key);
+
+private:
+    void handleLeft() const;
+    void handleRight() const;
+    void handleHome() const;
+    void handleEnd() const;
+    void handleDelete() const;
+    void handleBackSpace() const;
+    void handleClear() const;
+    void handleSend() const;
+    void handleHelp();
+    
+    void showNextStatusMsg();
+    void showStatusMsg(int index);
+    
+    int statusMsgIndex;
+    Timeout statusMsgTimeout;
+};
+
+class SendingState : public StateBase {
+public:
+    SendingState(System *system) : StateBase(System::Sending, system) { }
+
+    virtual void enterState();
+
+    virtual void handleKey(char key);
+    
+private:
+    void playSymbol();
+    void endSymbol();
+    void nextSymbol();
+
+    static float ToneTime;
+    static float PauseTime;
+
+    Timeout timer;    
+};
+
+#endif
\ No newline at end of file