Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (C) 2011 Cliff L. Biffle, all rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include "Chatpad.h"
- #include "Arduino.h"
- #include "HardwareSerial.h"
- #include <avr/pgmspace.h>
- // Masks for modifier bits
- static const byte kShiftMask = (1 << 0);
- static const byte kGreenSquareMask = (1 << 1);
- static const byte kOrangeCircleMask = (1 << 2);
- static const byte kPeopleMask = (1 << 3);
- // Voodoo protocol messages
- static const byte kInitMessage[] = { 0x87, 0x02, 0x8C, 0x1F, 0xCC };
- static const byte kAwakeMessage[] = { 0x87, 0x02, 0x8C, 0x1B, 0xD0 };
- void Chatpad::init(HardwareSerial &serial, Chatpad::callback_t callback) {
- _serial = &serial;
- _callback = callback;
- _last_modifiers = 0;
- _last_key0 = 0;
- _last_key1 = 0;
- _last_ping = 0;
- Serial.begin(19200);
- Serial.write(kInitMessage, sizeof(kInitMessage));
- // while(Serial.peek() != 0xA5)
- // {
- // Serial.read();
- // continue;
- // }
- }
- void Chatpad::poll() {
- // Only act if a full message is available.
- if (Serial.available() >= 8) {
- for (int i = 0; i < 8; i++) {
- _buffer[i] = Serial.read();
- }
- // We expect "status report" packets beginning with 0xA5, but don't know
- // what to do with them -- so we silently discard them.
- if (_buffer[0] == 0xA5) return;
- // We *do not* expect other types of packets. If we find one, complain
- // to the user.
- if (_buffer[0] != 0xB4) {
- return;
- }
- if (_buffer[1] != 0xC5) {
- return;
- }
- // Check the checksum.
- unsigned char checksum = _buffer[0];
- for (int i = 1; i < 7; i++) checksum += _buffer[i];
- checksum = -checksum;
- if (checksum != _buffer[7]) {
- return;
- }
- // Packet looks good!
- // Dissect the parts we care about:
- byte modifiers = _buffer[3];
- byte key0 = _buffer[4];
- byte key1 = _buffer[5];
- // Check for changes in the modifiers.
- byte modifier_changes = modifiers ^ _last_modifiers;
- if (modifier_changes & kShiftMask) {
- dispatch(KeyShift, modifiers & kShiftMask);
- }
- if (modifier_changes & kGreenSquareMask) {
- dispatch(KeyGreenSquare, modifiers & kGreenSquareMask);
- }
- if (modifier_changes & kOrangeCircleMask) {
- dispatch(KeyOrangeCircle, modifiers & kOrangeCircleMask);
- }
- if (modifier_changes & kPeopleMask) {
- dispatch(KeyPeople, modifiers & kPeopleMask);
- }
- _last_modifiers = modifiers;
- // Check for changes in the other keys
- if (key0 && key0 != _last_key0 && key0 != _last_key1) {
- dispatch(key0, Down);
- }
- if (key1 && key1 != _last_key0 && key1 != _last_key1) {
- dispatch(key1, Down);
- }
- if (_last_key0 && _last_key0 != key0 && _last_key0 != key1) {
- dispatch(_last_key0, Up);
- }
- if (_last_key1 && _last_key1 != key0 && _last_key1 != key1) {
- dispatch(_last_key1, Up);
- }
- _last_key0 = key0;
- _last_key1 = key1;
- }
- uint32_t time = millis();
- if (time - _last_ping > 1000) {
- _last_ping = time;
- Serial.write(kAwakeMessage, sizeof(kAwakeMessage));
- }
- }
- bool Chatpad::isShiftDown() const {
- return _last_modifiers & kShiftMask;
- }
- bool Chatpad::isGreenSquareDown() const {
- return _last_modifiers & kGreenSquareMask;
- }
- bool Chatpad::isOrangeCircleDown() const {
- return _last_modifiers & kOrangeCircleMask;
- }
- bool Chatpad::isPeopleDown() const {
- return _last_modifiers & kPeopleMask;
- }
- void Chatpad::dispatch(uint8_t code, int is_down) {
- _callback(*this, (keycode_t) code, is_down? Down : Up);
- }
- /**************
- * Translation
- */
- // These tables have been compacted and must be accessed using this formula:
- // index = (((keycode & 0xF0) - 0x10) >> 1) | ((keycode & 0x0F) - 1)
- static const char kAsciiTable[] PROGMEM = {
- '7', /* 11 Key7 */
- '6', /* 12 Key6 */
- '5', /* 13 Key5 */
- '4', /* 14 Key4 */
- '3', /* 15 Key3 */
- '2', /* 16 Key2 */
- '1', /* 17 Key1 */
- 0, /* 18 Unused */
- 'u', /* 21 KeyU */
- 'y', /* 22 KeyY */
- 't', /* 23 KeyT */
- 'r', /* 24 KeyR */
- 'e', /* 25 KeyE */
- 'w', /* 26 KeyW */
- 'q', /* 27 KeyQ */
- 0, /* 28 Unused */
- 'j', /* 31 KeyJ */
- 'h', /* 32 KeyH */
- 'g', /* 33 KeyG */
- 'f', /* 34 KeyF */
- 'd', /* 35 KeyD */
- 's', /* 36 KeyS */
- 'a', /* 37 KeyA */
- 0, /* 38 Unused */
- 'n', /* 41 KeyN */
- 'b', /* 42 KeyB */
- 'v', /* 43 KeyV */
- 'c', /* 44 KeyC */
- 'x', /* 45 KeyX */
- 'z', /* 46 KeyZ */
- 0, /* 47 Unused */
- 0, /* 48 Unused */
- 0, /* 51 KeyRight */
- 'm', /* 52 KeyM */
- '.', /* 53 KeyPeriod */
- ' ', /* 54 KeySpace */
- 0, /* 55 KeyLeft */
- 0, /* 56 Unused */
- 0, /* 57 Unused */
- 0, /* 58 Unused */
- 0, /* 61 Unused */
- ',', /* 62 KeyComma */
- '\n', /* 63 KeyEnter */
- 'p', /* 64 KeyP */
- '0', /* 65 Key0 */
- '9', /* 66 Key9 */
- '8', /* 67 Key8 */
- 0, /* 68 Unused */
- '\b', /* 71 KeyBackspace */
- 'l', /* 72 KeyL */
- 0, /* 73 Unused */
- 0, /* 74 Unused */
- 'o', /* 75 KeyO */
- 'i', /* 76 KeyI */
- 'k', /* 77 KeyK */
- 0, /* 78 Unused */
- };
- static const char kAsciiTable_Shifted[] PROGMEM = {
- '&', /* 11 Key7 */
- '^', /* 12 Key6 */
- '%', /* 13 Key5 */
- '$', /* 14 Key4 */
- '#', /* 15 Key3 */
- '@', /* 16 Key2 */
- '!', /* 17 Key1 */
- 0, /* 18 Unused */
- 'U', /* 21 KeyU */
- 'Y', /* 22 KeyY */
- 'T', /* 23 KeyT */
- 'R', /* 24 KeyR */
- 'E', /* 25 KeyE */
- 'W', /* 26 KeyW */
- 'Q', /* 27 KeyQ */
- 0, /* 28 Unused */
- 'J', /* 31 KeyJ */
- 'H', /* 32 KeyH */
- 'G', /* 33 KeyG */
- 'F', /* 34 KeyF */
- 'D', /* 35 KeyD */
- 'S', /* 36 KeyS */
- 'A', /* 37 KeyA */
- 0, /* 38 Unused */
- 'N', /* 41 KeyN */
- 'B', /* 42 KeyB */
- 'V', /* 43 KeyV */
- 'C', /* 44 KeyC */
- 'X', /* 45 KeyX */
- 'Z', /* 46 KeyZ */
- 0, /* 47 Unused */
- 0, /* 48 Unused */
- 0, /* 51 KeyRight */
- 'M', /* 52 KeyM */
- '>', /* 53 KeyPeriod */
- ' ', /* 54 KeySpace */
- 0, /* 55 KeyLeft */
- 0, /* 56 Unused */
- 0, /* 57 Unused */
- 0, /* 58 Unused */
- 0, /* 61 Unused */
- '<', /* 62 KeyComma */
- '\n', /* 63 KeyEnter */
- 'P', /* 64 KeyP */
- ')', /* 65 Key0 */
- '(', /* 66 Key9 */
- '*', /* 67 Key8 */
- 0, /* 68 Unused */
- '\b', /* 71 KeyBackspace */
- 'L', /* 72 KeyL */
- 0, /* 73 Unused */
- 0, /* 74 Unused */
- 'O', /* 75 KeyO */
- 'I', /* 76 KeyI */
- 'K', /* 77 KeyK */
- 0, /* 78 Unused */
- };
- char Chatpad::toAscii(keycode_t code) {
- byte index = (((code - 0x11) & 0x70) >> 1) | ((code - 0x11) & 0x7);
- if (index >= sizeof(kAsciiTable)) return 0;
- if (isShiftDown()) {
- return pgm_read_byte_near(kAsciiTable_Shifted + index);
- } else {
- return pgm_read_byte_near(kAsciiTable + index);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement