├── HID.cpp ├── LICENSE ├── README.md ├── USBAPI.h ├── keypad.ino └── keypad_numlockled.ino /HID.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Copyright (c) 2011, Peter Barrett 4 | ** 5 | ** Permission to use, copy, modify, and/or distribute this software for 6 | ** any purpose with or without fee is hereby granted, provided that the 7 | ** above copyright notice and this permission notice appear in all copies. 8 | ** 9 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | ** SOFTWARE. 17 | */ 18 | 19 | #include "USBAPI.h" 20 | 21 | #if defined(USBCON) 22 | #ifdef HID_ENABLED 23 | 24 | //#define RAWHID_ENABLED 25 | 26 | // Singletons for mouse and keyboard 27 | 28 | Mouse_ Mouse; 29 | Keyboard_ Keyboard; 30 | 31 | //================================================================================ 32 | //================================================================================ 33 | 34 | // HID report descriptor 35 | 36 | #define LSB(_x) ((_x) & 0xFF) 37 | #define MSB(_x) ((_x) >> 8) 38 | 39 | #define RAWHID_USAGE_PAGE 0xFFC0 40 | #define RAWHID_USAGE 0x0C00 41 | #define RAWHID_TX_SIZE 64 42 | #define RAWHID_RX_SIZE 64 43 | 44 | extern const u8 _hidReportDescriptor[] PROGMEM; 45 | const u8 _hidReportDescriptor[] = { 46 | 47 | // Mouse 48 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 49 | 0x09, 0x02, // USAGE (Mouse) 50 | 0xa1, 0x01, // COLLECTION (Application) 51 | 0x09, 0x01, // USAGE (Pointer) 52 | 0xa1, 0x00, // COLLECTION (Physical) 53 | 0x85, 0x01, // REPORT_ID (1) 54 | 0x05, 0x09, // USAGE_PAGE (Button) 55 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) 56 | 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 57 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 58 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 59 | 0x95, 0x03, // REPORT_COUNT (3) 60 | 0x75, 0x01, // REPORT_SIZE (1) 61 | 0x81, 0x02, // INPUT (Data,Var,Abs) 62 | 0x95, 0x01, // REPORT_COUNT (1) 63 | 0x75, 0x05, // REPORT_SIZE (5) 64 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 65 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 66 | 0x09, 0x30, // USAGE (X) 67 | 0x09, 0x31, // USAGE (Y) 68 | 0x09, 0x38, // USAGE (Wheel) 69 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) 70 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 71 | 0x75, 0x08, // REPORT_SIZE (8) 72 | 0x95, 0x03, // REPORT_COUNT (3) 73 | 0x81, 0x06, // INPUT (Data,Var,Rel) 74 | 0xc0, // END_COLLECTION 75 | 0xc0, // END_COLLECTION 76 | 77 | // Keyboard 78 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 79 | 0x09, 0x06, // USAGE (Keyboard) 80 | 0xa1, 0x01, // COLLECTION (Application) 81 | 0x85, 0x02, // REPORT_ID (2) 82 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 83 | 84 | 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 85 | 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 86 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 87 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 88 | 0x75, 0x01, // REPORT_SIZE (1) 89 | 90 | 0x95, 0x08, // REPORT_COUNT (8) 91 | 0x81, 0x02, // INPUT (Data,Var,Abs) 92 | 0x95, 0x01, // REPORT_COUNT (1) 93 | 0x75, 0x08, // REPORT_SIZE (8) 94 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 95 | 96 | 0x95, 0x05, // REPORT_COUNT (5) 97 | 0x75, 0x01, // REPORT_SIZE (1) 98 | 0x05, 0x08, // USAGE_PAGE (LEDs) 99 | 0x19, 0x01, // USAGE_MINIMUM (1) 100 | 0x29, 0x05, // USAGE_MAXIMUM (5) 101 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) // LED report 102 | 0x95, 0x01, // REPORT_COUNT (1) 103 | 0x75, 0x03, // REPORT_SIZE (3) 104 | 0x91, 0x01, // OUTPUT (Constant) // padding 105 | 106 | 0x95, 0x06, // REPORT_COUNT (6) 107 | 0x75, 0x08, // REPORT_SIZE (8) 108 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 109 | 0x25, 0x65, // LOGICAL_MAXIMUM (101) 110 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 111 | 112 | 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 113 | 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 114 | 0x81, 0x00, // INPUT (Data,Ary,Abs) 115 | 0xc0, // END_COLLECTION 116 | 117 | #ifdef RAWHID_ENABLED 118 | // RAW HID 119 | 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 120 | 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), 121 | 122 | 0xA1, 0x01, // Collection 0x01 123 | 0x85, 0x03, // REPORT_ID (3) 124 | 0x75, 0x08, // report size = 8 bits 125 | 0x15, 0x00, // logical minimum = 0 126 | 0x26, 0xFF, 0x00, // logical maximum = 255 127 | 128 | 0x95, 64, // report count TX 129 | 0x09, 0x01, // usage 130 | 0x81, 0x02, // Input (array) 131 | 132 | 0x95, 64, // report count RX 133 | 0x09, 0x02, // usage 134 | 0x91, 0x02, // Output (array) 135 | 0xC0 // end collection 136 | #endif 137 | }; 138 | 139 | extern const HIDDescriptor _hidInterface PROGMEM; 140 | const HIDDescriptor _hidInterface = 141 | { 142 | D_INTERFACE(HID_INTERFACE,1,3,0,0), 143 | D_HIDREPORT(sizeof(_hidReportDescriptor)), 144 | D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) 145 | }; 146 | 147 | //================================================================================ 148 | //================================================================================ 149 | // Driver 150 | 151 | u8 _hid_protocol = 1; 152 | u8 _hid_idle = 1; 153 | 154 | #define WEAK __attribute__ ((weak)) 155 | 156 | int WEAK HID_GetInterface(u8* interfaceNum) 157 | { 158 | interfaceNum[0] += 1; // uses 1 159 | return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); 160 | } 161 | 162 | int WEAK HID_GetDescriptor(int /* i */) 163 | { 164 | return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); 165 | } 166 | 167 | void WEAK HID_SendReport(u8 id, const void* data, int len) 168 | { 169 | USB_Send(HID_TX, &id, 1); 170 | USB_Send(HID_TX | TRANSFER_RELEASE,data,len); 171 | } 172 | 173 | bool WEAK HID_Setup(Setup& setup) 174 | { 175 | u8 r = setup.bRequest; 176 | u8 requestType = setup.bmRequestType; 177 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 178 | { 179 | if (HID_GET_REPORT == r) 180 | { 181 | //HID_GetReport(); 182 | return true; 183 | } 184 | if (HID_GET_PROTOCOL == r) 185 | { 186 | //Send8(_hid_protocol); // TODO 187 | return true; 188 | } 189 | } 190 | 191 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 192 | { 193 | if (HID_SET_PROTOCOL == r) 194 | { 195 | _hid_protocol = setup.wValueL; 196 | return true; 197 | } 198 | 199 | if (HID_SET_IDLE == r) 200 | { 201 | _hid_idle = setup.wValueL; 202 | return true; 203 | } 204 | 205 | if (HID_SET_REPORT == r) 206 | { 207 | if (setup.wLength == 2) 208 | { 209 | uint8_t data[2]; 210 | if (2 == USB_RecvControl(data, 2)) 211 | { 212 | Keyboard.setLedStatus(data[1]); 213 | return true; 214 | } 215 | } 216 | } 217 | } 218 | return false; 219 | } 220 | 221 | //================================================================================ 222 | //================================================================================ 223 | // Mouse 224 | 225 | Mouse_::Mouse_(void) : _buttons(0) 226 | { 227 | } 228 | 229 | void Mouse_::begin(void) 230 | { 231 | } 232 | 233 | void Mouse_::end(void) 234 | { 235 | } 236 | 237 | void Mouse_::click(uint8_t b) 238 | { 239 | _buttons = b; 240 | move(0,0,0); 241 | _buttons = 0; 242 | move(0,0,0); 243 | } 244 | 245 | void Mouse_::move(signed char x, signed char y, signed char wheel) 246 | { 247 | u8 m[4]; 248 | m[0] = _buttons; 249 | m[1] = x; 250 | m[2] = y; 251 | m[3] = wheel; 252 | HID_SendReport(1,m,4); 253 | } 254 | 255 | void Mouse_::buttons(uint8_t b) 256 | { 257 | if (b != _buttons) 258 | { 259 | _buttons = b; 260 | move(0,0,0); 261 | } 262 | } 263 | 264 | void Mouse_::press(uint8_t b) 265 | { 266 | buttons(_buttons | b); 267 | } 268 | 269 | void Mouse_::release(uint8_t b) 270 | { 271 | buttons(_buttons & ~b); 272 | } 273 | 274 | bool Mouse_::isPressed(uint8_t b) 275 | { 276 | if ((b & _buttons) > 0) 277 | return true; 278 | return false; 279 | } 280 | 281 | //================================================================================ 282 | //================================================================================ 283 | // Keyboard 284 | 285 | Keyboard_::Keyboard_(void) 286 | { 287 | } 288 | 289 | void Keyboard_::begin(void) 290 | { 291 | _ledStatus = 0; 292 | } 293 | 294 | void Keyboard_::end(void) 295 | { 296 | } 297 | 298 | void Keyboard_::sendReport(KeyReport* keys) 299 | { 300 | HID_SendReport(2,keys,sizeof(KeyReport)); 301 | } 302 | 303 | extern 304 | const uint8_t _asciimap[128] PROGMEM; 305 | 306 | #define SHIFT 0x80 307 | const uint8_t _asciimap[128] = 308 | { 309 | 0x00, // NUL 310 | 0x00, // SOH 311 | 0x00, // STX 312 | 0x00, // ETX 313 | 0x00, // EOT 314 | 0x00, // ENQ 315 | 0x00, // ACK 316 | 0x00, // BEL 317 | 0x2a, // BS Backspace 318 | 0x2b, // TAB Tab 319 | 0x28, // LF Enter 320 | 0x00, // VT 321 | 0x00, // FF 322 | 0x00, // CR 323 | 0x00, // SO 324 | 0x00, // SI 325 | 0x00, // DEL 326 | 0x00, // DC1 327 | 0x00, // DC2 328 | 0x00, // DC3 329 | 0x00, // DC4 330 | 0x00, // NAK 331 | 0x00, // SYN 332 | 0x00, // ETB 333 | 0x00, // CAN 334 | 0x00, // EM 335 | 0x00, // SUB 336 | 0x00, // ESC 337 | 0x00, // FS 338 | 0x00, // GS 339 | 0x00, // RS 340 | 0x00, // US 341 | 342 | 0x2c, // ' ' 343 | 0x1e|SHIFT, // ! 344 | 0x34|SHIFT, // " 345 | 0x20|SHIFT, // # 346 | 0x21|SHIFT, // $ 347 | 0x22|SHIFT, // % 348 | 0x24|SHIFT, // & 349 | 0x34, // ' 350 | 0x26|SHIFT, // ( 351 | 0x27|SHIFT, // ) 352 | 0x25|SHIFT, // * 353 | 0x2e|SHIFT, // + 354 | 0x36, // , 355 | 0x2d, // - 356 | 0x37, // . 357 | 0x38, // / 358 | 0x27, // 0 359 | 0x1e, // 1 360 | 0x1f, // 2 361 | 0x20, // 3 362 | 0x21, // 4 363 | 0x22, // 5 364 | 0x23, // 6 365 | 0x24, // 7 366 | 0x25, // 8 367 | 0x26, // 9 368 | 0x33|SHIFT, // : 369 | 0x33, // ; 370 | 0x36|SHIFT, // < 371 | 0x2e, // = 372 | 0x37|SHIFT, // > 373 | 0x38|SHIFT, // ? 374 | 0x1f|SHIFT, // @ 375 | 0x04|SHIFT, // A 376 | 0x05|SHIFT, // B 377 | 0x06|SHIFT, // C 378 | 0x07|SHIFT, // D 379 | 0x08|SHIFT, // E 380 | 0x09|SHIFT, // F 381 | 0x0a|SHIFT, // G 382 | 0x0b|SHIFT, // H 383 | 0x0c|SHIFT, // I 384 | 0x0d|SHIFT, // J 385 | 0x0e|SHIFT, // K 386 | 0x0f|SHIFT, // L 387 | 0x10|SHIFT, // M 388 | 0x11|SHIFT, // N 389 | 0x12|SHIFT, // O 390 | 0x13|SHIFT, // P 391 | 0x14|SHIFT, // Q 392 | 0x15|SHIFT, // R 393 | 0x16|SHIFT, // S 394 | 0x17|SHIFT, // T 395 | 0x18|SHIFT, // U 396 | 0x19|SHIFT, // V 397 | 0x1a|SHIFT, // W 398 | 0x1b|SHIFT, // X 399 | 0x1c|SHIFT, // Y 400 | 0x1d|SHIFT, // Z 401 | 0x2f, // [ 402 | 0x31, // bslash 403 | 0x30, // ] 404 | 0x23|SHIFT, // ^ 405 | 0x2d|SHIFT, // _ 406 | 0x35, // ` 407 | 0x04, // a 408 | 0x05, // b 409 | 0x06, // c 410 | 0x07, // d 411 | 0x08, // e 412 | 0x09, // f 413 | 0x0a, // g 414 | 0x0b, // h 415 | 0x0c, // i 416 | 0x0d, // j 417 | 0x0e, // k 418 | 0x0f, // l 419 | 0x10, // m 420 | 0x11, // n 421 | 0x12, // o 422 | 0x13, // p 423 | 0x14, // q 424 | 0x15, // r 425 | 0x16, // s 426 | 0x17, // t 427 | 0x18, // u 428 | 0x19, // v 429 | 0x1a, // w 430 | 0x1b, // x 431 | 0x1c, // y 432 | 0x1d, // z 433 | 0x2f|SHIFT, // 434 | 0x31|SHIFT, // | 435 | 0x30|SHIFT, // } 436 | 0x35|SHIFT, // ~ 437 | 0 // DEL 438 | }; 439 | 440 | uint8_t USBPutChar(uint8_t c); 441 | 442 | // press() adds the specified key (printing, non-printing, or modifier) 443 | // to the persistent key report and sends the report. Because of the way 444 | // USB HID works, the host acts like the key remains pressed until we 445 | // call release(), releaseAll(), or otherwise clear the report and resend. 446 | size_t Keyboard_::press(uint8_t k) 447 | { 448 | uint8_t i; 449 | if (k >= 136) { // it's a non-printing key (not a modifier) 450 | k = k - 136; 451 | } else if (k >= 128) { // it's a modifier key 452 | _keyReport.modifiers |= (1<<(k-128)); 453 | k = 0; 454 | } else { // it's a printing key 455 | k = pgm_read_byte(_asciimap + k); 456 | if (!k) { 457 | setWriteError(); 458 | return 0; 459 | } 460 | if (k & 0x80) { // it's a capital letter or other character reached with shift 461 | _keyReport.modifiers |= 0x02; // the left shift modifier 462 | k &= 0x7F; 463 | } 464 | } 465 | 466 | // Add k to the key report only if it's not already present 467 | // and if there is an empty slot. 468 | if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 469 | _keyReport.keys[2] != k && _keyReport.keys[3] != k && 470 | _keyReport.keys[4] != k && _keyReport.keys[5] != k) { 471 | 472 | for (i=0; i<6; i++) { 473 | if (_keyReport.keys[i] == 0x00) { 474 | _keyReport.keys[i] = k; 475 | break; 476 | } 477 | } 478 | if (i == 6) { 479 | setWriteError(); 480 | return 0; 481 | } 482 | } 483 | sendReport(&_keyReport); 484 | return 1; 485 | } 486 | 487 | // release() takes the specified key out of the persistent key report and 488 | // sends the report. This tells the OS the key is no longer pressed and that 489 | // it shouldn't be repeated any more. 490 | size_t Keyboard_::release(uint8_t k) 491 | { 492 | uint8_t i; 493 | if (k >= 136) { // it's a non-printing key (not a modifier) 494 | k = k - 136; 495 | } else if (k >= 128) { // it's a modifier key 496 | _keyReport.modifiers &= ~(1<<(k-128)); 497 | k = 0; 498 | } else { // it's a printing key 499 | k = pgm_read_byte(_asciimap + k); 500 | if (!k) { 501 | return 0; 502 | } 503 | if (k & 0x80) { // it's a capital letter or other character reached with shift 504 | _keyReport.modifiers &= ~(0x02); // the left shift modifier 505 | k &= 0x7F; 506 | } 507 | } 508 | 509 | // Test the key report to see if k is present. Clear it if it exists. 510 | // Check all positions in case the key is present more than once (which it shouldn't be) 511 | for (i=0; i<6; i++) { 512 | if (0 != k && _keyReport.keys[i] == k) { 513 | _keyReport.keys[i] = 0x00; 514 | } 515 | } 516 | 517 | sendReport(&_keyReport); 518 | return 1; 519 | } 520 | 521 | void Keyboard_::releaseAll(void) 522 | { 523 | _keyReport.keys[0] = 0; 524 | _keyReport.keys[1] = 0; 525 | _keyReport.keys[2] = 0; 526 | _keyReport.keys[3] = 0; 527 | _keyReport.keys[4] = 0; 528 | _keyReport.keys[5] = 0; 529 | _keyReport.modifiers = 0; 530 | sendReport(&_keyReport); 531 | } 532 | 533 | size_t Keyboard_::write(uint8_t c) 534 | { 535 | uint8_t p = press(c); // Keydown 536 | release(c); // Keyup 537 | return p; // just return the result of press() since release() almost always returns 1 538 | } 539 | 540 | void Keyboard_::setLedStatus(uint8_t s) 541 | { 542 | _ledStatus = s; 543 | } 544 | 545 | uint8_t Keyboard_::getLedStatus(void) 546 | { 547 | return _ledStatus; 548 | } 549 | 550 | #endif 551 | 552 | #endif /* if defined(USBCON) */ 553 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # numeric-keypad 2 | Numeric keypad implemented for Pro Micro using Arduino IDE 3 | -------------------------------------------------------------------------------- /USBAPI.h: -------------------------------------------------------------------------------- 1 | /* 2 | USBAPI.h 3 | Copyright (c) 2005-2014 Arduino. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __USBAPI__ 21 | #define __USBAPI__ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | typedef unsigned char u8; 30 | typedef unsigned short u16; 31 | typedef unsigned long u32; 32 | 33 | #include "Arduino.h" 34 | 35 | #if defined(USBCON) 36 | 37 | #include "USBDesc.h" 38 | #include "USBCore.h" 39 | 40 | //================================================================================ 41 | //================================================================================ 42 | // USB 43 | 44 | class USBDevice_ 45 | { 46 | public: 47 | USBDevice_(); 48 | bool configured(); 49 | 50 | void attach(); 51 | void detach(); // Serial port goes down too... 52 | void poll(); 53 | }; 54 | extern USBDevice_ USBDevice; 55 | 56 | //================================================================================ 57 | //================================================================================ 58 | // Serial over CDC (Serial1 is the physical port) 59 | 60 | struct ring_buffer; 61 | 62 | #ifndef SERIAL_BUFFER_SIZE 63 | #if (RAMEND < 1000) 64 | #define SERIAL_BUFFER_SIZE 16 65 | #else 66 | #define SERIAL_BUFFER_SIZE 64 67 | #endif 68 | #endif 69 | #if (SERIAL_BUFFER_SIZE>256) 70 | #error Please lower the CDC Buffer size 71 | #endif 72 | 73 | class Serial_ : public Stream 74 | { 75 | private: 76 | int peek_buffer; 77 | public: 78 | Serial_() { peek_buffer = -1; }; 79 | void begin(unsigned long); 80 | void begin(unsigned long, uint8_t); 81 | void end(void); 82 | 83 | virtual int available(void); 84 | virtual int peek(void); 85 | virtual int read(void); 86 | virtual void flush(void); 87 | virtual size_t write(uint8_t); 88 | virtual size_t write(const uint8_t*, size_t); 89 | using Print::write; // pull in write(str) and write(buf, size) from Print 90 | operator bool(); 91 | 92 | volatile uint8_t _rx_buffer_head; 93 | volatile uint8_t _rx_buffer_tail; 94 | unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; 95 | }; 96 | extern Serial_ Serial; 97 | 98 | #define HAVE_CDCSERIAL 99 | 100 | //================================================================================ 101 | //================================================================================ 102 | // Mouse 103 | 104 | #define MOUSE_LEFT 1 105 | #define MOUSE_RIGHT 2 106 | #define MOUSE_MIDDLE 4 107 | #define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) 108 | 109 | class Mouse_ 110 | { 111 | private: 112 | uint8_t _buttons; 113 | void buttons(uint8_t b); 114 | public: 115 | Mouse_(void); 116 | void begin(void); 117 | void end(void); 118 | void click(uint8_t b = MOUSE_LEFT); 119 | void move(signed char x, signed char y, signed char wheel = 0); 120 | void press(uint8_t b = MOUSE_LEFT); // press LEFT by default 121 | void release(uint8_t b = MOUSE_LEFT); // release LEFT by default 122 | bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default 123 | }; 124 | extern Mouse_ Mouse; 125 | 126 | //================================================================================ 127 | //================================================================================ 128 | // Keyboard 129 | 130 | #define KEY_LEFT_CTRL 0x80 131 | #define KEY_LEFT_SHIFT 0x81 132 | #define KEY_LEFT_ALT 0x82 133 | #define KEY_LEFT_GUI 0x83 134 | #define KEY_RIGHT_CTRL 0x84 135 | #define KEY_RIGHT_SHIFT 0x85 136 | #define KEY_RIGHT_ALT 0x86 137 | #define KEY_RIGHT_GUI 0x87 138 | 139 | #define KEY_UP_ARROW 0xDA 140 | #define KEY_DOWN_ARROW 0xD9 141 | #define KEY_LEFT_ARROW 0xD8 142 | #define KEY_RIGHT_ARROW 0xD7 143 | #define KEY_BACKSPACE 0xB2 144 | #define KEY_TAB 0xB3 145 | #define KEY_RETURN 0xB0 146 | #define KEY_ESC 0xB1 147 | #define KEY_INSERT 0xD1 148 | #define KEY_DELETE 0xD4 149 | #define KEY_PAGE_UP 0xD3 150 | #define KEY_PAGE_DOWN 0xD6 151 | #define KEY_HOME 0xD2 152 | #define KEY_END 0xD5 153 | #define KEY_CAPS_LOCK 0xC1 154 | #define KEY_F1 0xC2 155 | #define KEY_F2 0xC3 156 | #define KEY_F3 0xC4 157 | #define KEY_F4 0xC5 158 | #define KEY_F5 0xC6 159 | #define KEY_F6 0xC7 160 | #define KEY_F7 0xC8 161 | #define KEY_F8 0xC9 162 | #define KEY_F9 0xCA 163 | #define KEY_F10 0xCB 164 | #define KEY_F11 0xCC 165 | #define KEY_F12 0xCD 166 | 167 | #define KEY_NUM_LOCK 0xDB 168 | #define KEY_SCROLL_LOCK 0xCF 169 | 170 | #define LED_NUM_LOCK 0x01 171 | #define LED_CAPS_LOCK 0x02 172 | #define LED_SCROLL_LOCK 0x04 173 | 174 | // Low level key report: up to 6 keys and shift, ctrl etc at once 175 | typedef struct 176 | { 177 | uint8_t modifiers; 178 | uint8_t reserved; 179 | uint8_t keys[6]; 180 | } KeyReport; 181 | 182 | class Keyboard_ : public Print 183 | { 184 | private: 185 | KeyReport _keyReport; 186 | void sendReport(KeyReport* keys); 187 | uint8_t _ledStatus; 188 | 189 | public: 190 | Keyboard_(void); 191 | void begin(void); 192 | void end(void); 193 | virtual size_t write(uint8_t k); 194 | virtual size_t press(uint8_t k); 195 | virtual size_t release(uint8_t k); 196 | virtual void releaseAll(void); 197 | virtual void setLedStatus(uint8_t); 198 | virtual uint8_t getLedStatus(void); 199 | }; 200 | extern Keyboard_ Keyboard; 201 | 202 | //================================================================================ 203 | //================================================================================ 204 | // Low level API 205 | 206 | typedef struct 207 | { 208 | uint8_t bmRequestType; 209 | uint8_t bRequest; 210 | uint8_t wValueL; 211 | uint8_t wValueH; 212 | uint16_t wIndex; 213 | uint16_t wLength; 214 | } Setup; 215 | 216 | //================================================================================ 217 | //================================================================================ 218 | // HID 'Driver' 219 | 220 | int HID_GetInterface(uint8_t* interfaceNum); 221 | int HID_GetDescriptor(int i); 222 | bool HID_Setup(Setup& setup); 223 | void HID_SendReport(uint8_t id, const void* data, int len); 224 | 225 | //================================================================================ 226 | //================================================================================ 227 | // MSC 'Driver' 228 | 229 | int MSC_GetInterface(uint8_t* interfaceNum); 230 | int MSC_GetDescriptor(int i); 231 | bool MSC_Setup(Setup& setup); 232 | bool MSC_Data(uint8_t rx,uint8_t tx); 233 | 234 | //================================================================================ 235 | //================================================================================ 236 | // CSC 'Driver' 237 | 238 | int CDC_GetInterface(uint8_t* interfaceNum); 239 | int CDC_GetDescriptor(int i); 240 | bool CDC_Setup(Setup& setup); 241 | 242 | //================================================================================ 243 | //================================================================================ 244 | 245 | #define TRANSFER_PGM 0x80 246 | #define TRANSFER_RELEASE 0x40 247 | #define TRANSFER_ZERO 0x20 248 | 249 | int USB_SendControl(uint8_t flags, const void* d, int len); 250 | int USB_RecvControl(void* d, int len); 251 | 252 | uint8_t USB_Available(uint8_t ep); 253 | int USB_Send(uint8_t ep, const void* data, int len); // blocking 254 | int USB_Recv(uint8_t ep, void* data, int len); // non-blocking 255 | int USB_Recv(uint8_t ep); // non-blocking 256 | void USB_Flush(uint8_t ep); 257 | 258 | #endif 259 | 260 | #endif /* if defined(USBCON) */ 261 | -------------------------------------------------------------------------------- /keypad.ino: -------------------------------------------------------------------------------- 1 | // #include // uncomment if needed - not present in 1.6.5 2 | 3 | const int COLUMNS = 4; 4 | const int ROWS = 5; 5 | const int HB_LED = 17; 6 | 7 | #define HEARTBEAT_ENABLED 1 8 | 9 | // These are the column pins. They're configured for input with 10 | // internal pullup 11 | 12 | int input_pins[COLUMNS] = { 20, 19, 18, 15 } ; 13 | 14 | // These are the row strobes. They're configured for output 15 | // and initially all set to high. Individual pins are set to 16 | // low to read that row. Only one row is low at any time. 17 | 18 | int strobe_pins[ROWS] = { 8, 7, 6, 5, 4 }; 19 | 20 | unsigned long key_state[ROWS][COLUMNS]; 21 | 22 | // Codes for numeric keypad 23 | // NUM / * - 24 | // 7 8 9 + 25 | // 4 5 6 x 26 | // 1 2 3 x 27 | // 0 x . ENTER 28 | 29 | int keycode[ROWS][COLUMNS] = { { 0xDB, 0xDC, 0xDD, 0xDE }, 30 | { 0xE7, 0xE8, 0xE9, 0xDF }, 31 | { 0xE4, 0xE5, 0xE6, 0 }, 32 | { 0xE1, 0xE2, 0xE3, 0 }, 33 | { 0xEA, 0, 0xEB, 0XE0 } }; 34 | 35 | int strobe_row = 0; 36 | int q = 0; 37 | 38 | void setup() { 39 | int cnt; 40 | int cnt2; 41 | 42 | #ifdef HEARTBEAT_ENABLED 43 | pinMode(HB_LED, OUTPUT); 44 | #endif 45 | 46 | for (cnt = 0; cnt < ROWS; cnt++) { 47 | pinMode(strobe_pins[cnt], OUTPUT); 48 | digitalWrite(strobe_pins[cnt], HIGH); 49 | 50 | for (cnt2 = 0; cnt2 < COLUMNS; cnt2++) key_state[cnt][cnt2] = 0; 51 | } 52 | 53 | for (cnt = 0; cnt < COLUMNS; cnt++) { 54 | pinMode(input_pins[cnt], INPUT_PULLUP); 55 | } 56 | 57 | Keyboard.begin(); 58 | } 59 | 60 | const int DEBOUNCE_MS = 20; 61 | 62 | bool debounce(unsigned long t_now, unsigned long t_prev) { 63 | unsigned long diff; 64 | 65 | diff = t_now - t_prev; // need to check for underflow? 66 | 67 | if (diff <= DEBOUNCE_MS) return true; 68 | else return false; 69 | } 70 | 71 | void loop() { 72 | unsigned long tick_now = millis(); 73 | int cnt; 74 | 75 | #ifdef HEARTBEAT_ENABLED 76 | if (q == 0) digitalWrite(HB_LED, LOW); 77 | else if (q == 128) digitalWrite(HB_LED, HIGH); 78 | q++; 79 | q &= 0xff; 80 | // should just make this into an unsigned char, but keeping it as int 81 | // in case we want to adjust heartbeat freq. 82 | #endif 83 | 84 | // since we use non zero to indicate pressed state, we need 85 | // to handle the edge case where millis() returns 0 86 | 87 | if (tick_now == 0) tick_now = 1; 88 | 89 | // every time we enter this loop, we're reading only the switches 90 | // on strobe_row 91 | 92 | if (strobe_row >= ROWS) strobe_row = 0; 93 | 94 | digitalWrite(strobe_pins[strobe_row], LOW); 95 | delay(2); // give it some time to stabilize just in case 96 | 97 | // We check all the switches in the row 98 | 99 | for (cnt = 0; cnt < COLUMNS; cnt++) { 100 | // ignore state change for pin if in debounce period 101 | if (key_state[strobe_row][cnt] != 0) 102 | if (debounce(tick_now, key_state[strobe_row][cnt]) == true) 103 | continue; 104 | 105 | if (digitalRead(input_pins[cnt]) == HIGH) { 106 | if (key_state[strobe_row][cnt] != 0) { 107 | Keyboard.release(keycode[strobe_row][cnt]); 108 | key_state[strobe_row][cnt] = 0; 109 | } 110 | } else { 111 | if (key_state[strobe_row][cnt] == 0) { 112 | Keyboard.press(keycode[strobe_row][cnt]); 113 | key_state[strobe_row][cnt] = tick_now; 114 | } 115 | } 116 | } 117 | 118 | digitalWrite(strobe_pins[strobe_row], HIGH); 119 | strobe_row++; 120 | delay(5); 121 | } 122 | -------------------------------------------------------------------------------- /keypad_numlockled.ino: -------------------------------------------------------------------------------- 1 | // These are the column pins, to be configured for input with 2 | // internal pullup 3 | 4 | int input_pins[4] = { 20, 19, 18, 15 } ; 5 | 6 | // These are the row strobes. They're configured for output 7 | // and initially all set to high. Individual pins are set to 8 | // low to read that row. Only one row is low at any time. 9 | 10 | int strobe_pins[5] = { 8, 7, 6, 5, 4 }; 11 | unsigned long key_state[5][4]; 12 | int statusLed = -1; 13 | 14 | // Codes for numeric keypad 15 | // NUM / * - 16 | // 7 8 9 + 17 | // 4 5 6 x 18 | // 1 2 3 x 19 | // 0 x . ENTER 20 | 21 | int keycode[5][4] = { { 0xDB, 0xDC, 0xDD, 0xDE }, 22 | { 0xE7, 0xE8, 0xE9, 0xDF }, 23 | { 0xE4, 0xE5, 0xE6, 0 }, 24 | { 0xE1, 0xE2, 0xE3, 0 }, 25 | { 0xEA, 0, 0xEB, 0XE0 } }; 26 | 27 | int strobe_row = 0; 28 | int q = 0; 29 | const int NUMLOCK_PIN = 3; 30 | const int HEARTBEAT_PIN = 17; 31 | 32 | void setup() { 33 | int cnt; 34 | int cnt2; 35 | 36 | // This is for the heartbeat 37 | 38 | pinMode(HEARTBEAT_PIN, OUTPUT); 39 | 40 | for (cnt = 0; cnt < 5; cnt++) { 41 | pinMode(strobe_pins[cnt], OUTPUT); 42 | digitalWrite(strobe_pins[cnt], HIGH); 43 | 44 | for (cnt2 = 0; cnt2 < 4; cnt2++) key_state[cnt][cnt2] = 0; 45 | } 46 | 47 | for (cnt = 0; cnt < 4; cnt++) { 48 | pinMode(input_pins[cnt], INPUT_PULLUP); 49 | } 50 | 51 | // set num lock off 52 | pinMode(NUMLOCK_PIN, OUTPUT); 53 | digitalWrite(NUMLOCK_PIN, LOW); 54 | 55 | Keyboard.begin(); 56 | } 57 | 58 | bool debounce(unsigned long t_now, unsigned long t_prev) { 59 | unsigned long diff; 60 | 61 | diff = t_now - t_prev; // need to check for underflow? 62 | 63 | if (diff <= 20) return true; 64 | else return false; 65 | } 66 | 67 | void loop() { 68 | unsigned long tick_now = millis(); 69 | int cnt; 70 | int ledStatus; 71 | 72 | // Num Lock 73 | 74 | ledStatus = Keyboard.getLedStatus(); 75 | 76 | if (statusLed != ledStatus) { 77 | if ((ledStatus & LED_NUM_LOCK) == LED_NUM_LOCK) { 78 | digitalWrite(NUMLOCK_PIN, HIGH); 79 | } else { 80 | digitalWrite(NUMLOCK_PIN, LOW); 81 | } 82 | statusLed = ledStatus; 83 | } 84 | 85 | // Heartbeat LED. Comment this out if you don't want blinkenlights 86 | 87 | if (q == 0) digitalWrite(HEARTBEAT_PIN, LOW); 88 | else if (q == 128) digitalWrite(HEARTBEAT_PIN, HIGH); 89 | q++; 90 | if (q == 256) q = 0; 91 | 92 | // end of heartbeat code 93 | 94 | // since we use non zero to indicate pressed state, we need 95 | // to handle the edge case where millis() returns 0 96 | 97 | if (tick_now == 0) tick_now = 1; 98 | 99 | // every time we enter this loop, we're reading only the switches 100 | // on strobe_row 101 | 102 | if (strobe_row >= 5) strobe_row = 0; 103 | 104 | digitalWrite(strobe_pins[strobe_row], LOW); 105 | delay(2); // give it some time to stabilize just in case 106 | 107 | // We check all the switches in the row 108 | 109 | for (cnt = 0; cnt < 4; cnt++) { 110 | // ignore state change for pin if in debounce period 111 | if (key_state[strobe_row][cnt] != 0) 112 | if (debounce(tick_now, key_state[strobe_row][cnt]) == true) 113 | continue; 114 | 115 | if (digitalRead(input_pins[cnt]) == HIGH) { 116 | if (key_state[strobe_row][cnt] != 0) { 117 | Keyboard.release(keycode[strobe_row][cnt]); 118 | key_state[strobe_row][cnt] = 0; 119 | } 120 | } else { 121 | if (key_state[strobe_row][cnt] == 0) { 122 | Keyboard.press(keycode[strobe_row][cnt]); 123 | key_state[strobe_row][cnt] = tick_now; 124 | } 125 | } 126 | } 127 | 128 | digitalWrite(strobe_pins[strobe_row], HIGH); 129 | strobe_row++; 130 | delay(5); 131 | } 132 | --------------------------------------------------------------------------------