Mercurial > louis > kiibohd-controller
changeset 123:0c5d1fe99302
Adding CLI and CDC Serial support for Teensy 2.0 and Teensy 2.0++
- Includes serial putchar and getchar cleanup (overall)
- Moved avr-capsense to DPH (renaming)
- Basic cleanup for including CLI on the avr architecture
author | Jacob Alexander <haata@kiibohd.com> |
---|---|
date | Mon, 31 Mar 2014 01:07:48 -0700 |
parents | 2bb16439e6ca |
children | 2b81083dcaef |
files | CMakeLists.txt Debug/cli/cli.c Debug/print/print.c Debug/print/print.h Lib/_buildvars.h Output/pjrcUSB/arm/usb_desc.c Output/pjrcUSB/arm/usb_desc.h Output/pjrcUSB/avr/usb_keyboard_debug.c Output/pjrcUSB/avr/usb_keyboard_debug.h Output/pjrcUSB/avr/usb_keyboard_serial.c Output/pjrcUSB/avr/usb_keyboard_serial.h Output/pjrcUSB/output_com.c Output/pjrcUSB/output_com.h Output/pjrcUSB/setup.cmake README Scan/DPH/scan_loop.c Scan/DPH/scan_loop.h Scan/DPH/setup.cmake Scan/SKM67001/setup.cmake Scan/avr-capsense/scan_loop.c Scan/avr-capsense/scan_loop.h Scan/avr-capsense/setup.cmake Scan/matrix/matrix_scan.c Scan/matrix/matrix_scan.h Scan/matrix/matrix_template.h Scan/matrix/scan_loop.c Scan/matrix/scan_loop.h avr.cmake main.c setup.cmake |
diffstat | 30 files changed, 2724 insertions(+), 2061 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sat Mar 22 14:32:06 2014 -0700 +++ b/CMakeLists.txt Mon Mar 31 01:07:48 2014 -0700 @@ -28,8 +28,8 @@ #| "avr" # Teensy++ 2.0 #| "arm" # Teensy 3.0 #| "arm" # Teensy 3.1 -set( COMPILER_FAMILY "arm" ) -#set( COMPILER_FAMILY "avr" ) +#set( COMPILER_FAMILY "arm" ) +set( COMPILER_FAMILY "avr" ) message( STATUS "Compiler Family:" ) message( "${COMPILER_FAMILY}" ) @@ -138,9 +138,10 @@ # #| After Changes Size Information +#| TODO Do lookup on Flash and RAM sizes and do % used add_custom_target( SizeAfter ALL ${SIZE} --target=${FORMAT} ${TARGET_HEX} ${TARGET_ELF} DEPENDS ${TARGET_ELF} - COMMENT "Size after generation:" + COMMENT "Size after generation\n\tFlash Usage: data (hex)\n\t RAM Usage: data (elf)" )
--- a/Debug/cli/cli.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Debug/cli/cli.c Mon Mar 31 01:07:48 2014 -0700 @@ -85,15 +85,14 @@ uint8_t prev_buf_pos = CLILineBufferCurrent; // Process each character while available - int result = 0; while ( 1 ) { // No more characters to process - result = usb_serial_getchar(); // Retrieve from serial module // TODO Make USB agnostic - if ( result == -1 ) + if ( output_availablechar() == 0 ) break; - char cur_char = (char)result; + // Retrieve from output module + char cur_char = (char)output_getchar(); // Make sure buffer isn't full if ( CLILineBufferCurrent >= CLILineBufferMaxSize ) @@ -405,7 +404,7 @@ void cliFunc_restart( char* args ) { // Trigger an overall software reset - SOFTWARE_RESET(); + output_softReset(); } void cliFunc_version( char* args )
--- a/Debug/print/print.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Debug/print/print.c Mon Mar 31 01:07:48 2014 -0700 @@ -31,24 +31,8 @@ // ----- Functions ----- -// USB HID String Output -void usb_debug_putstr( char* s ) -{ -#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR - while ( *s != '\0' ) - usb_debug_putchar( *s++ ); -#elif defined(_mk20dx128_) || defined(_mk20dx256_) // ARM - // Count characters until NULL character, then send the amount counted - uint32_t count = 0; - while ( s[count] != '\0' ) - count++; - - usb_serial_write( s, count ); -#endif -} - // Multiple string Output -void usb_debug_putstrs( char* first, ... ) +void printstrs( char* first, ... ) { // Initialize the variadic function parameter list va_list ap; @@ -61,7 +45,7 @@ while ( !( cur[0] == '\0' && cur[1] == '\0' && cur[2] == '\0' ) ) { // Print out the given string - usb_debug_putstr( cur ); + output_putstr( cur ); // Get the next argument ready cur = va_arg( ap, char* ); @@ -71,21 +55,17 @@ } // Print a constant string -void _print(const char *s) +void _print( const char* s ) { #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR + // Pull string out of flash char c; - - // Acquire the character from flash, and print it, as long as it's not NULL - // Also, if a newline is found, print a carrige return as well - while ( ( c = pgm_read_byte(s++) ) != '\0' ) + while ( ( c = pgm_read_byte( s++ ) ) != '\0' ) { - if ( c == '\n' ) - usb_debug_putchar('\r'); - usb_debug_putchar(c); + output_putchar( c ); } #elif defined(_mk20dx128_) || defined(_mk20dx256_) // ARM - usb_debug_putstr( (char*)s ); + output_putstr( (char*)s ); #endif }
--- a/Debug/print/print.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Debug/print/print.h Mon Mar 31 01:07:48 2014 -0700 @@ -26,15 +26,11 @@ // Compiler Includes #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) - #include <avr/pgmspace.h> -#include "avr/usb_keyboard_debug.h" +#endif -#elif defined(_mk20dx128_) || defined(_mk20dx256_) - -#include "arm/usb_serial.h" - -#endif +// Project Includes +#include <output_com.h> @@ -50,15 +46,15 @@ */ // Function Aliases -#define dPrint(c) usb_debug_putstr(c) -#define dPrintStr(c) usb_debug_putstr(c) -#define dPrintStrs(...) usb_debug_putstrs(__VA_ARGS__, "\0\0\0") // Convenience Variadic Macro -#define dPrintStrNL(c) dPrintStrs (c, NL) // Appends New Line Macro -#define dPrintStrsNL(...) usb_debug_putstrs(__VA_ARGS__, NL, "\0\0\0") // Appends New Line Macro +#define dPrint(c) output_putstr(c) +#define dPrintStr(c) output_putstr(c) +#define dPrintStrs(...) printstrs(__VA_ARGS__, "\0\0\0") // Convenience Variadic Macro +#define dPrintStrNL(c) dPrintStrs (c, NL) // Appends New Line Macro +#define dPrintStrsNL(...) printstrs(__VA_ARGS__, NL, "\0\0\0") // Appends New Line Macro // Special Msg Constructs (Uses VT100 tags) #define dPrintMsg(colour_code_str,msg,...) \ - usb_debug_putstrs("\033[", colour_code_str, "m", msg, "\033[0m - ", __VA_ARGS__, NL, "\0\0\0") + printstrs("\033[", colour_code_str, "m", msg, "\033[0m - ", __VA_ARGS__, NL, "\0\0\0") #define printMsgNL(colour_code_str,msg,str) \ print("\033[" colour_code_str "m" msg "\033[0m - " str NL) #define printMsg(colour_code_str,msg,str) \ @@ -89,8 +85,7 @@ #define print(s) _print(PSTR(s)) void _print(const char *s); -void usb_debug_putstr( char* s ); -void usb_debug_putstrs( char* first, ... ); +void printstrs( char* first, ... ); // Printing numbers
--- a/Lib/_buildvars.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Lib/_buildvars.h Mon Mar 31 01:07:48 2014 -0700 @@ -30,7 +30,7 @@ // You can change these to give your code its own name. #define STR_MANUFACTURER L"@MANUFACTURER@" -#define STR_PRODUCT L"ForceGauge - @ScanModule@ @MacroModule@ @OutputModule@ @DebugModule@" +#define STR_PRODUCT L"Keyboard - @ScanModule@ @MacroModule@ @OutputModule@ @DebugModule@" #define STR_SERIAL L"@GitLastCommitDate@"
--- a/Output/pjrcUSB/arm/usb_desc.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Output/pjrcUSB/arm/usb_desc.c Mon Mar 31 01:07:48 2014 -0700 @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modified by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -10,10 +11,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner.
--- a/Output/pjrcUSB/arm/usb_desc.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Output/pjrcUSB/arm/usb_desc.h Mon Mar 31 01:07:48 2014 -0700 @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modified by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -10,10 +11,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -89,6 +90,7 @@ #define NUM_ENDPOINTS 6 #define NUM_USB_BUFFERS 30 #define NUM_INTERFACE 4 + #define CDC_IAD_DESCRIPTOR 1 #define CDC_STATUS_INTERFACE 0 #define CDC_DATA_INTERFACE 1 // Serial @@ -98,22 +100,27 @@ #define CDC_ACM_SIZE 16 #define CDC_RX_SIZE 64 #define CDC_TX_SIZE 64 + #define KEYBOARD_INTERFACE 2 // Keyboard #define KEYBOARD_ENDPOINT 1 #define KEYBOARD_SIZE 8 #define KEYBOARD_INTERVAL 1 + #define MOUSE_INTERFACE 3 // Mouse #define MOUSE_ENDPOINT 5 #define MOUSE_SIZE 8 #define MOUSE_INTERVAL 2 + #define JOYSTICK_INTERFACE 4 // Joystick #define JOYSTICK_ENDPOINT 6 #define JOYSTICK_SIZE 16 #define JOYSTICK_INTERVAL 1 + #define KEYBOARD_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9) #define MOUSE_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) #define JOYSTICK_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9) #define CONFIG_DESC_SIZE (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
--- a/Output/pjrcUSB/avr/usb_keyboard_debug.c Sat Mar 22 14:32:06 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,705 +0,0 @@ -/* USB Keyboard Plus Debug Channel Example for Teensy USB Development Board - * http://www.pjrc.com/teensy/usb_keyboard.html - * Copyright (c) 2009 PJRC.COM, LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// Version 1.0: Initial Release -// Version 1.1: Add support for Teensy 2.0 - -#define USB_SERIAL_PRIVATE_INCLUDE -#include "usb_keyboard_debug.h" - -/************************************************************************** - * - * Configurable Options - * - **************************************************************************/ - -// USB devices are supposed to implment a halt feature, which is -// rarely (if ever) used. If you comment this line out, the halt -// code will be removed, saving 102 bytes of space (gcc 4.3.0). -// This is not strictly USB compliant, but works with all major -// operating systems. -#define SUPPORT_ENDPOINT_HALT - - - -/************************************************************************** - * - * Endpoint Buffer Configuration - * - **************************************************************************/ - -#define ENDPOINT0_SIZE 32 - -#define KEYBOARD_INTERFACE 0 -#define KEYBOARD_ENDPOINT 3 -#define KEYBOARD_SIZE 8 -#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER - -#define DEBUG_INTERFACE 1 -#define DEBUG_TX_ENDPOINT 4 -#define DEBUG_TX_SIZE 32 -#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER - -static const uint8_t PROGMEM endpoint_config_table[] = { - 0, - 0, - 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, - 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER -}; - - -/************************************************************************** - * - * Descriptor Data - * - **************************************************************************/ - -// Descriptors are the data that your computer reads when it auto-detects -// this USB device (called "enumeration" in USB lingo). The most commonly -// changed items are editable at the top of this file. Changing things -// in here should only be done by those who've read chapter 9 of the USB -// spec and relevant portions of any USB class specifications! - - -static const uint8_t PROGMEM device_descriptor[] = { - 18, // bLength - 1, // bDescriptorType - 0x00, 0x02, // bcdUSB - 0, // bDeviceClass - 0, // bDeviceSubClass - 0, // bDeviceProtocol - ENDPOINT0_SIZE, // bMaxPacketSize0 - LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor - LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct - 0x00, 0x01, // bcdDevice - 1, // iManufacturer - 2, // iProduct - 3, // iSerialNumber - 1 // bNumConfigurations -}; - -// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 -static const uint8_t PROGMEM keyboard_hid_report_desc[] = { - 0x05, 0x01, // Usage Page (Generic Desktop), - 0x09, 0x06, // Usage (Keyboard), - 0xA1, 0x01, // Collection (Application), - 0x75, 0x01, // Report Size (1), - 0x95, 0x08, // Report Count (8), - 0x05, 0x07, // Usage Page (Key Codes), - 0x19, 0xE0, // Usage Minimum (224), - 0x29, 0xE7, // Usage Maximum (231), - 0x15, 0x00, // Logical Minimum (0), - 0x25, 0x01, // Logical Maximum (1), - 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte - 0x95, 0x01, // Report Count (1), - 0x75, 0x08, // Report Size (8), - 0x81, 0x03, // Input (Constant), ;Reserved byte - 0x95, 0x05, // Report Count (5), - 0x75, 0x01, // Report Size (1), - 0x05, 0x08, // Usage Page (LEDs), - 0x19, 0x01, // Usage Minimum (1), - 0x29, 0x05, // Usage Maximum (5), - 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report - 0x95, 0x01, // Report Count (1), - 0x75, 0x03, // Report Size (3), - 0x91, 0x03, // Output (Constant), ;LED report padding - 0x95, 0x06, // Report Count (6), - 0x75, 0x08, // Report Size (8), - 0x15, 0x00, // Logical Minimum (0), - 0x25, 0x68, // Logical Maximum(104), - 0x05, 0x07, // Usage Page (Key Codes), - 0x19, 0x00, // Usage Minimum (0), - 0x29, 0x68, // Usage Maximum (104), - 0x81, 0x00, // Input (Data, Array), - 0xc0 // End Collection -}; - -static const uint8_t PROGMEM debug_hid_report_desc[] = { - //0x06, 0x30, 0xFF, // Usage Page 0xFF31 (vendor defined) - 0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined) - 0x09, 0x74, // Usage 0x74 - 0xA1, 0x53, // Collection 0x53 - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - 0x95, DEBUG_TX_SIZE, // report count - 0x09, 0x75, // usage - 0x81, 0x02, // Input (array) - 0xC0 // end collection -}; - -#define CONFIG1_DESC_SIZE (9+9+9+7+9+9+7) -#define KEYBOARD_HID_DESC_OFFSET (9+9) -#define DEBUG_HID_DESC_OFFSET (9+9+9+7+9) -static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 - 9, // bLength; - 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength - MSB(CONFIG1_DESC_SIZE), - 2, // bNumInterfaces - 1, // bConfigurationValue - 0, // iConfiguration - 0xC0, // bmAttributes - 50, // bMaxPower - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - KEYBOARD_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x01, // bInterfaceSubClass (0x01 = Boot) - 0x01, // bInterfaceProtocol (0x01 = Keyboard) - 0, // iInterface - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - 0, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - sizeof(keyboard_hid_report_desc), // wDescriptorLength - 0, - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - KEYBOARD_SIZE, 0, // wMaxPacketSize - 1, // bInterval - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - DEBUG_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x00, // bInterfaceSubClass - 0x00, // bInterfaceProtocol - 0, // iInterface - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - 0, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - sizeof(debug_hid_report_desc), // wDescriptorLength - 0, - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - DEBUG_TX_SIZE, 0, // wMaxPacketSize - 1 // bInterval -}; - -// If you're desperate for a little extra code memory, these strings -// can be completely removed if iManufacturer, iProduct, iSerialNumber -// in the device desciptor are changed to zeros. -struct usb_string_descriptor_struct { - uint8_t bLength; - uint8_t bDescriptorType; - int16_t wString[]; -}; -static const struct usb_string_descriptor_struct PROGMEM string0 = { - 4, - 3, - {0x0409} -}; -static const struct usb_string_descriptor_struct PROGMEM string1 = { - sizeof(STR_MANUFACTURER), - 3, - STR_MANUFACTURER -}; -static const struct usb_string_descriptor_struct PROGMEM string2 = { - sizeof(STR_PRODUCT), - 3, - STR_PRODUCT -}; -static const struct usb_string_descriptor_struct PROGMEM string3 = { - sizeof(STR_SERIAL), - 3, - STR_SERIAL -}; - -// This table defines which descriptor data is sent for each specific -// request from the host (in wValue and wIndex). -static const struct descriptor_list_struct { - uint16_t wValue; - uint16_t wIndex; - const uint8_t *addr; - uint8_t length; -} PROGMEM descriptor_list[] = { - {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, - {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, - {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, - {0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, - {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, - {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, - {0x0300, 0x0000, (const uint8_t *)&string0, 4}, - {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, - {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}, - {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL)} -}; -#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) - - -/************************************************************************** - * - * Variables - these are the only non-stack RAM usage - * - **************************************************************************/ - -// zero when we are not configured, non-zero when enumerated -static volatile uint8_t usb_configuration=0; - -// the time remaining before we transmit any partially full -// packet, or send a zero length packet. -static volatile uint8_t debug_flush_timer=0; - - -/************************************************************************** - * - * Public Functions - these are the API intended for the user - * - **************************************************************************/ - - -// initialize USB -void usb_init(void) -{ - HW_CONFIG(); - USB_FREEZE(); // enable USB - PLL_CONFIG(); // config PLL - while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock - USB_CONFIG(); // start USB clock - UDCON = 0; // enable attach resistor - usb_configuration = 0; - UDIEN = (1<<EORSTE)|(1<<SOFE); - sei(); -} - -// return 0 if the USB is not configured, or the configuration -// number selected by the HOST -uint8_t usb_configured(void) -{ - return usb_configuration; -} - -// send the contents of USBKeys_Array and USBKeys_Modifiers -int8_t usb_keyboard_send(void) -{ - uint8_t i, intr_state, timeout; - - if (!usb_configuration) return -1; - intr_state = SREG; - cli(); - UENUM = KEYBOARD_ENDPOINT; - timeout = UDFNUML + 50; - while (1) { - // are we ready to transmit? - if (UEINTX & (1<<RWAL)) break; - SREG = intr_state; - // has the USB gone offline? - if (!usb_configuration) return -1; - // have we waited too long? - if (UDFNUML == timeout) return -1; - // get ready to try checking again - intr_state = SREG; - cli(); - UENUM = KEYBOARD_ENDPOINT; - } - UEDATX = USBKeys_Modifiers; - UEDATX = 0; - for (i=0; i<6; i++) { - UEDATX = USBKeys_Array[i]; - } - UEINTX = 0x3A; - USBKeys_Idle_Count = 0; - SREG = intr_state; - return 0; -} - -// transmit a character. 0 returned on success, -1 on error -int8_t usb_debug_putchar(uint8_t c) -{ - static uint8_t previous_timeout=0; - uint8_t timeout, intr_state; - - // if we're not online (enumerated and configured), error - if (!usb_configuration) return -1; - // interrupts are disabled so these functions can be - // used from the main program or interrupt context, - // even both in the same program! - intr_state = SREG; - cli(); - UENUM = DEBUG_TX_ENDPOINT; - // if we gave up due to timeout before, don't wait again - if (previous_timeout) { - if (!(UEINTX & (1<<RWAL))) { - SREG = intr_state; - return -1; - } - previous_timeout = 0; - } - // wait for the FIFO to be ready to accept data - timeout = UDFNUML + 4; - while (1) { - // are we ready to transmit? - if (UEINTX & (1<<RWAL)) break; - SREG = intr_state; - // have we waited too long? - if (UDFNUML == timeout) { - previous_timeout = 1; - return -1; - } - // has the USB gone offline? - if (!usb_configuration) return -1; - // get ready to try checking again - intr_state = SREG; - cli(); - UENUM = DEBUG_TX_ENDPOINT; - } - // actually write the byte into the FIFO - UEDATX = c; - // if this completed a packet, transmit it now! - if (!(UEINTX & (1<<RWAL))) { - UEINTX = 0x3A; - debug_flush_timer = 0; - } else { - debug_flush_timer = 2; - } - SREG = intr_state; - return 0; -} - - -// immediately transmit any buffered output. -void usb_debug_flush_output(void) -{ - uint8_t intr_state; - - intr_state = SREG; - cli(); - if (debug_flush_timer) { - UENUM = DEBUG_TX_ENDPOINT; - while ((UEINTX & (1<<RWAL))) { - UEDATX = 0; - } - UEINTX = 0x3A; - debug_flush_timer = 0; - } - SREG = intr_state; -} - - - -/************************************************************************** - * - * Private Functions - not intended for general user consumption.... - * - **************************************************************************/ - - - -// USB Device Interrupt - handle all device-level events -// the transmit buffer flushing is triggered by the start of frame -// -ISR(USB_GEN_vect) -{ - uint8_t intbits, t, i; - static uint8_t div4=0; - - intbits = UDINT; - UDINT = 0; - if (intbits & (1<<EORSTI)) { - UENUM = 0; - UECONX = 1; - UECFG0X = EP_TYPE_CONTROL; - UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER; - UEIENX = (1<<RXSTPE); - usb_configuration = 0; - } - if ((intbits & (1<<SOFI)) && usb_configuration) { - t = debug_flush_timer; - if (t) { - debug_flush_timer = -- t; - if (!t) { - UENUM = DEBUG_TX_ENDPOINT; - while ((UEINTX & (1<<RWAL))) { - UEDATX = 0; - } - UEINTX = 0x3A; - } - } - if (USBKeys_Idle_Config && (++div4 & 3) == 0) { - UENUM = KEYBOARD_ENDPOINT; - if (UEINTX & (1<<RWAL)) { - USBKeys_Idle_Count++; - if (USBKeys_Idle_Count == USBKeys_Idle_Config) { - USBKeys_Idle_Count = 0; - UEDATX = USBKeys_Modifiers; - UEDATX = 0; - for (i=0; i<6; i++) { - UEDATX = USBKeys_Array[i]; - } - UEINTX = 0x3A; - } - } - } - } -} - - - -// Misc functions to wait for ready and send/receive packets -static inline void usb_wait_in_ready(void) -{ - while (!(UEINTX & (1<<TXINI))) ; -} -static inline void usb_send_in(void) -{ - UEINTX = ~(1<<TXINI); -} -static inline void usb_wait_receive_out(void) -{ - while (!(UEINTX & (1<<RXOUTI))) ; -} -static inline void usb_ack_out(void) -{ - UEINTX = ~(1<<RXOUTI); -} - - - -// USB Endpoint Interrupt - endpoint 0 is handled here. The -// other endpoints are manipulated by the user-callable -// functions, and the start-of-frame interrupt. -// -ISR(USB_COM_vect) -{ - uint8_t intbits; - const uint8_t *list; - const uint8_t *cfg; - uint8_t i, n, len, en; - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - uint16_t desc_val; - const uint8_t *desc_addr; - uint8_t desc_length; - - UENUM = 0; - intbits = UEINTX; - if (intbits & (1<<RXSTPI)) { - bmRequestType = UEDATX; - bRequest = UEDATX; - wValue = UEDATX; - wValue |= (UEDATX << 8); - wIndex = UEDATX; - wIndex |= (UEDATX << 8); - wLength = UEDATX; - wLength |= (UEDATX << 8); - UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); - if (bRequest == GET_DESCRIPTOR) { - list = (const uint8_t *)descriptor_list; - for (i=0; ; i++) { - if (i >= NUM_DESC_LIST) { - UECONX = (1<<STALLRQ)|(1<<EPEN); //stall - return; - } - desc_val = pgm_read_word(list); - if (desc_val != wValue) { - list += sizeof(struct descriptor_list_struct); - continue; - } - list += 2; - desc_val = pgm_read_word(list); - if (desc_val != wIndex) { - list += sizeof(struct descriptor_list_struct)-2; - continue; - } - list += 2; - desc_addr = (const uint8_t *)pgm_read_word(list); - list += 2; - desc_length = pgm_read_byte(list); - break; - } - len = (wLength < 256) ? wLength : 255; - if (len > desc_length) len = desc_length; - do { - // wait for host ready for IN packet - do { - i = UEINTX; - } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); - if (i & (1<<RXOUTI)) return; // abort - // send IN packet - n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; - for (i = n; i; i--) { - UEDATX = pgm_read_byte(desc_addr++); - } - len -= n; - usb_send_in(); - } while (len || n == ENDPOINT0_SIZE); - return; - } - if (bRequest == SET_ADDRESS) { - usb_send_in(); - usb_wait_in_ready(); - UDADDR = wValue | (1<<ADDEN); - return; - } - if (bRequest == SET_CONFIGURATION && bmRequestType == 0) { - usb_configuration = wValue; - usb_send_in(); - cfg = endpoint_config_table; - for (i=1; i<5; i++) { - UENUM = i; - en = pgm_read_byte(cfg++); - UECONX = en; - if (en) { - UECFG0X = pgm_read_byte(cfg++); - UECFG1X = pgm_read_byte(cfg++); - } - } - UERST = 0x1E; - UERST = 0; - return; - } - if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) { - usb_wait_in_ready(); - UEDATX = usb_configuration; - usb_send_in(); - return; - } - - if (bRequest == GET_STATUS) { - usb_wait_in_ready(); - i = 0; - #ifdef SUPPORT_ENDPOINT_HALT - if (bmRequestType == 0x82) { - UENUM = wIndex; - if (UECONX & (1<<STALLRQ)) i = 1; - UENUM = 0; - } - #endif - UEDATX = i; - UEDATX = 0; - usb_send_in(); - return; - } - #ifdef SUPPORT_ENDPOINT_HALT - if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) - && bmRequestType == 0x02 && wValue == 0) { - i = wIndex & 0x7F; - if (i >= 1 && i <= MAX_ENDPOINT) { - usb_send_in(); - UENUM = i; - if (bRequest == SET_FEATURE) { - UECONX = (1<<STALLRQ)|(1<<EPEN); - } else { - UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN); - UERST = (1 << i); - UERST = 0; - } - return; - } - } - #endif - if (wIndex == KEYBOARD_INTERFACE) { - if (bmRequestType == 0xA1) { - if (bRequest == HID_GET_REPORT) { - usb_wait_in_ready(); - UEDATX = USBKeys_Modifiers; - UEDATX = 0; - for (i=0; i<6; i++) { - UEDATX = USBKeys_Array[i]; - } - usb_send_in(); - return; - } - if (bRequest == HID_GET_IDLE) { - usb_wait_in_ready(); - UEDATX = USBKeys_Idle_Config; - usb_send_in(); - return; - } - if (bRequest == HID_GET_PROTOCOL) { - usb_wait_in_ready(); - UEDATX = USBKeys_Protocol; - usb_send_in(); - return; - } - } - if (bmRequestType == 0x21) { - if (bRequest == HID_SET_REPORT) { - usb_wait_receive_out(); - USBKeys_LEDs = UEDATX; - usb_ack_out(); - usb_send_in(); - return; - } - if (bRequest == HID_SET_IDLE) { - USBKeys_Idle_Config = (wValue >> 8); - USBKeys_Idle_Count = 0; - //usb_wait_in_ready(); - usb_send_in(); - return; - } - if (bRequest == HID_SET_PROTOCOL) { - USBKeys_Protocol = wValue; - //usb_wait_in_ready(); - usb_send_in(); - return; - } - } - } - if (wIndex == DEBUG_INTERFACE) { - if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { - len = wLength; - do { - // wait for host ready for IN packet - do { - i = UEINTX; - } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); - if (i & (1<<RXOUTI)) return; // abort - // send IN packet - n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; - for (i = n; i; i--) { - UEDATX = 0; - } - len -= n; - usb_send_in(); - } while (len || n == ENDPOINT0_SIZE); - return; - } - } - } - UECONX = (1<<STALLRQ) | (1<<EPEN); // stall -} -
--- a/Output/pjrcUSB/avr/usb_keyboard_debug.h Sat Mar 22 14:32:06 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#ifndef usb_serial_h__ -#define usb_serial_h__ - -#include <stdint.h> -#include "output_com.h" - -void usb_init(void); // initialize everything -uint8_t usb_configured(void); // is the USB port configured - -int8_t usb_keyboard_send(void); - - -int8_t usb_debug_putchar(uint8_t c); // transmit a character -void usb_debug_flush_output(void); // immediately transmit any buffered output -#define USB_DEBUG_HID - - -// Everything below this point is only intended for usb_serial.c -#ifdef USB_SERIAL_PRIVATE_INCLUDE -#include <avr/io.h> -#include <avr/pgmspace.h> -#include <avr/interrupt.h> - -#define EP_TYPE_CONTROL 0x00 -#define EP_TYPE_BULK_IN 0x81 -#define EP_TYPE_BULK_OUT 0x80 -#define EP_TYPE_INTERRUPT_IN 0xC1 -#define EP_TYPE_INTERRUPT_OUT 0xC0 -#define EP_TYPE_ISOCHRONOUS_IN 0x41 -#define EP_TYPE_ISOCHRONOUS_OUT 0x40 - -#define EP_SINGLE_BUFFER 0x02 -#define EP_DOUBLE_BUFFER 0x06 - -#define EP_SIZE(s) ((s) == 64 ? 0x30 : \ - ((s) == 32 ? 0x20 : \ - ((s) == 16 ? 0x10 : \ - 0x00))) - -#define MAX_ENDPOINT 4 - -#define LSB(n) (n & 255) -#define MSB(n) ((n >> 8) & 255) - -#if defined(__AVR_AT90USB162__) -#define HW_CONFIG() -#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0))) -#define USB_CONFIG() (USBCON = (1<<USBE)) -#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) -#elif defined(__AVR_ATmega32U4__) -#define HW_CONFIG() (UHWCON = 0x01) -#define PLL_CONFIG() (PLLCSR = 0x12) -#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) -#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) -#elif defined(__AVR_AT90USB646__) -#define HW_CONFIG() (UHWCON = 0x81) -#define PLL_CONFIG() (PLLCSR = 0x1A) -#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) -#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) -#elif defined(__AVR_AT90USB1286__) -#define HW_CONFIG() (UHWCON = 0x81) -#define PLL_CONFIG() (PLLCSR = 0x16) -#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) -#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) -#endif - -// standard control endpoint request types -#define GET_STATUS 0 -#define CLEAR_FEATURE 1 -#define SET_FEATURE 3 -#define SET_ADDRESS 5 -#define GET_DESCRIPTOR 6 -#define GET_CONFIGURATION 8 -#define SET_CONFIGURATION 9 -#define GET_INTERFACE 10 -#define SET_INTERFACE 11 -// HID (human interface device) -#define HID_GET_REPORT 1 -#define HID_GET_IDLE 2 -#define HID_GET_PROTOCOL 3 -#define HID_SET_REPORT 9 -#define HID_SET_IDLE 10 -#define HID_SET_PROTOCOL 11 -// CDC (communication class device) -#define CDC_SET_LINE_CODING 0x20 -#define CDC_GET_LINE_CODING 0x21 -#define CDC_SET_CONTROL_LINE_STATE 0x22 -#endif -#endif -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Output/pjrcUSB/avr/usb_keyboard_serial.c Mon Mar 31 01:07:48 2014 -0700 @@ -0,0 +1,1126 @@ +/* USB Keyboard and CDC Serial Device for Teensy USB Development Board + * Copyright (c) 2009 PJRC.COM, LLC + * Modifications by Jacob Alexander (2011-2014) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +// Local Includes +#include "usb_keyboard_serial.h" + + +// ----- Functions ----- + +// Set the avr into firmware reload mode +void usb_debug_reload() +{ + cli(); + // Disable watchdog, if enabled + // Disable all peripherals + + UDCON = 1; + USBCON = (1 << FRZCLK); // Disable USB + UCSR1B = 0; + _delay_ms( 5 ); + +#if defined(__AVR_AT90USB162__) // Teensy 1.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; + TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; + DDRB = 0; DDRC = 0; DDRD = 0; + PORTB = 0; PORTC = 0; PORTD = 0; + asm volatile("jmp 0x3E00"); +#elif defined(__AVR_ATmega32U4__) // Teensy 2.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; + DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; + PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0x7E00"); +#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; + DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; + PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0xFC00"); +#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; + DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; + PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0x1FC00"); +#endif +} + + +// WDT Setup for software reset the chip +void wdt_init(void) +{ + MCUSR = 0; + wdt_disable(); +} + + +/************************************************************************** + * + * Configurable Options + * + **************************************************************************/ + +// When you write data, it goes into a USB endpoint buffer, which +// is transmitted to the PC when it becomes full, or after a timeout +// with no more writes. Even if you write in exactly packet-size +// increments, this timeout is used to send a "zero length packet" +// that tells the PC no more data is expected and it should pass +// any buffered data to the application that may be waiting. If +// you want data sent immediately, call usb_serial_flush_output(). +#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ + +// If the PC is connected but not "listening", this is the length +// of time before usb_serial_getchar() returns with an error. This +// is roughly equivilant to a real UART simply transmitting the +// bits on a wire where nobody is listening, except you get an error +// code which you can ignore for serial-like discard of data, or +// use to know your data wasn't sent. +#define TRANSMIT_TIMEOUT 25 /* in milliseconds */ + +// USB devices are supposed to implment a halt feature, which is +// rarely (if ever) used. If you comment this line out, the halt +// code will be removed, saving 116 bytes of space (gcc 4.3.0). +// This is not strictly USB compliant, but works with all major +// operating systems. +#define SUPPORT_ENDPOINT_HALT + + + +/************************************************************************** + * + * Descriptor Data + * + **************************************************************************/ + +// Descriptors are the data that your computer reads when it auto-detects +// this USB device (called "enumeration" in USB lingo). The most commonly +// changed items are editable at the top of this file. Changing things +// in here should only be done by those who've read chapter 9 of the USB +// spec and relevant portions of any USB class specifications! + + +static const uint8_t PROGMEM device_descriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + ENDPOINT0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 3, // iSerialNumber + 1 // bNumConfigurations +}; + +// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 +static const uint8_t PROGMEM keyboard_hid_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application), + 0x75, 0x01, // Report Size (1), + 0x95, 0x08, // Report Count (8), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0xE0, // Usage Minimum (224), + 0x29, 0xE7, // Usage Maximum (231), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte + 0x95, 0x08, // Report Count (8), + 0x75, 0x01, // Report Size (1), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x05, 0x0C, // Usage Page (Consumer), + 0x09, 0xE9, // Usage (Volume Increment), + 0x09, 0xEA, // Usage (Volume Decrement), + 0x09, 0xE2, // Usage (Mute), + 0x09, 0xCD, // Usage (Play/Pause), + 0x09, 0xB5, // Usage (Scan Next Track), + 0x09, 0xB6, // Usage (Scan Previous Track), + 0x09, 0xB7, // Usage (Stop), + 0x09, 0xB8, // Usage (Eject), + 0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys + 0x95, 0x05, // Report Count (5), + 0x75, 0x01, // Report Size (1), + 0x05, 0x08, // Usage Page (LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report + 0x95, 0x01, // Report Count (1), + 0x75, 0x03, // Report Size (3), + 0x91, 0x03, // Output (Constant), ;LED report padding + 0x95, 0x06, // Report Count (6), + 0x75, 0x08, // Report Size (8), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x7F, // Logical Maximum(104), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0x00, // Usage Minimum (0), + 0x29, 0x7F, // Usage Maximum (104), + 0x81, 0x00, // Input (Data, Array), ;Normal keys + 0xc0 // End Collection +}; + +// <Configuration> + <Keyboard HID> + <Serial CDC> +#define CONFIG1_DESC_SIZE (9 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7) +#define KEYBOARD_HID_DESC_OFFSET (9 + 9) +#define SERIAL_CDC_DESC_OFFSET (9 + 9+9+7) +static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { +// --- Configuration --- +// - 9 bytes - + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + 9, // bLength; + 2, // bDescriptorType; + LSB(CONFIG1_DESC_SIZE), // wTotalLength + MSB(CONFIG1_DESC_SIZE), + 3, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0xC0, // bmAttributes + 50, // bMaxPower + +// --- Keyboard HID --- +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + KEYBOARD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x01, // bInterfaceSubClass (0x01 = Boot) + 0x01, // bInterfaceProtocol (0x01 = Keyboard) + 0, // iInterface +// - 9 bytes - + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(keyboard_hid_report_desc)), // wDescriptorLength + MSB(sizeof(keyboard_hid_report_desc)), +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + KEYBOARD_SIZE, 0, // wMaxPacketSize + KEYBOARD_INTERVAL, // bInterval + +// --- Serial CDC --- +// - 8 bytes - + // interface association descriptor, USB ECN, Table 9-Z + 8, // bLength + 11, // bDescriptorType + CDC_STATUS_INTERFACE, // bFirstInterface + 2, // bInterfaceCount + 0x02, // bFunctionClass + 0x02, // bFunctionSubClass + 0x01, // bFunctionProtocol + 4, // iFunction +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + CDC_STATUS_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface +// - 5 bytes - + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x00, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC +// - 5 bytes - + // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x01, // bDescriptorSubtype + 0x01, // bmCapabilities + 1, // bDataInterface +// - 4 bytes - + // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 + 4, // bFunctionLength + 0x24, // bDescriptorType + 0x02, // bDescriptorSubtype + 0x06, // bmCapabilities +// - 5 bytes - + // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x06, // bDescriptorSubtype + CDC_STATUS_INTERFACE, // bMasterInterface + CDC_DATA_INTERFACE, // bSlaveInterface0 +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_ACM_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + CDC_ACM_SIZE, 0, // wMaxPacketSize + 64, // bInterval +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + CDC_DATA_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_RX_ENDPOINT, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_RX_SIZE, 0, // wMaxPacketSize + 0, // bInterval +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_TX_SIZE, 0, // wMaxPacketSize + 0, // bInterval +}; + +// If you're desperate for a little extra code memory, these strings +// can be completely removed if iManufacturer, iProduct, iSerialNumber +// in the device desciptor are changed to zeros. +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + int16_t wString[]; +}; +static const struct usb_string_descriptor_struct PROGMEM string0 = { + 4, + 3, + {0x0409} +}; +static const struct usb_string_descriptor_struct PROGMEM string1 = { + sizeof(STR_MANUFACTURER), + 3, + STR_MANUFACTURER +}; +static const struct usb_string_descriptor_struct PROGMEM string2 = { + sizeof(STR_PRODUCT), + 3, + STR_PRODUCT +}; +static const struct usb_string_descriptor_struct PROGMEM string3 = { + sizeof(STR_SERIAL), + 3, + STR_SERIAL +}; + +// This table defines which descriptor data is sent for each specific +// request from the host (in wValue and wIndex). +static const struct descriptor_list_struct { + uint16_t wValue; + uint16_t wIndex; + const uint8_t *addr; + uint8_t length; +} PROGMEM descriptor_list[] = { + {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, + {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, + {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, + {0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, + {0x0300, 0x0000, (const uint8_t *)&string0, 4}, + {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, + {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}, + {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL)} +}; +#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) + + +/************************************************************************** + * + * Variables - these are the only non-stack RAM usage + * + **************************************************************************/ + +// zero when we are not configured, non-zero when enumerated +static volatile uint8_t usb_configuration=0; + +// the time remaining before we transmit any partially full +// packet, or send a zero length packet. +static volatile uint8_t transmit_flush_timer=0; +static uint8_t transmit_previous_timeout=0; + +// serial port settings (baud rate, control signals, etc) set +// by the PC. These are ignored, but kept in RAM. +static uint8_t cdc_line_coding[7]={0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08}; +static uint8_t cdc_line_rtsdtr=0; + + +/************************************************************************** + * + * Public Functions - these are the API intended for the user + * + **************************************************************************/ + + +// initialize USB +void usb_init(void) +{ + HW_CONFIG(); + USB_FREEZE(); // enable USB + PLL_CONFIG(); // config PLL + while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock + USB_CONFIG(); // start USB clock + UDCON = 0; // enable attach resistor + usb_configuration = 0; + UDIEN = (1<<EORSTE)|(1<<SOFE); + sei(); + + // Disable watchdog timer after possible software reset + //wdt_init(); // XXX Not working...seems to be ok without this, not sure though +} + +// return 0 if the USB is not configured, or the configuration +// number selected by the HOST +uint8_t usb_configured(void) +{ + return usb_configuration; +} + +// send the contents of USBKeys_Array and USBKeys_Modifiers +int8_t usb_keyboard_send(void) +{ + uint8_t i, intr_state, timeout; + + if (!usb_configuration) return -1; + intr_state = SREG; + cli(); + UENUM = KEYBOARD_ENDPOINT; + timeout = UDFNUML + 50; + while (1) { + // are we ready to transmit? + if (UEINTX & (1<<RWAL)) break; + SREG = intr_state; + // has the USB gone offline? + if (!usb_configuration) return -1; + // have we waited too long? + if (UDFNUML == timeout) return -1; + // get ready to try checking again + intr_state = SREG; + cli(); + UENUM = KEYBOARD_ENDPOINT; + } + UEDATX = USBKeys_Modifiers; + UEDATX = 0; + for (i=0; i<6; i++) { + UEDATX = USBKeys_Array[i]; + } + UEINTX = 0x3A; + USBKeys_Idle_Count = 0; + SREG = intr_state; + return 0; +} + +// get the next character, or -1 if nothing received +int16_t usb_serial_getchar(void) +{ + uint8_t c, intr_state; + + // interrupts are disabled so these functions can be + // used from the main program or interrupt context, + // even both in the same program! + intr_state = SREG; + cli(); + if (!usb_configuration) { + SREG = intr_state; + return -1; + } + UENUM = CDC_RX_ENDPOINT; + retry: + c = UEINTX; + if (!(c & (1<<RWAL))) { + // no data in buffer + if (c & (1<<RXOUTI)) { + UEINTX = 0x6B; + goto retry; + } + SREG = intr_state; + return -2; + } + // take one byte out of the buffer + c = UEDATX; + // if buffer completely used, release it + if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B; + SREG = intr_state; + return c; +} + +// number of bytes available in the receive buffer +uint8_t usb_serial_available(void) +{ + uint8_t n=0, i, intr_state; + + intr_state = SREG; + cli(); + if (usb_configuration) { + UENUM = CDC_RX_ENDPOINT; + n = UEBCLX; + if (!n) { + i = UEINTX; + if (i & (1<<RXOUTI) && !(i & (1<<RWAL))) UEINTX = 0x6B; + } + } + SREG = intr_state; + return n; +} + +// discard any buffered input +void usb_serial_flush_input(void) +{ + uint8_t intr_state; + + if (usb_configuration) { + intr_state = SREG; + cli(); + UENUM = CDC_RX_ENDPOINT; + while ((UEINTX & (1<<RWAL))) { + UEINTX = 0x6B; + } + SREG = intr_state; + } +} + +// transmit a character. 0 returned on success, -1 on error +int8_t usb_serial_putchar(uint8_t c) +{ + uint8_t timeout, intr_state; + + // if we're not online (enumerated and configured), error + if (!usb_configuration) return -1; + // interrupts are disabled so these functions can be + // used from the main program or interrupt context, + // even both in the same program! + intr_state = SREG; + cli(); + UENUM = CDC_TX_ENDPOINT; + // if we gave up due to timeout before, don't wait again + if (transmit_previous_timeout) { + if (!(UEINTX & (1<<RWAL))) { + SREG = intr_state; + return -1; + } + transmit_previous_timeout = 0; + } + // wait for the FIFO to be ready to accept data + timeout = UDFNUML + TRANSMIT_TIMEOUT; + while (1) { + // are we ready to transmit? + if (UEINTX & (1<<RWAL)) break; + SREG = intr_state; + // have we waited too long? This happens if the user + // is not running an application that is listening + if (UDFNUML == timeout) { + transmit_previous_timeout = 1; + return -1; + } + // has the USB gone offline? + if (!usb_configuration) return -1; + // get ready to try checking again + intr_state = SREG; + cli(); + UENUM = CDC_TX_ENDPOINT; + } + // actually write the byte into the FIFO + UEDATX = c; + // if this completed a packet, transmit it now! + if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A; + transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; + SREG = intr_state; + return 0; +} + + +// transmit a character, but do not wait if the buffer is full, +// 0 returned on success, -1 on buffer full or error +int8_t usb_serial_putchar_nowait(uint8_t c) +{ + uint8_t intr_state; + + if (!usb_configuration) return -1; + intr_state = SREG; + cli(); + UENUM = CDC_TX_ENDPOINT; + if (!(UEINTX & (1<<RWAL))) { + // buffer is full + SREG = intr_state; + return -2; + } + // actually write the byte into the FIFO + UEDATX = c; + // if this completed a packet, transmit it now! + if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A; + transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; + SREG = intr_state; + return 0; +} + +// transmit a buffer. +// 0 returned on success, -1 on error +// This function is optimized for speed! Each call takes approx 6.1 us overhead +// plus 0.25 us per byte. 12 Mbit/sec USB has 8.67 us per-packet overhead and +// takes 0.67 us per byte. If called with 64 byte packet-size blocks, this function +// can transmit at full USB speed using 43% CPU time. The maximum theoretical speed +// is 19 packets per USB frame, or 1216 kbytes/sec. However, bulk endpoints have the +// lowest priority, so any other USB devices will likely reduce the speed. Speed +// can also be limited by how quickly the PC-based software reads data, as the host +// controller in the PC will not allocate bandwitdh without a pending read request. +// (thanks to Victor Suarez for testing and feedback and initial code) + +int8_t usb_serial_write(const char *buffer, uint16_t size) +{ + uint8_t timeout, intr_state, write_size; + + // if we're not online (enumerated and configured), error + if (!usb_configuration) return -1; + // interrupts are disabled so these functions can be + // used from the main program or interrupt context, + // even both in the same program! + intr_state = SREG; + cli(); + UENUM = CDC_TX_ENDPOINT; + // if we gave up due to timeout before, don't wait again + /* + if (transmit_previous_timeout) { + if (!(UEINTX & (1<<RWAL))) { + SREG = intr_state; + return -2; + } + transmit_previous_timeout = 0; + } + */ + // each iteration of this loop transmits a packet + while (size) { + // wait for the FIFO to be ready to accept data + timeout = UDFNUML + TRANSMIT_TIMEOUT; + while (1) { + // are we ready to transmit? + if (UEINTX & (1<<RWAL)) break; + SREG = intr_state; + // have we waited too long? This happens if the user + // is not running an application that is listening + if (UDFNUML == timeout) { + transmit_previous_timeout = 1; + return -3; + } + // has the USB gone offline? + if (!usb_configuration) return -4; + // get ready to try checking again + intr_state = SREG; + cli(); + UENUM = CDC_TX_ENDPOINT; + } + + // compute how many bytes will fit into the next packet + write_size = CDC_TX_SIZE - UEBCLX; + if (write_size > size) write_size = size; + size -= write_size; + + // write the packet + switch (write_size) { + #if (CDC_TX_SIZE == 64) + case 64: UEDATX = *buffer++; + case 63: UEDATX = *buffer++; + case 62: UEDATX = *buffer++; + case 61: UEDATX = *buffer++; + case 60: UEDATX = *buffer++; + case 59: UEDATX = *buffer++; + case 58: UEDATX = *buffer++; + case 57: UEDATX = *buffer++; + case 56: UEDATX = *buffer++; + case 55: UEDATX = *buffer++; + case 54: UEDATX = *buffer++; + case 53: UEDATX = *buffer++; + case 52: UEDATX = *buffer++; + case 51: UEDATX = *buffer++; + case 50: UEDATX = *buffer++; + case 49: UEDATX = *buffer++; + case 48: UEDATX = *buffer++; + case 47: UEDATX = *buffer++; + case 46: UEDATX = *buffer++; + case 45: UEDATX = *buffer++; + case 44: UEDATX = *buffer++; + case 43: UEDATX = *buffer++; + case 42: UEDATX = *buffer++; + case 41: UEDATX = *buffer++; + case 40: UEDATX = *buffer++; + case 39: UEDATX = *buffer++; + case 38: UEDATX = *buffer++; + case 37: UEDATX = *buffer++; + case 36: UEDATX = *buffer++; + case 35: UEDATX = *buffer++; + case 34: UEDATX = *buffer++; + case 33: UEDATX = *buffer++; + #endif + #if (CDC_TX_SIZE >= 32) + case 32: UEDATX = *buffer++; + case 31: UEDATX = *buffer++; + case 30: UEDATX = *buffer++; + case 29: UEDATX = *buffer++; + case 28: UEDATX = *buffer++; + case 27: UEDATX = *buffer++; + case 26: UEDATX = *buffer++; + case 25: UEDATX = *buffer++; + case 24: UEDATX = *buffer++; + case 23: UEDATX = *buffer++; + case 22: UEDATX = *buffer++; + case 21: UEDATX = *buffer++; + case 20: UEDATX = *buffer++; + case 19: UEDATX = *buffer++; + case 18: UEDATX = *buffer++; + case 17: UEDATX = *buffer++; + #endif + #if (CDC_TX_SIZE >= 16) + case 16: UEDATX = *buffer++; + case 15: UEDATX = *buffer++; + case 14: UEDATX = *buffer++; + case 13: UEDATX = *buffer++; + case 12: UEDATX = *buffer++; + case 11: UEDATX = *buffer++; + case 10: UEDATX = *buffer++; + case 9: UEDATX = *buffer++; + #endif + case 8: UEDATX = *buffer++; + case 7: UEDATX = *buffer++; + case 6: UEDATX = *buffer++; + case 5: UEDATX = *buffer++; + case 4: UEDATX = *buffer++; + case 3: UEDATX = *buffer++; + case 2: UEDATX = *buffer++; + default: + case 1: UEDATX = *buffer++; + case 0: break; + } + // if this completed a packet, transmit it now! + if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A; + transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; + SREG = intr_state; + } + return 0; +} + +// immediately transmit any buffered output. +// This doesn't actually transmit the data - that is impossible! +// USB devices only transmit when the host allows, so the best +// we can do is release the FIFO buffer for when the host wants it +void usb_serial_flush_output(void) +{ + uint8_t intr_state; + + intr_state = SREG; + cli(); + if (transmit_flush_timer) { + UENUM = CDC_TX_ENDPOINT; + UEINTX = 0x3A; + transmit_flush_timer = 0; + } + SREG = intr_state; +} + +// functions to read the various async serial settings. These +// aren't actually used by USB at all (communication is always +// at full USB speed), but they are set by the host so we can +// set them properly if we're converting the USB to a real serial +// communication +uint32_t usb_serial_get_baud(void) +{ + uint32_t *baud = (uint32_t*)cdc_line_coding; + return *baud; +} +uint8_t usb_serial_get_stopbits(void) +{ + return cdc_line_coding[4]; +} +uint8_t usb_serial_get_paritytype(void) +{ + return cdc_line_coding[5]; +} +uint8_t usb_serial_get_numbits(void) +{ + return cdc_line_coding[6]; +} +uint8_t usb_serial_get_control(void) +{ + return cdc_line_rtsdtr; +} + +// write the control signals, DCD, DSR, RI, etc +// There is no CTS signal. If software on the host has transmitted +// data to you but you haven't been calling the getchar function, +// it remains buffered (either here or on the host) and can not be +// lost because you weren't listening at the right time, like it +// would in real serial communication. +int8_t usb_serial_set_control(uint8_t signals) +{ + uint8_t intr_state; + + intr_state = SREG; + cli(); + if (!usb_configuration) { + // we're not enumerated/configured + SREG = intr_state; + return -1; + } + + UENUM = CDC_ACM_ENDPOINT; + if (!(UEINTX & (1<<RWAL))) { + // unable to write + // TODO; should this try to abort the previously + // buffered message?? + SREG = intr_state; + return -1; + } + UEDATX = 0xA1; + UEDATX = 0x20; + UEDATX = 0; + UEDATX = 0; + UEDATX = 0; // 0 seems to work nicely. what if this is 1?? + UEDATX = 0; + UEDATX = 1; + UEDATX = 0; + UEDATX = signals; + UEINTX = 0x3A; + SREG = intr_state; + return 0; +} + + + +/************************************************************************** + * + * Private Functions - not intended for general user consumption.... + * + **************************************************************************/ + + + +// USB Device Interrupt - handle all device-level events +// the transmit buffer flushing is triggered by the start of frame +// +ISR(USB_GEN_vect) +{ + uint8_t intbits, t_cdc, i; + static uint8_t div4=0; + + intbits = UDINT; + UDINT = 0; + if (intbits & (1<<EORSTI)) { + UENUM = 0; + UECONX = 1; + UECFG0X = EP_TYPE_CONTROL; + UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER; + UEIENX = (1<<RXSTPE); + usb_configuration = 0; + cdc_line_rtsdtr = 0; + } + if ((intbits & (1<<SOFI)) && usb_configuration) { + t_cdc = transmit_flush_timer; + if (t_cdc) { + transmit_flush_timer = --t_cdc; + if (!t_cdc) { + UENUM = CDC_TX_ENDPOINT; + UEINTX = 0x3A; + } + } + if (USBKeys_Idle_Config && (++div4 & 3) == 0) { + UENUM = KEYBOARD_ENDPOINT; + if (UEINTX & (1<<RWAL)) { + USBKeys_Idle_Count++; + if (USBKeys_Idle_Count == USBKeys_Idle_Config) { + USBKeys_Idle_Count = 0; + UEDATX = USBKeys_Modifiers; + UEDATX = 0; + for (i=0; i<6; i++) { + UEDATX = USBKeys_Array[i]; + } + UEINTX = 0x3A; + } + } + } + } +} + + + +// Misc functions to wait for ready and send/receive packets +static inline void usb_wait_in_ready(void) +{ + while (!(UEINTX & (1<<TXINI))) ; +} +static inline void usb_send_in(void) +{ + UEINTX = ~(1<<TXINI); +} +static inline void usb_wait_receive_out(void) +{ + while (!(UEINTX & (1<<RXOUTI))) ; +} +static inline void usb_ack_out(void) +{ + UEINTX = ~(1<<RXOUTI); +} + + + +// USB Endpoint Interrupt - endpoint 0 is handled here. The +// other endpoints are manipulated by the user-callable +// functions, and the start-of-frame interrupt. +// +ISR(USB_COM_vect) +{ + uint8_t intbits; + const uint8_t *list; + const uint8_t *cfg; + uint8_t i, n, len, en; + uint8_t *p; + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint16_t desc_val; + const uint8_t *desc_addr; + uint8_t desc_length; + + UENUM = 0; + intbits = UEINTX; + if (intbits & (1<<RXSTPI)) { + bmRequestType = UEDATX; + bRequest = UEDATX; + wValue = UEDATX; + wValue |= (UEDATX << 8); + wIndex = UEDATX; + wIndex |= (UEDATX << 8); + wLength = UEDATX; + wLength |= (UEDATX << 8); + UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); + if (bRequest == GET_DESCRIPTOR) { + list = (const uint8_t *)descriptor_list; + for (i=0; ; i++) { + if (i >= NUM_DESC_LIST) { + UECONX = (1<<STALLRQ)|(1<<EPEN); //stall + return; + } + desc_val = pgm_read_word(list); + if (desc_val != wValue) { + list += sizeof(struct descriptor_list_struct); + continue; + } + list += 2; + desc_val = pgm_read_word(list); + if (desc_val != wIndex) { + list += sizeof(struct descriptor_list_struct)-2; + continue; + } + list += 2; + desc_addr = (const uint8_t *)pgm_read_word(list); + list += 2; + desc_length = pgm_read_byte(list); + break; + } + len = (wLength < 256) ? wLength : 255; + if (len > desc_length) len = desc_length; + do { + // wait for host ready for IN packet + do { + i = UEINTX; + } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); + if (i & (1<<RXOUTI)) return; // abort + // send IN packet + n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; + for (i = n; i; i--) { + UEDATX = pgm_read_byte(desc_addr++); + } + len -= n; + usb_send_in(); + } while (len || n == ENDPOINT0_SIZE); + return; + } + if (bRequest == SET_ADDRESS) { + usb_send_in(); + usb_wait_in_ready(); + UDADDR = wValue | (1<<ADDEN); + return; + } + if (bRequest == SET_CONFIGURATION && bmRequestType == 0) { + usb_configuration = wValue; + cdc_line_rtsdtr = 0; + transmit_flush_timer = 0; + usb_send_in(); + cfg = endpoint_config_table; + for (i=1; i<6; i++) { // 4+1 of 7 endpoints are used // XXX Important to change if more endpoints are used + UENUM = i; + en = pgm_read_byte(cfg++); + UECONX = en; + if (en) { + UECFG0X = pgm_read_byte(cfg++); + UECFG1X = pgm_read_byte(cfg++); + } + } + UERST = 0x1E; + UERST = 0; + return; + } + if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) { + usb_wait_in_ready(); + UEDATX = usb_configuration; + usb_send_in(); + return; + } + + if (bRequest == CDC_GET_LINE_CODING && bmRequestType == 0xA1) { + usb_wait_in_ready(); + p = cdc_line_coding; + for (i=0; i<7; i++) { + UEDATX = *p++; + } + usb_send_in(); + return; + } + + if (bRequest == CDC_SET_LINE_CODING && bmRequestType == 0x21) { + usb_wait_receive_out(); + p = cdc_line_coding; + for (i=0; i<7; i++) { + *p++ = UEDATX; + } + usb_ack_out(); + usb_send_in(); + return; + } + + if (bRequest == CDC_SET_CONTROL_LINE_STATE && bmRequestType == 0x21) { + cdc_line_rtsdtr = wValue; + usb_wait_in_ready(); + usb_send_in(); + return; + } + + if (bRequest == GET_STATUS) { + usb_wait_in_ready(); + i = 0; + #ifdef SUPPORT_ENDPOINT_HALT + if (bmRequestType == 0x82) { + UENUM = wIndex; + if (UECONX & (1<<STALLRQ)) i = 1; + UENUM = 0; + } + #endif + UEDATX = i; + UEDATX = 0; + usb_send_in(); + return; + } + + #ifdef SUPPORT_ENDPOINT_HALT + if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) + && bmRequestType == 0x02 && wValue == 0) { + i = wIndex & 0x7F; + if (i >= 1 && i <= MAX_ENDPOINT) { + usb_send_in(); + UENUM = i; + if (bRequest == SET_FEATURE) { + UECONX = (1<<STALLRQ)|(1<<EPEN); + } else { + UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN); + UERST = (1 << i); + UERST = 0; + } + return; + } + } + #endif + + if (wIndex == KEYBOARD_INTERFACE) { + if (bmRequestType == 0xA1) { + if (bRequest == HID_GET_REPORT) { + usb_wait_in_ready(); + UEDATX = USBKeys_Modifiers; + UEDATX = 0; + for (i=0; i<6; i++) { + UEDATX = USBKeys_Array[i]; + } + usb_send_in(); + return; + } + if (bRequest == HID_GET_IDLE) { + usb_wait_in_ready(); + UEDATX = USBKeys_Idle_Config; + usb_send_in(); + return; + } + if (bRequest == HID_GET_PROTOCOL) { + usb_wait_in_ready(); + UEDATX = USBKeys_Protocol; + usb_send_in(); + return; + } + } + if (bmRequestType == 0x21) { + if (bRequest == HID_SET_REPORT) { + usb_wait_receive_out(); + USBKeys_LEDs = UEDATX; + usb_ack_out(); + usb_send_in(); + return; + } + if (bRequest == HID_SET_IDLE) { + USBKeys_Idle_Config = (wValue >> 8); + USBKeys_Idle_Count = 0; + //usb_wait_in_ready(); + usb_send_in(); + return; + } + if (bRequest == HID_SET_PROTOCOL) { + USBKeys_Protocol = wValue; + //usb_wait_in_ready(); + usb_send_in(); + return; + } + } + } + } + UECONX = (1<<STALLRQ) | (1<<EPEN); // stall +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Output/pjrcUSB/avr/usb_keyboard_serial.h Mon Mar 31 01:07:48 2014 -0700 @@ -0,0 +1,221 @@ +/* USB Keyboard and CDC Serial Device for Teensy USB Development Board + * Copyright (c) 2009 PJRC.COM, LLC + * Modifications by Jacob Alexander (2011-2014) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef usb_keyboard_serial_h__ +#define usb_keyboard_serial_h__ + +// Compiler Includes +#include <stdint.h> + +// AVR Includes +#include <avr/io.h> +#include <avr/pgmspace.h> +#include <avr/interrupt.h> +#include <avr/wdt.h> + +// AVR Util Includes +#include <util/delay.h> + +// Local Includes +#include "output_com.h" + + +// ----- Function Declarations ----- + +// Basic USB Configuration +void usb_init(void); // initialize everything +uint8_t usb_configured(void); // is the USB port configured + +// Keyboard HID Functions +int8_t usb_keyboard_send(void); + +// Chip Level Functions +void usb_debug_reload(); // Enable firmware reflash mode +void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3"))); // Needed for software reset + +// USB Serial CDC Functions +int16_t usb_serial_getchar(void); // receive a character (-1 if timeout/error) +uint8_t usb_serial_available(void); // number of bytes in receive buffer +void usb_serial_flush_input(void); // discard any buffered input + +// transmitting data +int8_t usb_serial_putchar(uint8_t c); // transmit a character +int8_t usb_serial_putchar_nowait(uint8_t c); // transmit a character, do not wait +int8_t usb_serial_write(const char *buffer, uint16_t size); // transmit a buffer +void usb_serial_flush_output(void); // immediately transmit any buffered output + +// serial parameters +uint32_t usb_serial_get_baud(void); // get the baud rate +uint8_t usb_serial_get_stopbits(void); // get the number of stop bits +uint8_t usb_serial_get_paritytype(void);// get the parity type +uint8_t usb_serial_get_numbits(void); // get the number of data bits +uint8_t usb_serial_get_control(void); // get the RTS and DTR signal state +int8_t usb_serial_set_control(uint8_t signals); // set DSR, DCD, RI, etc + + + +// ----- Macros ----- + +// Software reset the chip +#define usb_debug_software_reset() do { wdt_enable( WDTO_15MS ); for(;;); } while(0) + +#define EP_SIZE(s) ((s) == 64 ? 0x30 : \ + ((s) == 32 ? 0x20 : \ + ((s) == 16 ? 0x10 : \ + 0x00))) + +#define LSB(n) (n & 255) +#define MSB(n) ((n >> 8) & 255) + + + +// ----- Defines ----- + +// constants corresponding to the various serial parameters +#define USB_SERIAL_DTR 0x01 +#define USB_SERIAL_RTS 0x02 +#define USB_SERIAL_1_STOP 0 +#define USB_SERIAL_1_5_STOP 1 +#define USB_SERIAL_2_STOP 2 +#define USB_SERIAL_PARITY_NONE 0 +#define USB_SERIAL_PARITY_ODD 1 +#define USB_SERIAL_PARITY_EVEN 2 +#define USB_SERIAL_PARITY_MARK 3 +#define USB_SERIAL_PARITY_SPACE 4 +#define USB_SERIAL_DCD 0x01 +#define USB_SERIAL_DSR 0x02 +#define USB_SERIAL_BREAK 0x04 +#define USB_SERIAL_RI 0x08 +#define USB_SERIAL_FRAME_ERR 0x10 +#define USB_SERIAL_PARITY_ERR 0x20 +#define USB_SERIAL_OVERRUN_ERR 0x40 + +#define EP_TYPE_CONTROL 0x00 +#define EP_TYPE_BULK_IN 0x81 +#define EP_TYPE_BULK_OUT 0x80 +#define EP_TYPE_INTERRUPT_IN 0xC1 +#define EP_TYPE_INTERRUPT_OUT 0xC0 +#define EP_TYPE_ISOCHRONOUS_IN 0x41 +#define EP_TYPE_ISOCHRONOUS_OUT 0x40 + +#define EP_SINGLE_BUFFER 0x02 +#define EP_DOUBLE_BUFFER 0x06 + +#define MAX_ENDPOINT 4 + +#if defined(__AVR_AT90USB162__) +#define HW_CONFIG() +#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0))) +#define USB_CONFIG() (USBCON = (1<<USBE)) +#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) + +#elif defined(__AVR_ATmega32U4__) +#define HW_CONFIG() (UHWCON = 0x01) +#define PLL_CONFIG() (PLLCSR = 0x12) +#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) +#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) + +#elif defined(__AVR_AT90USB646__) +#define HW_CONFIG() (UHWCON = 0x81) +#define PLL_CONFIG() (PLLCSR = 0x1A) +#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) +#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) + +#elif defined(__AVR_AT90USB1286__) +#define HW_CONFIG() (UHWCON = 0x81) +#define PLL_CONFIG() (PLLCSR = 0x16) +#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) +#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) +#endif + +// standard control endpoint request types +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 + +// HID (human interface device) +#define HID_GET_REPORT 1 +#define HID_GET_IDLE 2 +#define HID_GET_PROTOCOL 3 +#define HID_SET_REPORT 9 +#define HID_SET_IDLE 10 +#define HID_SET_PROTOCOL 11 + +// CDC (communication class device) +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 + + + +// ----- Endpoint Configuration ----- + +#define ENDPOINT0_SIZE 32 + +#define KEYBOARD_INTERFACE 0 +#define KEYBOARD_ENDPOINT 2 +#define KEYBOARD_SIZE 8 +#define KEYBOARD_INTERVAL 1 +#define KEYBOARD_HID_BUFFER EP_DOUBLE_BUFFER + +#define CDC_IAD_DESCRIPTOR 1 +#define CDC_STATUS_INTERFACE 1 +#define CDC_DATA_INTERFACE 2 +#define CDC_ACM_ENDPOINT 3 +#define CDC_RX_ENDPOINT 4 +#define CDC_TX_ENDPOINT 5 +#if defined(__AVR_AT90USB162__) +#define CDC_ACM_SIZE 16 +#define CDC_ACM_BUFFER EP_SINGLE_BUFFER +#define CDC_RX_SIZE 32 +#define CDC_RX_BUFFER EP_DOUBLE_BUFFER +#define CDC_TX_SIZE 32 +#define CDC_TX_BUFFER EP_DOUBLE_BUFFER +#else +#define CDC_ACM_SIZE 16 +#define CDC_ACM_BUFFER EP_SINGLE_BUFFER +#define CDC_RX_SIZE 64 +#define CDC_RX_BUFFER EP_DOUBLE_BUFFER +#define CDC_TX_SIZE 64 +#define CDC_TX_BUFFER EP_DOUBLE_BUFFER +#endif + +// Endpoint 0 is reserved for the control endpoint +// Endpoint 1 has a 256 byte buffer +// Endpoints 2-6 have 64 byte buffers +static const uint8_t PROGMEM endpoint_config_table[] = { + 0, // 256 byte + 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_HID_BUFFER, // 64 byte + 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(CDC_ACM_SIZE) | CDC_ACM_BUFFER, // 64 byte + 1, EP_TYPE_BULK_OUT, EP_SIZE(CDC_RX_SIZE) | CDC_RX_BUFFER, // 64 byte + 1, EP_TYPE_BULK_IN, EP_SIZE(CDC_TX_SIZE) | CDC_TX_BUFFER, // 64 byte +}; + +#endif // usb_keyboard_serial_h__ +
--- a/Output/pjrcUSB/output_com.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Output/pjrcUSB/output_com.c Mon Mar 31 01:07:48 2014 -0700 @@ -25,11 +25,13 @@ #include <Lib/OutputLib.h> // Project Includes +#include <cli.h> +#include <print.h> #include <scan_loop.h> // USB Includes #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) -#include "avr/usb_keyboard_debug.h" +#include "avr/usb_keyboard_serial.h" #elif defined(_mk20dx128_) || defined(_mk20dx256_) #include "arm/usb_keyboard.h" #include "arm/usb_dev.h" @@ -40,8 +42,31 @@ +// ----- Function Declarations ----- + +void cliFunc_holdKey ( char* args ); +void cliFunc_readLEDs ( char* args ); +void cliFunc_releaseKey( char* args ); +void cliFunc_sendKey ( char* args ); +void cliFunc_setLEDs ( char* args ); +void cliFunc_setMod ( char* args ); + + // ----- Variables ----- +// Output Module command dictionary +char* outputCLIDictName = "USB Module Commands"; +CLIDictItem outputCLIDict[] = { + { "holdKey", "Hold a space separated list of USB codes. Ignores already pressed keys.", cliFunc_holdKey }, + { "readLEDs", "Read LED byte. See setLEDs.", cliFunc_readLEDs }, + { "releaseKey", "Release a space separated list of USB codes. Ignores unpressed keys.", cliFunc_releaseKey }, + { "sendKey", "Send a space separated list of USB codes. Press/Release.", cliFunc_sendKey }, + { "setLEDs", "Set LED byte: 1 NumLck, 2 CapsLck, 4 ScrlLck, 16 Kana, etc.", cliFunc_setLEDs }, + { "setMod", "Set the modfier byte: 1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUI", cliFunc_setMod }, + { 0, 0, 0 } // Null entry for dictionary end +}; + + // which modifier keys are currently pressed // 1=left ctrl, 2=left shift, 4=left alt, 8=left gui // 16=right ctrl, 32=right shift, 64=right alt, 128=right gui @@ -69,7 +94,6 @@ uint8_t USBKeys_Idle_Count = 0; - // ----- Functions ----- // USB Module Setup @@ -81,9 +105,12 @@ usb_init(); while ( !usb_configured() ) /* wait */ ; + // Register USB Output dictionary + registerDictionary_cli( outputCLIDict, outputCLIDictName ); + // Wait an extra second for the PC's operating system to load drivers // and do whatever it does to actually be ready for input - //_delay_ms(1000); // TODO + //_delay_ms(1000); // TODO (is this actually necessary?) } @@ -110,8 +137,102 @@ inline void output_firmwareReload() { #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) + usb_debug_reload(); #elif defined(_mk20dx128_) || defined(_mk20dx256_) usb_device_reload(); #endif } + +// USB Input buffer available +inline unsigned int output_availablechar() +{ + return usb_serial_available(); +} + + +// USB Get Character from input buffer +inline int output_getchar() +{ +#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) + // XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) + return (int)usb_serial_getchar(); +#elif defined(_mk20dx128_) || defined(_mk20dx256_) + return usb_serial_getchar(); +#endif +} + + +// USB Send Character to output buffer +inline int output_putchar( char c ) +{ + return usb_serial_putchar( c ); +} + + +// USB Send String to output buffer, null terminated +inline int output_putstr( char* str ) +{ +#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR + uint16_t count = 0; +#elif defined(_mk20dx128_) || defined(_mk20dx256_) // ARM + uint32_t count = 0; +#endif + // Count characters until NULL character, then send the amount counted + while ( str[count] != '\0' ) + count++; + + return usb_serial_write( str, count ); +} + + +// Soft Chip Reset +inline void output_softReset() +{ +#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) + usb_debug_software_reset(); +#elif defined(_mk20dx128_) || defined(_mk20dx256_) + SOFTWARE_RESET(); +#endif +} + + +// ----- CLI Command Functions ----- + +void cliFunc_holdKey( char* args ) +{ + // TODO +} + + +void cliFunc_readLEDs( char* args ) +{ + // TODO +} + + +void cliFunc_releaseKey( char* args ) +{ + // TODO +} + + +void cliFunc_sendKey( char* args ) +{ + // TODO Argument handling + USBKeys_Array[0] = 4; // KEY_A + USBKeys_Sent = 1; +} + + +void cliFunc_setLEDs( char* args ) +{ + // TODO +} + + +void cliFunc_setMod( char* args ) +{ + // TODO +} +
--- a/Output/pjrcUSB/output_com.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Output/pjrcUSB/output_com.h Mon Mar 31 01:07:48 2014 -0700 @@ -59,10 +59,17 @@ // ----- Functions ----- void output_setup(); - void output_send(); void output_firmwareReload(); +void output_softReset(); + +// Relies on USB serial module +unsigned int output_availablechar(); + +int output_getchar(); +int output_putchar( char c ); +int output_putstr( char* str ); #endif
--- a/Output/pjrcUSB/setup.cmake Sat Mar 22 14:32:06 2014 -0700 +++ b/Output/pjrcUSB/setup.cmake Mon Mar 31 01:07:48 2014 -0700 @@ -17,7 +17,7 @@ set( OUTPUT_SRCS output_com.c - avr/usb_keyboard_debug.c + avr/usb_keyboard_serial.c ) #| ARM Compiler
--- a/README Sat Mar 22 14:32:06 2014 -0700 +++ b/README Mon Mar 31 01:07:48 2014 -0700 @@ -24,10 +24,12 @@ - avr-libc (1.8.0) -ARM Specific (Teensy 3.0) (Sourcery CodeBench Lite for ARM EABI +ARM Specific (Teensy 3.0/3.1) (Sourcery CodeBench Lite for ARM EABI (http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/) - arm-none-eabi -- TODO? +OR +- arm-none-eabi-gcc +- arm-none-eaby-binutils @@ -42,6 +44,7 @@ - Teensy 2.0 - Teensy 2.0++ - Teensy 3.0 + - Teensy 3.1 Open up CMakeLists.txt in your favourite text editor. You are looking for: @@ -57,13 +60,14 @@ #| "avr" # Teensy++ 1.0 #| "avr" # Teensy++ 2.0 #| "arm" # Teensy 3.0 + #| "arm" # Teensy 3.1 set( COMPILER_FAMILY "avr" ) Just change the COMPILER_FAMILY variable to whatever you are trying to build for. -NOTE: If you change this option, you will *may* to delete the build directory that is created in the Building sections below. +NOTE: If you change this option, you will *may* to delete the build directory that is created in the Building sections below. @@ -102,6 +106,7 @@ #| type "make clean" after changing this, so all files will be rebuilt #| #| "mk20dx128" # Teensy 3.0 + #| "mk20dx256" # Teensy 3.1 set( CHIP "mk20dx128" ) @@ -123,7 +128,7 @@ - Scan Module - Macro Module -- USB Module +- Output Module - Debug Module The Scan Module is where the most interesting stuff happens. These modules take in "keypress data". @@ -135,11 +140,11 @@ Some scan modules have very specialized hardware requirements, each module directory should have at least a link to the needed parts and/or schematics (TODO!). -The Macro Module takes care of the mapping of the key press/release code into a USB scan code. +The Macro Module takes care of the mapping of the key press/release code into an Output (USB) scan code. Any layering, macros, keypress intelligence/reaction is done here. -The USB Module is the output module of the microcontroller. Currently USB is the only output protocol. +The Output Module is the module dealing with output from the microcontroller. Currently USB is the only output protocol. Different USB output implementations are available, pjrc being the safest/least featureful one. Debug capabilities may depend on the module selected. @@ -161,7 +166,7 @@ #| All of the modules must be specified, as they generate the sources list of files to compile #| Any modifications to this file will cause a complete rebuild of the project - #| Please look at the {Scan,Macro,USB,Debug}/module.txt for information on the modules and how to create new ones + #| Please look at the {Scan,Macro,Output,Debug}/module.txt for information on the modules and how to create new ones ##| Deals with acquiring the keypress information and turning it into a key index set( ScanModule "avr-capsense" ) @@ -170,7 +175,7 @@ set( MacroModule "buffer" ) ##| Sends the current list of usb key codes through USB HID - set( USBModule "pjrc" ) + set( OutputModule "pjrc" ) ##| Debugging source to use, each module has it's own set of defines that it sets set( DebugModule "full" ) @@ -206,8 +211,8 @@ Scan/avr-capsense/scan_loop.c -- Detected Macro Module Source Files: Macro/buffer/macro.c - -- Detected USB Module Source Files: - USB/pjrc/usb_com.c;USB/pjrc/avr/usb_keyboard_debug.c + -- Detected Output Module Source Files: + Output/pjrc/usb_com.c;Output/pjrc/avr/usb_keyboard_debug.c -- Detected Debug Module Source Files: Debug/full/../led/led.c;Debug/full/../print/print.c -- Configuring done @@ -218,8 +223,8 @@ [ 12%] Building C object CMakeFiles/kiibohd.elf.dir/main.c.o [ 25%] Building C object CMakeFiles/kiibohd.elf.dir/Scan/avr-capsense/scan_loop.c.o [ 37%] Building C object CMakeFiles/kiibohd.elf.dir/Macro/buffer/macro.c.o - [ 50%] Building C object CMakeFiles/kiibohd.elf.dir/USB/pjrc/usb_com.c.o - [ 62%] Building C object CMakeFiles/kiibohd.elf.dir/USB/pjrc/avr/usb_keyboard_debug.c.o + [ 50%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrc/usb_com.c.o + [ 62%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrc/avr/usb_keyboard_debug.c.o [ 75%] Building C object CMakeFiles/kiibohd.elf.dir/Debug/led/led.c.o [ 87%] Building C object CMakeFiles/kiibohd.elf.dir/Debug/print/print.c.o Linking C executable kiibohd.elf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/DPH/scan_loop.c Mon Mar 31 01:07:48 2014 -0700 @@ -0,0 +1,1012 @@ +/* Copyright (C) 2011-2013 by Joseph Makuch + * Additions by Jacob Alexander (2013-2014) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +// ----- Includes ----- + +// Compiler Includes +#include <Lib/ScanLib.h> + +// Project Includes +#include <led.h> +#include <print.h> + +// Local Includes +#include "scan_loop.h" + + + +// ----- Defines ----- + +// TODO dfj defines...needs commenting and maybe some cleaning... +#define MAX_PRESS_DELTA_MV 450 // As measured from the Teensy ADC pin +#define THRESHOLD_MV (MAX_PRESS_DELTA_MV >> 1) +//(2560 / (0x3ff/2)) ~= 5 +#define MV_PER_ADC 5 +#define THRESHOLD (THRESHOLD_MV / MV_PER_ADC) + +#define STROBE_SETTLE 1 + +#define TEST_KEY_STROBE (0x05) +#define TEST_KEY_MASK (1 << 0) + +#define ADHSM 7 + +#define RIGHT_JUSTIFY 0 +#define LEFT_JUSTIFY (0xff) + +// set left or right justification here: +#define JUSTIFY_ADC RIGHT_JUSTIFY +#define ADLAR_MASK (1 << ADLAR) + +#ifdef JUSTIFY_ADC +#define ADLAR_BITS ((ADLAR_MASK) & (JUSTIFY_ADC)) +#else // defaults to right justification. +#define ADLAR_BITS 0 +#endif + +// full muxmask +#define FULL_MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2) | (1 << MUX3) | (1 << MUX4)) + +// F0-f7 pins only muxmask. +#define MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2)) + +// Strobe Masks +#define D_MASK (0xff) +#define E_MASK (0x03) +#define C_MASK (0xff) + +// set ADC clock prescale +#define PRESCALE_MASK ((1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2)) +#define PRESCALE_SHIFT (ADPS0) +#define PRESCALE 3 + +// Max number of strobes supported by the hardware +// Strobe lines are detected at startup, extra strobes cause anomalies like phantom keypresses +#define MAX_STROBES 18 + +// Number of consecutive samples required to pass debounce +#define DEBOUNCE_THRESHOLD 5 + +#define MUXES_COUNT 8 +#define MUXES_COUNT_XSHIFT 3 + +#define WARMUP_LOOPS ( 1024 ) +#define WARMUP_STOP (WARMUP_LOOPS - 1) + +#define SAMPLE_CONTROL 3 + +#define KEY_COUNT ((MAX_STROBES) * (MUXES_COUNT)) + +#define RECOVERY_CONTROL 1 +#define RECOVERY_SOURCE 0 +#define RECOVERY_SINK 2 + +#define ON 1 +#define OFF 0 + +// mix in 1/4 of the current average to the running average. -> (@mux_mix = 2) +#define MUX_MIX 2 + +#define IDLE_COUNT_MASK 0xff +#define IDLE_COUNT_SHIFT 8 + +// av = (av << shift) - av + sample; av >>= shift +// e.g. 1 -> (av + sample) / 2 simple average of new and old +// 2 -> (3 * av + sample) / 4 i.e. 3:1 mix of old to new. +// 3 -> (7 * av + sample) / 8 i.e. 7:1 mix of old to new. +#define KEYS_AVERAGES_MIX_SHIFT 3 + + + +// ----- Macros ----- + +// Make sure we haven't overflowed the buffer +#define bufferAdd(byte) \ + if ( KeyIndex_BufferUsed < KEYBOARD_BUFFER ) \ + KeyIndex_Buffer[KeyIndex_BufferUsed++] = byte + +// Select mux +#define SET_FULL_MUX(X) ((ADMUX) = (((ADMUX) & ~(FULL_MUX_MASK)) | ((X) & (FULL_MUX_MASK)))) + + + +// ----- Variables ----- + +// Buffer used to inform the macro processing module which keys have been detected as pressed +volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER]; +volatile uint8_t KeyIndex_BufferUsed; + + +// TODO dfj variables...needs cleaning up and commenting + +// Variables used to calculate the starting sense value (averaging) +uint32_t full_avg = 0; +uint32_t high_avg = 0; +uint32_t low_avg = 0; + +uint8_t high_count = 0; +uint8_t low_count = 0; + + +uint8_t ze_strober = 0; + +uint16_t samples[MUXES_COUNT]; + +uint8_t cur_keymap[MAX_STROBES]; + +uint8_t keymap_change; + +uint16_t threshold = THRESHOLD; + +uint8_t column = 0; + +uint16_t keys_averages_acc[KEY_COUNT]; +uint16_t keys_averages [KEY_COUNT]; +uint8_t keys_debounce [KEY_COUNT]; // Contains debounce statistics +uint8_t keys_problem [KEY_COUNT]; // Marks keys that should be ignored (determined by averaging at startup) + +uint8_t full_samples[KEY_COUNT]; + +// TODO: change this to 'booting', then count down. +uint16_t boot_count = 0; + +uint16_t idle_count = 0; +uint8_t idle = 1; + +uint8_t error = 0; +uint16_t error_data = 0; + +uint8_t total_strobes = MAX_STROBES; +uint8_t strobe_map[MAX_STROBES]; + +uint8_t dump_count = 0; + + + +// ----- Function Declarations ----- + +void dump( void ); + +void recovery( uint8_t on ); + +int sampleColumn( uint8_t column ); + +void capsense_scan( void ); + +void setup_ADC( void ); + +void strobe_w( uint8_t strobe_num ); + +uint8_t testColumn( uint8_t strobe ); + + + +// ----- Functions ----- + +// Initial setup for cap sense controller +inline void scan_setup() +{ + // TODO dfj code...needs cleanup + commenting... + setup_ADC(); + + DDRC = C_MASK; + PORTC = 0; + DDRD = D_MASK; + PORTD = 0; + DDRE = E_MASK; + PORTE = 0 ; + + // Hardcoded strobes for debugging + // Strobes start at 0 and go to 17 (18), not all Model Fs use all of the available strobes + // The single row ribbon connector Model Fs only have a max of 16 strobes +#define KISHSAVER_STROBE +//#define KISHSAVER_OLD_STROBE +//#define TERMINAL_6110668_OLD_STROBE +//#define UNSAVER_OLD_STROBE +#ifdef KISHSAVER_OLD_STROBE + total_strobes = 9; + + strobe_map[0] = 2; // Kishsaver doesn't use strobe 0 and 1 + strobe_map[1] = 3; + strobe_map[2] = 4; + strobe_map[3] = 5; + strobe_map[4] = 6; + strobe_map[5] = 7; + strobe_map[6] = 8; + strobe_map[7] = 9; + strobe_map[8] = 15; // Test point strobe (3 test points, sense 1, 4, 5) +#elif defined(KISHSAVER_STROBE) + total_strobes = 9; + + strobe_map[0] = 15; // Kishsaver doesn't use strobe 0 and 1 + strobe_map[1] = 14; + strobe_map[2] = 13; + strobe_map[3] = 12; + strobe_map[4] = 11; + strobe_map[5] = 10; + strobe_map[6] = 9; + strobe_map[7] = 8; + strobe_map[8] = 2; // Test point strobe (3 test points, sense 1, 4, 5) +#elif defined(TERMINAL_6110668_OLD_STROBE) + total_strobes = 16; + + strobe_map[0] = 0; + strobe_map[1] = 1; + strobe_map[2] = 2; + strobe_map[3] = 3; + strobe_map[4] = 4; + strobe_map[5] = 5; + strobe_map[6] = 6; + strobe_map[7] = 7; + strobe_map[8] = 8; + strobe_map[9] = 9; + strobe_map[10] = 10; + strobe_map[11] = 11; + strobe_map[12] = 12; + strobe_map[13] = 13; + strobe_map[14] = 14; + strobe_map[15] = 15; +#elif defined(UNSAVER_OLD_STROBE) + total_strobes = 14; + + strobe_map[0] = 0; + strobe_map[1] = 1; + strobe_map[2] = 2; + strobe_map[3] = 3; + strobe_map[4] = 4; + strobe_map[5] = 5; + strobe_map[6] = 6; + strobe_map[7] = 7; + strobe_map[8] = 8; + strobe_map[9] = 9; + strobe_map[10] = 10; + strobe_map[11] = 11; + strobe_map[12] = 12; + strobe_map[13] = 13; +#else + // Strobe detection + // TODO +#endif + + // TODO all this code should probably be in scan_resetKeyboard + for ( int i = 0; i < total_strobes; ++i) + { + cur_keymap[i] = 0; + } + + // Reset debounce table + for ( int i = 0; i < KEY_COUNT; ++i ) + { + keys_debounce[i] = 0; + } + + // Warm things up a bit before we start collecting data, taking real samples. + for ( uint8_t i = 0; i < total_strobes; ++i ) + { + sampleColumn( strobe_map[i] ); + } + + + // Reset the keyboard before scanning, we might be in a wierd state + // Also sets the KeyIndex_BufferUsed to 0 + scan_resetKeyboard(); +} + + +// Main Detection Loop +// This is where the important stuff happens +inline uint8_t scan_loop() +{ + capsense_scan(); + + // Error case, should not occur in normal operation + if ( error ) + { + erro_msg("Problem detected... "); + + // Keymap scan debug + for ( uint8_t i = 0; i < total_strobes; ++i ) + { + printHex(cur_keymap[strobe_map[i]]); + print(" "); + } + + print(" : "); + printHex(error); + error = 0; + print(" : "); + printHex(error_data); + error_data = 0; + + // Display keymaps and other debug information if warmup completede + if ( boot_count >= WARMUP_LOOPS ) + { + dump(); + } + } + + + // Return non-zero if macro and USB processing should be delayed + // Macro processing will always run if returning 0 + // USB processing only happens once the USB send timer expires, if it has not, scan_loop will be called + // after the macro processing has been completed + return 0; +} + + +// Reset Keyboard +void scan_resetKeyboard( void ) +{ + // Empty buffer, now that keyboard has been reset + KeyIndex_BufferUsed = 0; +} + + +// Send data to keyboard +// NOTE: Only used for converters, since the scan module shouldn't handle sending data in a controller +uint8_t scan_sendData( uint8_t dataPayload ) +{ + return 0; +} + + +// Reset/Hold keyboard +// NOTE: Only used for converters, not needed for full controllers +void scan_lockKeyboard( void ) +{ +} + +// NOTE: Only used for converters, not needed for full controllers +void scan_unlockKeyboard( void ) +{ +} + + +// Signal KeyIndex_Buffer that it has been properly read +// NOTE: Only really required for implementing "tricks" in converters for odd protocols +void scan_finishedWithBuffer( uint8_t sentKeys ) +{ + // Convenient place to clear the KeyIndex_Buffer + KeyIndex_BufferUsed = 0; + return; +} + + +// Signal KeyIndex_Buffer that it has been properly read and sent out by the USB module +// NOTE: Only really required for implementing "tricks" in converters for odd protocols +void scan_finishedWithUSBBuffer( uint8_t sentKeys ) +{ + return; +} + + +inline void capsense_scan() +{ + // Accumulated average used for the next scan + uint32_t cur_full_avg = 0; + uint32_t cur_high_avg = 0; + + // Reset average counters + low_avg = 0; + low_count = 0; + + high_count = 0; + + // Scan each of the mapped strobes in the matrix + for ( uint8_t strober = 0; strober < total_strobes; ++strober ) + { + uint8_t map_strobe = strobe_map[strober]; + + uint8_t tries = 1; + while ( tries++ && sampleColumn( map_strobe ) ) { tries &= 0x7; } // don't waste this one just because the last one was poop. + + // Only process sense data if warmup is finished + if ( boot_count >= WARMUP_LOOPS ) + { + column = testColumn( map_strobe ); + + idle |= column; // if column has any pressed keys, then we are not idle. + + // TODO Is this needed anymore? Really only helps debug -HaaTa + if( column != cur_keymap[map_strobe] && ( boot_count >= WARMUP_LOOPS ) ) + { + cur_keymap[map_strobe] = column; + keymap_change = 1; + } + + idle |= keymap_change; // if any keys have changed inc. released, then we are not idle. + } + + if ( error == 0x50 ) + { + error_data |= (((uint16_t)map_strobe) << 12); + } + + uint8_t strobe_line = map_strobe << MUXES_COUNT_XSHIFT; + for ( int i = 0; i < MUXES_COUNT; ++i ) + { + // discard sketchy low bit, and meaningless high bits. + uint8_t sample = samples[i] >> 1; + full_samples[strobe_line + i] = sample; + keys_averages_acc[strobe_line + i] += sample; + } + + // Accumulate 3 total averages (used for determining starting average during warmup) + // full_avg - Average of all sampled lines on the previous scan set + // cur_full_avg - Average of all sampled lines for this scan set + // high_avg - Average of all sampled lines above full_avg on the previous scan set + // cur_high_avg - Average of all sampled lines above full_avg + // low_avg - Average of all sampled lines below or equal to full_avg + if ( boot_count < WARMUP_LOOPS ) + { + for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) + { + uint8_t sample = samples[i] >> 1; + + // Sample is high, add it to high avg + if ( sample > full_avg ) + { + high_count++; + cur_high_avg += sample; + } + // Sample is low, add it to low avg + else + { + low_count++; + low_avg += sample; + } + + // If sample is higher than previous high_avg, then mark as "problem key" + keys_problem[strobe_line + i] = sample > high_avg ? sample : 0; + + // Prepare for next average + cur_full_avg += sample; + } + } + } // for strober + + // Update total sense average (only during warm-up) + if ( boot_count < WARMUP_LOOPS ) + { + full_avg = cur_full_avg / (total_strobes * MUXES_COUNT); + high_avg = cur_high_avg / high_count; + low_avg /= low_count; + + // Update the base average value using the low_avg (best chance of not ignoring a keypress) + for ( int i = 0; i < KEY_COUNT; ++i ) + { + keys_averages[i] = low_avg; + keys_averages_acc[i] = low_avg; + } + } + +#ifdef VERIFY_TEST_PAD + // verify test key is not down. + if ( ( cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK ) ) + { + error = 0x05; + error_data = cur_keymap[TEST_KEY_STROBE] << 8; + error_data += full_samples[TEST_KEY_STROBE * 8]; + } +#endif + + /** aggregate if booting, or if idle; + * else, if not booting, check for dirty USB. + * */ + + idle_count++; + idle_count &= IDLE_COUNT_MASK; + + // Warm up voltage references + if ( boot_count < WARMUP_LOOPS ) + { + boot_count++; + + switch ( boot_count ) + { + // First loop + case 1: + // Show msg at first iteration only + info_msg("Warming up the voltage references"); + break; + // Middle iterations + case 300: + case 600: + case 900: + case 1200: + print("."); + break; + // Last loop + case WARMUP_STOP: + print("\n"); + info_msg("Warmup finished using "); + printInt16( WARMUP_LOOPS ); + print(" iterations\n"); + + // Display the final calculated averages of all the sensed strobes + info_msg("Full average ("); + printInt8( total_strobes * MUXES_COUNT ); + print("): "); + printHex( full_avg ); + + print(" High average ("); + printInt8( high_count ); + print("): "); + printHex( high_avg ); + + print(" Low average ("); + printInt8( low_count ); + print("): "); + printHex( low_avg ); + print("\n"); + + // Display problem keys, and the sense value at the time + for ( uint8_t key = 0; key < KEY_COUNT; key++ ) + { + if ( keys_problem[key] ) + { + warn_msg("Problem key detected: "); + printHex( key ); + print(" ("); + printHex( keys_problem[key] ); + print(")\n"); + } + } + + info_print("If problem keys were detected, and were being held down, they will be reset as soon as let go"); + break; + } + } + else + { + // Reset accumulators and idle flag/counter + if ( keymap_change ) + { + for ( uint8_t c = 0; c < KEY_COUNT; ++c ) { keys_averages_acc[c] = 0; } + idle_count = 0; + idle = 0; + + keymap_change = 0; + } + + if ( !idle_count ) + { + if( idle ) + { + // aggregate + for ( uint8_t i = 0; i < KEY_COUNT; ++i ) + { + uint16_t acc = keys_averages_acc[i] >> IDLE_COUNT_SHIFT; + uint32_t av = keys_averages[i]; + + av = (av << KEYS_AVERAGES_MIX_SHIFT) - av + acc; + av >>= KEYS_AVERAGES_MIX_SHIFT; + + keys_averages[i] = av; + keys_averages_acc[i] = 0; + } + } + + if ( boot_count >= WARMUP_LOOPS ) + { + dump(); + } + } + + } +} + + +void setup_ADC() +{ + // disable adc digital pins. + DIDR1 |= (1 << AIN0D) | (1<<AIN1D); // set disable on pins 1,0. + DDRF = 0x0; + PORTF = 0x0; + uint8_t mux = 0 & 0x1f; // 0 == first. // 0x1e = 1.1V ref. + + // 0 = external aref 1,1 = 2.56V internal ref + uint8_t aref = ((1 << REFS1) | (1 << REFS0)) & ((1 << REFS1) | (1 << REFS0)); + uint8_t adate = (1 << ADATE) & (1 << ADATE); // trigger enable + uint8_t trig = 0 & ((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2)); // 0 = free running + // ps2, ps1 := /64 ( 2^6 ) ps2 := /16 (2^4), ps1 := 4, ps0 :=2, PS1,PS0 := 8 (2^8) + uint8_t prescale = ( ((PRESCALE) << PRESCALE_SHIFT) & PRESCALE_MASK ); // 001 == 2^1 == 2 + uint8_t hispeed = (1 << ADHSM); + uint8_t en_mux = (1 << ACME); + + ADCSRA = (1 << ADEN) | prescale; // ADC enable + + // select ref. + //ADMUX |= ((1 << REFS1) | (1 << REFS0)); // 2.56 V internal. + //ADMUX |= ((1 << REFS0) ); // Vcc with external cap. + //ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // 0,0 : aref. + ADMUX = aref | mux | ADLAR_BITS; + + // set free-running + ADCSRA |= adate; // trigger enable + ADCSRB = en_mux | hispeed | trig | (ADCSRB & ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2))); // trigger select free running + + ADCSRA |= (1 << ADEN); // ADC enable + ADCSRA |= (1 << ADSC); // start conversions q +} + + +void recovery( uint8_t on ) +{ + DDRB |= (1 << RECOVERY_CONTROL); + PORTB &= ~(1 << RECOVERY_SINK); // SINK always zero + DDRB &= ~(1 << RECOVERY_SOURCE); // SOURCE high imp + + if ( on ) + { + // set strobes to sink to gnd. + DDRC |= C_MASK; + DDRD |= D_MASK; + DDRE |= E_MASK; + + PORTC &= ~C_MASK; + PORTD &= ~D_MASK; + PORTE &= ~E_MASK; + + DDRB |= (1 << RECOVERY_SINK); // SINK pull + PORTB |= (1 << RECOVERY_CONTROL); + PORTB |= (1 << RECOVERY_SOURCE); // SOURCE high + DDRB |= (1 << RECOVERY_SOURCE); + } + else + { + PORTB &= ~(1 << RECOVERY_CONTROL); + DDRB &= ~(1 << RECOVERY_SOURCE); + PORTB &= ~(1 << RECOVERY_SOURCE); // SOURCE low + DDRB &= ~(1 << RECOVERY_SINK); // SINK high-imp + } +} + + +void hold_sample( uint8_t on ) +{ + if ( !on ) + { + PORTB |= (1 << SAMPLE_CONTROL); + DDRB |= (1 << SAMPLE_CONTROL); + } + else + { + DDRB |= (1 << SAMPLE_CONTROL); + PORTB &= ~(1 << SAMPLE_CONTROL); + } +} + + +void strobe_w( uint8_t strobe_num ) +{ + PORTC &= ~(C_MASK); + PORTD &= ~(D_MASK); + PORTE &= ~(E_MASK); + + // Strobe table + // Not all strobes are used depending on which are detected + switch ( strobe_num ) + { + + case 0: PORTD |= (1 << 0); break; + case 1: PORTD |= (1 << 1); break; + case 2: PORTD |= (1 << 2); break; + case 3: PORTD |= (1 << 3); break; + case 4: PORTD |= (1 << 4); break; + case 5: PORTD |= (1 << 5); break; + case 6: PORTD |= (1 << 6); break; + case 7: PORTD |= (1 << 7); break; + + case 8: PORTE |= (1 << 0); break; + case 9: PORTE |= (1 << 1); break; + + case 10: PORTC |= (1 << 0); break; + case 11: PORTC |= (1 << 1); break; + case 12: PORTC |= (1 << 2); break; + case 13: PORTC |= (1 << 3); break; + case 14: PORTC |= (1 << 4); break; + case 15: PORTC |= (1 << 5); break; + case 16: PORTC |= (1 << 6); break; + case 17: PORTC |= (1 << 7); break; + + default: + break; + } +} + + +inline uint16_t getADC(void) +{ + ADCSRA |= (1 << ADIF); // clear int flag by writing 1. + + //wait for last read to complete. + while ( !( ADCSRA & (1 << ADIF) ) ); + + return ADC; // return sample +} + + +int sampleColumn_8x( uint8_t column, uint16_t * buffer ) +{ + // ensure all probe lines are driven low, and chill for recovery delay. + ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions + + PORTC &= ~C_MASK; + PORTD &= ~D_MASK; + PORTE &= ~E_MASK; + + PORTF = 0; + DDRF = 0; + + recovery( OFF ); + strobe_w( column ); + + hold_sample( OFF ); + SET_FULL_MUX( 0 ); + + // Allow strobes to settle + for ( uint8_t i = 0; i < STROBE_SETTLE; ++i ) { getADC(); } + + hold_sample( ON ); + + uint8_t mux = 0; + SET_FULL_MUX( mux ); + getADC(); // throw away; unknown mux. + do { + SET_FULL_MUX( mux + 1 ); // our *next* sample will use this + + // retrieve current read. + buffer[mux] = getADC(); + mux++; + + } while ( mux < 8 ); + + hold_sample( OFF ); + recovery( ON ); + + // turn off adc. + ADCSRA &= ~(1 << ADEN); + + // pull all columns' strobe-lines low. + DDRC |= C_MASK; + DDRD |= D_MASK; + DDRE |= E_MASK; + + PORTC &= ~C_MASK; + PORTD &= ~D_MASK; + PORTE &= ~E_MASK; + + return 0; +} + + +int sampleColumn( uint8_t column ) +{ + int rval = 0; + + rval = sampleColumn_8x( column, samples ); + + return rval; +} + + +uint8_t testColumn( uint8_t strobe ) +{ + uint16_t db_delta = 0; + uint8_t db_sample = 0; + uint16_t db_threshold = 0; + + uint8_t column = 0; + uint8_t bit = 1; + + for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux ) + { + uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + mux]; + + uint8_t key = (strobe << MUXES_COUNT_XSHIFT) + mux; + + // Check if this is a bad key (e.g. test point, or non-existent key) + if ( keys_problem[key] ) + { + // If the sample value of the problem key goes below full_avg (overall initial average) + // re-enable the key + if ( (db_sample = samples[mux] >> 1) < full_avg ) + { + info_msg("Re-enabling problem key: "); + printHex( key ); + print("\n"); + + keys_problem[key] = 0; + } + // Otherwise, don't waste any more cycles processing the problem key + else + { + continue; + } + } + + // Keypress detected + // db_sample (uint8_t), discard meaningless high bit, and garbage low bit + if ( (db_sample = samples[mux] >> 1) > (db_threshold = threshold) + (db_delta = delta) ) + { + column |= bit; + + // Only register keypresses once the warmup is complete, or not enough debounce info + if ( keys_debounce[key] <= DEBOUNCE_THRESHOLD ) + { + // Add to the Macro processing buffer if debounce criteria met + // Automatically handles converting to a USB code and sending off to the PC + if ( keys_debounce[key] == DEBOUNCE_THRESHOLD ) + { +//#define KEYSCAN_DEBOUNCE_DEBUG +#ifdef KEYSCAN_DEBOUNCE_DEBUG + // Debug message + print("0x"); + printHex_op( key, 2 ); + print(" "); +#endif + + // Only add the key to the buffer once + // NOTE: Buffer can easily handle multiple adds, just more efficient + // and nicer debug messages :P + //bufferAdd( key ); + } + + keys_debounce[key]++; + +#define KEYSCAN_THRESHOLD_DEBUG +#ifdef KEYSCAN_THRESHOLD_DEBUG + // Debug message + // <key> [<strobe>:<mux>] : <sense val> : <delta + threshold> : <margin> + dbug_msg("0x"); + printHex_op( key, 2 ); + print(" ["); + printInt8( strobe ); + print(":"); + printInt8( mux ); + print("] : "); + printHex( db_sample ); // Sense + print(" : "); + printHex( db_threshold ); + print("+"); + printHex( db_delta ); + print("="); + printHex( db_threshold + db_delta ); // Sense compare + print(" : "); + printHex( db_sample - ( db_threshold + db_delta ) ); // Margin + print("\n"); +#endif + } + } + // Clear debounce entry if no keypress detected + else + { + // If the key was previously pressed, remove from the buffer + for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ ) + { + // Key to release found + if ( KeyIndex_Buffer[c] == key ) + { + // Shift keys from c position + for ( uint8_t k = c; k < KeyIndex_BufferUsed - 1; k++ ) + KeyIndex_Buffer[k] = KeyIndex_Buffer[k + 1]; + + // Decrement Buffer + KeyIndex_BufferUsed--; + + break; + } + } + + + // Clear debounce entry + keys_debounce[key] = 0; + } + + bit <<= 1; + } + return column; +} + + +void dump(void) { + +#ifdef DEBUG_FULL_SAMPLES_AVERAGES + // we don't want to debug-out during the measurements. + if ( !dump_count ) + { + // Averages currently set per key + for ( int i = 0; i < KEY_COUNT; ++i ) + { + if ( !(i & 0x0f) ) + { + print("\n"); + } + else if ( !(i & 0x07) ) + { + print(" "); + } + + print(" "); + printHex( keys_averages[i] ); + } + + print("\n"); + + // Previously read full ADC scans? + for ( int i = 0; i< KEY_COUNT; ++i) + { + if ( !(i & 0x0f) ) + { + print("\n"); + } + else if ( !(i & 0x07) ) + { + print(" "); + } + + print(" "); + printHex(full_samples[i]); + } + } +#endif + +#ifdef DEBUG_STROBE_SAMPLES_AVERAGES + // Per strobe information + uint8_t cur_strober = ze_strober; + print("\n"); + + printHex(cur_strober); + + // Previously read ADC scans on current strobe + print(" :"); + for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) + { + print(" "); + printHex(full_samples[(cur_strober << MUXES_COUNT_XSHIFT) + i]); + } + + // Averages current set on current strobe + print(" :"); + + for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) + { + print(" "); + printHex(keys_averages[(cur_strober << MUXES_COUNT_XSHIFT) + i]); + } + +#endif + +#ifdef DEBUG_USB_KEYMAP + print("\n "); + + // Current keymap values + for ( uint8_t i = 0; i < total_strobes; ++i ) + { + printHex(cur_keymap[i]); + print(" "); + } +#endif + + ze_strober++; + ze_strober &= 0xf; + + dump_count++; + dump_count &= 0x0f; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/DPH/scan_loop.h Mon Mar 31 01:07:48 2014 -0700 @@ -0,0 +1,64 @@ +/* Copyright (C) 2013 by Jacob Alexander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SCAN_LOOP_H +#define __SCAN_LOOP_H + +// ----- Includes ----- + +// Compiler Includes +#include <stdint.h> + +// Local Includes + + + +// ----- Defines ----- + +#define KEYBOARD_KEYS 0xFF // TODO Determine max number of keys +#define KEYBOARD_BUFFER 24 // Max number of key signals to buffer + // This limits the NKRO-ability, so at 24, the keyboard is 24KRO + // The buffer is really only needed for converter modules + // An alternative macro module could be written for matrix modules and still work well + + + +// ----- Variables ----- + +extern volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER]; +extern volatile uint8_t KeyIndex_BufferUsed; + + + +// ----- Functions ----- + +// Functions used by main.c +void scan_setup( void ); +uint8_t scan_loop( void ); + + +// Functions available to macro.c +uint8_t scan_sendData( uint8_t dataPayload ); + +void scan_finishedWithBuffer( uint8_t sentKeys ); +void scan_finishedWithUSBBuffer( uint8_t sentKeys ); +void scan_lockKeyboard( void ); +void scan_unlockKeyboard( void ); +void scan_resetKeyboard( void ); + + +#endif // __SCAN_LOOP_H +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/DPH/setup.cmake Mon Mar 31 01:07:48 2014 -0700 @@ -0,0 +1,54 @@ +###| CMake Kiibohd Controller Scan Module |### +# +# Written by Jacob Alexander in 2013-2014 for the Kiibohd Controller +# +# Released into the Public Domain +# +### + + +### +# Module C files +# + +set( SCAN_SRCS + scan_loop.c +) + + +### +# Module H files +# +set( SCAN_HDRS + scan_loop.h +) + + +### +# File Dependency Setup +# +ADD_FILE_DEPENDENCIES( scan_loop.c ${SCAN_HDRS} ) +#add_file_dependencies( scan_loop.c ${SCAN_HDRS} ) +#add_file_dependencies( macro.c keymap.h avrcapsense.h ) + + +### +# Module Specific Options +# +add_definitions( -I${HEAD_DIR}/Keymap ) + +#| Keymap Settings +add_definitions( + -DMODIFIER_MASK=avrcapsense_ModifierMask + #-DKEYINDEX_MASK=avrcapsense_ColemakMap + -DKEYINDEX_MASK=avrcapsense_DefaultMap +) + + +### +# Compiler Family Compatibility +# +set( ScanModuleCompatibility + avr +) +
--- a/Scan/SKM67001/setup.cmake Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/SKM67001/setup.cmake Mon Mar 31 01:07:48 2014 -0700 @@ -24,7 +24,7 @@ add_definitions( -I${HEAD_DIR}/Keymap ) add_definitions( -I${HEAD_DIR}/Scan/matrix -) +) #| Keymap Settings add_definitions(
--- a/Scan/avr-capsense/scan_loop.c Sat Mar 22 14:32:06 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1012 +0,0 @@ -/* Copyright (C) 2011-2013 by Joseph Makuch - * Additions by Jacob Alexander (2013) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - */ - -// ----- Includes ----- - -// Compiler Includes -#include <Lib/ScanLib.h> - -// Project Includes -#include <led.h> -#include <print.h> - -// Local Includes -#include "scan_loop.h" - - - -// ----- Defines ----- - -// TODO dfj defines...needs commenting and maybe some cleaning... -#define MAX_PRESS_DELTA_MV 450 // As measured from the Teensy ADC pin -#define THRESHOLD_MV (MAX_PRESS_DELTA_MV >> 1) -//(2560 / (0x3ff/2)) ~= 5 -#define MV_PER_ADC 5 -#define THRESHOLD (THRESHOLD_MV / MV_PER_ADC) - -#define STROBE_SETTLE 1 - -#define TEST_KEY_STROBE (0x05) -#define TEST_KEY_MASK (1 << 0) - -#define ADHSM 7 - -#define RIGHT_JUSTIFY 0 -#define LEFT_JUSTIFY (0xff) - -// set left or right justification here: -#define JUSTIFY_ADC RIGHT_JUSTIFY -#define ADLAR_MASK (1 << ADLAR) - -#ifdef JUSTIFY_ADC -#define ADLAR_BITS ((ADLAR_MASK) & (JUSTIFY_ADC)) -#else // defaults to right justification. -#define ADLAR_BITS 0 -#endif - -// full muxmask -#define FULL_MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2) | (1 << MUX3) | (1 << MUX4)) - -// F0-f7 pins only muxmask. -#define MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2)) - -// Strobe Masks -#define D_MASK (0xff) -#define E_MASK (0x03) -#define C_MASK (0xff) - -// set ADC clock prescale -#define PRESCALE_MASK ((1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2)) -#define PRESCALE_SHIFT (ADPS0) -#define PRESCALE 3 - -// Max number of strobes supported by the hardware -// Strobe lines are detected at startup, extra strobes cause anomalies like phantom keypresses -#define MAX_STROBES 18 - -// Number of consecutive samples required to pass debounce -#define DEBOUNCE_THRESHOLD 5 - -#define MUXES_COUNT 8 -#define MUXES_COUNT_XSHIFT 3 - -#define WARMUP_LOOPS ( 1024 ) -#define WARMUP_STOP (WARMUP_LOOPS - 1) - -#define SAMPLE_CONTROL 3 - -#define KEY_COUNT ((MAX_STROBES) * (MUXES_COUNT)) - -#define RECOVERY_CONTROL 1 -#define RECOVERY_SOURCE 0 -#define RECOVERY_SINK 2 - -#define ON 1 -#define OFF 0 - -// mix in 1/4 of the current average to the running average. -> (@mux_mix = 2) -#define MUX_MIX 2 - -#define IDLE_COUNT_MASK 0xff -#define IDLE_COUNT_SHIFT 8 - -// av = (av << shift) - av + sample; av >>= shift -// e.g. 1 -> (av + sample) / 2 simple average of new and old -// 2 -> (3 * av + sample) / 4 i.e. 3:1 mix of old to new. -// 3 -> (7 * av + sample) / 8 i.e. 7:1 mix of old to new. -#define KEYS_AVERAGES_MIX_SHIFT 3 - - - -// ----- Macros ----- - -// Make sure we haven't overflowed the buffer -#define bufferAdd(byte) \ - if ( KeyIndex_BufferUsed < KEYBOARD_BUFFER ) \ - KeyIndex_Buffer[KeyIndex_BufferUsed++] = byte - -// Select mux -#define SET_FULL_MUX(X) ((ADMUX) = (((ADMUX) & ~(FULL_MUX_MASK)) | ((X) & (FULL_MUX_MASK)))) - - - -// ----- Variables ----- - -// Buffer used to inform the macro processing module which keys have been detected as pressed -volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER]; -volatile uint8_t KeyIndex_BufferUsed; - - -// TODO dfj variables...needs cleaning up and commenting - -// Variables used to calculate the starting sense value (averaging) -uint32_t full_avg = 0; -uint32_t high_avg = 0; -uint32_t low_avg = 0; - -uint8_t high_count = 0; -uint8_t low_count = 0; - - -uint8_t ze_strober = 0; - -uint16_t samples[MUXES_COUNT]; - -uint8_t cur_keymap[MAX_STROBES]; - -uint8_t keymap_change; - -uint16_t threshold = THRESHOLD; - -uint8_t column = 0; - -uint16_t keys_averages_acc[KEY_COUNT]; -uint16_t keys_averages [KEY_COUNT]; -uint8_t keys_debounce [KEY_COUNT]; // Contains debounce statistics -uint8_t keys_problem [KEY_COUNT]; // Marks keys that should be ignored (determined by averaging at startup) - -uint8_t full_samples[KEY_COUNT]; - -// TODO: change this to 'booting', then count down. -uint16_t boot_count = 0; - -uint16_t idle_count = 0; -uint8_t idle = 1; - -uint8_t error = 0; -uint16_t error_data = 0; - -uint8_t total_strobes = MAX_STROBES; -uint8_t strobe_map[MAX_STROBES]; - -uint8_t dump_count = 0; - - - -// ----- Function Declarations ----- - -void dump( void ); - -void recovery( uint8_t on ); - -int sampleColumn( uint8_t column ); - -void capsense_scan( void ); - -void setup_ADC( void ); - -void strobe_w( uint8_t strobe_num ); - -uint8_t testColumn( uint8_t strobe ); - - - -// ----- Functions ----- - -// Initial setup for cap sense controller -inline void scan_setup() -{ - // TODO dfj code...needs cleanup + commenting... - setup_ADC(); - - DDRC = C_MASK; - PORTC = 0; - DDRD = D_MASK; - PORTD = 0; - DDRE = E_MASK; - PORTE = 0 ; - - // Hardcoded strobes for debugging - // Strobes start at 0 and go to 17 (18), not all Model Fs use all of the available strobes - // The single row ribbon connector Model Fs only have a max of 16 strobes -#define KISHSAVER_STROBE -//#define KISHSAVER_OLD_STROBE -//#define TERMINAL_6110668_OLD_STROBE -//#define UNSAVER_OLD_STROBE -#ifdef KISHSAVER_OLD_STROBE - total_strobes = 9; - - strobe_map[0] = 2; // Kishsaver doesn't use strobe 0 and 1 - strobe_map[1] = 3; - strobe_map[2] = 4; - strobe_map[3] = 5; - strobe_map[4] = 6; - strobe_map[5] = 7; - strobe_map[6] = 8; - strobe_map[7] = 9; - strobe_map[8] = 15; // Test point strobe (3 test points, sense 1, 4, 5) -#elif defined(KISHSAVER_STROBE) - total_strobes = 9; - - strobe_map[0] = 15; // Kishsaver doesn't use strobe 0 and 1 - strobe_map[1] = 14; - strobe_map[2] = 13; - strobe_map[3] = 12; - strobe_map[4] = 11; - strobe_map[5] = 10; - strobe_map[6] = 9; - strobe_map[7] = 8; - strobe_map[8] = 2; // Test point strobe (3 test points, sense 1, 4, 5) -#elif defined(TERMINAL_6110668_OLD_STROBE) - total_strobes = 16; - - strobe_map[0] = 0; - strobe_map[1] = 1; - strobe_map[2] = 2; - strobe_map[3] = 3; - strobe_map[4] = 4; - strobe_map[5] = 5; - strobe_map[6] = 6; - strobe_map[7] = 7; - strobe_map[8] = 8; - strobe_map[9] = 9; - strobe_map[10] = 10; - strobe_map[11] = 11; - strobe_map[12] = 12; - strobe_map[13] = 13; - strobe_map[14] = 14; - strobe_map[15] = 15; -#elif defined(UNSAVER_OLD_STROBE) - total_strobes = 14; - - strobe_map[0] = 0; - strobe_map[1] = 1; - strobe_map[2] = 2; - strobe_map[3] = 3; - strobe_map[4] = 4; - strobe_map[5] = 5; - strobe_map[6] = 6; - strobe_map[7] = 7; - strobe_map[8] = 8; - strobe_map[9] = 9; - strobe_map[10] = 10; - strobe_map[11] = 11; - strobe_map[12] = 12; - strobe_map[13] = 13; -#else - // Strobe detection - // TODO -#endif - - // TODO all this code should probably be in scan_resetKeyboard - for ( int i = 0; i < total_strobes; ++i) - { - cur_keymap[i] = 0; - } - - // Reset debounce table - for ( int i = 0; i < KEY_COUNT; ++i ) - { - keys_debounce[i] = 0; - } - - // Warm things up a bit before we start collecting data, taking real samples. - for ( uint8_t i = 0; i < total_strobes; ++i ) - { - sampleColumn( strobe_map[i] ); - } - - - // Reset the keyboard before scanning, we might be in a wierd state - // Also sets the KeyIndex_BufferUsed to 0 - scan_resetKeyboard(); -} - - -// Main Detection Loop -// This is where the important stuff happens -inline uint8_t scan_loop() -{ - capsense_scan(); - - // Error case, should not occur in normal operation - if ( error ) - { - erro_msg("Problem detected... "); - - // Keymap scan debug - for ( uint8_t i = 0; i < total_strobes; ++i ) - { - printHex(cur_keymap[strobe_map[i]]); - print(" "); - } - - print(" : "); - printHex(error); - error = 0; - print(" : "); - printHex(error_data); - error_data = 0; - - // Display keymaps and other debug information if warmup completede - if ( boot_count >= WARMUP_LOOPS ) - { - dump(); - } - } - - - // Return non-zero if macro and USB processing should be delayed - // Macro processing will always run if returning 0 - // USB processing only happens once the USB send timer expires, if it has not, scan_loop will be called - // after the macro processing has been completed - return 0; -} - - -// Reset Keyboard -void scan_resetKeyboard( void ) -{ - // Empty buffer, now that keyboard has been reset - KeyIndex_BufferUsed = 0; -} - - -// Send data to keyboard -// NOTE: Only used for converters, since the scan module shouldn't handle sending data in a controller -uint8_t scan_sendData( uint8_t dataPayload ) -{ - return 0; -} - - -// Reset/Hold keyboard -// NOTE: Only used for converters, not needed for full controllers -void scan_lockKeyboard( void ) -{ -} - -// NOTE: Only used for converters, not needed for full controllers -void scan_unlockKeyboard( void ) -{ -} - - -// Signal KeyIndex_Buffer that it has been properly read -// NOTE: Only really required for implementing "tricks" in converters for odd protocols -void scan_finishedWithBuffer( uint8_t sentKeys ) -{ - // Convenient place to clear the KeyIndex_Buffer - KeyIndex_BufferUsed = 0; - return; -} - - -// Signal KeyIndex_Buffer that it has been properly read and sent out by the USB module -// NOTE: Only really required for implementing "tricks" in converters for odd protocols -void scan_finishedWithUSBBuffer( uint8_t sentKeys ) -{ - return; -} - - -inline void capsense_scan() -{ - // Accumulated average used for the next scan - uint32_t cur_full_avg = 0; - uint32_t cur_high_avg = 0; - - // Reset average counters - low_avg = 0; - low_count = 0; - - high_count = 0; - - // Scan each of the mapped strobes in the matrix - for ( uint8_t strober = 0; strober < total_strobes; ++strober ) - { - uint8_t map_strobe = strobe_map[strober]; - - uint8_t tries = 1; - while ( tries++ && sampleColumn( map_strobe ) ) { tries &= 0x7; } // don't waste this one just because the last one was poop. - - // Only process sense data if warmup is finished - if ( boot_count >= WARMUP_LOOPS ) - { - column = testColumn( map_strobe ); - - idle |= column; // if column has any pressed keys, then we are not idle. - - // TODO Is this needed anymore? Really only helps debug -HaaTa - if( column != cur_keymap[map_strobe] && ( boot_count >= WARMUP_LOOPS ) ) - { - cur_keymap[map_strobe] = column; - keymap_change = 1; - } - - idle |= keymap_change; // if any keys have changed inc. released, then we are not idle. - } - - if ( error == 0x50 ) - { - error_data |= (((uint16_t)map_strobe) << 12); - } - - uint8_t strobe_line = map_strobe << MUXES_COUNT_XSHIFT; - for ( int i = 0; i < MUXES_COUNT; ++i ) - { - // discard sketchy low bit, and meaningless high bits. - uint8_t sample = samples[i] >> 1; - full_samples[strobe_line + i] = sample; - keys_averages_acc[strobe_line + i] += sample; - } - - // Accumulate 3 total averages (used for determining starting average during warmup) - // full_avg - Average of all sampled lines on the previous scan set - // cur_full_avg - Average of all sampled lines for this scan set - // high_avg - Average of all sampled lines above full_avg on the previous scan set - // cur_high_avg - Average of all sampled lines above full_avg - // low_avg - Average of all sampled lines below or equal to full_avg - if ( boot_count < WARMUP_LOOPS ) - { - for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) - { - uint8_t sample = samples[i] >> 1; - - // Sample is high, add it to high avg - if ( sample > full_avg ) - { - high_count++; - cur_high_avg += sample; - } - // Sample is low, add it to low avg - else - { - low_count++; - low_avg += sample; - } - - // If sample is higher than previous high_avg, then mark as "problem key" - keys_problem[strobe_line + i] = sample > high_avg ? sample : 0; - - // Prepare for next average - cur_full_avg += sample; - } - } - } // for strober - - // Update total sense average (only during warm-up) - if ( boot_count < WARMUP_LOOPS ) - { - full_avg = cur_full_avg / (total_strobes * MUXES_COUNT); - high_avg = cur_high_avg / high_count; - low_avg /= low_count; - - // Update the base average value using the low_avg (best chance of not ignoring a keypress) - for ( int i = 0; i < KEY_COUNT; ++i ) - { - keys_averages[i] = low_avg; - keys_averages_acc[i] = low_avg; - } - } - -#ifdef VERIFY_TEST_PAD - // verify test key is not down. - if ( ( cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK ) ) - { - error = 0x05; - error_data = cur_keymap[TEST_KEY_STROBE] << 8; - error_data += full_samples[TEST_KEY_STROBE * 8]; - } -#endif - - /** aggregate if booting, or if idle; - * else, if not booting, check for dirty USB. - * */ - - idle_count++; - idle_count &= IDLE_COUNT_MASK; - - // Warm up voltage references - if ( boot_count < WARMUP_LOOPS ) - { - boot_count++; - - switch ( boot_count ) - { - // First loop - case 1: - // Show msg at first iteration only - info_msg("Warming up the voltage references"); - break; - // Middle iterations - case 300: - case 600: - case 900: - case 1200: - print("."); - break; - // Last loop - case WARMUP_STOP: - print("\n"); - info_msg("Warmup finished using "); - printInt16( WARMUP_LOOPS ); - print(" iterations\n"); - - // Display the final calculated averages of all the sensed strobes - info_msg("Full average ("); - printInt8( total_strobes * MUXES_COUNT ); - print("): "); - printHex( full_avg ); - - print(" High average ("); - printInt8( high_count ); - print("): "); - printHex( high_avg ); - - print(" Low average ("); - printInt8( low_count ); - print("): "); - printHex( low_avg ); - print("\n"); - - // Display problem keys, and the sense value at the time - for ( uint8_t key = 0; key < KEY_COUNT; key++ ) - { - if ( keys_problem[key] ) - { - warn_msg("Problem key detected: "); - printHex( key ); - print(" ("); - printHex( keys_problem[key] ); - print(")\n"); - } - } - - info_print("If problem keys were detected, and were being held down, they will be reset as soon as let go"); - break; - } - } - else - { - // Reset accumulators and idle flag/counter - if ( keymap_change ) - { - for ( uint8_t c = 0; c < KEY_COUNT; ++c ) { keys_averages_acc[c] = 0; } - idle_count = 0; - idle = 0; - - keymap_change = 0; - } - - if ( !idle_count ) - { - if( idle ) - { - // aggregate - for ( uint8_t i = 0; i < KEY_COUNT; ++i ) - { - uint16_t acc = keys_averages_acc[i] >> IDLE_COUNT_SHIFT; - uint32_t av = keys_averages[i]; - - av = (av << KEYS_AVERAGES_MIX_SHIFT) - av + acc; - av >>= KEYS_AVERAGES_MIX_SHIFT; - - keys_averages[i] = av; - keys_averages_acc[i] = 0; - } - } - - if ( boot_count >= WARMUP_LOOPS ) - { - dump(); - } - } - - } -} - - -void setup_ADC() -{ - // disable adc digital pins. - DIDR1 |= (1 << AIN0D) | (1<<AIN1D); // set disable on pins 1,0. - DDRF = 0x0; - PORTF = 0x0; - uint8_t mux = 0 & 0x1f; // 0 == first. // 0x1e = 1.1V ref. - - // 0 = external aref 1,1 = 2.56V internal ref - uint8_t aref = ((1 << REFS1) | (1 << REFS0)) & ((1 << REFS1) | (1 << REFS0)); - uint8_t adate = (1 << ADATE) & (1 << ADATE); // trigger enable - uint8_t trig = 0 & ((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2)); // 0 = free running - // ps2, ps1 := /64 ( 2^6 ) ps2 := /16 (2^4), ps1 := 4, ps0 :=2, PS1,PS0 := 8 (2^8) - uint8_t prescale = ( ((PRESCALE) << PRESCALE_SHIFT) & PRESCALE_MASK ); // 001 == 2^1 == 2 - uint8_t hispeed = (1 << ADHSM); - uint8_t en_mux = (1 << ACME); - - ADCSRA = (1 << ADEN) | prescale; // ADC enable - - // select ref. - //ADMUX |= ((1 << REFS1) | (1 << REFS0)); // 2.56 V internal. - //ADMUX |= ((1 << REFS0) ); // Vcc with external cap. - //ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // 0,0 : aref. - ADMUX = aref | mux | ADLAR_BITS; - - // set free-running - ADCSRA |= adate; // trigger enable - ADCSRB = en_mux | hispeed | trig | (ADCSRB & ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2))); // trigger select free running - - ADCSRA |= (1 << ADEN); // ADC enable - ADCSRA |= (1 << ADSC); // start conversions q -} - - -void recovery( uint8_t on ) -{ - DDRB |= (1 << RECOVERY_CONTROL); - PORTB &= ~(1 << RECOVERY_SINK); // SINK always zero - DDRB &= ~(1 << RECOVERY_SOURCE); // SOURCE high imp - - if ( on ) - { - // set strobes to sink to gnd. - DDRC |= C_MASK; - DDRD |= D_MASK; - DDRE |= E_MASK; - - PORTC &= ~C_MASK; - PORTD &= ~D_MASK; - PORTE &= ~E_MASK; - - DDRB |= (1 << RECOVERY_SINK); // SINK pull - PORTB |= (1 << RECOVERY_CONTROL); - PORTB |= (1 << RECOVERY_SOURCE); // SOURCE high - DDRB |= (1 << RECOVERY_SOURCE); - } - else - { - PORTB &= ~(1 << RECOVERY_CONTROL); - DDRB &= ~(1 << RECOVERY_SOURCE); - PORTB &= ~(1 << RECOVERY_SOURCE); // SOURCE low - DDRB &= ~(1 << RECOVERY_SINK); // SINK high-imp - } -} - - -void hold_sample( uint8_t on ) -{ - if ( !on ) - { - PORTB |= (1 << SAMPLE_CONTROL); - DDRB |= (1 << SAMPLE_CONTROL); - } - else - { - DDRB |= (1 << SAMPLE_CONTROL); - PORTB &= ~(1 << SAMPLE_CONTROL); - } -} - - -void strobe_w( uint8_t strobe_num ) -{ - PORTC &= ~(C_MASK); - PORTD &= ~(D_MASK); - PORTE &= ~(E_MASK); - - // Strobe table - // Not all strobes are used depending on which are detected - switch ( strobe_num ) - { - - case 0: PORTD |= (1 << 0); break; - case 1: PORTD |= (1 << 1); break; - case 2: PORTD |= (1 << 2); break; - case 3: PORTD |= (1 << 3); break; - case 4: PORTD |= (1 << 4); break; - case 5: PORTD |= (1 << 5); break; - case 6: PORTD |= (1 << 6); break; - case 7: PORTD |= (1 << 7); break; - - case 8: PORTE |= (1 << 0); break; - case 9: PORTE |= (1 << 1); break; - - case 10: PORTC |= (1 << 0); break; - case 11: PORTC |= (1 << 1); break; - case 12: PORTC |= (1 << 2); break; - case 13: PORTC |= (1 << 3); break; - case 14: PORTC |= (1 << 4); break; - case 15: PORTC |= (1 << 5); break; - case 16: PORTC |= (1 << 6); break; - case 17: PORTC |= (1 << 7); break; - - default: - break; - } -} - - -inline uint16_t getADC(void) -{ - ADCSRA |= (1 << ADIF); // clear int flag by writing 1. - - //wait for last read to complete. - while ( !( ADCSRA & (1 << ADIF) ) ); - - return ADC; // return sample -} - - -int sampleColumn_8x( uint8_t column, uint16_t * buffer ) -{ - // ensure all probe lines are driven low, and chill for recovery delay. - ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions - - PORTC &= ~C_MASK; - PORTD &= ~D_MASK; - PORTE &= ~E_MASK; - - PORTF = 0; - DDRF = 0; - - recovery( OFF ); - strobe_w( column ); - - hold_sample( OFF ); - SET_FULL_MUX( 0 ); - - // Allow strobes to settle - for ( uint8_t i = 0; i < STROBE_SETTLE; ++i ) { getADC(); } - - hold_sample( ON ); - - uint8_t mux = 0; - SET_FULL_MUX( mux ); - getADC(); // throw away; unknown mux. - do { - SET_FULL_MUX( mux + 1 ); // our *next* sample will use this - - // retrieve current read. - buffer[mux] = getADC(); - mux++; - - } while ( mux < 8 ); - - hold_sample( OFF ); - recovery( ON ); - - // turn off adc. - ADCSRA &= ~(1 << ADEN); - - // pull all columns' strobe-lines low. - DDRC |= C_MASK; - DDRD |= D_MASK; - DDRE |= E_MASK; - - PORTC &= ~C_MASK; - PORTD &= ~D_MASK; - PORTE &= ~E_MASK; - - return 0; -} - - -int sampleColumn( uint8_t column ) -{ - int rval = 0; - - rval = sampleColumn_8x( column, samples ); - - return rval; -} - - -uint8_t testColumn( uint8_t strobe ) -{ - uint16_t db_delta = 0; - uint8_t db_sample = 0; - uint16_t db_threshold = 0; - - uint8_t column = 0; - uint8_t bit = 1; - - for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux ) - { - uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + mux]; - - uint8_t key = (strobe << MUXES_COUNT_XSHIFT) + mux; - - // Check if this is a bad key (e.g. test point, or non-existent key) - if ( keys_problem[key] ) - { - // If the sample value of the problem key goes below full_avg (overall initial average) - // re-enable the key - if ( (db_sample = samples[mux] >> 1) < full_avg ) - { - info_msg("Re-enabling problem key: "); - printHex( key ); - print("\n"); - - keys_problem[key] = 0; - } - // Otherwise, don't waste any more cycles processing the problem key - else - { - continue; - } - } - - // Keypress detected - // db_sample (uint8_t), discard meaningless high bit, and garbage low bit - if ( (db_sample = samples[mux] >> 1) > (db_threshold = threshold) + (db_delta = delta) ) - { - column |= bit; - - // Only register keypresses once the warmup is complete, or not enough debounce info - if ( keys_debounce[key] <= DEBOUNCE_THRESHOLD ) - { - // Add to the Macro processing buffer if debounce criteria met - // Automatically handles converting to a USB code and sending off to the PC - if ( keys_debounce[key] == DEBOUNCE_THRESHOLD ) - { -//#define KEYSCAN_DEBOUNCE_DEBUG -#ifdef KEYSCAN_DEBOUNCE_DEBUG - // Debug message - print("0x"); - printHex_op( key, 2 ); - print(" "); -#endif - - // Only add the key to the buffer once - // NOTE: Buffer can easily handle multiple adds, just more efficient - // and nicer debug messages :P - //bufferAdd( key ); - } - - keys_debounce[key]++; - -#define KEYSCAN_THRESHOLD_DEBUG -#ifdef KEYSCAN_THRESHOLD_DEBUG - // Debug message - // <key> [<strobe>:<mux>] : <sense val> : <delta + threshold> : <margin> - dbug_msg("0x"); - printHex_op( key, 2 ); - print(" ["); - printInt8( strobe ); - print(":"); - printInt8( mux ); - print("] : "); - printHex( db_sample ); // Sense - print(" : "); - printHex( db_threshold ); - print("+"); - printHex( db_delta ); - print("="); - printHex( db_threshold + db_delta ); // Sense compare - print(" : "); - printHex( db_sample - ( db_threshold + db_delta ) ); // Margin - print("\n"); -#endif - } - } - // Clear debounce entry if no keypress detected - else - { - // If the key was previously pressed, remove from the buffer - for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ ) - { - // Key to release found - if ( KeyIndex_Buffer[c] == key ) - { - // Shift keys from c position - for ( uint8_t k = c; k < KeyIndex_BufferUsed - 1; k++ ) - KeyIndex_Buffer[k] = KeyIndex_Buffer[k + 1]; - - // Decrement Buffer - KeyIndex_BufferUsed--; - - break; - } - } - - - // Clear debounce entry - keys_debounce[key] = 0; - } - - bit <<= 1; - } - return column; -} - - -void dump(void) { - -#ifdef DEBUG_FULL_SAMPLES_AVERAGES - // we don't want to debug-out during the measurements. - if ( !dump_count ) - { - // Averages currently set per key - for ( int i = 0; i < KEY_COUNT; ++i ) - { - if ( !(i & 0x0f) ) - { - print("\n"); - } - else if ( !(i & 0x07) ) - { - print(" "); - } - - print(" "); - printHex( keys_averages[i] ); - } - - print("\n"); - - // Previously read full ADC scans? - for ( int i = 0; i< KEY_COUNT; ++i) - { - if ( !(i & 0x0f) ) - { - print("\n"); - } - else if ( !(i & 0x07) ) - { - print(" "); - } - - print(" "); - printHex(full_samples[i]); - } - } -#endif - -#ifdef DEBUG_STROBE_SAMPLES_AVERAGES - // Per strobe information - uint8_t cur_strober = ze_strober; - print("\n"); - - printHex(cur_strober); - - // Previously read ADC scans on current strobe - print(" :"); - for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) - { - print(" "); - printHex(full_samples[(cur_strober << MUXES_COUNT_XSHIFT) + i]); - } - - // Averages current set on current strobe - print(" :"); - - for ( uint8_t i = 0; i < MUXES_COUNT; ++i ) - { - print(" "); - printHex(keys_averages[(cur_strober << MUXES_COUNT_XSHIFT) + i]); - } - -#endif - -#ifdef DEBUG_USB_KEYMAP - print("\n "); - - // Current keymap values - for ( uint8_t i = 0; i < total_strobes; ++i ) - { - printHex(cur_keymap[i]); - print(" "); - } -#endif - - ze_strober++; - ze_strober &= 0xf; - - dump_count++; - dump_count &= 0x0f; -} -
--- a/Scan/avr-capsense/scan_loop.h Sat Mar 22 14:32:06 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* Copyright (C) 2013 by Jacob Alexander - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __SCAN_LOOP_H -#define __SCAN_LOOP_H - -// ----- Includes ----- - -// Compiler Includes -#include <stdint.h> - -// Local Includes - - - -// ----- Defines ----- - -#define KEYBOARD_KEYS 0xFF // TODO Determine max number of keys -#define KEYBOARD_BUFFER 24 // Max number of key signals to buffer - // This limits the NKRO-ability, so at 24, the keyboard is 24KRO - // The buffer is really only needed for converter modules - // An alternative macro module could be written for matrix modules and still work well - - - -// ----- Variables ----- - -extern volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER]; -extern volatile uint8_t KeyIndex_BufferUsed; - - - -// ----- Functions ----- - -// Functions used by main.c -void scan_setup( void ); -uint8_t scan_loop( void ); - - -// Functions available to macro.c -uint8_t scan_sendData( uint8_t dataPayload ); - -void scan_finishedWithBuffer( uint8_t sentKeys ); -void scan_finishedWithUSBBuffer( uint8_t sentKeys ); -void scan_lockKeyboard( void ); -void scan_unlockKeyboard( void ); -void scan_resetKeyboard( void ); - - -#endif // __SCAN_LOOP_H -
--- a/Scan/avr-capsense/setup.cmake Sat Mar 22 14:32:06 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -###| CMake Kiibohd Controller Scan Module |### -# -# Written by Jacob Alexander in 2013 for the Kiibohd Controller -# -# Released into the Public Domain -# -### - - -### -# Module C files -# - -set( SCAN_SRCS - scan_loop.c -) - - -### -# Module H files -# -set( SCAN_HDRS - scan_loop.h -) - - -### -# File Dependency Setup -# -ADD_FILE_DEPENDENCIES( scan_loop.c ${SCAN_HDRS} ) -#add_file_dependencies( scan_loop.c ${SCAN_HDRS} ) -#add_file_dependencies( macro.c keymap.h avrcapsense.h ) - - -### -# Module Specific Options -# -add_definitions( -I${HEAD_DIR}/Keymap ) - -#| Keymap Settings -add_definitions( - -DMODIFIER_MASK=avrcapsense_ModifierMask - #-DKEYINDEX_MASK=avrcapsense_ColemakMap - -DKEYINDEX_MASK=avrcapsense_DefaultMap -) - - -### -# Compiler Family Compatibility -# -set( ScanModuleCompatibility - avr -) -
--- a/Scan/matrix/matrix_scan.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/matrix/matrix_scan.c Mon Mar 31 01:07:48 2014 -0700 @@ -1,15 +1,15 @@ -/* Copyright (C) 2011 by Jacob Alexander - * +/* Copyright (C) 2011,2014 by Jacob Alexander + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- a/Scan/matrix/matrix_scan.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/matrix/matrix_scan.h Mon Mar 31 01:07:48 2014 -0700 @@ -1,15 +1,15 @@ -/* Copyright (C) 2011 by Jacob Alexander - * +/* Copyright (C) 2011,2014 by Jacob Alexander + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- a/Scan/matrix/matrix_template.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/matrix/matrix_template.h Mon Mar 31 01:07:48 2014 -0700 @@ -1,15 +1,15 @@ -/* Copyright (C) 2011 by Jacob Alexander - * +/* Copyright (C) 2011,2014 by Jacob Alexander + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -69,7 +69,7 @@ // Just layout the matrix by rows and columns // Usually you'll want to set the scanMode above to scanDual or scanCol_powrRow/scanRow_powrCol // The mode allows for optimization in the kind of scanning algorithms that are done -// +// // The key numbers are used to translate into the keymap table (array) (and always start from 1, not 0). // Thus if a row doesn't use all the key positions, you can denote it as 0, which will be ignored/skipped on each scan // See the keymap.h file for the various preconfigured arrays.
--- a/Scan/matrix/scan_loop.c Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/matrix/scan_loop.c Mon Mar 31 01:07:48 2014 -0700 @@ -1,15 +1,15 @@ -/* Copyright (C) 2011-2012 by Jacob Alexander - * +/* Copyright (C) 2011-2012,2014 by Jacob Alexander + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- a/Scan/matrix/scan_loop.h Sat Mar 22 14:32:06 2014 -0700 +++ b/Scan/matrix/scan_loop.h Mon Mar 31 01:07:48 2014 -0700 @@ -1,15 +1,15 @@ -/* Copyright (C) 2011-2012 by Jacob Alexander - * +/* Copyright (C) 2011-2012,2014 by Jacob Alexander + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- a/avr.cmake Sat Mar 22 14:32:06 2014 -0700 +++ b/avr.cmake Mon Mar 31 01:07:48 2014 -0700 @@ -1,6 +1,6 @@ ###| CMAKE Kiibohd Controller |### # -# Jacob Alexander 2011-2013 +# Jacob Alexander 2011-2014 # Due to this file's usefulness: # # Released into the Public Domain @@ -37,8 +37,8 @@ #| "atmega32u4" # Teensy 2.0 #| "at90usb646" # Teensy++ 1.0 #| "at90usb1286" # Teensy++ 2.0 -#set( MCU "atmega32u4" ) -set( MCU "at90usb1286" ) +set( MCU "atmega32u4" ) +#set( MCU "at90usb1286" ) message( STATUS "MCU Selected:" ) message( "${MCU}" ) @@ -51,6 +51,15 @@ ) +#| CPU Type +#| This is only informational for AVR microcontrollers +#| The field can be determined by the microcontroller chip, but currently only one CPU type is used atm +set( CPU "megaAVR" ) + +message( STATUS "CPU Selected:" ) +message( "${CPU}" ) + + #| USB Defines set( VENDOR_ID "0x16C0" ) set( PRODUCT_ID "0x047D" ) @@ -66,7 +75,7 @@ #| Warning Options #| -Wall...: warning level -set( WARN "-Wall -Wstrict-prototypes" ) +set( WARN "-Wall" ) #| Tuning Options @@ -75,7 +84,7 @@ set( TUNING "-funsigned-char -funsigned-bitfields -ffunction-sections -fpack-struct -fshort-enums" ) -#| Optimization level, can be [0, 1, 2, 3, s]. +#| Optimization level, can be [0, 1, 2, 3, s]. #| 0 = turn off optimization. s = optimize for size. #| (Note: 3 is not always the best optimization level. See avr-libc FAQ.) set( OPT "s" )
--- a/main.c Sat Mar 22 14:32:06 2014 -0700 +++ b/main.c Mon Mar 31 01:07:48 2014 -0700 @@ -139,57 +139,43 @@ { // Configuring Pins pinSetup(); - init_errorLED(); + + // Enable CLI + init_cli(); // Setup Output Module output_setup(); - // Enable CLI - init_cli(); - // Setup ISR Timer for flagging a kepress send to USB usbTimerSetup(); + // Setup the scanning module + //scan_setup(); + // Main Detection Loop - uint8_t ledTimer = F_CPU / 1000000; // Enable LED for a short time while ( 1 ) { - // Setup the scanning module - scan_setup(); + // Process CLI + process_cli(); - while ( 1 ) - { - // Acquire Key Indices - // Loop continuously until scan_loop returns 0 - cli(); - while ( scan_loop() ); - sei(); - - // Run Macros over Key Indices and convert to USB Keys - process_macros(); - - // Send keypresses over USB if the ISR has signalled that it's time - if ( !sendKeypresses ) - continue; + // Acquire Key Indices + // Loop continuously until scan_loop returns 0 + cli(); + //while ( scan_loop() ); + sei(); - // Send USB Data - output_send(); - - // Clear sendKeypresses Flag - sendKeypresses = 0; - - // Indicate Error, if valid - errorLED( ledTimer ); + // Run Macros over Key Indices and convert to USB Keys + process_macros(); - if ( ledTimer > 0 ) - ledTimer--; - } + // Send keypresses over USB if the ISR has signalled that it's time + if ( !sendKeypresses ) + continue; - // Loop should never get here (indicate error) - ledTimer = 255; + // Send USB Data + output_send(); - // HID Debug Error message - erro_print("Detection loop error, this is very bad...bug report!"); + // Clear sendKeypresses Flag + sendKeypresses = 0; } }
--- a/setup.cmake Sat Mar 22 14:32:06 2014 -0700 +++ b/setup.cmake Mon Mar 31 01:07:48 2014 -0700 @@ -20,7 +20,7 @@ #| Please look at the {Scan,Macro,USB,Debug}/module.txt for information on the modules and how to create new ones ##| Deals with acquiring the keypress information and turning it into a key index -set( ScanModule "MBC-55X" ) +set( ScanModule "SKM67001" ) ##| Uses the key index and potentially applies special conditions to it, mapping it to a usb key code set( MacroModule "buffer" )