Advertisement
Pew446

Chatpad.cpp

Oct 8th, 2013
122
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * Copyright (C) 2011 Cliff L. Biffle, all rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are met:
  6.  *
  7.  * - Redistributions of source code must retain the above copyright notice, this
  8.  *   list of conditions and the following disclaimer.
  9.  * - Redistributions in binary form must reproduce the above copyright notice,
  10.  *   this list of conditions and the following disclaimer in the documentation
  11.  *   and/or other materials provided with the distribution.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23.  * POSSIBILITY OF SUCH DAMAGE.
  24.  */
  25. #include "Chatpad.h"
  26. #include "Arduino.h"
  27. #include "HardwareSerial.h"
  28.  
  29. #include <avr/pgmspace.h>
  30.  
  31. // Masks for modifier bits
  32. static const byte kShiftMask = (1 << 0);
  33. static const byte kGreenSquareMask = (1 << 1);
  34. static const byte kOrangeCircleMask = (1 << 2);
  35. static const byte kPeopleMask = (1 << 3);
  36.  
  37. // Voodoo protocol messages
  38. static const byte kInitMessage[] = { 0x87, 0x02, 0x8C, 0x1F, 0xCC };
  39. static const byte kAwakeMessage[] = { 0x87, 0x02, 0x8C, 0x1B, 0xD0 };
  40.  
  41. void Chatpad::init(HardwareSerial &serial, Chatpad::callback_t callback) {
  42.   _serial = &serial;
  43.   _callback = callback;
  44.   _last_modifiers = 0;
  45.   _last_key0 = 0;
  46.   _last_key1 = 0;
  47.   _last_ping = 0;
  48.   Serial.begin(19200);
  49.   Serial.write(kInitMessage, sizeof(kInitMessage));
  50. //  while(Serial.peek() != 0xA5)
  51. //  {
  52. //   Serial.read();
  53. //   continue;
  54. //  }
  55. }
  56.  
  57. void Chatpad::poll() {
  58.   // Only act if a full message is available.
  59.   if (Serial.available() >= 8) {
  60.     for (int i = 0; i < 8; i++) {
  61.       _buffer[i] = Serial.read();
  62.     }
  63.  
  64.     // We expect "status report" packets beginning with 0xA5, but don't know
  65.     // what to do with them -- so we silently discard them.
  66.     if (_buffer[0] == 0xA5) return;
  67.  
  68.     // We *do not* expect other types of packets.  If we find one, complain
  69.     // to the user.
  70.     if (_buffer[0] != 0xB4) {
  71.       return;
  72.     }
  73.     if (_buffer[1] != 0xC5) {
  74.       return;
  75.     }
  76.  
  77.     // Check the checksum.
  78.     unsigned char checksum = _buffer[0];
  79.     for (int i = 1; i < 7; i++) checksum += _buffer[i];
  80.     checksum = -checksum;
  81.     if (checksum != _buffer[7]) {
  82.       return;
  83.     }
  84.  
  85.     // Packet looks good!
  86.     // Dissect the parts we care about:
  87.     byte modifiers = _buffer[3];
  88.     byte key0 = _buffer[4];
  89.     byte key1 = _buffer[5];
  90.  
  91.     // Check for changes in the modifiers.
  92.     byte modifier_changes = modifiers ^ _last_modifiers;
  93.     if (modifier_changes & kShiftMask) {
  94.       dispatch(KeyShift, modifiers & kShiftMask);
  95.     }
  96.     if (modifier_changes & kGreenSquareMask) {
  97.       dispatch(KeyGreenSquare, modifiers & kGreenSquareMask);
  98.     }
  99.     if (modifier_changes & kOrangeCircleMask) {
  100.       dispatch(KeyOrangeCircle, modifiers & kOrangeCircleMask);
  101.     }
  102.     if (modifier_changes & kPeopleMask) {
  103.       dispatch(KeyPeople, modifiers & kPeopleMask);
  104.     }
  105.     _last_modifiers = modifiers;
  106.  
  107.     // Check for changes in the other keys
  108.     if (key0 && key0 != _last_key0 && key0 != _last_key1) {
  109.       dispatch(key0, Down);
  110.     }
  111.     if (key1 && key1 != _last_key0 && key1 != _last_key1) {
  112.       dispatch(key1, Down);
  113.     }
  114.     if (_last_key0 && _last_key0 != key0 && _last_key0 != key1) {
  115.       dispatch(_last_key0, Up);
  116.     }
  117.     if (_last_key1 && _last_key1 != key0 && _last_key1 != key1) {
  118.       dispatch(_last_key1, Up);
  119.     }
  120.     _last_key0 = key0;
  121.     _last_key1 = key1;
  122.   }
  123.  
  124.   uint32_t time = millis();
  125.   if (time - _last_ping > 1000) {
  126.     _last_ping = time;
  127.     Serial.write(kAwakeMessage, sizeof(kAwakeMessage));
  128.   }
  129. }
  130.  
  131. bool Chatpad::isShiftDown() const {
  132.   return _last_modifiers & kShiftMask;
  133. }
  134.  
  135. bool Chatpad::isGreenSquareDown() const {
  136.   return _last_modifiers & kGreenSquareMask;
  137. }
  138.  
  139. bool Chatpad::isOrangeCircleDown() const {
  140.   return _last_modifiers & kOrangeCircleMask;
  141. }
  142.  
  143. bool Chatpad::isPeopleDown() const {
  144.   return _last_modifiers & kPeopleMask;
  145. }
  146.  
  147. void Chatpad::dispatch(uint8_t code, int is_down) {
  148.   _callback(*this, (keycode_t) code, is_down? Down : Up);
  149. }
  150.  
  151. /**************
  152.  * Translation
  153.  */
  154.  
  155. // These tables have been compacted and must be accessed using this formula:
  156. //  index = (((keycode & 0xF0) - 0x10) >> 1) | ((keycode & 0x0F) - 1)
  157. static const char kAsciiTable[] PROGMEM = {
  158.   '7', /* 11 Key7 */
  159.   '6', /* 12 Key6 */
  160.   '5', /* 13 Key5 */
  161.   '4', /* 14 Key4 */
  162.   '3', /* 15 Key3 */
  163.   '2', /* 16 Key2 */
  164.   '1', /* 17 Key1 */
  165.   0, /* 18 Unused */
  166.  
  167.   'u', /* 21 KeyU */
  168.   'y', /* 22 KeyY */
  169.   't', /* 23 KeyT */
  170.   'r', /* 24 KeyR */
  171.   'e', /* 25 KeyE */
  172.   'w', /* 26 KeyW */
  173.   'q', /* 27 KeyQ */
  174.   0, /* 28 Unused */
  175.  
  176.   'j', /* 31 KeyJ */
  177.   'h', /* 32 KeyH */
  178.   'g', /* 33 KeyG */
  179.   'f', /* 34 KeyF */
  180.   'd', /* 35 KeyD */
  181.   's', /* 36 KeyS */
  182.   'a', /* 37 KeyA */
  183.   0, /* 38 Unused */
  184.  
  185.   'n', /* 41 KeyN */
  186.   'b', /* 42 KeyB */
  187.   'v', /* 43 KeyV */
  188.   'c', /* 44 KeyC */
  189.   'x', /* 45 KeyX */
  190.   'z', /* 46 KeyZ */
  191.   0, /* 47 Unused */
  192.   0, /* 48 Unused */
  193.  
  194.   0, /* 51 KeyRight */
  195.   'm', /* 52 KeyM */
  196.   '.', /* 53 KeyPeriod */
  197.   ' ', /* 54 KeySpace */
  198.   0, /* 55 KeyLeft */
  199.   0, /* 56 Unused */
  200.   0, /* 57 Unused */
  201.   0, /* 58 Unused */
  202.  
  203.   0, /* 61 Unused */
  204.   ',', /* 62 KeyComma */
  205.   '\n', /* 63 KeyEnter */
  206.   'p', /* 64 KeyP */
  207.   '0', /* 65 Key0 */
  208.   '9', /* 66 Key9 */
  209.   '8', /* 67 Key8 */
  210.   0, /* 68 Unused */
  211.  
  212.   '\b', /* 71 KeyBackspace */
  213.   'l', /* 72 KeyL */
  214.   0, /* 73 Unused */
  215.   0, /* 74 Unused */
  216.   'o', /* 75 KeyO */
  217.   'i', /* 76 KeyI */
  218.   'k', /* 77 KeyK */
  219.   0, /* 78 Unused */
  220. };
  221.  
  222. static const char kAsciiTable_Shifted[] PROGMEM = {
  223.   '&', /* 11 Key7 */
  224.   '^', /* 12 Key6 */
  225.   '%', /* 13 Key5 */
  226.   '$', /* 14 Key4 */
  227.   '#', /* 15 Key3 */
  228.   '@', /* 16 Key2 */
  229.   '!', /* 17 Key1 */
  230.   0, /* 18 Unused */
  231.  
  232.   'U', /* 21 KeyU */
  233.   'Y', /* 22 KeyY */
  234.   'T', /* 23 KeyT */
  235.   'R', /* 24 KeyR */
  236.   'E', /* 25 KeyE */
  237.   'W', /* 26 KeyW */
  238.   'Q', /* 27 KeyQ */
  239.   0, /* 28 Unused */
  240.  
  241.   'J', /* 31 KeyJ */
  242.   'H', /* 32 KeyH */
  243.   'G', /* 33 KeyG */
  244.   'F', /* 34 KeyF */
  245.   'D', /* 35 KeyD */
  246.   'S', /* 36 KeyS */
  247.   'A', /* 37 KeyA */
  248.   0, /* 38 Unused */
  249.  
  250.   'N', /* 41 KeyN */
  251.   'B', /* 42 KeyB */
  252.   'V', /* 43 KeyV */
  253.   'C', /* 44 KeyC */
  254.   'X', /* 45 KeyX */
  255.   'Z', /* 46 KeyZ */
  256.   0, /* 47 Unused */
  257.   0, /* 48 Unused */
  258.  
  259.   0, /* 51 KeyRight */
  260.   'M', /* 52 KeyM */
  261.   '>', /* 53 KeyPeriod */
  262.   ' ', /* 54 KeySpace */
  263.   0, /* 55 KeyLeft */
  264.   0, /* 56 Unused */
  265.   0, /* 57 Unused */
  266.   0, /* 58 Unused */
  267.  
  268.   0, /* 61 Unused */
  269.   '<', /* 62 KeyComma */
  270.   '\n', /* 63 KeyEnter */
  271.   'P', /* 64 KeyP */
  272.   ')', /* 65 Key0 */
  273.   '(', /* 66 Key9 */
  274.   '*', /* 67 Key8 */
  275.   0, /* 68 Unused */
  276.  
  277.   '\b', /* 71 KeyBackspace */
  278.   'L', /* 72 KeyL */
  279.   0, /* 73 Unused */
  280.   0, /* 74 Unused */
  281.   'O', /* 75 KeyO */
  282.   'I', /* 76 KeyI */
  283.   'K', /* 77 KeyK */
  284.   0, /* 78 Unused */
  285. };
  286.  
  287. char Chatpad::toAscii(keycode_t code) {
  288.   byte index = (((code - 0x11) & 0x70) >> 1) | ((code - 0x11) & 0x7);
  289.   if (index >= sizeof(kAsciiTable)) return 0;
  290.  
  291.   if (isShiftDown()) {
  292.     return pgm_read_byte_near(kAsciiTable_Shifted + index);
  293.   } else {
  294.     return pgm_read_byte_near(kAsciiTable + index);
  295.   }
  296. }
Advertisement
RAW Paste Data Copied
Advertisement