#| "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}" )
#
#| 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)"
)
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 )
void cliFunc_restart( char* args )
{
// Trigger an overall software reset
- SOFTWARE_RESET();
+ output_softReset();
}
void cliFunc_version( char* args )
// ----- 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;
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* );
}
// 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
}
// Compiler Includes
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_)
-
#include <avr/pgmspace.h>
-#include "avr/usb_keyboard_debug.h"
-
-#elif defined(_mk20dx128_) || defined(_mk20dx256_)
-
-#include "arm/usb_serial.h"
-
#endif
+// Project Includes
+#include <output_com.h>
+
// ----- Defines -----
*/
// 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) \
#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
// 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@"
/* 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
* 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.
/* 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
* 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.
#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
#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
+++ /dev/null
-/* 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
-}
-
+++ /dev/null
-#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
+/* 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
+/* 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__
+
#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"
+// ----- 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
uint8_t USBKeys_Idle_Count = 0;
-
// ----- Functions -----
// USB Module Setup
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?)
}
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
+}
+
// ----- 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
set( OUTPUT_SRCS
output_com.c
- avr/usb_keyboard_debug.c
+ avr/usb_keyboard_serial.c
)
#| ARM Compiler
- 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
- 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:
#| "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.
#| type "make clean" after changing this, so all files will be rebuilt
#|
#| "mk20dx128" # Teensy 3.0
+ #| "mk20dx256" # Teensy 3.1
set( CHIP "mk20dx128" )
- 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".
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.
#| 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" )
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" )
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
[ 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
+/* 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
+/* 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
+###| 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
+)
+
add_definitions( -I${HEAD_DIR}/Keymap )
add_definitions(
-I${HEAD_DIR}/Scan/matrix
-)
+)
#| Keymap Settings
add_definitions(
+++ /dev/null
-/* 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;
-}
-
+++ /dev/null
-/* 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
-###| 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
-)
-
-/* 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
-/* 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
-/* 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
// 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.
-/* 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
-/* 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
###| CMAKE Kiibohd Controller |###
#
-# Jacob Alexander 2011-2013
+# Jacob Alexander 2011-2014
# Due to this file's usefulness:
#
# Released into the Public Domain
#| "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}" )
)
+#| 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" )
#| Warning Options
#| -Wall...: warning level
-set( WARN "-Wall -Wstrict-prototypes" )
+set( WARN "-Wall" )
#| Tuning Options
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" )
{
// Configuring Pins
pinSetup();
- init_errorLED();
-
- // Setup Output Module
- output_setup();
// Enable CLI
init_cli();
+ // Setup Output Module
+ output_setup();
+
// 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();
-
- 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;
-
- // Send USB Data
- output_send();
+ // Process CLI
+ process_cli();
- // Clear sendKeypresses Flag
- sendKeypresses = 0;
+ // Acquire Key Indices
+ // Loop continuously until scan_loop returns 0
+ cli();
+ //while ( scan_loop() );
+ sei();
- // 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;
}
}
#| 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" )