├── documentation ├── board.jpg └── connector.jpg ├── examples ├── Chatpad_Leonardo_Keyboard │ └── Chatpad_Leonardo_Keyboard.ino └── Chatpad_Example │ └── Chatpad_Example.pde ├── library.properties ├── keywords.txt ├── LICENSE.txt ├── README.md ├── Chatpad.h └── Chatpad.cpp /documentation/board.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frequem/Chatpad/HEAD/documentation/board.jpg -------------------------------------------------------------------------------- /documentation/connector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frequem/Chatpad/HEAD/documentation/connector.jpg -------------------------------------------------------------------------------- /examples/Chatpad_Leonardo_Keyboard/Chatpad_Leonardo_Keyboard.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | Chatpad chatpad; 5 | 6 | void setup() { 7 | Keyboard.begin(); 8 | Serial.begin(9600); 9 | Serial1.begin(19200); 10 | chatpad.Init(Serial1, onPress, onRelease); 11 | } 12 | 13 | void loop(){ 14 | chatpad.run(); 15 | } 16 | 17 | void onPress(char key){ 18 | Keyboard.press(key); 19 | } 20 | 21 | void onRelease(char key){ 22 | Keyboard.release(key); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Chatpad 2 | version=1.0.0 3 | author=frequem 4 | maintainer=frequem 5 | sentence=Library for connectiong to Microsoft's XBOX chatpad.
6 | paragraph=This is a Wiring Framework (Arduino) library to provide an easy way to interface Microsoft's XBOX chatpad.
This library does NOT work in conjunction with SoftwareSerial, since that does not support simultaneous sending and receiving. It does however work with AltSoftSerial by PaulStoffregen.
SMFSW's SeqTimer is needed to compile this library.

Issues or questions: https://github.com/frequem/Chatpad/issues
7 | category=Device Control 8 | url=https://github.com/frequem/Chatpad 9 | architectures=* 10 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ######################################## 2 | # Syntax Coloring Map For 3 | # ExampleLibrary 4 | # 5 | # Fields (Data Members) - KEYWORD2 6 | # Methods (Member Functions) 7 | # - FUNCTION2 (or KEYWORD2) 8 | # Constants - LITERAL2 9 | # Datatypes - KEYWORD5 (or KEYWORD1) 10 | ######################################## 11 | 12 | ######################################## 13 | # Datatypes (KEYWORD5 or KEYWORD1) 14 | ######################################## 15 | 16 | ExampleLibrary KEYWORD1 17 | 18 | ######################################## 19 | # Methods and Functions 20 | # (FUNCTION2 or KEYWORD2) 21 | ######################################## 22 | 23 | doThatThing KEYWORD2 24 | 25 | ######################################## 26 | # Constants (LITERAL2) 27 | ######################################## 28 | 29 | FORWARD LITERAL2 30 | BACKWARD LITERAL2 31 | -------------------------------------------------------------------------------- /examples/Chatpad_Example/Chatpad_Example.pde: -------------------------------------------------------------------------------- 1 | /* 2 | || @author frequem 3 | || @url https://github.com/frequem/Chatpad/ 4 | || 5 | || @description 6 | || | 7 | || | This is an example sketch using the Chatpad Wiring Library. 8 | || | 9 | || # 10 | || 11 | || @license Please see the accompanying LICENSE.txt file for this project. 12 | || 13 | */ 14 | 15 | #include "Chatpad.h" 16 | 17 | Chatpad chatpad;// Create a Chatpad object. 18 | AltSoftSerial chatpadSerial;// Serial connection to the chatpad 19 | 20 | void setup(){ 21 | Serial.begin(9600); //USB Serial for printing to Serial Monitor 22 | chatpadSerial.begin(19200); // always 19200 for the chatpadSerial, cannot be moved into chatpad class since that takes a stream object and all streams shall be supported 23 | chatpad.Init(chatpadSerial, onPress, onRelease); 24 | } 25 | 26 | void loop(){ 27 | chatpad.run(); //important 28 | } 29 | 30 | void onPress(char key){ 31 | Serial.print("pressing "); 32 | Serial.println(key); 33 | } 34 | 35 | void onRelease(char key){ 36 | Serial.print("releasing "); 37 | Serial.println(key); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 B Hagman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chatpad 2 | ============== 3 | 4 | ## Description 5 | 6 | A [Arduino](https://en.wikipedia.org/wiki/Arduino)/[Wiring](https://en.wikipedia.org/wiki/Wiring_(development_platform)) library for connectiong to Microsoft's XBOX chatpad. 7 | 8 | This library does NOT work in conjunction with SoftwareSerial, since that does not support simultaneous sending and receiving. 9 | 10 | It does however work with [AltSoftSerial by PaulStoffregen](https://github.com/PaulStoffregen/AltSoftSerial). 11 | 12 | [SMFSW's SeqTimer](https://github.com/SMFSW/SeqTimer) is needed to compile this library. 13 | 14 | ## Example 15 | 16 | ```cpp 17 | #include "Chatpad.h" 18 | 19 | Chatpad chatpad;// Create a Chatpad object. 20 | AltSoftSerial chatpadSerial;// Serial connection to the chatpad 21 | 22 | void setup(){ 23 | Serial.begin(9600); //USB Serial for printing to Serial Monitor 24 | 25 | //can be replaced with one of the hardware serials 26 | //cannot be moved into chatpad class since that takes a stream object and all streams shall be supported 27 | chatpadSerial.begin(19200); // always 19200 for the chatpadSerial 28 | chatpad.Init(chatpadSerial, onPress, onRelease); 29 | } 30 | 31 | void loop(){ 32 | chatpad.run(); //important 33 | } 34 | 35 | void onPress(char key){ 36 | Serial.print("pressing "); 37 | Serial.println(key); 38 | } 39 | 40 | void onRelease(char key){ 41 | Serial.print("releasing "); 42 | Serial.println(key); 43 | } 44 | 45 | ``` 46 | 47 | 48 | -------------------------------------------------------------------------------- /Chatpad.h: -------------------------------------------------------------------------------- 1 | #ifndef CHATPAD_H 2 | #define CHATPAD_H 3 | 4 | #include "Arduino.h" 5 | #include 6 | 7 | const uint8_t MODIFIER_SHIFT = 0b0001; 8 | const uint8_t MODIFIER_LEFTCTRL = 0b0010; 9 | const uint8_t MODIFIER_RIGHTCTRL = 0b0100; 10 | const uint8_t MODIFIER_MESSENGER = 0b1000; 11 | 12 | const uint8_t COMMANDKEY_SHIFT = 0b0001; 13 | const uint8_t COMMANDKEY_CAPS_LOCK = 0b0010; 14 | const uint8_t COMMANDKEY_CTRL = 0b0100; 15 | const uint8_t COMMANDKEY_ALT = 0b1000; 16 | 17 | //from arduino's Keyboard.h 18 | 19 | const uint8_t KEY_UP_ARROW = 0xDA; 20 | const uint8_t KEY_DOWN_ARROW = 0xD9; 21 | const uint8_t KEY_LEFT_ARROW = 0xD8; 22 | const uint8_t KEY_RIGHT_ARROW = 0xD7; 23 | const uint8_t KEY_BACKSPACE = 0xB2; 24 | const uint8_t KEY_RETURN = 0xB0; 25 | const uint8_t KEY_TAB = 0xB3; 26 | const uint8_t KEY_LEFT_CTRL = 0x80; 27 | const uint8_t KEY_LEFT_ALT = 0x82; 28 | const uint8_t KEY_LEFT_SHIFT = 0x81; 29 | const uint8_t KEY_CAPS_LOCK = 0xC1; 30 | 31 | class Chatpad{ 32 | public: 33 | Chatpad(); 34 | void Init(Stream& serialstream); 35 | void Init(Stream& serialstream, void (*f_press)(char), void (*f_release)(char)); 36 | 37 | void run(); 38 | 39 | void pressHandler(void (*f_press)(char)); 40 | void releaseHandler(void (*f_release)(char)); 41 | 42 | //debug 43 | void bufferUpdateHandler(void (*f_buffer_update)(uint8_t[8])); 44 | private: 45 | Stream *m_serialstream; 46 | SeqTimer m_timer; 47 | uint8_t m_buffer[8]; 48 | char m_lastkeys[2]; 49 | uint8_t m_commandkeys; 50 | 51 | void (*handler_onPress)(char); 52 | void (*handler_onRelease)(char); 53 | //debug 54 | void (*handler_onBufferUpdate)(uint8_t[8]); 55 | 56 | void buffer_evaluate(); 57 | void commandkeys_evaluate(uint8_t modifier); 58 | 59 | void chatpad_onPress(char key); 60 | void chatpad_onRelease(char key); 61 | void chatpad_onBufferUpdate(uint8_t buf[8]); 62 | 63 | void chatpad_fix_stream(); 64 | void chatpad_init(); 65 | void chatpad_keep_awake(); 66 | 67 | static char chatpad_to_char(uint8_t chatpad_byte, uint8_t modifier); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /Chatpad.cpp: -------------------------------------------------------------------------------- 1 | #include "Chatpad.h" 2 | 3 | Chatpad::Chatpad() {} 4 | 5 | void Chatpad::Init(Stream &serialstream) { 6 | m_serialstream = &serialstream; 7 | m_commandkeys = 0; 8 | m_timer.init(1000); 9 | 10 | chatpad_init(); 11 | chatpad_keep_awake(); 12 | } 13 | 14 | void Chatpad::Init(Stream &serialstream, void (*f_press)(char), 15 | void (*f_release)(char)) { 16 | pressHandler(f_press); 17 | releaseHandler(f_release); 18 | 19 | Init(serialstream); 20 | } 21 | 22 | void Chatpad::pressHandler(void (*f_press)(char)) { handler_onPress = f_press; } 23 | 24 | void Chatpad::releaseHandler(void (*f_release)(char)) { 25 | handler_onRelease = f_release; 26 | } 27 | 28 | void Chatpad::bufferUpdateHandler(void (*f_buffer_update)(uint8_t[8])) { 29 | handler_onBufferUpdate = f_buffer_update; 30 | } 31 | 32 | void Chatpad::run() { 33 | if (m_timer.getTimer()) { 34 | chatpad_keep_awake(); 35 | } 36 | 37 | if (m_serialstream->available() >= 8) { 38 | m_serialstream->readBytes(m_buffer, 8); 39 | if ((m_buffer[0] != 0xB4) && (m_buffer[0] != 0xA5)) { 40 | chatpad_fix_stream(); 41 | return; 42 | } 43 | if (m_buffer[0] == 0xB4) { 44 | chatpad_onBufferUpdate(m_buffer); 45 | buffer_evaluate(); 46 | } 47 | } 48 | } 49 | 50 | void Chatpad::commandkeys_evaluate(uint8_t modifiers) { 51 | static uint8_t mods[] = {MODIFIER_SHIFT | MODIFIER_RIGHTCTRL, MODIFIER_SHIFT, MODIFIER_MESSENGER}; 52 | static uint8_t com[] = {COMMANDKEY_CAPS_LOCK, COMMANDKEY_SHIFT, COMMANDKEY_CTRL}; 53 | static uint8_t keys[] = {KEY_CAPS_LOCK, KEY_LEFT_SHIFT, KEY_LEFT_CTRL}; 54 | 55 | for (int i = 0; i < 3; i++) { 56 | if (((modifiers & mods[i]) == mods[i]) && !(m_commandkeys & com[i])) { 57 | m_commandkeys |= com[i]; 58 | chatpad_onPress(keys[i]); 59 | } else if (!((modifiers & mods[i]) == mods[i]) && (m_commandkeys & com[i])) { 60 | m_commandkeys &= ~com[i]; 61 | chatpad_onRelease(keys[i]); 62 | } 63 | } 64 | } 65 | 66 | void Chatpad::buffer_evaluate() { 67 | commandkeys_evaluate(m_buffer[3]); 68 | 69 | char k = chatpad_to_char(m_buffer[4], m_buffer[3]); 70 | 71 | if (k != 0 && m_lastkeys[0] == 0) { // k1 is pressed 72 | chatpad_onPress(k); 73 | m_lastkeys[0] = k; 74 | return; 75 | } 76 | if (m_lastkeys[0] != 0 && k == 0) { // k1 is released 77 | chatpad_onRelease(m_lastkeys[0]); 78 | m_lastkeys[0] = 0; 79 | return; 80 | } 81 | if (k != 0 && k == m_lastkeys[1]) { // k2 switched to k1 82 | chatpad_onRelease(m_lastkeys[0]); 83 | m_lastkeys[0] = m_lastkeys[1]; 84 | m_lastkeys[1] = 0; 85 | return; 86 | } 87 | if (k != 0 && m_lastkeys[0] != 0 && 88 | k != m_lastkeys[0]) { // k1 changed char (maybe caps?..) 89 | chatpad_onRelease(m_lastkeys[0]); 90 | chatpad_onPress(k); 91 | m_lastkeys[0] = k; 92 | return; 93 | } 94 | 95 | k = chatpad_to_char(m_buffer[5], m_buffer[3]); 96 | 97 | if (k != 0 && m_lastkeys[1] == 0) { // k2 is pressed 98 | chatpad_onPress(k); 99 | m_lastkeys[1] = k; 100 | return; 101 | } 102 | if (m_lastkeys[1] != 0 && k == 0) { // k2 is released 103 | chatpad_onRelease(m_lastkeys[1]); 104 | m_lastkeys[1] = 0; 105 | } 106 | } 107 | 108 | void Chatpad::chatpad_onPress(char key) { 109 | if (handler_onPress) 110 | handler_onPress(key); 111 | } 112 | 113 | void Chatpad::chatpad_onRelease(char key) { 114 | if (handler_onRelease) 115 | handler_onRelease(key); 116 | } 117 | 118 | void Chatpad::chatpad_onBufferUpdate(uint8_t buf[8]) { 119 | if (handler_onBufferUpdate) 120 | handler_onBufferUpdate(buf); 121 | } 122 | 123 | void Chatpad::chatpad_fix_stream() { 124 | for (int i = 1; i < 8; i++) { 125 | if ((m_buffer[i] == 0xB4) || (m_buffer[i] == 0xA5)) { 126 | while (m_serialstream->available() < i) 127 | ; 128 | m_serialstream->readBytes(m_buffer, i); 129 | break; 130 | } 131 | } 132 | } 133 | 134 | void Chatpad::chatpad_init() { 135 | m_serialstream->write(0x87); 136 | m_serialstream->write(0x02); 137 | m_serialstream->write(0x8C); 138 | m_serialstream->write(0x1F); 139 | m_serialstream->write(0xCC); 140 | m_serialstream->flush(); 141 | } 142 | 143 | void Chatpad::chatpad_keep_awake() { 144 | m_serialstream->write(0x87); 145 | m_serialstream->write(0x02); 146 | m_serialstream->write(0x8C); 147 | m_serialstream->write(0x1B); 148 | m_serialstream->write(0xD0); 149 | m_serialstream->flush(); 150 | } 151 | 152 | char Chatpad::chatpad_to_char(uint8_t chatpad_byte, uint8_t modifier) { 153 | uint8_t c = 0; 154 | switch (chatpad_byte) { 155 | case 0x65: 156 | return '0'; 157 | case 0x17: 158 | return '1'; 159 | case 0x16: 160 | return '2'; 161 | case 0x15: 162 | return '3'; 163 | case 0x14: 164 | return '4'; 165 | case 0x13: 166 | return '5'; 167 | case 0x12: 168 | return '6'; 169 | case 0x11: 170 | return '7'; 171 | case 0x67: 172 | return '8'; 173 | case 0x66: 174 | return '9'; 175 | case 0x37: 176 | c = 'a'; 177 | break; 178 | case 0x42: 179 | c = 'b'; 180 | break; 181 | case 0x44: 182 | c = 'c'; 183 | break; 184 | case 0x35: 185 | c = 'd'; 186 | break; 187 | case 0x25: 188 | c = 'e'; 189 | break; 190 | case 0x34: 191 | c = 'f'; 192 | break; 193 | case 0x33: 194 | c = 'g'; 195 | break; 196 | case 0x32: 197 | c = 'h'; 198 | break; 199 | case 0x76: 200 | c = 'i'; 201 | break; 202 | case 0x31: 203 | c = 'j'; 204 | break; 205 | case 0x77: 206 | c = 'k'; 207 | break; 208 | case 0x72: 209 | c = 'l'; 210 | break; 211 | case 0x52: 212 | c = 'm'; 213 | break; 214 | case 0x41: 215 | c = 'n'; 216 | break; 217 | case 0x75: 218 | c = 'o'; 219 | break; 220 | case 0x64: 221 | c = 'p'; 222 | break; 223 | case 0x27: 224 | c = 'q'; 225 | break; 226 | case 0x24: 227 | c = 'r'; 228 | break; 229 | case 0x36: 230 | c = 's'; 231 | break; 232 | case 0x23: 233 | c = 't'; 234 | break; 235 | case 0x21: 236 | c = 'u'; 237 | break; 238 | case 0x43: 239 | c = 'v'; 240 | break; 241 | case 0x26: 242 | c = 'w'; 243 | break; 244 | case 0x45: 245 | c = 'x'; 246 | break; 247 | case 0x22: 248 | c = 'y'; 249 | break; 250 | case 0x46: 251 | c = 'z'; 252 | break; 253 | case 0x54: 254 | return ' '; 255 | case 0x62: 256 | c = ','; 257 | break; 258 | case 0x53: 259 | c = '.'; 260 | break; 261 | case 0x71: 262 | return KEY_BACKSPACE; 263 | case 0x51: 264 | c = KEY_RIGHT_ARROW; 265 | break; 266 | case 0x55: 267 | c = KEY_LEFT_ARROW; 268 | break; 269 | case 0x63: 270 | return KEY_RETURN; 271 | default: 272 | return 0; 273 | } 274 | 275 | if (modifier & MODIFIER_SHIFT) { 276 | if (c >= 'a' && c <= 'z') 277 | return c - 32; 278 | } 279 | 280 | if (modifier & MODIFIER_LEFTCTRL) { 281 | switch (c) { 282 | case 'q': 283 | return '!'; 284 | case 'w': 285 | return '@'; 286 | case 'r': 287 | return '#'; 288 | case 't': 289 | return '%'; 290 | case 'y': 291 | return '^'; 292 | case 'u': 293 | return '&'; 294 | case 'i': 295 | return '*'; 296 | case 'o': 297 | return '('; 298 | case 'p': 299 | return ')'; 300 | case 'a': 301 | return '~'; 302 | case 'd': 303 | return '{'; 304 | case 'f': 305 | return '}'; 306 | case 'h': 307 | return '/'; 308 | case 'j': 309 | return '\''; 310 | case 'k': 311 | return '['; 312 | case 'l': 313 | return ']'; 314 | case ',': 315 | return ':'; 316 | case 'z': 317 | return '`'; 318 | case 'v': 319 | return '-'; 320 | case 'b': 321 | return '|'; 322 | case 'n': 323 | return '<'; 324 | case 'm': 325 | return '>'; 326 | case '.': 327 | return '?'; 328 | case KEY_RIGHT_ARROW: 329 | return KEY_DOWN_ARROW; 330 | case KEY_LEFT_ARROW: 331 | return KEY_UP_ARROW; 332 | } 333 | } 334 | 335 | if (modifier & MODIFIER_RIGHTCTRL) { 336 | switch (c) { 337 | case 'r': 338 | return '$'; 339 | case 'p': 340 | return '='; 341 | case 'h': 342 | return '\\'; 343 | case 'j': 344 | return '"'; 345 | case ',': 346 | return ';'; 347 | case 'v': 348 | return '_'; 349 | case 'b': 350 | return '+'; 351 | case KEY_RIGHT_ARROW: 352 | return KEY_DOWN_ARROW; 353 | case KEY_LEFT_ARROW: 354 | return KEY_UP_ARROW; 355 | } 356 | } 357 | 358 | return c; 359 | } 360 | --------------------------------------------------------------------------------