Olivier Smeesters
/
DtmfKit
A DTMF sequence editor and player for HAM radio equipment command & control.
Revision 0:1324e7d9d471, committed 2011-03-07
- Comitter:
- osmeest
- Date:
- Mon Mar 07 22:51:19 2011 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 1324e7d9d471 ExtTextLCD.lib --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/KeyMapper.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/KeyboardMonitor.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/KeyboardState.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/KeyboardStateChangeMonitor.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/LongKeyPressMonitor.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/SingleKeyPressMonitor.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyMapper.h --- /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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyPressEventHandler.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyPressEventServer.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardEventServer.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardManager.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"
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardMonitor.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardState.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardStateChangeMonitor.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardStateEventServer.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/KeyboardStateHandler.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/LongKeyPressMonitor.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_
diff -r 000000000000 -r 1324e7d9d471 KeyboardManager/kbd_mgr/SingleKeyPressMonitor.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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/SineWave.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/SoundWaveGenerator.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/TriangleWave.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/WaveBuffer.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/WaveCombo.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/BufferedWave.h --- /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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/SineWave.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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/SoundWaveGenerator.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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/TriangleWave.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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/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_
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/WaveBuffer.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
diff -r 000000000000 -r 1324e7d9d471 SoundWaveGenerator/snd_wave_generator/WaveCombo.h --- /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
diff -r 000000000000 -r 1324e7d9d471 command_state.cpp --- /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
diff -r 000000000000 -r 1324e7d9d471 display_manager.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 dtmf_generator.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 edit_state.cpp --- /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(); +} +
diff -r 000000000000 -r 1324e7d9d471 init_state.cpp --- /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(); +}
diff -r 000000000000 -r 1324e7d9d471 interactive_state.cpp --- /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(); +}
diff -r 000000000000 -r 1324e7d9d471 key_handler.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 keyboard_manager.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 main.cpp --- /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); + } +}
diff -r 000000000000 -r 1324e7d9d471 mbed.bld --- /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
diff -r 000000000000 -r 1324e7d9d471 mbed_display_manager.cpp --- /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(); +}
diff -r 000000000000 -r 1324e7d9d471 mbed_display_manager.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 mbed_dtmf_generator.cpp --- /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(); +}
diff -r 000000000000 -r 1324e7d9d471 mbed_dtmf_generator.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 mbed_keyboard_manager.cpp --- /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); + } +}
diff -r 000000000000 -r 1324e7d9d471 mbed_keyboard_manager.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 sending_state.cpp --- /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(); +}
diff -r 000000000000 -r 1324e7d9d471 state.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 state_base.cpp --- /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); +}
diff -r 000000000000 -r 1324e7d9d471 system.cpp --- /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); +}
diff -r 000000000000 -r 1324e7d9d471 system.hpp --- /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
diff -r 000000000000 -r 1324e7d9d471 system_states.hpp --- /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