├── .gitignore ├── BLE.ino ├── BLE_WASD.ino ├── BluefruitConfig.h ├── Controller.ino ├── HID.cpp_1.6.5_modified ├── KeyReport.ino ├── LICENSE ├── PS2.ino ├── README.md ├── Special_functions.ino ├── TEST.ino ├── USB.ino ├── USBAPI.h_1.6.5_modified └── define.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | .idea 31 | 32 | BLE_WASD.iml 33 | -------------------------------------------------------------------------------- /BLE.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Functions associated with BLE communication 3 | */ 4 | 5 | /** 6 | * Start the low energy bluetooth module 7 | */ 8 | void start_BLE() { 9 | #if defined (DEBUG) 10 | ble.begin(1); 11 | #endif 12 | #if not defined (DEBUG) 13 | ble.begin(0); 14 | #endif 15 | } 16 | 17 | /** 18 | * Stops bluetooth 19 | */ 20 | void stop_BLE() { 21 | if (ble.isConnected()) { 22 | ble.disconnect(); 23 | ble.println( F("AT+GAPDISCONNECT") ); 24 | } 25 | 26 | ble.end(); 27 | // Doing a begin forces disconnect more reliably 28 | start_BLE(); 29 | // Stop advertising so connection is not automatically restablished 30 | ble.println(F("AT+GAPSTOPADV")); 31 | ble.end(); 32 | } 33 | 34 | void reconfigure_BLE() { 35 | /* Initialise the module */ 36 | 37 | #if defined (DEBUG) 38 | Serial.print(F("Initialising the Bluefruit LE module: ")); 39 | Serial.println(F("Performing a factory reset: ")); 40 | #endif 41 | 42 | ble.factoryReset(); 43 | 44 | //Disable command echo from Bluefruit 45 | ble.echo(false); 46 | 47 | ble.info(); 48 | 49 | //rename device 50 | ble.println(F("AT+GAPDEVNAME=BLE_WASD")); 51 | 52 | /* Enable HID Service */ 53 | #if defined (DEBUG) 54 | Serial.println(F("Enable HID Service (including Keyboard): ")); 55 | #endif 56 | 57 | if (! ble.sendCommandCheckOK(F( "AT+BleKeyboardEn=On" ))) { 58 | #if defined (DEBUG) 59 | Serial.println(F("Could not enable Keyboard")); 60 | #endif 61 | } 62 | 63 | /* Add or remove service requires a reset */ 64 | if (! ble.reset() ) { 65 | #if defined (DEBUG) 66 | Serial.println(F("Couldn't reset??")); 67 | #endif 68 | } 69 | } 70 | 71 | /** 72 | * Sends the key report over BLE 73 | */ 74 | void send_ble_report(KeyReport report) { 75 | String cmd = "AT+BLEKEYBOARDCODE=" + report_to_string(report); 76 | send(cmd); 77 | } 78 | 79 | /** 80 | * Sends safely - probably slower but there are potential issues with 81 | * repeating keys if you do not 82 | */ 83 | void send(String cmd) { 84 | int commandLength = cmd.length() + 1; 85 | char buffer[commandLength]; 86 | int attempts=0; 87 | cmd.toCharArray(buffer, commandLength); 88 | while (!ble.sendCommandCheckOK(buffer)) { 89 | attempts++; 90 | if (!ble.isConnected()) { 91 | break; 92 | } 93 | if (attempts > 5) { 94 | #if defined (DEBUG) 95 | Serial.println(F("Giving up!")); 96 | #endif 97 | break; 98 | } 99 | } 100 | } 101 | 102 | /** 103 | * Sends a media control (rather than the HID key code) 104 | */ 105 | void send_ble_media(uint8_t hidKey) { 106 | String str = "AT+BLEHIDCONTROLKEY="; 107 | switch (hidKey) { 108 | case (HID_PLAY_PAUSE): 109 | str += "PLAYPAUSE"; 110 | break; 111 | case (HID_STOP): 112 | str += "MEDIASTOP"; 113 | break; 114 | case (HID_NEXT_TRACK): 115 | str += "MEDIANEXT"; 116 | break; 117 | case (HID_PREV_TRACK): 118 | str += "MEDIAPREVIOUS"; 119 | break; 120 | case (HID_VOL_UP): 121 | str += "VOLUME+,100"; 122 | break; 123 | case (HID_VOL_DWN): 124 | str += "VOLUME-,100"; 125 | break; 126 | case (HID_MUTE): 127 | str += "MUTE"; 128 | break; 129 | default: 130 | return; 131 | } 132 | send(str); 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /BLE_WASD.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Adafruit_BLE.h" 3 | #include "Adafruit_BluefruitLE_SPI.h" 4 | #include "BluefruitConfig.h" 5 | #include "define.h" 6 | 7 | #if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VARIANT_ARDUINO_ZERO_) 8 | #include 9 | #endif 10 | 11 | // TODO - still getting key repeats n multikey press - try sending another clear if buffer empty? 12 | // TODO - still is often too slow why? 13 | // TODO - should I try earlier firmware - should I try 0.7.0 beta 14 | 15 | /** 16 | * BLE WASD Keyboard V3 17 | * 18 | * Daniel Nugent 19 | * Dorian Rudolf 20 | * Michael Cox 21 | * 22 | * This program uses an adafruit BLE + Micro microcontroller to decode PS2, remap the scan codes to HID, and send over bluetooth GAT 23 | * Additional parts include the the tricket lipo backpack, WASD code keyboard, microusb male, and 3.7v batteries 24 | * 25 | * Ctrl + Shift + esc will reconfigure the keyboard 26 | * -Use on first use or if the bluetooth module freezes or changes name 27 | * 28 | * Make sure you keyboard can run on 3.3v or make sure you can provide it with 5v 29 | * 30 | */ 31 | 32 | // Create the bluefruit object, either software serial...uncomment these lines 33 | /* 34 | /* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */ 35 | Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST); 36 | 37 | /** 38 | * Initial setup 39 | */ 40 | void setup() { 41 | 42 | #if defined (DEBUG) 43 | Serial.begin(115200); //debuging 44 | // If USB connection is not there this can cause failure to start 45 | // DEBUG must be off when wired USB is not connected for serial comms! 46 | while (!Serial) 47 | ; // required for Flora & Micro 48 | delay(500); 49 | #endif 50 | 51 | #if defined (TEST_SERIAL_INPUT) || defined (TEST_HELLO_WORLD) 52 | setup_test_keymaps(); 53 | #endif 54 | 55 | setup_keymaps(); 56 | setup_PS2(); 57 | start_keyboard(); 58 | } 59 | 60 | /** 61 | * Main loop - repeats processing the entered PS2 keys 62 | */ 63 | void loop() { 64 | 65 | #if defined (TEST_SERIAL_INPUT) 66 | test_serial_input(); 67 | #endif 68 | 69 | #if defined (TEST_HELLO_WORLD) 70 | test_hello_world(); 71 | #endif 72 | 73 | process_buffer(); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /BluefruitConfig.h: -------------------------------------------------------------------------------- 1 | // COMMON SETTINGS 2 | // ---------------------------------------------------------------------------------------------- 3 | // These settings are used in both SW UART, HW UART and SPI mode 4 | // ---------------------------------------------------------------------------------------------- 5 | #define BUFSIZE 128 // Size of the read buffer for incoming data 6 | #define VERBOSE_MODE true // If set to 'true' enables debug output 7 | 8 | 9 | // HARDWARE SPI SETTINGS 10 | // ---------------------------------------------------------------------------------------------- 11 | // The following macros declare the pins to use for HW SPI communication. 12 | // SCK, MISO and MOSI should be connected to the HW SPI pins on the Uno, etc. 13 | // This should be used with nRF51822 based Bluefruit LE modules that use SPI. 14 | // ---------------------------------------------------------------------------------------------- 15 | #define BLUEFRUIT_SPI_CS 8 16 | #define BLUEFRUIT_SPI_IRQ 7 17 | #define BLUEFRUIT_SPI_RST 4 // Optional but recommended, set to -1 if unused 18 | -------------------------------------------------------------------------------- /Controller.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Controller responsible for tracking whether we are in wired or wireless mode and routing key presses 3 | * accordingly 4 | */ 5 | 6 | // Stores the state of the cable / bluetooth switch 7 | volatile boolean bluetooth = true; 8 | volatile boolean usb = false; 9 | 10 | /** 11 | * Sends the current key report either over bluetooth or USB cable 12 | */ 13 | void send_key_report() { 14 | KeyReport keyReport = getKeyReport(); 15 | if (bluetooth) { 16 | send_ble_report(keyReport); 17 | } else if (usb) { 18 | send_usb_report(keyReport); 19 | } else { 20 | clear_key_report(); 21 | } 22 | } 23 | 24 | /** 25 | * Sends the current consumer key reports either over bluetooth or USB cable 26 | */ 27 | void send_media_control(uint8_t mediaHidKey) { 28 | if (bluetooth) { 29 | send_ble_media(mediaHidKey); 30 | } else if (usb) { 31 | send_usb_media(mediaHidKey); 32 | } 33 | } 34 | 35 | /** 36 | * Clears all currently set modifiers - not sure if this is really needed 37 | */ 38 | void clear_all() { 39 | clear_key_report(); 40 | send_key_report(); 41 | clear_LEDs(); 42 | } 43 | 44 | /** 45 | * Starts wireless mode ensuring that we don't process key presses until we are ready 46 | */ 47 | void startup_BLE(boolean reset) { 48 | start_BLE(); 49 | if (reset) { 50 | reconfigure_BLE(); 51 | } 52 | // Show two LEDs - a broken line = wireless 53 | bluetooth = true; 54 | clear_all(); 55 | flash_LEDs(3); 56 | start_PS2(); 57 | } 58 | 59 | 60 | 61 | /** 62 | * Stops wireless mode ensuring that further key presses are ignored 63 | */ 64 | void shutdown_BLE() { 65 | stop_PS2(); 66 | clear_all(); 67 | delay(250); // delay needed or control key can get stuck 68 | bluetooth = false; 69 | stop_BLE(); 70 | } 71 | 72 | /** 73 | * Starts wired mode ensuring that we don't process key presses until we are ready 74 | */ 75 | void startup_USB(boolean reset) { 76 | start_USB(); 77 | if (reset) { 78 | reconfigure_USB(); 79 | } 80 | // Show three LEDs - a full line = wired 81 | usb = true; 82 | clear_all(); 83 | flash_LEDs(7); 84 | start_PS2(); 85 | } 86 | 87 | /** 88 | * Stops wired mode ensuring that further key presses are ignored 89 | */ 90 | void shutdown_USB() { 91 | stop_PS2(); 92 | clear_all(); 93 | delay(250); // delay needed or control key can get stuck 94 | usb = false; 95 | stop_USB(); 96 | } 97 | 98 | /** 99 | * Switches mode from bluetooth to USB and vice versa 100 | */ 101 | void switch_mode() { 102 | if (bluetooth) { 103 | #if defined (DEBUG) 104 | Serial.println(F("Switching to USB keyboard")); 105 | #endif 106 | shutdown_BLE(); 107 | startup_USB(false); 108 | } else { 109 | #if defined (DEBUG) 110 | Serial.println(F("Switching to Bluetooth keyboard")); 111 | #endif 112 | shutdown_USB(); 113 | startup_BLE(false); 114 | } 115 | } 116 | 117 | /** 118 | * Performs a hard reset for the current mode - USB or bluetooth 119 | */ 120 | void reconfigure() { 121 | if (bluetooth) { 122 | #if defined (DEBUG) 123 | Serial.println(F("Reconfiguring Bluetooth keyboard")); 124 | #endif 125 | shutdown_BLE(); 126 | startup_BLE(true); 127 | } else { 128 | #if defined (DEBUG) 129 | Serial.println(F("Reconfiguring USB keyboard")); 130 | #endif 131 | shutdown_USB(); 132 | startup_USB(true); 133 | } 134 | } 135 | 136 | /** 137 | * Method to perform the initial keyboard start 138 | * 139 | * Currently this defaults to bluetooth 140 | */ 141 | void start_keyboard() { 142 | if (bluetooth) { 143 | #if defined (DEBUG) 144 | Serial.println(F("Starting as Bluetooth keyboard")); 145 | #endif 146 | startup_BLE(false); 147 | } else { 148 | #if defined (DEBUG) 149 | Serial.println(F("Starting as USB keyboard")); 150 | #endif 151 | startup_USB(false); 152 | } 153 | } 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /HID.cpp_1.6.5_modified: -------------------------------------------------------------------------------- 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 | Remote_ Remote; 31 | 32 | //================================================================================ 33 | //================================================================================ 34 | 35 | // HID report descriptor 36 | 37 | #define LSB(_x) ((_x) & 0xFF) 38 | #define MSB(_x) ((_x) >> 8) 39 | 40 | #define RAWHID_USAGE_PAGE 0xFFC0 41 | #define RAWHID_USAGE 0x0C00 42 | #define RAWHID_TX_SIZE 64 43 | #define RAWHID_RX_SIZE 64 44 | 45 | extern const u8 _hidReportDescriptor[] PROGMEM; 46 | const u8 _hidReportDescriptor[] = { 47 | 48 | // Mouse 49 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 50 | 0x09, 0x02, // USAGE (Mouse) 51 | 0xa1, 0x01, // COLLECTION (Application) 52 | 0x09, 0x01, // USAGE (Pointer) 53 | 0xa1, 0x00, // COLLECTION (Physical) 54 | 0x85, 0x01, // REPORT_ID (1) 55 | 0x05, 0x09, // USAGE_PAGE (Button) 56 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) 57 | 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 58 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 59 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 60 | 0x95, 0x03, // REPORT_COUNT (3) 61 | 0x75, 0x01, // REPORT_SIZE (1) 62 | 0x81, 0x02, // INPUT (Data,Var,Abs) 63 | 0x95, 0x01, // REPORT_COUNT (1) 64 | 0x75, 0x05, // REPORT_SIZE (5) 65 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 66 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 67 | 0x09, 0x30, // USAGE (X) 68 | 0x09, 0x31, // USAGE (Y) 69 | 0x09, 0x38, // USAGE (Wheel) 70 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) 71 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 72 | 0x75, 0x08, // REPORT_SIZE (8) 73 | 0x95, 0x03, // REPORT_COUNT (3) 74 | 0x81, 0x06, // INPUT (Data,Var,Rel) 75 | 0xc0, // END_COLLECTION 76 | 0xc0, // END_COLLECTION 77 | 78 | // Keyboard 79 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 80 | 0x09, 0x06, // USAGE (Keyboard) 81 | 0xa1, 0x01, // COLLECTION (Application) 82 | 0x85, 0x02, // REPORT_ID (2) 83 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 84 | 85 | 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 86 | 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 87 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 88 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 89 | 0x75, 0x01, // REPORT_SIZE (1) 90 | 91 | 0x95, 0x08, // REPORT_COUNT (8) 92 | 0x81, 0x02, // INPUT (Data,Var,Abs) 93 | 0x95, 0x01, // REPORT_COUNT (1) 94 | 0x75, 0x08, // REPORT_SIZE (8) 95 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 96 | 97 | 0x95, 0x06, // REPORT_COUNT (6) 98 | 0x75, 0x08, // REPORT_SIZE (8) 99 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 100 | 0x25, 0x65, // LOGICAL_MAXIMUM (101) 101 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 102 | 103 | 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 104 | 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 105 | 0x81, 0x00, // INPUT (Data,Ary,Abs) 106 | 0xc0, // END_COLLECTION 107 | 108 | #ifdef RAWHID_ENABLED 109 | // RAW HID 110 | 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 111 | 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), 112 | 113 | 0xA1, 0x01, // Collection 0x01 114 | 0x85, 0x03, // REPORT_ID (3) 115 | 0x75, 0x08, // report size = 8 bits 116 | 0x15, 0x00, // logical minimum = 0 117 | 0x26, 0xFF, 0x00, // logical maximum = 255 118 | 119 | 0x95, 64, // report count TX 120 | 0x09, 0x01, // usage 121 | 0x81, 0x02, // Input (array) 122 | 123 | 0x95, 64, // report count RX 124 | 0x09, 0x02, // usage 125 | 0x91, 0x02, // Output (array) 126 | 0xC0 // end collection 127 | #endif 128 | 129 | //----------------------------------------------------------------------------- 130 | 131 | /* Cross-platform support for controls found on IR Remotes */ 132 | 133 | 0x05, 0x0c, // Usage Page (Consumer Devices) 134 | 0x09, 0x01, // Usage (Consumer Control) 135 | 0xa1, 0x01, // Collection (Application) 136 | 0x85, 0x04, // REPORT_ID (4) 137 | 0x15, 0x00, // Logical Minimum (0) 138 | 0x25, 0x01, // Logical Maximum (1) 139 | 0x09, 0xe9, // Usage (Volume Up) 140 | 0x09, 0xea, // Usage (Volume Down) 141 | 0x75, 0x01, // Report Size (1) 142 | 0x95, 0x02, // Report Count (2) 143 | 0x81, 0x06, // Input (Data, Variable, Relative) 144 | 145 | 0x09, 0xe2, // Usage (Mute) 146 | 0x95, 0x01, // Report Count (1) 147 | 0x81, 0x06, // Input (Data, Variable, Relative) 148 | 149 | 0x09, 0xb0, // Usage (Play) 150 | 0x95, 0x01, // Report Count (1) 151 | 0x81, 0x06, // Input (Data, Variable, Relative) 152 | 153 | 0x09, 0xb1, // Usage (Pause) 154 | 0x95, 0x01, // Report Count (1) 155 | 0x81, 0x06, // Input (Data, Variable, Relative) 156 | 157 | 0x09, 0xb7, // Usage (Stop) 158 | 0x95, 0x01, // Report Count (1) 159 | 0x81, 0x06, // Input (Data, Variable, Relative) 160 | 161 | 0x09, 0xb5, // Usage (Next) 162 | 0x95, 0x01, // Report Count (1) 163 | 0x81, 0x06, // Input (Data, Variable, Relative) 164 | 165 | 0x09, 0xb6, // Usage (Previous) 166 | 0x95, 0x01, // Report Count (1) 167 | 0x81, 0x06, // Input (Data, Variable, Relative) 168 | 169 | 0x09, 0xb3, // Usage (Fast Forward) 170 | 0x95, 0x01, // Report Count (1) 171 | 0x81, 0x06, // Input (Data, Variable, Relative) 172 | 173 | 0x09, 0xb4, // Usage (Rewind) 174 | 0x95, 0x01, // Report Count (1) 175 | 0x81, 0x06, // Input (Data, Variable, Relative) 176 | 177 | 0x09, 0xcd, // Usage (Play/Pause) 178 | 0x95, 0x01, // Report Count (1) 179 | 0x81, 0x06, // Input (Data, Variable, Relative) 180 | 181 | 0x95, 0x05, // Report Count (5) Number of bits remaining in byte 182 | 0x81, 0x07, // Input (Constant, Variable, Relative) 183 | 0xc0 // End Collection 184 | 185 | }; 186 | 187 | extern const HIDDescriptor _hidInterface PROGMEM; 188 | const HIDDescriptor _hidInterface = 189 | { 190 | D_INTERFACE(HID_INTERFACE,1,3,0,0), 191 | D_HIDREPORT(sizeof(_hidReportDescriptor)), 192 | D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) 193 | }; 194 | 195 | //================================================================================ 196 | //================================================================================ 197 | // Driver 198 | 199 | u8 _hid_protocol = 1; 200 | u8 _hid_idle = 1; 201 | 202 | #define WEAK __attribute__ ((weak)) 203 | 204 | int WEAK HID_GetInterface(u8* interfaceNum) 205 | { 206 | interfaceNum[0] += 1; // uses 1 207 | return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); 208 | } 209 | 210 | int WEAK HID_GetDescriptor(int /* i */) 211 | { 212 | return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); 213 | } 214 | 215 | void WEAK HID_SendReport(u8 id, const void* data, int len) 216 | { 217 | USB_Send(HID_TX, &id, 1); 218 | USB_Send(HID_TX | TRANSFER_RELEASE,data,len); 219 | } 220 | 221 | bool WEAK HID_Setup(Setup& setup) 222 | { 223 | u8 r = setup.bRequest; 224 | u8 requestType = setup.bmRequestType; 225 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 226 | { 227 | if (HID_GET_REPORT == r) 228 | { 229 | //HID_GetReport(); 230 | return true; 231 | } 232 | if (HID_GET_PROTOCOL == r) 233 | { 234 | //Send8(_hid_protocol); // TODO 235 | return true; 236 | } 237 | } 238 | 239 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 240 | { 241 | if (HID_SET_PROTOCOL == r) 242 | { 243 | _hid_protocol = setup.wValueL; 244 | return true; 245 | } 246 | 247 | if (HID_SET_IDLE == r) 248 | { 249 | _hid_idle = setup.wValueL; 250 | return true; 251 | } 252 | } 253 | return false; 254 | } 255 | 256 | //================================================================================ 257 | //================================================================================ 258 | // Mouse 259 | 260 | Mouse_::Mouse_(void) : _buttons(0) 261 | { 262 | } 263 | 264 | void Mouse_::begin(void) 265 | { 266 | } 267 | 268 | void Mouse_::end(void) 269 | { 270 | } 271 | 272 | void Mouse_::click(uint8_t b) 273 | { 274 | _buttons = b; 275 | move(0,0,0); 276 | _buttons = 0; 277 | move(0,0,0); 278 | } 279 | 280 | void Mouse_::move(signed char x, signed char y, signed char wheel) 281 | { 282 | u8 m[4]; 283 | m[0] = _buttons; 284 | m[1] = x; 285 | m[2] = y; 286 | m[3] = wheel; 287 | HID_SendReport(1,m,4); 288 | } 289 | 290 | void Mouse_::buttons(uint8_t b) 291 | { 292 | if (b != _buttons) 293 | { 294 | _buttons = b; 295 | move(0,0,0); 296 | } 297 | } 298 | 299 | void Mouse_::press(uint8_t b) 300 | { 301 | buttons(_buttons | b); 302 | } 303 | 304 | void Mouse_::release(uint8_t b) 305 | { 306 | buttons(_buttons & ~b); 307 | } 308 | 309 | bool Mouse_::isPressed(uint8_t b) 310 | { 311 | if ((b & _buttons) > 0) 312 | return true; 313 | return false; 314 | } 315 | 316 | //================================================================================ 317 | //================================================================================ 318 | // Keyboard 319 | 320 | Keyboard_::Keyboard_(void) 321 | { 322 | } 323 | 324 | void Keyboard_::begin(void) 325 | { 326 | } 327 | 328 | void Keyboard_::end(void) 329 | { 330 | } 331 | 332 | void Keyboard_::sendReport(KeyReport* keys) 333 | { 334 | HID_SendReport(2,keys,sizeof(KeyReport)); 335 | } 336 | 337 | extern 338 | const uint8_t _asciimap[128] PROGMEM; 339 | 340 | #define SHIFT 0x80 341 | const uint8_t _asciimap[128] = 342 | { 343 | 0x00, // NUL 344 | 0x00, // SOH 345 | 0x00, // STX 346 | 0x00, // ETX 347 | 0x00, // EOT 348 | 0x00, // ENQ 349 | 0x00, // ACK 350 | 0x00, // BEL 351 | 0x2a, // BS Backspace 352 | 0x2b, // TAB Tab 353 | 0x28, // LF Enter 354 | 0x00, // VT 355 | 0x00, // FF 356 | 0x00, // CR 357 | 0x00, // SO 358 | 0x00, // SI 359 | 0x00, // DEL 360 | 0x00, // DC1 361 | 0x00, // DC2 362 | 0x00, // DC3 363 | 0x00, // DC4 364 | 0x00, // NAK 365 | 0x00, // SYN 366 | 0x00, // ETB 367 | 0x00, // CAN 368 | 0x00, // EM 369 | 0x00, // SUB 370 | 0x00, // ESC 371 | 0x00, // FS 372 | 0x00, // GS 373 | 0x00, // RS 374 | 0x00, // US 375 | 376 | 0x2c, // ' ' 377 | 0x1e|SHIFT, // ! 378 | 0x34|SHIFT, // " 379 | 0x20|SHIFT, // # 380 | 0x21|SHIFT, // $ 381 | 0x22|SHIFT, // % 382 | 0x24|SHIFT, // & 383 | 0x34, // ' 384 | 0x26|SHIFT, // ( 385 | 0x27|SHIFT, // ) 386 | 0x25|SHIFT, // * 387 | 0x2e|SHIFT, // + 388 | 0x36, // , 389 | 0x2d, // - 390 | 0x37, // . 391 | 0x38, // / 392 | 0x27, // 0 393 | 0x1e, // 1 394 | 0x1f, // 2 395 | 0x20, // 3 396 | 0x21, // 4 397 | 0x22, // 5 398 | 0x23, // 6 399 | 0x24, // 7 400 | 0x25, // 8 401 | 0x26, // 9 402 | 0x33|SHIFT, // : 403 | 0x33, // ; 404 | 0x36|SHIFT, // < 405 | 0x2e, // = 406 | 0x37|SHIFT, // > 407 | 0x38|SHIFT, // ? 408 | 0x1f|SHIFT, // @ 409 | 0x04|SHIFT, // A 410 | 0x05|SHIFT, // B 411 | 0x06|SHIFT, // C 412 | 0x07|SHIFT, // D 413 | 0x08|SHIFT, // E 414 | 0x09|SHIFT, // F 415 | 0x0a|SHIFT, // G 416 | 0x0b|SHIFT, // H 417 | 0x0c|SHIFT, // I 418 | 0x0d|SHIFT, // J 419 | 0x0e|SHIFT, // K 420 | 0x0f|SHIFT, // L 421 | 0x10|SHIFT, // M 422 | 0x11|SHIFT, // N 423 | 0x12|SHIFT, // O 424 | 0x13|SHIFT, // P 425 | 0x14|SHIFT, // Q 426 | 0x15|SHIFT, // R 427 | 0x16|SHIFT, // S 428 | 0x17|SHIFT, // T 429 | 0x18|SHIFT, // U 430 | 0x19|SHIFT, // V 431 | 0x1a|SHIFT, // W 432 | 0x1b|SHIFT, // X 433 | 0x1c|SHIFT, // Y 434 | 0x1d|SHIFT, // Z 435 | 0x2f, // [ 436 | 0x31, // bslash 437 | 0x30, // ] 438 | 0x23|SHIFT, // ^ 439 | 0x2d|SHIFT, // _ 440 | 0x35, // ` 441 | 0x04, // a 442 | 0x05, // b 443 | 0x06, // c 444 | 0x07, // d 445 | 0x08, // e 446 | 0x09, // f 447 | 0x0a, // g 448 | 0x0b, // h 449 | 0x0c, // i 450 | 0x0d, // j 451 | 0x0e, // k 452 | 0x0f, // l 453 | 0x10, // m 454 | 0x11, // n 455 | 0x12, // o 456 | 0x13, // p 457 | 0x14, // q 458 | 0x15, // r 459 | 0x16, // s 460 | 0x17, // t 461 | 0x18, // u 462 | 0x19, // v 463 | 0x1a, // w 464 | 0x1b, // x 465 | 0x1c, // y 466 | 0x1d, // z 467 | 0x2f|SHIFT, // 468 | 0x31|SHIFT, // | 469 | 0x30|SHIFT, // } 470 | 0x35|SHIFT, // ~ 471 | 0 // DEL 472 | }; 473 | 474 | uint8_t USBPutChar(uint8_t c); 475 | 476 | // press() adds the specified key (printing, non-printing, or modifier) 477 | // to the persistent key report and sends the report. Because of the way 478 | // USB HID works, the host acts like the key remains pressed until we 479 | // call release(), releaseAll(), or otherwise clear the report and resend. 480 | size_t Keyboard_::press(uint8_t k) 481 | { 482 | uint8_t i; 483 | if (k >= 136) { // it's a non-printing key (not a modifier) 484 | k = k - 136; 485 | } else if (k >= 128) { // it's a modifier key 486 | _keyReport.modifiers |= (1<<(k-128)); 487 | k = 0; 488 | } else { // it's a printing key 489 | k = pgm_read_byte(_asciimap + k); 490 | if (!k) { 491 | setWriteError(); 492 | return 0; 493 | } 494 | if (k & 0x80) { // it's a capital letter or other character reached with shift 495 | _keyReport.modifiers |= 0x02; // the left shift modifier 496 | k &= 0x7F; 497 | } 498 | } 499 | 500 | // Add k to the key report only if it's not already present 501 | // and if there is an empty slot. 502 | if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 503 | _keyReport.keys[2] != k && _keyReport.keys[3] != k && 504 | _keyReport.keys[4] != k && _keyReport.keys[5] != k) { 505 | 506 | for (i=0; i<6; i++) { 507 | if (_keyReport.keys[i] == 0x00) { 508 | _keyReport.keys[i] = k; 509 | break; 510 | } 511 | } 512 | if (i == 6) { 513 | setWriteError(); 514 | return 0; 515 | } 516 | } 517 | sendReport(&_keyReport); 518 | return 1; 519 | } 520 | 521 | // release() takes the specified key out of the persistent key report and 522 | // sends the report. This tells the OS the key is no longer pressed and that 523 | // it shouldn't be repeated any more. 524 | size_t Keyboard_::release(uint8_t k) 525 | { 526 | uint8_t i; 527 | if (k >= 136) { // it's a non-printing key (not a modifier) 528 | k = k - 136; 529 | } else if (k >= 128) { // it's a modifier key 530 | _keyReport.modifiers &= ~(1<<(k-128)); 531 | k = 0; 532 | } else { // it's a printing key 533 | k = pgm_read_byte(_asciimap + k); 534 | if (!k) { 535 | return 0; 536 | } 537 | if (k & 0x80) { // it's a capital letter or other character reached with shift 538 | _keyReport.modifiers &= ~(0x02); // the left shift modifier 539 | k &= 0x7F; 540 | } 541 | } 542 | 543 | // Test the key report to see if k is present. Clear it if it exists. 544 | // Check all positions in case the key is present more than once (which it shouldn't be) 545 | for (i=0; i<6; i++) { 546 | if (0 != k && _keyReport.keys[i] == k) { 547 | _keyReport.keys[i] = 0x00; 548 | } 549 | } 550 | 551 | sendReport(&_keyReport); 552 | return 1; 553 | } 554 | 555 | void Keyboard_::releaseAll(void) 556 | { 557 | _keyReport.keys[0] = 0; 558 | _keyReport.keys[1] = 0; 559 | _keyReport.keys[2] = 0; 560 | _keyReport.keys[3] = 0; 561 | _keyReport.keys[4] = 0; 562 | _keyReport.keys[5] = 0; 563 | _keyReport.modifiers = 0; 564 | sendReport(&_keyReport); 565 | } 566 | 567 | size_t Keyboard_::write(uint8_t c) 568 | { 569 | uint8_t p = press(c); // Keydown 570 | release(c); // Keyup 571 | return p; // just return the result of press() since release() almost always returns 1 572 | } 573 | 574 | //================================================================================ 575 | //================================================================================ 576 | // Remote 577 | 578 | Remote_::Remote_(void) 579 | { 580 | } 581 | 582 | void Remote_::begin(void) 583 | { 584 | } 585 | 586 | void Remote_::end(void) 587 | { 588 | } 589 | 590 | void Remote_::increase(void) 591 | { 592 | u8 m[2]; 593 | m[0] = VOLUME_UP; 594 | m[1] = 0; 595 | HID_SendReport(4,m,2); 596 | } 597 | 598 | void Remote_::decrease(void) 599 | { 600 | u8 m[2]; 601 | m[0] = VOLUME_DOWN; 602 | m[1] = 0; 603 | HID_SendReport(4,m,2); 604 | } 605 | 606 | void Remote_::mute(void) 607 | { 608 | u8 m[2]; 609 | m[0] = VOLUME_MUTE; 610 | m[1] = 0; 611 | HID_SendReport(4,m,2); 612 | } 613 | 614 | void Remote_::play(void) 615 | { 616 | u8 m[2]; 617 | m[0] = REMOTE_PLAY; 618 | m[1] = 0; 619 | HID_SendReport(4,m,2); 620 | } 621 | 622 | void Remote_::pause(void) 623 | { 624 | u8 m[2]; 625 | m[0] = REMOTE_PAUSE; 626 | m[1] = 0; 627 | HID_SendReport(4,m,2); 628 | } 629 | 630 | void Remote_::stop(void) 631 | { 632 | u8 m[2]; 633 | m[0] = REMOTE_STOP; 634 | m[1] = 0; 635 | HID_SendReport(4,m,2); 636 | } 637 | 638 | void Remote_::next(void) 639 | { 640 | u8 m[2]; 641 | m[0] = REMOTE_NEXT; 642 | m[1] = 0; 643 | HID_SendReport(4,m,2); 644 | } 645 | 646 | void Remote_::previous(void) 647 | { 648 | u8 m[2]; 649 | m[0] = REMOTE_PREVIOUS; 650 | m[1] = 0; 651 | HID_SendReport(4,m,2); 652 | } 653 | 654 | void Remote_::forward(void) 655 | { 656 | u8 m[2]; 657 | m[0] = 0; 658 | m[1] = REMOTE_FAST_FORWARD >> 8; 659 | HID_SendReport(4,m,2); 660 | } 661 | 662 | void Remote_::rewind(void) 663 | { 664 | u8 m[2]; 665 | m[0] = 0; 666 | m[1] = REMOTE_REWIND >> 8; 667 | HID_SendReport(4,m,2); 668 | } 669 | 670 | void Remote_::playpause(void) 671 | { 672 | u8 m[2]; 673 | m[0] = 0; 674 | m[1] = REMOTE_PLAY_PAUSE >> 8; 675 | HID_SendReport(4,m,2); 676 | } 677 | 678 | void Remote_::clear(void) 679 | { 680 | u8 m[2]; 681 | m[0] = 0; 682 | m[1] = 0; 683 | HID_SendReport(4,m,2); 684 | } 685 | 686 | #endif 687 | 688 | #endif /* if defined(USBCON) */ 689 | -------------------------------------------------------------------------------- /KeyReport.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Functions for manipulating and testing the key report which will be send for either wired 3 | * or wireless use 4 | */ 5 | 6 | // Stores the parts of the USB HID key command 7 | KeyReport keyReport; 8 | 9 | /** 10 | * Updates the key report given a key press 11 | * 12 | * Up to six keys can be simultaneously pressed plus the modifier keys 13 | * 14 | */ 15 | void report_add(uint8_t hidKey) { 16 | uint8_t i; 17 | if (hidKey >= HID_LEFT_CTRL) { 18 | keyReport.modifiers |= 1 << (hidKey - HID_LEFT_CTRL); 19 | } else if (keyReport.keys[0] != hidKey && keyReport.keys[1] != hidKey 20 | && keyReport.keys[2] != hidKey && keyReport.keys[3] != hidKey 21 | && keyReport.keys[4] != hidKey && keyReport.keys[5] != hidKey) { 22 | for (i = 0; i < 6; ++i) { 23 | if (keyReport.keys[i] == 0) { 24 | keyReport.keys[i] = hidKey; 25 | break; 26 | } 27 | } 28 | } 29 | } 30 | 31 | boolean is_clear() { 32 | return keyReport.modifiers == 0 && keyReport.keys[0] == 0 && keyReport.keys[1] == 0 33 | && keyReport.keys[2] == 0 && keyReport.keys[3] == 0 34 | && keyReport.keys[4] == 0 && keyReport.keys[5] == 0; 35 | 36 | } 37 | 38 | /** 39 | * Updates the key report given a key release 40 | */ 41 | void report_remove(uint8_t hidKey) { 42 | uint8_t i; 43 | if (hidKey >= HID_LEFT_CTRL) { 44 | keyReport.modifiers &= ~(1 << (hidKey - HID_LEFT_CTRL)); 45 | } else { 46 | for (i = 0; i < 6; ++i) { 47 | if (keyReport.keys[i] == hidKey) { 48 | keyReport.keys[i] = 0; 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * Test modifiers to see if shift is currently pressed 57 | */ 58 | bool is_shift() { 59 | return keyReport.modifiers == 0x02; 60 | } 61 | 62 | /** 63 | * Test modifiers to see if control is currently pressed 64 | */ 65 | bool is_control() { 66 | return keyReport.modifiers == 0x01; 67 | } 68 | 69 | /** 70 | * Test modifiers to see if control and shift are currently pressed 71 | */ 72 | bool is_control_shift() { 73 | return keyReport.modifiers == 0x03; 74 | } 75 | 76 | /** 77 | * Clears all currently set modifiers - not sure if this is really needed 78 | */ 79 | void clear_modifiers() { 80 | keyReport.modifiers = 0; 81 | } 82 | 83 | /** 84 | * Clears all currently set modifiers - not sure if this is really needed 85 | */ 86 | void clear_key_report() { 87 | keyReport.modifiers = 0x00; 88 | keyReport.keys[0] = 0x00; 89 | keyReport.keys[1] = 0x00; 90 | keyReport.keys[2] = 0x00; 91 | keyReport.keys[3] = 0x00; 92 | keyReport.keys[4] = 0x00; 93 | keyReport.keys[5] = 0x00; 94 | } 95 | 96 | /** 97 | * Gets the key report 98 | */ 99 | KeyReport getKeyReport() { 100 | return keyReport; 101 | } 102 | 103 | /** 104 | * Outputs a debug string for the current key report 105 | */ 106 | void log_key_report(KeyReport report) { 107 | #if defined (DEBUG) 108 | String cmd = "0xFD-" + report_to_string(report); 109 | Serial.println(cmd); 110 | #endif 111 | } 112 | 113 | /** 114 | * Returns a string representation of a key report 115 | */ 116 | String report_to_string(KeyReport report) { 117 | String cmd = hex_to_str(report.modifiers); 118 | cmd += "-"; 119 | cmd += hex_to_str(report.reserved); 120 | cmd += "-"; 121 | cmd += hex_to_str(report.keys[0]); 122 | cmd += "-"; 123 | cmd += hex_to_str(report.keys[1]); 124 | cmd += "-"; 125 | cmd += hex_to_str(report.keys[2]); 126 | cmd += "-"; 127 | cmd += hex_to_str(report.keys[3]); 128 | cmd += "-"; 129 | cmd += hex_to_str(report.keys[4]); 130 | cmd += "-"; 131 | cmd += hex_to_str(report.keys[5]); 132 | return cmd; 133 | } 134 | 135 | /** 136 | * Create a two character hex string for debugging 137 | */ 138 | String hex_to_str(uint8_t hidKey) { 139 | String str = String(hidKey, HEX); 140 | if (hidKey < 16) { 141 | str = "0" + str; 142 | } 143 | str.toUpperCase(); 144 | return str; 145 | } 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | -------------------------------------------------------------------------------- /PS2.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Functions associated with PS2 communication 3 | */ 4 | 5 | // Storage of keymaps 6 | uint8_t PS2_to_HID_keymap[255]; 7 | uint8_t PS2Long_to_HID_keymap[255]; 8 | 9 | //buffer to store key strokes 10 | static volatile uint8_t buffer[BUFFER_SIZE]; 11 | 12 | //keep track of our place in the buffer 13 | static volatile uint8_t head, tail, tailMinus1; 14 | 15 | //keep track of PS2 bits sent and received 16 | static volatile uint8_t sendBits, msg, bitCount, setBits; 17 | 18 | //the LED setting 19 | uint8_t leds; 20 | 21 | // Should we send the LED state to the keyboard and stop receiving for a while 22 | volatile bool sendLeds; 23 | 24 | // Has the extended PS2 mode been entered 25 | bool ext; 26 | 27 | // Are we in key release 28 | bool brk; 29 | 30 | volatile bool autoLEDclear = false; 31 | 32 | // The number of PS2 key codes we should now ignore e.g. after Pause key is pressed 33 | int skip; 34 | 35 | // When we switch from wireless to wired or back we will disable adding to key report or sending keys 36 | // But we will allow LED processing 37 | volatile bool enabled = false; 38 | 39 | /** 40 | * Set up the PS2 interface 41 | */ 42 | void setup_PS2() { 43 | delay(1000); 44 | pinMode(CLK_PIN, INPUT_PULLUP); 45 | pinMode(DATA_PIN, INPUT_PULLUP); 46 | 47 | //clear buffer 48 | for (int i = 0; i < BUFFER_SIZE; i++) { 49 | buffer[i] = 0; 50 | } 51 | 52 | attachInterrupt(1, ps2interrupt, FALLING); 53 | 54 | head = 0; 55 | tail = 0; 56 | tailMinus1 = BUFFER_SIZE - 1; 57 | sendBits = 0; 58 | } 59 | 60 | /** 61 | * The ISR for the external interrupt 62 | */ 63 | void ps2interrupt(void) { 64 | static uint8_t bitcount = 0; 65 | static uint8_t incoming = 0; 66 | static uint32_t prev_ms = 0; 67 | uint32_t now_ms; 68 | uint8_t n, val; 69 | 70 | if (!sendBits) { 71 | val = digitalRead(DATA_PIN); 72 | now_ms = millis(); 73 | if (now_ms - prev_ms > 250) { 74 | bitcount = 0; 75 | incoming = 0; 76 | } 77 | prev_ms = now_ms; 78 | n = bitcount - 1; 79 | if (n <= 7) { 80 | incoming |= (val << n); 81 | } 82 | bitcount++; 83 | if (bitcount == 11) { 84 | add_to_buffer(incoming); 85 | bitcount = 0; 86 | incoming = 0; 87 | } 88 | } else { 89 | --sendBits; 90 | uint8_t b = bitCount - 1; 91 | if (b == 8) { 92 | digitalWrite(DATA_PIN, !(setBits & 1)); 93 | } else if (b == 9) { 94 | pinMode(DATA_PIN, INPUT_PULLUP); 95 | } else if (b < 8) { 96 | bool bt = (msg >> b) & 1; 97 | digitalWrite(DATA_PIN, bt); 98 | setBits += bt; 99 | } 100 | ++bitCount; 101 | } 102 | } 103 | 104 | /** 105 | * Adds the specified PS2 key code to the buffer 106 | */ 107 | void add_to_buffer(uint8_t input) { 108 | #if defined (DEBUG) 109 | Serial.print(F("Raw PS2: ")); 110 | Serial.println(input, HEX); 111 | #endif 112 | 113 | uint8_t i = head + 1; 114 | if (i >= BUFFER_SIZE) { 115 | i = 0; 116 | } 117 | if (tail == 0) { 118 | tailMinus1 = BUFFER_SIZE - 1; 119 | } else { 120 | tailMinus1 = tail - 1; 121 | } 122 | 123 | if (i != tail && i != tailMinus1) { 124 | buffer[i] = input; 125 | head = i; 126 | } 127 | if (i == tailMinus1) { 128 | buffer[i] = PS2_BUFFER_OVERFLOW; 129 | head = i; 130 | } 131 | 132 | log_buffer_stats(i); 133 | } 134 | 135 | void log_buffer_stats(uint8_t i) { 136 | #if defined (DEBUG) 137 | Serial.print("Buffer: last="); 138 | Serial.print(i); 139 | Serial.print(" head="); 140 | Serial.print(head); 141 | Serial.print(" tail="); 142 | Serial.print(tail); 143 | // Serial.print(" tailMinus1="); 144 | // Serial.print(tailMinus1); 145 | if (i == tailMinus1) { 146 | Serial.println(" *** OVERFLOW ***"); 147 | } else if (head == tail) { 148 | Serial.println(" *** EMPTY ***"); 149 | } else { 150 | Serial.println(); 151 | } 152 | #endif 153 | } 154 | 155 | /** 156 | * Reads the next PS2 key code from the buffer 157 | */ 158 | static inline uint8_t get_scan_code(void) { 159 | uint8_t c, i; 160 | 161 | i = tail; 162 | if (i == head) { 163 | return 0; 164 | } 165 | i++; 166 | if (i >= BUFFER_SIZE) { 167 | i = 0; 168 | } 169 | c = buffer[i]; 170 | tail = i; 171 | 172 | if (tail == 0) { 173 | tailMinus1 = BUFFER_SIZE - 1; 174 | } else { 175 | tailMinus1 = tail - 1; 176 | } 177 | 178 | 179 | log_buffer_stats(i); 180 | 181 | return c; 182 | } 183 | 184 | /** 185 | * Gets the next PS2 key press from the buffer and decides what to do in response 186 | */ 187 | void process_buffer() { 188 | uint8_t ps2Key = get_scan_code(); 189 | uint8_t hidKey; 190 | if (ps2Key) { 191 | if (skip) { 192 | --skip; 193 | } else { 194 | if (ps2Key == PS2_BUFFER_OVERFLOW) { 195 | ext = false; 196 | brk = false; 197 | clear_key_report(); 198 | send_key_report(); 199 | #if defined (DEBUG) 200 | Serial.println(F("CLEAR DOWN ON BUFFER OVERFLOW!")); 201 | #endif 202 | } else if (ps2Key == PS2_EXTENDED) { 203 | ext = true; 204 | } else if (ps2Key == PS2_RELEASE) { 205 | brk = true; 206 | } else if (ps2Key == PS2_LED_ACK) { 207 | if (sendLeds) { 208 | sendLeds = false; 209 | send_ps2_msg(leds); 210 | } else if (autoLEDclear) { 211 | delay(1000); 212 | clear_LEDs(); 213 | } 214 | } else { 215 | if (ps2Key == PS2_PAUSE_SEQUENCE) { 216 | hidKey = HID_PAUSE; 217 | skip = 7; 218 | brk = true; 219 | report_add(hidKey); 220 | send_key_report(); 221 | } else { 222 | hidKey = 223 | ext ? PS2Long_to_HID_keymap[ps2Key] : PS2_to_HID_keymap[ps2Key]; 224 | } 225 | 226 | if (hidKey) { 227 | // Even if key reporting is disabled we still allow special functions 228 | // for reset etc but do not send any keys out 229 | boolean send_key = special_functions(hidKey, brk); 230 | if (send_key && enabled) { 231 | if (is_media(hidKey)) { 232 | if (!brk) { 233 | send_media_control(hidKey); 234 | } 235 | } else { 236 | if (brk) { 237 | report_remove(hidKey); 238 | if (hidKey == HID_NUM_LCK 239 | || hidKey == HID_SCR_LCK 240 | || hidKey == HID_CAPS) { 241 | if (hidKey == HID_NUM_LCK) { 242 | leds ^= 2; 243 | } else if (hidKey == HID_SCR_LCK) { 244 | leds ^= 1; 245 | } else if (hidKey == HID_CAPS) { 246 | leds ^= 4; 247 | } 248 | set_LEDs(leds); 249 | } 250 | } else { 251 | report_add(hidKey); 252 | } 253 | send_key_report(); 254 | } 255 | } 256 | } 257 | 258 | brk = false; 259 | ext = false; 260 | } 261 | } 262 | } else { 263 | // No scan code - should I send another clear for good measure? 264 | } 265 | } 266 | 267 | /** 268 | * Initiates a clear of the caps/scroll/num lock LEDs 269 | * 270 | * This method is used to clear the LEDs on a switch between wired and wireless 271 | */ 272 | void clear_LEDs() { 273 | autoLEDclear = false; 274 | sendLeds = true; 275 | leds = 0; 276 | send_ps2_msg((byte) PS2_SET_RESET_LEDS); 277 | } 278 | 279 | /** 280 | * Initiates a set of the caps/scroll/num lock LEDs 281 | * 282 | * This method is used to indicate which mode wired or wireless has been entered 283 | */ 284 | void set_LEDs(uint8_t reqdLeds) { 285 | sendLeds = true; 286 | leds = reqdLeds; 287 | send_ps2_msg((byte) PS2_SET_RESET_LEDS); 288 | } 289 | 290 | /** 291 | * Flashes the specified LEDs on then off 292 | */ 293 | void flash_LEDs(uint8_t reqdLeds) { 294 | set_LEDs(reqdLeds); 295 | autoLEDclear = true; 296 | } 297 | 298 | /** 299 | * Starts processing of key presses into the key report 300 | */ 301 | void start_PS2() { 302 | enabled = true; 303 | } 304 | 305 | /** 306 | * Stops processing of key presses into the key report 307 | */ 308 | void stop_PS2() { 309 | enabled = false; 310 | } 311 | 312 | /** 313 | * Sends a message up to the keyboard in order to set LEDs 314 | */ 315 | void send_ps2_msg(uint8_t ps2Msg) { 316 | noInterrupts(); 317 | pinMode(CLK_PIN, OUTPUT); 318 | digitalWrite(CLK_PIN, LOW); 319 | delayMicroseconds(60); 320 | pinMode(CLK_PIN, INPUT_PULLUP); 321 | msg = ps2Msg; 322 | bitCount = 0; 323 | sendBits = 12; 324 | setBits = 0; 325 | pinMode(DATA_PIN, OUTPUT); 326 | digitalWrite(DATA_PIN, LOW); 327 | interrupts(); 328 | 329 | #if defined (TEST_SERIAL_INPUT) 330 | test_ps2_msg(ps2Msg); 331 | #endif 332 | 333 | #if defined (DEBUG) && not defined (TEST_SERIAL_INPUT) 334 | debug_ps2_msg(ps2Msg); 335 | #endif 336 | } 337 | 338 | 339 | void debug_ps2_msg(uint8_t ps2Msg) { 340 | if (ps2Msg == PS2_SET_RESET_LEDS) { 341 | Serial.println(F("SET RESET LEDSs")); 342 | } else { 343 | Serial.print(F("LEDS:")); 344 | if (ps2Msg & 2) { 345 | Serial.print(F("ON-")); 346 | } else { 347 | Serial.print(F("OFF-")); 348 | } 349 | if (ps2Msg & 4) { 350 | Serial.print(F("ON-")); 351 | } else { 352 | Serial.print(F("OFF-")); 353 | } 354 | if (ps2Msg & 1) { 355 | Serial.print(F("ON")); 356 | } else { 357 | Serial.print(F("OFF")); 358 | } 359 | Serial.println(); 360 | } 361 | } 362 | 363 | /** 364 | * Tests if a HID key code corresponds to a media key 365 | */ 366 | bool is_media(uint8_t hidKey) { 367 | 368 | switch (hidKey) { 369 | case (HID_PLAY_PAUSE): 370 | case (HID_STOP): 371 | case (HID_NEXT_TRACK): 372 | case (HID_PREV_TRACK): 373 | case (HID_VOL_UP): 374 | case (HID_VOL_DWN): 375 | case (HID_MUTE): 376 | return true; 377 | break; 378 | } 379 | return false; 380 | } 381 | 382 | /** 383 | * Sets up the keyboard mapping from PS2 to HID 384 | */ 385 | void setup_keymaps() { 386 | PS2_to_HID_keymap[PS2_A] = HID_A; 387 | PS2_to_HID_keymap[PS2_B] = HID_B; 388 | PS2_to_HID_keymap[PS2_C] = HID_C; 389 | PS2_to_HID_keymap[PS2_D] = HID_D; 390 | PS2_to_HID_keymap[PS2_E] = HID_E; 391 | PS2_to_HID_keymap[PS2_F] = HID_F; 392 | PS2_to_HID_keymap[PS2_G] = HID_G; 393 | PS2_to_HID_keymap[PS2_H] = HID_H; 394 | PS2_to_HID_keymap[PS2_I] = HID_I; 395 | PS2_to_HID_keymap[PS2_J] = HID_J; 396 | PS2_to_HID_keymap[PS2_K] = HID_K; 397 | PS2_to_HID_keymap[PS2_L] = HID_L; 398 | PS2_to_HID_keymap[PS2_M] = HID_M; 399 | PS2_to_HID_keymap[PS2_N] = HID_N; 400 | PS2_to_HID_keymap[PS2_O] = HID_O; 401 | PS2_to_HID_keymap[PS2_P] = HID_P; 402 | PS2_to_HID_keymap[PS2_Q] = HID_Q; 403 | PS2_to_HID_keymap[PS2_R] = HID_R; 404 | PS2_to_HID_keymap[PS2_S] = HID_S; 405 | PS2_to_HID_keymap[PS2_T] = HID_T; 406 | PS2_to_HID_keymap[PS2_U] = HID_U; 407 | PS2_to_HID_keymap[PS2_V] = HID_V; 408 | PS2_to_HID_keymap[PS2_W] = HID_W; 409 | PS2_to_HID_keymap[PS2_X] = HID_X; 410 | PS2_to_HID_keymap[PS2_Y] = HID_Y; 411 | PS2_to_HID_keymap[PS2_Z] = HID_Z; 412 | PS2_to_HID_keymap[PS2_0] = HID_0; 413 | PS2_to_HID_keymap[PS2_1] = HID_1; 414 | PS2_to_HID_keymap[PS2_2] = HID_2; 415 | PS2_to_HID_keymap[PS2_3] = HID_3; 416 | PS2_to_HID_keymap[PS2_4] = HID_4; 417 | PS2_to_HID_keymap[PS2_5] = HID_5; 418 | PS2_to_HID_keymap[PS2_6] = HID_6; 419 | PS2_to_HID_keymap[PS2_7] = HID_7; 420 | PS2_to_HID_keymap[PS2_8] = HID_8; 421 | PS2_to_HID_keymap[PS2_9] = HID_9; 422 | PS2_to_HID_keymap[PS2_ACCENT] = HID_ACCENT; 423 | PS2_to_HID_keymap[PS2_HYPH] = HID_HYPH; 424 | PS2_to_HID_keymap[PS2_EQUAL] = HID_EQUAL; 425 | PS2_to_HID_keymap[PS2_BACK_SLASH] = HID_BACK_SLASH; 426 | PS2_to_HID_keymap[PS2_BACK_SPACE] = HID_BACK_SPACE; 427 | PS2_to_HID_keymap[PS2_SPACE] = HID_SPACE; 428 | PS2_to_HID_keymap[PS2_TAB] = HID_TAB; 429 | PS2_to_HID_keymap[PS2_CAPS] = HID_CAPS; 430 | PS2_to_HID_keymap[PS2_LEFT_SHIFT] = HID_LEFT_SHIFT; 431 | PS2_to_HID_keymap[PS2_LEFT_CTRL] = HID_LEFT_CTRL; 432 | PS2_to_HID_keymap[PS2_LEFT_ALT] = HID_LEFT_ALT; 433 | PS2_to_HID_keymap[PS2_RIGHT_SHIFT] = HID_RIGHT_SHIFT; 434 | PS2_to_HID_keymap[PS2_ENTER] = HID_ENTER; 435 | PS2_to_HID_keymap[PS2_ESC] = HID_ESC; 436 | PS2_to_HID_keymap[PS2_F1] = HID_F1; 437 | PS2_to_HID_keymap[PS2_F2] = HID_F2; 438 | PS2_to_HID_keymap[PS2_F3] = HID_F3; 439 | PS2_to_HID_keymap[PS2_F4] = HID_F4; 440 | PS2_to_HID_keymap[PS2_F5] = HID_F5; 441 | PS2_to_HID_keymap[PS2_F6] = HID_F6; 442 | PS2_to_HID_keymap[PS2_F7] = HID_F7; 443 | PS2_to_HID_keymap[PS2_F8] = HID_F8; 444 | PS2_to_HID_keymap[PS2_F9] = HID_F9; 445 | PS2_to_HID_keymap[PS2_F10] = HID_F10; 446 | PS2_to_HID_keymap[PS2_F11] = HID_F11; 447 | PS2_to_HID_keymap[PS2_F12] = HID_F12; 448 | PS2_to_HID_keymap[PS2_SCROLL] = HID_SCR_LCK; 449 | PS2_to_HID_keymap[PS2_LEFT_BRACKET] = HID_LEFT_BRACKET; 450 | PS2_to_HID_keymap[PS2_NUM] = HID_NUM_LCK; 451 | PS2_to_HID_keymap[PS2_KP_STAR] = HID_KP_STAR; 452 | PS2_to_HID_keymap[PS2_KP_HYPH] = HID_KP_HYPH; 453 | PS2_to_HID_keymap[PS2_KP_PLUS] = HID_KP_PLUS; 454 | PS2_to_HID_keymap[PS2_KP_PERIOD] = HID_KP_PERIOD; 455 | PS2_to_HID_keymap[PS2_KP_0] = HID_KP_0; 456 | PS2_to_HID_keymap[PS2_KP_1] = HID_KP_1; 457 | PS2_to_HID_keymap[PS2_KP_2] = HID_KP_2; 458 | PS2_to_HID_keymap[PS2_KP_3] = HID_KP_3; 459 | PS2_to_HID_keymap[PS2_KP_4] = HID_KP_4; 460 | PS2_to_HID_keymap[PS2_KP_5] = HID_KP_5; 461 | PS2_to_HID_keymap[PS2_KP_6] = HID_KP_6; 462 | PS2_to_HID_keymap[PS2_KP_7] = HID_KP_7; 463 | PS2_to_HID_keymap[PS2_KP_8] = HID_KP_8; 464 | PS2_to_HID_keymap[PS2_KP_9] = HID_KP_9; 465 | PS2_to_HID_keymap[PS2_RIGHT_BRACKET] = HID_RIGHT_BRACKET; 466 | PS2_to_HID_keymap[PS2_SEMI_COLON] = HID_SEMI_COLON; 467 | PS2_to_HID_keymap[PS2_APOSTROPHY] = HID_APOSTROPHY; 468 | PS2_to_HID_keymap[PS2_COMMA] = HID_COMMA; 469 | PS2_to_HID_keymap[PS2_PERIOD] = HID_PERIOD; 470 | PS2_to_HID_keymap[PS2_FWD_SLASH] = HID_FWD_SLASH; 471 | PS2_to_HID_keymap[PS2_BACK_SLASH_NON_US] = HID_BACK_SLASH_NON_US; 472 | 473 | PS2Long_to_HID_keymap[PS2_PRNT_SCR] = HID_PRNT_SCR; 474 | PS2Long_to_HID_keymap[PS2_RIGHT_ALT] = HID_RIGHT_ALT; 475 | PS2Long_to_HID_keymap[PS2_RIGHT_CTRL] = HID_RIGHT_CTRL; 476 | PS2Long_to_HID_keymap[PS2_PREV_TRACK] = HID_PREV_TRACK; 477 | PS2Long_to_HID_keymap[PS2_LEFT_GUI] = HID_LEFT_GUI; 478 | PS2Long_to_HID_keymap[PS2_VOL_DWN] = HID_VOL_DWN; 479 | PS2Long_to_HID_keymap[PS2_MUTE] = HID_MUTE; 480 | PS2Long_to_HID_keymap[PS2_RIGHT_GUI] = HID_RIGHT_GUI; 481 | PS2Long_to_HID_keymap[PS2_APPLICATION] = HID_APPLICATION; 482 | PS2Long_to_HID_keymap[PS2_VOL_UP] = HID_VOL_UP; 483 | PS2Long_to_HID_keymap[PS2_PLAY_PAUSE] = HID_PLAY_PAUSE; 484 | PS2Long_to_HID_keymap[PS2_STOP] = HID_STOP; 485 | PS2Long_to_HID_keymap[PS2_KP_FWD_SLASH] = HID_KP_FWD_SLASH; 486 | PS2Long_to_HID_keymap[PS2_NEXT_TRACK] = HID_NEXT_TRACK; 487 | PS2Long_to_HID_keymap[PS2_KP_ENTER] = HID_KP_ENTER; 488 | PS2Long_to_HID_keymap[PS2_END] = HID_END; 489 | PS2Long_to_HID_keymap[PS2_LEFT_ARROW] = HID_LEFT_ARROW; 490 | PS2Long_to_HID_keymap[PS2_HOME] = HID_HOME; 491 | PS2Long_to_HID_keymap[PS2_PAUSE_KEY_FAKE] = HID_PAUSE; 492 | PS2Long_to_HID_keymap[PS2_INSERT] = HID_INSERT; 493 | PS2Long_to_HID_keymap[PS2_DELETE] = HID_DEL; 494 | PS2Long_to_HID_keymap[PS2_DOWN_ARROW] = HID_DOWN_ARROW; 495 | PS2Long_to_HID_keymap[PS2_RIGHT_ARROW] = HID_RIGHT_ARROW; 496 | PS2Long_to_HID_keymap[PS2_UP_ARROW] = HID_UP_ARROW; 497 | PS2Long_to_HID_keymap[PS2_PG_DWN] = HID_PG_DWN; 498 | PS2Long_to_HID_keymap[PS2_PG_UP] = HID_PG_UP; 499 | } 500 | 501 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BLE_WASD 2 | Bluetooth enabled WASD keyboard 3 | See https://hackaday.io/project/7646-ble-wasdmechanical-keyboard for build instructions! 4 | 5 | This fork contains improvements from original to 6 | 7 | a) fix some bugs 8 | b) add two way PS2 comms so that capslock/numlock/scrolllock LEDS work 9 | c) provide an optional "wired" mode. The thought here is to be able to use as a wired keyboard without unplugging the bluefruit from the keyboard and possibly benefit from some improved reduction in latecy when we are wired. The ability to send the media keys from the CODE keyboard also has to be preserved here and this requires some addition to the arduino library code 10 | 11 | WORK IN PROGRESS 12 | -------------------------------------------------------------------------------- /Special_functions.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * special_functions - intercept keyboard commands before they get sent 3 | * 4 | * Used to: 5 | * 6 | * 1) reconfigure the keyboard and clear any stuck modifiers 7 | * 2) Reset BLE on Ctrl-Shift-Esc 8 | * 3) Send media key commands 9 | * 10 | * Could be modified to do whatever you would like... 11 | * 12 | * Possibly convert the keypad into a T9 keyboard 13 | * 14 | * Return a 1 to send the key and a 0 to block it from being sent 15 | */ 16 | 17 | bool special_functions(uint8_t hidKey, bool brk) { 18 | 19 | //reset modifiers - just to clean up every now and then 20 | if (hidKey == HID_ENTER) { 21 | clear_modifiers(); 22 | } 23 | 24 | //reconfigure keyboard 25 | if (hidKey == HID_ESC && is_control_shift()) { 26 | if (brk) { 27 | reconfigure(); 28 | } 29 | return 0; 30 | } 31 | 32 | //switch bluetooth to USB or back 33 | if (hidKey == HID_ESC && is_control()) { 34 | if (brk) { 35 | switch_mode(); 36 | } 37 | return 0; 38 | } 39 | 40 | //remap keypad to work as T9 keyboard... 41 | 42 | return 1; 43 | 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /TEST.ino: -------------------------------------------------------------------------------- 1 | 2 | #if defined (TEST_SERIAL_INPUT) || defined (TEST_HELLO_WORLD) 3 | 4 | /** 5 | * Test functions that permit typing ASCII into the serial monitor and have it converted to PS2 keycodes and 6 | * injected into the buffer as if a PS2 keyboard was connected to the bluefruit. 7 | * 8 | * This is for offline working when a suitable keyboard is not connected to the bluefruit LE micro 9 | */ 10 | uint8_t ASCII_to_PS2_keymap[255]; 11 | uint8_t ASCII_to_modifier_keymap[255]; 12 | 13 | static char inputBuffer[TEST_BUFFER_SIZE]; 14 | static uint8_t count = 0; 15 | 16 | uint32_t startup_ms = 0; 17 | 18 | /** 19 | * Reads ascii input from the serial comms and adds it as PS key codes to the PS2 buffer 20 | */ 21 | void test_serial_input() { 22 | 23 | get_test_input(inputBuffer, TEST_BUFFER_SIZE); 24 | if (count > 0) { 25 | 26 | process_test_input(); 27 | count = 0; 28 | } 29 | } 30 | 31 | /** 32 | * Adds a ascii input string as a sequence of PS2 keycodes to the buffer 33 | */ 34 | void test_input(String input) { 35 | 36 | input.toCharArray(inputBuffer, TEST_BUFFER_SIZE); 37 | count = input.length(); 38 | process_test_input(); 39 | } 40 | 41 | /** 42 | * Handles the LED message sent back to the keyboard 43 | */ 44 | void test_ps2_msg(uint8_t ps2Msg) { 45 | if (ps2Msg == PS2_SET_RESET_LEDS) { 46 | add_to_buffer(PS2_LED_ACK); 47 | } 48 | #if defined (DEBUG) 49 | debug_ps2_msg(ps2Msg); 50 | #endif 51 | } 52 | 53 | /** 54 | * Returns the amount fo free memory 55 | */ 56 | void free_mem () 57 | { 58 | extern int __heap_start, *__brkval; 59 | int v; 60 | int freeRam = (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 61 | 62 | #if defined (DEBUG) 63 | Serial.print(F("Free RAM: ")); 64 | Serial.print(freeRam); 65 | Serial.println(); 66 | #endif 67 | } 68 | 69 | /** 70 | * Processes some ascii characters from the input buffer and converts to 71 | * PS2 keycodes 72 | */ 73 | void process_test_input() { 74 | String result = inputBuffer; 75 | 76 | #if defined (DEBUG) 77 | Serial.print(F("Test input: (")); 78 | Serial.print(count); 79 | Serial.print(F(") ")); 80 | Serial.println(result); 81 | #endif 82 | 83 | 84 | if (result.equals("MEM")) { 85 | free_mem(); 86 | } else 87 | if (result.equals("PLAYPAUSE")) { 88 | add_to_buffer(PS2_EXTENDED); 89 | add_to_buffer(PS2_PLAY_PAUSE); 90 | add_to_buffer(PS2_EXTENDED); 91 | add_to_buffer(PS2_RELEASE); 92 | add_to_buffer(PS2_PLAY_PAUSE); 93 | } else if (result.equals("STOP")) { 94 | add_to_buffer(PS2_EXTENDED); 95 | add_to_buffer(PS2_STOP); 96 | add_to_buffer(PS2_EXTENDED); 97 | add_to_buffer(PS2_RELEASE); 98 | add_to_buffer(PS2_STOP); 99 | } else if (result.equals("NEXT")) { 100 | add_to_buffer(PS2_EXTENDED); 101 | add_to_buffer(PS2_NEXT_TRACK); 102 | add_to_buffer(PS2_EXTENDED); 103 | add_to_buffer(PS2_RELEASE); 104 | add_to_buffer(PS2_NEXT_TRACK); 105 | } else if (result.equals("PREV")) { 106 | add_to_buffer(PS2_EXTENDED); 107 | add_to_buffer(PS2_PREV_TRACK); 108 | add_to_buffer(PS2_EXTENDED); 109 | add_to_buffer(PS2_RELEASE); 110 | add_to_buffer(PS2_PREV_TRACK); 111 | } else if (result.equals("VOLUP")) { 112 | add_to_buffer(PS2_EXTENDED); 113 | add_to_buffer(PS2_VOL_UP); 114 | add_to_buffer(PS2_EXTENDED); 115 | add_to_buffer(PS2_RELEASE); 116 | add_to_buffer(PS2_VOL_UP); 117 | } else if (result.equals("VOLDOWN")) { 118 | add_to_buffer(PS2_EXTENDED); 119 | add_to_buffer(PS2_VOL_DWN); 120 | add_to_buffer(PS2_EXTENDED); 121 | add_to_buffer(PS2_RELEASE); 122 | add_to_buffer(PS2_VOL_DWN); 123 | } else if (result.equals("MUTE")) { 124 | add_to_buffer(PS2_EXTENDED); 125 | add_to_buffer(PS2_MUTE); 126 | add_to_buffer(PS2_EXTENDED); 127 | add_to_buffer(PS2_RELEASE); 128 | add_to_buffer(PS2_MUTE); 129 | } else if (result.equals("SWITCH")) { 130 | add_to_buffer(PS2_LEFT_CTRL); 131 | add_to_buffer(PS2_ESC); 132 | add_to_buffer(PS2_RELEASE); 133 | add_to_buffer(PS2_ESC); 134 | add_to_buffer(PS2_RELEASE); 135 | add_to_buffer(PS2_LEFT_CTRL); 136 | } else if (result.equals("RESET")) { 137 | add_to_buffer(PS2_LEFT_CTRL); 138 | add_to_buffer(PS2_LEFT_SHIFT); 139 | add_to_buffer(PS2_ESC); 140 | add_to_buffer(PS2_RELEASE); 141 | add_to_buffer(PS2_ESC); 142 | add_to_buffer(PS2_RELEASE); 143 | add_to_buffer(PS2_LEFT_SHIFT); 144 | add_to_buffer(PS2_RELEASE); 145 | add_to_buffer(PS2_LEFT_CTRL); 146 | } else { 147 | for (int i = 0; i < count; ++i) { 148 | uint8_t ps2Key = ASCII_to_PS2_keymap[inputBuffer[i]]; 149 | uint8_t modifier = ASCII_to_modifier_keymap[inputBuffer[i]]; 150 | 151 | if (modifier) { 152 | add_to_buffer(modifier); 153 | } 154 | if (ps2Key) { 155 | add_to_buffer(ps2Key); 156 | add_to_buffer(PS2_RELEASE); 157 | add_to_buffer(ps2Key); 158 | } 159 | if (modifier) { 160 | add_to_buffer(PS2_RELEASE); 161 | add_to_buffer(modifier); 162 | } 163 | } 164 | } 165 | } 166 | 167 | /** 168 | * Reads a sequence of ASCII character input over the serial interface 169 | * 170 | * This is useful for testing the program via the serial monitor when no PS2 keyboard is available. 171 | */ 172 | void get_test_input(char inputBuffer[], uint8_t maxSize) 173 | { 174 | // timeout in 100 milliseconds 175 | TimeoutTimer timeout(100); 176 | 177 | memset(inputBuffer, 0, maxSize); 178 | while ( (!Serial.available()) && !timeout.expired() ) { 179 | delay(1); 180 | } 181 | 182 | if ( timeout.expired() ) return; 183 | 184 | delay(2); 185 | count = 0; 186 | do 187 | { 188 | count += Serial.readBytes(inputBuffer + count, maxSize); 189 | delay(2); 190 | } while ( (count < maxSize) && (Serial.available()) ); 191 | } 192 | 193 | /** 194 | * Put this in the process loop and if 10 seconds has passed since startup "hello world" 195 | * PS2 input will be injected into the buffer. 196 | * 197 | * This is useful for testing detached from the serial cable when no PS2 keyboard is available. 198 | */ 199 | void test_hello_world() { 200 | if (startup_ms == 0) { 201 | startup_ms = millis(); 202 | } 203 | uint32_t now_ms = millis(); 204 | if ((now_ms - startup_ms) > 10000) { 205 | test_input("hello world "); 206 | startup_ms = now_ms; 207 | } 208 | } 209 | 210 | /** 211 | * Allows the red LED near to the USB port to be flashed. 212 | * 213 | * This was useful for diagnosing where the code had got to when debugging why 214 | * things were not working when detached from serial monitor. 215 | */ 216 | void blink(uint8_t count) { 217 | for (int i = 0; i < count; ++i) { 218 | digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) 219 | delay(1000); // wait for a second 220 | digitalWrite(13, LOW); // turn the LED off by making the voltage LOW 221 | delay(1000); // wait for a second 222 | } 223 | } 224 | 225 | 226 | /** 227 | * Sets up the keyboard mapping from PS2 to HID 228 | */ 229 | void setup_test_keymaps() { 230 | ASCII_to_PS2_keymap['a'] = PS2_A; 231 | ASCII_to_PS2_keymap['b'] = PS2_B; 232 | ASCII_to_PS2_keymap['c'] = PS2_C; 233 | ASCII_to_PS2_keymap['d'] = PS2_D; 234 | ASCII_to_PS2_keymap['e'] = PS2_E; 235 | ASCII_to_PS2_keymap['f'] = PS2_F; 236 | ASCII_to_PS2_keymap['g'] = PS2_G; 237 | ASCII_to_PS2_keymap['h'] = PS2_H; 238 | ASCII_to_PS2_keymap['i'] = PS2_I; 239 | ASCII_to_PS2_keymap['j'] = PS2_J; 240 | ASCII_to_PS2_keymap['k'] = PS2_K; 241 | ASCII_to_PS2_keymap['l'] = PS2_L; 242 | ASCII_to_PS2_keymap['m'] = PS2_M; 243 | ASCII_to_PS2_keymap['n'] = PS2_N; 244 | ASCII_to_PS2_keymap['o'] = PS2_O; 245 | ASCII_to_PS2_keymap['p'] = PS2_P; 246 | ASCII_to_PS2_keymap['q'] = PS2_Q; 247 | ASCII_to_PS2_keymap['r'] = PS2_R; 248 | ASCII_to_PS2_keymap['s'] = PS2_S; 249 | ASCII_to_PS2_keymap['t'] = PS2_T; 250 | ASCII_to_PS2_keymap['u'] = PS2_U; 251 | ASCII_to_PS2_keymap['v'] = PS2_V; 252 | ASCII_to_PS2_keymap['w'] = PS2_W; 253 | ASCII_to_PS2_keymap['x'] = PS2_X; 254 | ASCII_to_PS2_keymap['y'] = PS2_Y; 255 | ASCII_to_PS2_keymap['z'] = PS2_Z; 256 | 257 | ASCII_to_PS2_keymap['A'] = PS2_A; 258 | ASCII_to_PS2_keymap['B'] = PS2_B; 259 | ASCII_to_PS2_keymap['C'] = PS2_C; 260 | ASCII_to_PS2_keymap['D'] = PS2_D; 261 | ASCII_to_PS2_keymap['E'] = PS2_E; 262 | ASCII_to_PS2_keymap['F'] = PS2_F; 263 | ASCII_to_PS2_keymap['G'] = PS2_G; 264 | ASCII_to_PS2_keymap['H'] = PS2_H; 265 | ASCII_to_PS2_keymap['I'] = PS2_I; 266 | ASCII_to_PS2_keymap['J'] = PS2_J; 267 | ASCII_to_PS2_keymap['K'] = PS2_K; 268 | ASCII_to_PS2_keymap['L'] = PS2_L; 269 | ASCII_to_PS2_keymap['M'] = PS2_M; 270 | ASCII_to_PS2_keymap['N'] = PS2_N; 271 | ASCII_to_PS2_keymap['O'] = PS2_O; 272 | ASCII_to_PS2_keymap['P'] = PS2_P; 273 | ASCII_to_PS2_keymap['Q'] = PS2_Q; 274 | ASCII_to_PS2_keymap['R'] = PS2_R; 275 | ASCII_to_PS2_keymap['S'] = PS2_S; 276 | ASCII_to_PS2_keymap['T'] = PS2_T; 277 | ASCII_to_PS2_keymap['U'] = PS2_U; 278 | ASCII_to_PS2_keymap['V'] = PS2_V; 279 | ASCII_to_PS2_keymap['W'] = PS2_W; 280 | ASCII_to_PS2_keymap['X'] = PS2_X; 281 | ASCII_to_PS2_keymap['Y'] = PS2_Y; 282 | ASCII_to_PS2_keymap['Z'] = PS2_Z; 283 | 284 | ASCII_to_modifier_keymap['A'] = PS2_LEFT_SHIFT; 285 | ASCII_to_modifier_keymap['B'] = PS2_LEFT_SHIFT; 286 | ASCII_to_modifier_keymap['C'] = PS2_LEFT_SHIFT; 287 | ASCII_to_modifier_keymap['D'] = PS2_LEFT_SHIFT; 288 | ASCII_to_modifier_keymap['E'] = PS2_LEFT_SHIFT; 289 | ASCII_to_modifier_keymap['F'] = PS2_LEFT_SHIFT; 290 | ASCII_to_modifier_keymap['G'] = PS2_LEFT_SHIFT; 291 | ASCII_to_modifier_keymap['H'] = PS2_LEFT_SHIFT; 292 | ASCII_to_modifier_keymap['I'] = PS2_LEFT_SHIFT; 293 | ASCII_to_modifier_keymap['J'] = PS2_LEFT_SHIFT; 294 | ASCII_to_modifier_keymap['K'] = PS2_LEFT_SHIFT; 295 | ASCII_to_modifier_keymap['L'] = PS2_LEFT_SHIFT; 296 | ASCII_to_modifier_keymap['M'] = PS2_LEFT_SHIFT; 297 | ASCII_to_modifier_keymap['N'] = PS2_LEFT_SHIFT; 298 | ASCII_to_modifier_keymap['O'] = PS2_LEFT_SHIFT; 299 | ASCII_to_modifier_keymap['P'] = PS2_LEFT_SHIFT; 300 | ASCII_to_modifier_keymap['Q'] = PS2_LEFT_SHIFT; 301 | ASCII_to_modifier_keymap['R'] = PS2_LEFT_SHIFT; 302 | ASCII_to_modifier_keymap['S'] = PS2_LEFT_SHIFT; 303 | ASCII_to_modifier_keymap['T'] = PS2_LEFT_SHIFT; 304 | ASCII_to_modifier_keymap['U'] = PS2_LEFT_SHIFT; 305 | ASCII_to_modifier_keymap['V'] = PS2_LEFT_SHIFT; 306 | ASCII_to_modifier_keymap['W'] = PS2_LEFT_SHIFT; 307 | ASCII_to_modifier_keymap['X'] = PS2_LEFT_SHIFT; 308 | ASCII_to_modifier_keymap['Y'] = PS2_LEFT_SHIFT; 309 | ASCII_to_modifier_keymap['Z'] = PS2_LEFT_SHIFT; 310 | 311 | ASCII_to_PS2_keymap['0'] = PS2_0; 312 | ASCII_to_PS2_keymap['1'] = PS2_1; 313 | ASCII_to_PS2_keymap['2'] = PS2_2; 314 | ASCII_to_PS2_keymap['3'] = PS2_3; 315 | ASCII_to_PS2_keymap['4'] = PS2_4; 316 | ASCII_to_PS2_keymap['5'] = PS2_5; 317 | ASCII_to_PS2_keymap['6'] = PS2_6; 318 | ASCII_to_PS2_keymap['7'] = PS2_7; 319 | ASCII_to_PS2_keymap['8'] = PS2_8; 320 | ASCII_to_PS2_keymap['9'] = PS2_9; 321 | 322 | ASCII_to_PS2_keymap[')'] = PS2_0; 323 | ASCII_to_PS2_keymap['!'] = PS2_1; 324 | ASCII_to_PS2_keymap['"'] = PS2_2; 325 | ASCII_to_PS2_keymap['£'] = PS2_3; 326 | ASCII_to_PS2_keymap['$'] = PS2_4; 327 | ASCII_to_PS2_keymap['%'] = PS2_5; 328 | ASCII_to_PS2_keymap['^'] = PS2_6; 329 | ASCII_to_PS2_keymap['&'] = PS2_7; 330 | ASCII_to_PS2_keymap['*'] = PS2_8; 331 | ASCII_to_PS2_keymap['('] = PS2_9; 332 | 333 | ASCII_to_modifier_keymap[')'] = PS2_LEFT_SHIFT; 334 | ASCII_to_modifier_keymap['!'] = PS2_LEFT_SHIFT; 335 | ASCII_to_modifier_keymap['"'] = PS2_LEFT_SHIFT; 336 | ASCII_to_modifier_keymap['£'] = PS2_LEFT_SHIFT; 337 | ASCII_to_modifier_keymap['$'] = PS2_LEFT_SHIFT; 338 | ASCII_to_modifier_keymap['%'] = PS2_LEFT_SHIFT; 339 | ASCII_to_modifier_keymap['^'] = PS2_LEFT_SHIFT; 340 | ASCII_to_modifier_keymap['&'] = PS2_LEFT_SHIFT; 341 | ASCII_to_modifier_keymap['*'] = PS2_LEFT_SHIFT; 342 | ASCII_to_modifier_keymap['('] = PS2_LEFT_SHIFT; 343 | 344 | ASCII_to_PS2_keymap['`'] = PS2_ACCENT; 345 | ASCII_to_PS2_keymap['-'] = PS2_HYPH; 346 | ASCII_to_PS2_keymap['='] = PS2_EQUAL; 347 | 348 | ASCII_to_PS2_keymap[';'] = PS2_SEMI_COLON; 349 | ASCII_to_PS2_keymap['\''] = PS2_APOSTROPHY; 350 | ASCII_to_PS2_keymap['#'] = 0; // PS2_HASH; 351 | 352 | ASCII_to_PS2_keymap['\\'] = PS2_BACK_SLASH_NON_US; 353 | 354 | ASCII_to_PS2_keymap[','] = PS2_COMMA; 355 | ASCII_to_PS2_keymap['.'] = PS2_PERIOD; 356 | ASCII_to_PS2_keymap['/'] = PS2_FWD_SLASH; 357 | 358 | ASCII_to_PS2_keymap['¬'] = PS2_ACCENT; 359 | ASCII_to_PS2_keymap['_'] = PS2_HYPH; 360 | ASCII_to_PS2_keymap['+'] = PS2_EQUAL; 361 | 362 | ASCII_to_PS2_keymap[':'] = PS2_SEMI_COLON; 363 | ASCII_to_PS2_keymap['@'] = PS2_APOSTROPHY; 364 | ASCII_to_PS2_keymap['~'] = 0; // PS2_HASH; 365 | 366 | ASCII_to_PS2_keymap['|'] = PS2_BACK_SLASH_NON_US; 367 | 368 | ASCII_to_PS2_keymap['<'] = PS2_COMMA; 369 | ASCII_to_PS2_keymap['>'] = PS2_PERIOD; 370 | ASCII_to_PS2_keymap['?'] = PS2_FWD_SLASH; 371 | 372 | ASCII_to_modifier_keymap['¬'] = PS2_LEFT_SHIFT; 373 | ASCII_to_modifier_keymap['_'] = PS2_LEFT_SHIFT; 374 | ASCII_to_modifier_keymap['+'] = PS2_LEFT_SHIFT; 375 | 376 | ASCII_to_modifier_keymap[':'] = PS2_LEFT_SHIFT; 377 | ASCII_to_modifier_keymap['@'] = PS2_LEFT_SHIFT; 378 | ASCII_to_modifier_keymap['~'] = 0; // PS2_HASH; 379 | 380 | ASCII_to_modifier_keymap['|'] = PS2_LEFT_SHIFT; 381 | 382 | ASCII_to_modifier_keymap['<'] = PS2_LEFT_SHIFT; 383 | ASCII_to_modifier_keymap['>'] = PS2_LEFT_SHIFT; 384 | ASCII_to_modifier_keymap['?'] = PS2_LEFT_SHIFT; 385 | 386 | ASCII_to_PS2_keymap[' '] = PS2_SPACE; 387 | } 388 | 389 | #endif 390 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /USB.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Functions concerned with wired mode of the keyboard 3 | */ 4 | 5 | /** 6 | * Starts USB 7 | */ 8 | void start_USB() { 9 | Keyboard.begin(); 10 | Remote.begin(); 11 | } 12 | 13 | /** 14 | * Stops USB 15 | */ 16 | void stop_USB() { 17 | Keyboard.end(); 18 | Remote.end(); 19 | } 20 | 21 | /** 22 | * Stops USB 23 | */ 24 | void reconfigure_USB() { 25 | // Nothing to do here at the moment 26 | } 27 | 28 | /** 29 | * Sends the key report over USB 30 | */ 31 | void send_usb_report(KeyReport report) { 32 | log_key_report(keyReport); 33 | Keyboard.sendReport(&keyReport); 34 | } 35 | 36 | /** 37 | * Sends a media control key (rather than the HID key code) 38 | */ 39 | void send_usb_media(uint8_t hidKey) { 40 | switch (hidKey) { 41 | case (HID_PLAY_PAUSE): 42 | #if defined (DEBUG) 43 | Serial.println(F("Remote->PlayPause")); 44 | #endif 45 | Remote.playpause(); 46 | Remote.clear(); 47 | break; 48 | case (HID_STOP): 49 | #if defined (DEBUG) 50 | Serial.println(F("Remote->Stop")); 51 | #endif 52 | Remote.stop(); 53 | Remote.clear(); 54 | break; 55 | case (HID_NEXT_TRACK): 56 | #if defined (DEBUG) 57 | Serial.println(F("Remote->Next")); 58 | #endif 59 | Remote.next(); 60 | Remote.clear(); 61 | break; 62 | case (HID_PREV_TRACK): 63 | #if defined (DEBUG) 64 | Serial.println(F("Remote->Prev")); 65 | #endif 66 | Remote.previous(); 67 | Remote.clear(); 68 | break; 69 | case (HID_VOL_UP): 70 | #if defined (DEBUG) 71 | Serial.println(F("Remote->VolUp")); 72 | #endif 73 | Remote.increase(); 74 | Remote.clear(); 75 | break; 76 | case (HID_VOL_DWN): 77 | #if defined (DEBUG) 78 | Serial.println(F("Remote->VolDwn")); 79 | #endif 80 | Remote.decrease(); 81 | Remote.clear(); 82 | break; 83 | case (HID_MUTE): 84 | #if defined (DEBUG) 85 | Serial.println(F("Remote->Mute")); 86 | #endif 87 | Remote.mute(); 88 | Remote.clear(); 89 | break; 90 | default: 91 | return; 92 | } 93 | } 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /USBAPI.h_1.6.5_modified: -------------------------------------------------------------------------------- 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 | // Low level key report: up to 6 keys and shift, ctrl etc at once 168 | typedef struct 169 | { 170 | uint8_t modifiers; 171 | uint8_t reserved; 172 | uint8_t keys[6]; 173 | } KeyReport; 174 | 175 | class Keyboard_ : public Print 176 | { 177 | private: 178 | KeyReport _keyReport; 179 | public: 180 | void sendReport(KeyReport* keys); 181 | Keyboard_(void); 182 | void begin(void); 183 | void end(void); 184 | virtual size_t write(uint8_t k); 185 | virtual size_t press(uint8_t k); 186 | virtual size_t release(uint8_t k); 187 | virtual void releaseAll(void); 188 | }; 189 | extern Keyboard_ Keyboard; 190 | 191 | //================================================================================ 192 | //================================================================================ 193 | // Remote 194 | 195 | #define REMOTE_CLEAR 0 196 | #define VOLUME_UP 1 197 | #define VOLUME_DOWN 2 198 | #define VOLUME_MUTE 4 199 | #define REMOTE_PLAY 8 200 | #define REMOTE_PAUSE 16 201 | #define REMOTE_STOP 32 202 | #define REMOTE_NEXT 64 203 | #define REMOTE_PREVIOUS 128 204 | #define REMOTE_FAST_FORWARD 256 205 | #define REMOTE_REWIND 512 206 | #define REMOTE_PLAY_PAUSE 1024 207 | 208 | class Remote_ 209 | { 210 | private: 211 | public: 212 | Remote_(void); 213 | void begin(void); 214 | void end(void); 215 | 216 | // Volume 217 | void increase(void); 218 | void decrease(void); 219 | void mute(void); 220 | 221 | // Playback 222 | void playpause(void); 223 | void play(void); 224 | void pause(void); 225 | void stop(void); 226 | 227 | // Track Controls 228 | void next(void); 229 | void previous(void); 230 | void forward(void); 231 | void rewind(void); 232 | 233 | // Send an empty report to prevent repeated actions 234 | void clear(void); 235 | }; 236 | extern Remote_ Remote; 237 | 238 | //================================================================================ 239 | //================================================================================ 240 | // Low level API 241 | 242 | typedef struct 243 | { 244 | uint8_t bmRequestType; 245 | uint8_t bRequest; 246 | uint8_t wValueL; 247 | uint8_t wValueH; 248 | uint16_t wIndex; 249 | uint16_t wLength; 250 | } Setup; 251 | 252 | //================================================================================ 253 | //================================================================================ 254 | // HID 'Driver' 255 | 256 | int HID_GetInterface(uint8_t* interfaceNum); 257 | int HID_GetDescriptor(int i); 258 | bool HID_Setup(Setup& setup); 259 | void HID_SendReport(uint8_t id, const void* data, int len); 260 | 261 | //================================================================================ 262 | //================================================================================ 263 | // MSC 'Driver' 264 | 265 | int MSC_GetInterface(uint8_t* interfaceNum); 266 | int MSC_GetDescriptor(int i); 267 | bool MSC_Setup(Setup& setup); 268 | bool MSC_Data(uint8_t rx,uint8_t tx); 269 | 270 | //================================================================================ 271 | //================================================================================ 272 | // CSC 'Driver' 273 | 274 | int CDC_GetInterface(uint8_t* interfaceNum); 275 | int CDC_GetDescriptor(int i); 276 | bool CDC_Setup(Setup& setup); 277 | 278 | //================================================================================ 279 | //================================================================================ 280 | 281 | #define TRANSFER_PGM 0x80 282 | #define TRANSFER_RELEASE 0x40 283 | #define TRANSFER_ZERO 0x20 284 | 285 | int USB_SendControl(uint8_t flags, const void* d, int len); 286 | int USB_RecvControl(void* d, int len); 287 | 288 | uint8_t USB_Available(uint8_t ep); 289 | int USB_Send(uint8_t ep, const void* data, int len); // blocking 290 | int USB_Recv(uint8_t ep, void* data, int len); // non-blocking 291 | int USB_Recv(uint8_t ep); // non-blocking 292 | void USB_Flush(uint8_t ep); 293 | 294 | #endif 295 | 296 | #endif /* if defined(USBCON) */ 297 | -------------------------------------------------------------------------------- /define.h: -------------------------------------------------------------------------------- 1 | 2 | // Uncomment to allow debug output on serial port 3 | //#define DEBUG 1 4 | 5 | // Uncomment to permit entering strings into serial input and have them played in as if a PS2 keyboard was connected 6 | //#define TEST_SERIAL_INPUT 1 7 | 8 | // Uncomment to periodically play "hello world" in as if PS2 keyboard was connected 9 | //#define TEST_HELLO_WORLD 1 10 | 11 | /** 12 | * Size of buffer for key strokes - much more than 200 it stops working 13 | */ 14 | #define BUFFER_SIZE 200 15 | 16 | /** 17 | * Size of buffer for test key strokes 18 | */ 19 | #define TEST_BUFFER_SIZE 200 20 | 21 | /* 22 | * pins to use for PS2 keyboard 23 | */ 24 | #define CLK_PIN 2 25 | #define DATA_PIN 3 26 | 27 | /** 28 | * HID key codes 29 | */ 30 | 31 | #define HID_NOEVENT 0x00 //Reserved (no event indicated) 32 | #define HID_ERR_RLL_OVER 0x01 //Keyboard ErrorRollOver 33 | #define HID_POST_FAIL 0x02 //Keyboard POSTFail 34 | #define HID_ERR_UNDEF 0x03 //Keyboard ErrorUndefined 35 | #define HID_A 0x04 //Keyboard a and A 36 | #define HID_B 0x05 //Keyboard b and B 37 | #define HID_C 0x06 //Keyboard c and C 38 | #define HID_D 0x07 //Keyboard d and D 39 | #define HID_E 0x08 //Keyboard e and E 40 | #define HID_F 0x09 //Keyboard f and F 41 | #define HID_G 0x0A //Keyboard g and G 42 | #define HID_H 0x0B //Keyboard h and H 43 | #define HID_I 0x0C //Keyboard i and I 44 | #define HID_J 0x0D //Keyboard j and J 45 | #define HID_K 0x0E //Keyboard k and K 46 | #define HID_L 0x0F //Keyboard l and L 47 | #define HID_M 0x10 //Keyboard m and M 48 | #define HID_N 0x11 //Keyboard n and N 49 | #define HID_O 0x12 //Keyboard o and O 50 | #define HID_P 0x13 //Keyboard p and P 51 | #define HID_Q 0x14 //Keyboard q and Q 52 | #define HID_R 0x15 //Keyboard r and R 53 | #define HID_S 0x16 //Keyboard s and S 54 | #define HID_T 0x17 //Keyboard t and T 55 | #define HID_U 0x18 //Keyboard u and U 56 | #define HID_V 0x19 //Keyboard v and V 57 | #define HID_W 0x1A //Keyboard w and W 58 | #define HID_X 0x1B //Keyboard x and X 59 | #define HID_Y 0x1C //Keyboard y and Y 60 | #define HID_Z 0x1D //Keyboard z and Z 61 | #define HID_1 0x1E //Keyboard 1 and ! 62 | #define HID_2 0x1F //Keyboard 2 and @ 63 | #define HID_3 0x20 //Keyboard 3 and # 64 | #define HID_4 0x21 //Keyboard 4 and $ 65 | #define HID_5 0x22 //Keyboard 5 and % 66 | #define HID_6 0x23 //Keyboard 6 and ^ 67 | #define HID_7 0x24 //Keyboard 7 and & 68 | #define HID_8 0x25 //Keyboard 8 and * 69 | #define HID_9 0x26 //Keyboard 9 and ( 70 | #define HID_0 0x27 //Keyboard 0 and ) 71 | #define HID_ENTER 0x28 //Keyboard Return (ENTER) 72 | #define HID_ESC 0x29 //Keyboard ESCAPE 73 | #define HID_BACK_SPACE 0x2A //Keyboard DELETE (Backspace) 74 | #define HID_TAB 0x2B //Keyboard Tab 75 | #define HID_SPACE 0x2C //Keyboard Spacebar 76 | #define HID_HYPH 0x2D //Keyboard - and (underscore) 77 | #define HID_EQUAL 0x2E //Keyboard = and + 78 | #define HID_LEFT_BRACKET 0x2F //Keyboard [ and { 79 | #define HID_RIGHT_BRACKET 0x30 //Keyboard ] and } 80 | #define HID_BACK_SLASH 0x31 //Keyboard \ and | 81 | #define HID_POUND 0x32 //Keyboard Non-US # and ~ 82 | #define HID_SEMI_COLON 0x33 //Keyboard ; and : 83 | #define HID_APOSTROPHY 0x34 //Keyboard ' and " 84 | #define HID_ACCENT 0x35 //Keyboard Grave Accent and Tilde 85 | #define HID_COMMA 0x36 //Keyboard, and < 86 | #define HID_PERIOD 0x37 //Keyboard . and > 87 | #define HID_FWD_SLASH 0x38 //Keyboard / and ? 88 | #define HID_CAPS 0x39 //Keyboard Caps Lock 89 | #define HID_F1 0x3A //Keyboard F1 90 | #define HID_F2 0x3B //Keyboard F2 91 | #define HID_F3 0x3C //Keyboard F3 92 | #define HID_F4 0x3D //Keyboard F4 93 | #define HID_F5 0x3E //Keyboard F5 94 | #define HID_F6 0x3F //Keyboard F6 95 | #define HID_F7 0x40 //Keyboard F7 96 | #define HID_F8 0x41 //Keyboard F8 97 | #define HID_F9 0x42 //Keyboard F9 98 | #define HID_F10 0x43 //Keyboard F10 99 | #define HID_F11 0x44 //Keyboard F11 100 | #define HID_F12 0x45 //Keyboard F12 101 | #define HID_PRNT_SCR 0x46 //Keyboard PrintScreen 102 | #define HID_SCR_LCK 0x47 //Keyboard Scroll Lock 103 | #define HID_PAUSE 0x48 //Keyboard Pause 104 | #define HID_INSERT 0x49 //Keyboard Insert 105 | #define HID_HOME 0x4A //Keyboard Home 106 | #define HID_PG_UP 0x4B //Keyboard PageUp 107 | #define HID_DEL 0x4C //Keyboard Delete Forward 108 | #define HID_END 0x4D //Keyboard End 109 | #define HID_PG_DWN 0x4E //Keyboard PageDown 110 | #define HID_RIGHT_ARROW 0x4F //Keyboard RightArrow 111 | #define HID_LEFT_ARROW 0x50 //Keyboard LeftArrow 112 | #define HID_DOWN_ARROW 0x51 //Keyboard DownArrow 113 | #define HID_UP_ARROW 0x52 //Keyboard UpArrow 114 | #define HID_NUM_LCK 0x53 //Keypad Num Lock and Clear 115 | #define HID_KP_FWD_SLASH 0x54 //Keypad / 116 | #define HID_KP_STAR 0x55 //Keypad * 117 | #define HID_KP_HYPH 0x56 //Keypad - 118 | #define HID_KP_PLUS 0x57 //Keypad + 119 | #define HID_KP_ENTER 0x58 //Keypad ENTER 120 | #define HID_KP_1 0x59 //Keypad 1 and End 121 | #define HID_KP_2 0x5A //Keypad 2 and Down Arrow 122 | #define HID_KP_3 0x5B //Keypad 3 and PageDn 123 | #define HID_KP_4 0x5C //Keypad 4 and Left Arrow 124 | #define HID_KP_5 0x5D //Keypad 5 125 | #define HID_KP_6 0x5E //Keypad 6 and Right Arrow 126 | #define HID_KP_7 0x5F //Keypad 7 and Home 127 | #define HID_KP_8 0x60 //Keypad 8 and Up Arrow 128 | #define HID_KP_9 0x61 //Keypad 9 and PageUp 129 | #define HID_KP_0 0x62 //Keypad 0 and Insert 130 | #define HID_KP_PERIOD 0x63 //Keypad . and Delete 131 | #define HID_BACK_SLASH_NON_US 0x64 //Keyboard Non-US \ and | 132 | #define HID_APPLICATION 0x65 //Keyboard Application 133 | #define HID_POWER 0x66 //Keyboard Power 134 | #define HID_KP_EQUAL 0x67 //Keypad = 135 | #define HID_F13 0x68 //Keyboard F13 136 | #define HID_F14 0x69 //Keyboard F14 137 | #define HID_F15 0x6A //Keyboard F15 138 | #define HID_F16 0x6B //Keyboard F16 139 | #define HID_F17 0x6C //Keyboard F17 140 | #define HID_F18 0x6D //Keyboard F18 141 | #define HID_F19 0x6E //Keyboard F19 142 | #define HID_F20 0x6F //Keyboard F20 143 | #define HID_F21 0x70 //Keyboard F21 144 | #define HID_F22 0x71 //Keyboard F22 145 | #define HID_F23 0x72 //Keyboard F23 146 | #define HID_F24 0x73 //Keyboard F24 147 | #define HID_EXECUTE 0x74 //Keyboard Execute 148 | #define HID_HELP 0x75 //Keyboard Help 149 | #define HID_MENU 0x76 //Keyboard Menu 150 | #define HID_SELECT 0x77 //Keyboard Select 151 | #define HID_STOP 0x78 //Keyboard Stop 152 | #define HID_AGAIN 0x79 //Keyboard Again 153 | #define HID_UNDO 0x7A //Keyboard Undo 154 | #define HID_CUT 0x7B //Keyboard Cut 155 | #define HID_COPY 0x7C //Keyboard Copy 156 | #define HID_PASTE 0x7D //Keyboard Paste 157 | #define HID_FIND 0x7E //Keyboard Find 158 | #define HID_MUTE 0x7F //Keyboard Mute 159 | #define HID_VOL_UP 0x80 //Keyboard Volume Up 160 | #define HID_VOL_DWN 0x81 //Keyboard Volume Down 161 | #define HID_LCKING_CAPS 0x82 //Keyboard Locking Caps Lock 162 | #define HID_LCKING_NUM 0x83 //Keyboard Locking Num Lock 163 | #define HID_LCKING_SCR 0x84 //Keyboard Locking Scroll Lock 164 | #define HID_KP_COMMA 0x85 //Keypad Comma 165 | #define HID_KP_EQUAL_SIGN 0x86 //Keypad Equal Sign 166 | #define HID_INTR_1 0x87 //Keyboard International1 167 | #define HID_INTR_2 0x88 //Keyboard International2 168 | #define HID_INTR_3 0x89 //Keyboard International3 169 | #define HID_INTR_4 0x8A //Keyboard International4 170 | #define HID_INTR_5 0x8B //Keyboard International5 171 | #define HID_INTR_6 0x8C //Keyboard International6 172 | #define HID_INTR_7 0x8D //Keyboard International7 173 | #define HID_INTR_8 0x8E //Keyboard International8 174 | #define HID_INTR_9 0x8F //Keyboard International9 175 | #define HID_LANG_1 0x90 //Keyboard LANG1 176 | #define HID_LANG_2 0x91 //Keyboard LANG2 177 | #define HID_LANG_3 0x92 //Keyboard LANG3 178 | #define HID_LANG_4 0x93 //Keyboard LANG4 179 | #define HID_LANG_5 0x94 //Keyboard LANG5 180 | #define HID_LANG_6 0x95 //Keyboard LANG6 181 | #define HID_LANG_7 0x96 //Keyboard LANG7 182 | #define HID_LANG_8 0x97 //Keyboard LANG8 183 | #define HID_LANG_9 0x98 //Keyboard LANG9 184 | #define HID_ALT_ERASE 0x99 //Keyboard Alternate Erase 185 | #define HID_SYS_REQ 0x9A //Keyboard SysReq/Attention 186 | #define HID_CANCEL 0x9B //Keyboard Cancel 187 | #define HID_CLEAR 0x9C //Keyboard Clear 188 | #define HID_PRIOR 0x9D //Keyboard Prior 189 | #define HID_RETURN 0x9E //Keyboard Return 190 | #define HID_SEPERATOR 0x9F //Keyboard Separator 191 | #define HID_OUT 0xA0 //Keyboard Out 192 | #define HID_OPER 0xA1 //Keyboard Oper 193 | #define HID_CLEAR_AGAIN 0xA2 //Keyboard Clear/Again 194 | #define HID_CR_SEL 0xA3 //Keyboard CrSel/Props 195 | #define HID_ EX_SEL 0xA4 //Keyboard ExSel 196 | #define HID_NEXT_TRACK 0xB5 //Keyboard Next Track 197 | #define HID_PREV_TRACK 0xB6 //Keyboard Previous Track 198 | #define HID_PLAY_PAUSE 0xCD //Keyboard Play Pause 199 | #define HID_LEFT_CTRL 0xE0 //Keyboard LeftControl 200 | #define HID_LEFT_SHIFT 0xE1 //Keyboard LeftShift 201 | #define HID_LEFT_ALT 0xE2 //Keyboard LeftAlt 202 | #define HID_LEFT_GUI 0xE3 //Keyboard Left GUI 203 | #define HID_RIGHT_CTRL 0xE4 //Keyboard RightControl 204 | #define HID_RIGHT_SHIFT 0xE5 //Keyboard RightShift 205 | #define HID_RIGHT_ALT 0xE6 //Keyboard RightAlt 206 | #define HID_RIGHT_GUI 0xE7 //Keyboard Right GUI 207 | 208 | 209 | /** 210 | * PS2 key codes 211 | */ 212 | 213 | #define PS2_A 0x1C 214 | #define PS2_B 0x32 215 | #define PS2_C 0x21 216 | #define PS2_D 0x23 217 | #define PS2_E 0x24 218 | #define PS2_F 0x2B 219 | #define PS2_G 0x34 220 | #define PS2_H 0x33 221 | #define PS2_I 0x43 222 | #define PS2_J 0x3B 223 | #define PS2_K 0x42 224 | #define PS2_L 0x4B 225 | #define PS2_M 0x3A 226 | #define PS2_N 0x31 227 | #define PS2_O 0x44 228 | #define PS2_P 0x4D 229 | #define PS2_Q 0x15 230 | #define PS2_R 0x2D 231 | #define PS2_S 0x1B 232 | #define PS2_T 0x2C 233 | #define PS2_U 0x3C 234 | #define PS2_V 0x2A 235 | #define PS2_W 0x1D 236 | #define PS2_X 0x22 237 | #define PS2_Y 0x35 238 | #define PS2_Z 0x1A 239 | #define PS2_0 0x45 240 | #define PS2_1 0x16 241 | #define PS2_2 0x1E 242 | #define PS2_3 0x26 243 | #define PS2_4 0x25 244 | #define PS2_5 0x2E 245 | #define PS2_6 0x36 246 | #define PS2_7 0x3D 247 | #define PS2_8 0x3E 248 | #define PS2_9 0x46 249 | #define PS2_ACCENT 0x0E 250 | #define PS2_HYPH 0x4E 251 | #define PS2_EQUAL 0x55 252 | #define PS2_BACK_SLASH 0x5D 253 | #define PS2_BACK_SLASH_NON_US 0x61 254 | #define PS2_BACK_SPACE 0x66 255 | #define PS2_SPACE 0x29 256 | #define PS2_TAB 0x0D 257 | #define PS2_CAPS 0x58 258 | #define PS2_LEFT_SHIFT 0x12 259 | #define PS2_LEFT_CTRL 0x14 260 | #define PS2_LEFT_GUI 0x1F // 0xE01F 261 | #define PS2_LEFT_ALT 0x11 262 | #define PS2_RIGHT_SHIFT 0x59 263 | #define PS2_RIGHT_CTRL 0x14 // 0xE014 264 | #define PS2_RIGHT_GUI 0x27 // 0xE027 265 | #define PS2_RIGHT_ALT 0x11 // 0xE011 266 | #define PS2_APPLICATION 0x2F // 0xE02F 267 | #define PS2_ENTER 0x5A 268 | #define PS2_ESC 0x76 269 | #define PS2_F1 0x05 270 | #define PS2_F2 0x06 271 | #define PS2_F3 0x04 272 | #define PS2_F4 0x0C 273 | #define PS2_F5 0x03 274 | #define PS2_F6 0x0B 275 | #define PS2_F7 0x83 276 | #define PS2_F8 0x0A 277 | #define PS2_F9 0x01 278 | #define PS2_F10 0x09 279 | #define PS2_F11 0x78 280 | #define PS2_F12 0x07 281 | #define PS2_PRNT_SCR 0x12 // 0xE012E07C 282 | #define PS2_SCROLL 0x7E 283 | #define PS2_LEFT_BRACKET 0x54 284 | #define PS2_INSERT 0x70 // 0xE070 285 | #define PS2_HOME 0x6C // 0xE06C 286 | #define PS2_PG_UP 0x7D // 0xE07D 287 | #define PS2_DELETE 0x71 // 0xE071 288 | #define PS2_END 0x69 // 0xE069 289 | #define PS2_PG_DWN 0x7A // 0xE07A 290 | #define PS2_UP_ARROW 0x75 // 0xE075 291 | #define PS2_LEFT_ARROW 0x6B // 0xE06B 292 | #define PS2_DOWN_ARROW 0x72 // 0xE072 293 | #define PS2_RIGHT_ARROW 0x74 // 0xE074 294 | #define PS2_NUM 0x77 295 | #define PS2_KP_FWD_SLASH 0x4A // 0xE04A 296 | #define PS2_KP_STAR 0x7C 297 | #define PS2_KP_HYPH 0x7B 298 | #define PS2_KP_PLUS 0x79 299 | #define PS2_KP_ENTER 0x5A // 0xE05A 300 | #define PS2_KP_PERIOD 0x71 301 | #define PS2_KP_0 0x70 302 | #define PS2_KP_1 0x69 303 | #define PS2_KP_2 0x72 304 | #define PS2_KP_3 0x7A 305 | #define PS2_KP_4 0x6B 306 | #define PS2_KP_5 0x73 307 | #define PS2_KP_6 0x74 308 | #define PS2_KP_7 0x6C 309 | #define PS2_KP_8 0x75 310 | #define PS2_KP_9 0x7D 311 | #define PS2_RIGHT_BRACKET 0x5B 312 | #define PS2_SEMI_COLON 0x4C 313 | #define PS2_APOSTROPHY 0x52 314 | #define PS2_COMMA 0x41 315 | #define PS2_PERIOD 0x49 316 | #define PS2_FWD_SLASH 0x4A 317 | #define PS2_PLAY_PAUSE 0x34 // 0xE034 318 | #define PS2_STOP 0x3B // 0xE03B 319 | #define PS2_VOL_UP 0x32 // 0xE032 320 | #define PS2_PREV_TRACK 0x15 // 0xE015 321 | #define PS2_NEXT_TRACK 0x4D // 0xE04D 322 | #define PS2_VOL_DWN 0x21 // 0xE021 323 | #define PS2_MUTE 0x23 // 0xE023 324 | 325 | #define PS2_RELEASE 0xF0 326 | #define PS2_EXTENDED 0xE0 327 | #define PS2_LED_ACK 0xFA 328 | 329 | #define PS2_PAUSE_SEQUENCE 0xE1 // 0xE11477E10F014F077 330 | #define PS2_PAUSE_KEY_FAKE 0x6D 331 | 332 | #define PS2_SET_RESET_LEDS 0xED //Set the keyboard LEDs 333 | 334 | #define PS2_BUFFER_OVERFLOW 0xFF // My special marker for buffer overflow 335 | 336 | /** 337 | * Arrays for storing the key mapping from PS2 to HID 338 | */ 339 | 340 | typedef unsigned char uint8_t; 341 | 342 | 343 | 344 | 345 | --------------------------------------------------------------------------------