@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2014 by Jacob Alexander | |||
/* Copyright (C) 2014-2015 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 | |||
@@ -422,7 +422,7 @@ void cliFunc_version( char* args ) | |||
print( NL ); | |||
print( " \033[1mRevision:\033[0m " CLI_Revision NL ); | |||
print( " \033[1mBranch:\033[0m " CLI_Branch NL ); | |||
print( " \033[1mTree Status:\033[0m " CLI_ModifiedStatus NL ); | |||
print( " \033[1mTree Status:\033[0m " CLI_ModifiedStatus CLI_ModifiedFiles NL ); | |||
print( " \033[1mRepo Origin:\033[0m " CLI_RepoOrigin NL ); | |||
print( " \033[1mCommit Date:\033[0m " CLI_CommitDate NL ); | |||
print( " \033[1mCommit Author:\033[0m " CLI_CommitAuthor NL ); |
@@ -0,0 +1,40 @@ | |||
# The module defines the following variables: | |||
# DFU_SUFFIX_EXECUTABLE - path to ctags command line client | |||
# DFU_SUFFIX_FOUND - true if the command line client was found | |||
# DFU_SUFFIX_VERSION_STRING - the version of dfu-suffix found (since CMake 2.8.8) | |||
# Example usage: | |||
# find_package( DFUSuffix ) | |||
# if( DFU_SUFFIX_FOUND ) | |||
# message("ctags found: ${DFU_SUFFIX_EXECUTABLE}") | |||
# endif() | |||
find_program ( DFU_SUFFIX_EXECUTABLE | |||
NAMES dfu-suffix | |||
DOC "dfu-suffix executable" | |||
) | |||
mark_as_advanced ( DFU_SUFFIX_EXECUTABLE ) | |||
if ( DFU_SUFFIX_EXECUTABLE ) | |||
execute_process ( COMMAND ${DFU_SUFFIX_EXECUTABLE} --version | |||
OUTPUT_VARIABLE dfu_suffix_version | |||
ERROR_QUIET | |||
OUTPUT_STRIP_TRAILING_WHITESPACE | |||
) | |||
if ( dfu_suffix_version MATCHES "^dfu-suffix \\(dfu-util\\)" ) | |||
string ( REPLACE "\n" "" DFU_SUFFIX_VERSION_STRING ${dfu_suffix_version} ) | |||
string ( REPLACE "dfu-suffix (dfu-util) " "" DFU_SUFFIX_VERSION_STRING ${DFU_SUFFIX_VERSION_STRING} ) | |||
string ( REGEX REPLACE "Copyright .*$" "" DFU_SUFFIX_VERSION_STRING ${DFU_SUFFIX_VERSION_STRING} ) | |||
endif () | |||
unset ( dfu_suffix_version ) | |||
endif () | |||
# Handle the QUIETLY and REQUIRED arguments and set DFU_SUFFIX_FOUND to TRUE if | |||
# all listed variables are TRUE | |||
include ( FindPackageHandleStandardArgs ) | |||
find_package_handle_standard_args ( DFU_SUFFIX | |||
REQUIRED_VARS DFU_SUFFIX_EXECUTABLE | |||
VERSION_VAR DFU_SUFFIX_VERSION_STRING | |||
) | |||
@@ -1,6 +1,6 @@ | |||
###| CMAKE Kiibohd Controller Source Configurator |### | |||
# | |||
# Written by Jacob Alexander in 2011-2014 for the Kiibohd Controller | |||
# Written by Jacob Alexander in 2011-2015 for the Kiibohd Controller | |||
# | |||
# Released into the Public Domain | |||
# | |||
@@ -46,12 +46,25 @@ endif () | |||
#| Convert the .ELF into a .bin to load onto the McHCK | |||
#| Then sign using dfu-suffix (requries dfu-util) | |||
if ( DEFINED DFU ) | |||
# dfu-suffix is required to sign the dfu binary | |||
find_package ( DFUSuffix ) | |||
set( TARGET_BIN ${TARGET}.dfu.bin ) | |||
add_custom_command( TARGET ${TARGET_ELF} POST_BUILD | |||
COMMAND ${OBJ_COPY} ${BIN_FLAGS} ${TARGET_ELF} ${TARGET_BIN} | |||
COMMENT "Creating dfu binary file: ${TARGET_BIN}" | |||
) | |||
if ( DFU_SUFFIX_FOUND ) | |||
add_custom_command( TARGET ${TARGET_ELF} POST_BUILD | |||
COMMAND ${OBJ_COPY} ${BIN_FLAGS} ${TARGET_ELF} ${TARGET_BIN} | |||
COMMAND ${DFU_SUFFIX_EXECUTABLE} --add ${TARGET_BIN} --vid ${BOOT_VENDOR_ID} --pid ${BOOT_PRODUCT_ID} 1> /dev/null | |||
COMMENT "Create and sign dfu bin file: ${TARGET_BIN}" | |||
) | |||
else () | |||
message ( WARNING "DFU Binary has not been signed, requires dfu-suffix..." ) | |||
add_custom_command( TARGET ${TARGET_ELF} POST_BUILD | |||
COMMAND ${OBJ_COPY} ${BIN_FLAGS} ${TARGET_ELF} ${TARGET_BIN} | |||
COMMENT "Creating dfu binary file: ${TARGET_BIN}" | |||
) | |||
endif () | |||
endif () | |||
@@ -1,6 +1,6 @@ | |||
###| CMAKE Kiibohd Controller KLL Configurator |### | |||
# | |||
# Written by Jacob Alexander in 2014 for the Kiibohd Controller | |||
# Written by Jacob Alexander in 2014-2015 for the Kiibohd Controller | |||
# | |||
# Released into the Public Domain | |||
# | |||
@@ -46,14 +46,10 @@ endif () # kll/kll.py exists | |||
#| KLL_DEPENDS is used to build a dependency tree for kll.py, this way when files are changed, kll.py gets re-run | |||
#| Search for capabilities.kll in each module directory | |||
foreach ( DIR ${ScanModulePath} ${MacroModulePath} ${OutputModulePath} ${DebugModulePath} ) | |||
# capabilities.kll exists, add to BaseMap | |||
set ( filename "${PROJECT_SOURCE_DIR}/${DIR}/capabilities.kll" ) | |||
if ( EXISTS ${filename} ) | |||
set ( BaseMap_Args ${BaseMap_Args} ${filename} ) | |||
set ( KLL_DEPENDS ${KLL_DEPENDS} ${filename} ) | |||
endif () | |||
#| Add each of the detected capabilities.kll | |||
foreach ( filename ${ScanModule_KLL} ${MacroModule_KLL} ${OutputModule_KLL} ${DebugModule_KLL} ) | |||
set ( BaseMap_Args ${BaseMap_Args} ${filename} ) | |||
set ( KLL_DEPENDS ${KLL_DEPENDS} ${filename} ) | |||
endforeach () | |||
#| If set BaseMap cannot be found, use default map | |||
@@ -118,21 +114,25 @@ endforeach () | |||
# | |||
#| KLL Options | |||
set ( kll_backend -b kiibohd ) | |||
set ( kll_template -t ${PROJECT_SOURCE_DIR}/kll/templates/kiibohdKeymap.h ) | |||
set ( kll_outputname generatedKeymap.h ) | |||
set ( kll_output -o ${kll_outputname} ) | |||
set ( kll_define_output --defines-output kll_defs.h ) | |||
set ( kll_define_template --defines-template ${PROJECT_SOURCE_DIR}/kll/templates/kiibohdDefs.h ) | |||
set ( kll_backend --backend kiibohd ) | |||
set ( kll_template --templates ${PROJECT_SOURCE_DIR}/kll/templates/kiibohdKeymap.h ${PROJECT_SOURCE_DIR}/kll/templates/kiibohdDefs.h ) | |||
set ( kll_outputname generatedKeymap.h kll_defs.h ) | |||
set ( kll_output --outputs ${kll_outputname} ) | |||
#| KLL Cmd | |||
set ( kll_cmd ${PROJECT_SOURCE_DIR}/kll/kll.py ${BaseMap_Args} ${DefaultMap_Args} ${PartialMap_Args} ${kll_backend} ${kll_template} ${kll_output} ${kll_define_template} ${kll_define_output} ) | |||
set ( kll_cmd ${PROJECT_SOURCE_DIR}/kll/kll.py ${BaseMap_Args} ${DefaultMap_Args} ${PartialMap_Args} ${kll_backend} ${kll_template} ${kll_output} ) | |||
add_custom_command ( OUTPUT ${kll_outputname} | |||
COMMAND ${kll_cmd} | |||
DEPENDS ${KLL_DEPENDS} | |||
COMMENT "Generating KLL Layout" | |||
) | |||
#| KLL Regen Convenience Target | |||
add_custom_target ( kll_regen | |||
COMMAND ${kll_cmd} | |||
COMMENT "Re-generating KLL Layout" | |||
) | |||
#| Append generated file to required sources so it becomes a dependency in the main build | |||
set ( SRCS ${SRCS} ${kll_outputname} ) | |||
@@ -1,6 +1,6 @@ | |||
###| CMAKE Kiibohd Controller Source Configurator |### | |||
# | |||
# Written by Jacob Alexander in 2011-2014 for the Kiibohd Controller | |||
# Written by Jacob Alexander in 2011-2015 for the Kiibohd Controller | |||
# | |||
# Released into the Public Domain | |||
# | |||
@@ -104,10 +104,8 @@ function ( AddModule ModuleType ModuleName ) | |||
PathPrepend ( Module_SRCS ${ModulePath} ${Module_SRCS} ) | |||
# Check the current scope to see if a sub-module added some source files | |||
set ( Module_SRCS ${${ModuleType}_SRCS} ${Module_SRCS} ) | |||
# Append each of the sources to each type of module srcs list | |||
set ( ${ModuleType}_SRCS ${Module_SRCS} ) | |||
set ( ${ModuleType}_SRCS ${${ModuleType}_SRCS} ${Module_SRCS} ) | |||
# Add .h files | |||
add_definitions ( -I${ModuleFullPath} ) | |||
@@ -124,8 +122,17 @@ function ( AddModule ModuleType ModuleName ) | |||
endif () | |||
endforeach () | |||
# Finally, add the sources to the parent scope (i.e. return) | |||
# Check for any capabilities.kll files in the Module | |||
set ( kll_capabilities_file "${ModuleFullPath}/capabilities.kll" ) | |||
if ( EXISTS ${kll_capabilities_file} ) | |||
# Add the kll file and any submodule kll files to the running list | |||
set ( ${ModuleType}Module_KLL ${${ModuleType}Module_KLL} ${kll_capabilities_file} ) | |||
endif () | |||
# Finally, add the sources and kll files to the parent scope (i.e. return) | |||
set ( ${ModuleType}_SRCS ${${ModuleType}_SRCS} PARENT_SCOPE ) | |||
set ( ${ModuleType}Module_KLL ${${ModuleType}Module_KLL} PARENT_SCOPE ) | |||
endfunction () | |||
@@ -150,7 +157,7 @@ find_package ( Ctags ) # Optional | |||
# | |||
#| Manufacturer name | |||
set( MANUFACTURER "Kiibohd" ) | |||
set ( MANUFACTURER "Kiibohd" ) | |||
#| Serial Number | |||
@@ -158,19 +165,29 @@ set( MANUFACTURER "Kiibohd" ) | |||
#| Modified | |||
#| Takes a bit of work to extract the "M " using CMake, and not using it if there are no modifications | |||
execute_process( COMMAND ${GIT_EXECUTABLE} status -s -uno --porcelain | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} status -s -uno --porcelain | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Modified_INFO | |||
ERROR_QUIET | |||
OUTPUT_STRIP_TRAILING_WHITESPACE | |||
) | |||
string( LENGTH "${Git_Modified_INFO}" Git_Modified_LENGTH ) | |||
set( Git_Modified_Status "Clean" ) | |||
string ( LENGTH "${Git_Modified_INFO}" Git_Modified_LENGTH ) | |||
set ( Git_Modified_Status "Clean" ) | |||
if ( ${Git_Modified_LENGTH} GREATER 2 ) | |||
string( SUBSTRING "${Git_Modified_INFO}" 1 2 Git_Modified_Flag_INFO ) | |||
set( Git_Modified_Status "Dirty" ) | |||
string ( SUBSTRING "${Git_Modified_INFO}" 1 2 Git_Modified_Flag_INFO ) | |||
set ( Git_Modified_Status "Dirty" ) | |||
endif () | |||
#| List of modified files | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Modified_Files | |||
ERROR_QUIET | |||
OUTPUT_STRIP_TRAILING_WHITESPACE | |||
) | |||
string ( REGEX REPLACE "\n" "\\\\r\\\\n\\\\t" Git_Modified_Files "${Git_Modified_Files}" ) | |||
set ( Git_Modified_Files "\\r\\n\\t${Git_Modified_Files}" ) | |||
#| Branch | |||
execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
@@ -180,7 +197,7 @@ execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD | |||
) | |||
#| Date | |||
execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format=%ci | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} show -s --format=%ci | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Date_INFO | |||
ERROR_QUIET | |||
@@ -188,7 +205,7 @@ execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format=%ci | |||
) | |||
#| Commit Author and Email | |||
execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format="%cn <%ce>" | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} show -s --format="%cn <%ce>" | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Commit_Author | |||
ERROR_QUIET | |||
@@ -196,7 +213,7 @@ execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format="%cn <%ce>" | |||
) | |||
#| Commit Revision | |||
execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format=%H | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} show -s --format=%H | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Commit_Revision | |||
ERROR_QUIET | |||
@@ -204,7 +221,7 @@ execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format=%H | |||
) | |||
#| Origin URL | |||
execute_process( COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url | |||
execute_process ( COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url | |||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | |||
OUTPUT_VARIABLE Git_Origin_URL | |||
ERROR_QUIET | |||
@@ -212,25 +229,25 @@ execute_process( COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url | |||
) | |||
#| Build Date | |||
execute_process( COMMAND "date" "+%Y-%m-%d %T %z" | |||
execute_process ( COMMAND "date" "+%Y-%m-%d %T %z" | |||
OUTPUT_VARIABLE Build_Date | |||
ERROR_QUIET | |||
OUTPUT_STRIP_TRAILING_WHITESPACE | |||
) | |||
#| Last Commit Date | |||
set( GitLastCommitDate "${Git_Modified_Status} ${Git_Branch_INFO} - ${Git_Date_INFO}" ) | |||
set ( GitLastCommitDate "${Git_Modified_Status} ${Git_Branch_INFO} - ${Git_Date_INFO}" ) | |||
#| Uses CMake variables to include as defines | |||
#| Primarily for USB configuration | |||
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Lib/_buildvars.h buildvars.h ) | |||
configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/Lib/_buildvars.h buildvars.h ) | |||
### | |||
# Source Defines | |||
# | |||
set( SRCS | |||
set ( SRCS | |||
${MAIN_SRCS} | |||
${COMPILER_SRCS} | |||
${Scan_SRCS} | |||
@@ -240,7 +257,7 @@ set( SRCS | |||
) | |||
#| Directories to include by default | |||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) | |||
include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) | |||
@@ -248,20 +265,20 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) | |||
# ctag Generation | |||
# | |||
if( CTAGS_EXECUTABLE ) | |||
if ( CTAGS_EXECUTABLE ) | |||
# Populate list of directories for ctags to parse | |||
# NOTE: Doesn't support dots in the folder names... | |||
foreach( filename ${SRCS} ) | |||
string( REGEX REPLACE "/[a-zA-Z0-9_-]+.c$" "" pathglob ${filename} ) | |||
file( GLOB filenames "${pathglob}/*.c" ) | |||
set( CTAG_PATHS ${CTAG_PATHS} ${filenames} ) | |||
file( GLOB filenames "${pathglob}/*.h" ) | |||
set( CTAG_PATHS ${CTAG_PATHS} ${filenames} ) | |||
endforeach() | |||
foreach ( filename ${SRCS} ) | |||
string ( REGEX REPLACE "/[a-zA-Z0-9_-]+.c$" "" pathglob ${filename} ) | |||
file ( GLOB filenames "${pathglob}/*.c" ) | |||
set ( CTAG_PATHS ${CTAG_PATHS} ${filenames} ) | |||
file ( GLOB filenames "${pathglob}/*.h" ) | |||
set ( CTAG_PATHS ${CTAG_PATHS} ${filenames} ) | |||
endforeach () | |||
# Generate the ctags | |||
execute_process( COMMAND ctags ${CTAG_PATHS} | |||
execute_process ( COMMAND ctags ${CTAG_PATHS} | |||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |||
) | |||
endif() | |||
endif () | |||
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2013-2014 by Jacob Alexander | |||
/* Copyright (C) 2013-2015 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 | |||
@@ -38,6 +38,7 @@ | |||
#define CLI_Revision "@Git_Commit_Revision@" | |||
#define CLI_Branch "@Git_Branch_INFO@" | |||
#define CLI_ModifiedStatus "@Git_Modified_Status@" | |||
#define CLI_ModifiedFiles "@Git_Modified_Files@" | |||
#define CLI_RepoOrigin "@Git_Origin_URL@" | |||
#define CLI_CommitDate "@Git_Date_INFO@" | |||
#define CLI_CommitAuthor @Git_Commit_Author@ |
@@ -49,7 +49,7 @@ done | |||
if [[ "$SERIAL_PORT" != "" ]] && [[ -e "$SERIAL_PORT" ]]; then | |||
echo "NOTE: This may fail if the uC is in a bad state or does not support remote flashing" | |||
printf "reload\r" > $SERIAL_PORT | |||
sleep 1 | |||
sleep 2 | |||
fi | |||
# Load via dfu-util |
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2014 by Jacob Alexander | |||
/* Copyright (C) 2014-2015 by Jacob Alexander | |||
* | |||
* This file is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
@@ -121,9 +121,11 @@ uint8_t macroPauseMode = 0; | |||
uint16_t macroStepCounter = 0; | |||
// Key Trigger List Buffer | |||
// Key Trigger List Buffer and Layer Cache | |||
// The layer cache is set on press only, hold and release events refer to the value set on press | |||
TriggerGuide macroTriggerListBuffer[ MaxScanCode ]; | |||
uint8_t macroTriggerListBufferSize = 0; | |||
var_uint_t macroTriggerListLayerCache[ MaxScanCode ]; | |||
// Pending Trigger Macro Index List | |||
// * Any trigger macros that need processing from a previous macro processing loop | |||
@@ -311,8 +313,24 @@ void Macro_layerShift_capability( uint8_t state, uint8_t stateType, uint8_t *arg | |||
// Looks up the trigger list for the given scan code (from the active layer) | |||
// NOTE: Calling function must handle the NULL pointer case | |||
nat_ptr_t *Macro_layerLookup( uint8_t scanCode, uint8_t latch_expire ) | |||
nat_ptr_t *Macro_layerLookup( TriggerGuide *guide, uint8_t latch_expire ) | |||
{ | |||
uint8_t scanCode = guide->scanCode; | |||
// TODO Analog | |||
// If a normal key, and not pressed, do a layer cache lookup | |||
if ( guide->type == 0x00 && guide->state != 0x01 ) | |||
{ | |||
// Cached layer | |||
var_uint_t cachedLayer = macroTriggerListLayerCache[ scanCode ]; | |||
// Lookup map, then layer | |||
nat_ptr_t **map = (nat_ptr_t**)LayerIndex[ cachedLayer ].triggerMap; | |||
const Layer *layer = &LayerIndex[ cachedLayer ]; | |||
return map[ scanCode - layer->first ]; | |||
} | |||
// If no trigger macro is defined at the given layer, fallthrough to the next layer | |||
for ( uint16_t layerIndex = 0; layerIndex < macroLayerIndexStackSize; layerIndex++ ) | |||
{ | |||
@@ -342,6 +360,9 @@ nat_ptr_t *Macro_layerLookup( uint8_t scanCode, uint8_t latch_expire ) | |||
&& scanCode >= layer->first | |||
&& *map[ scanCode - layer->first ] != 0 ) | |||
{ | |||
// Set the layer cache | |||
macroTriggerListLayerCache[ scanCode ] = macroLayerIndexStack[ layerIndex ]; | |||
return map[ scanCode - layer->first ]; | |||
} | |||
} | |||
@@ -359,6 +380,9 @@ nat_ptr_t *Macro_layerLookup( uint8_t scanCode, uint8_t latch_expire ) | |||
&& scanCode >= layer->first | |||
&& *map[ scanCode - layer->first ] != 0 ) | |||
{ | |||
// Set the layer cache to default map | |||
macroTriggerListLayerCache[ scanCode ] = 0; | |||
return map[ scanCode - layer->first ]; | |||
} | |||
@@ -836,7 +860,7 @@ inline void Macro_updateTriggerMacroPendingList() | |||
uint8_t latch_expire = macroTriggerListBuffer[ key ].state == 0x03; | |||
// Lookup Trigger List | |||
nat_ptr_t *triggerList = Macro_layerLookup( macroTriggerListBuffer[ key ].scanCode, latch_expire ); | |||
nat_ptr_t *triggerList = Macro_layerLookup( ¯oTriggerListBuffer[ key ], latch_expire ); | |||
// Number of Triggers in list | |||
nat_ptr_t triggerListSize = triggerList[0]; |
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2011-2014 by Jacob Alexander | |||
/* Copyright (C) 2011-2015 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 | |||
@@ -113,7 +113,7 @@ | |||
#define KEY_UP 0x52 | |||
#define KEY_NUM_LOCK 0x53 | |||
#define KEYPAD_SLASH 0x54 | |||
#define KEYPAD_ASTERIX 0x55 | |||
#define KEYPAD_ASTERISK 0x55 | |||
#define KEYPAD_MINUS 0x56 | |||
#define KEYPAD_PLUS 0x57 | |||
#define KEYPAD_ENTER 0x58 |
@@ -300,7 +300,7 @@ static void usb_setup() | |||
data = reply_buffer; | |||
break; | |||
case 0x0082: // GET_STATUS (endpoint) | |||
if (setup.wIndex > NUM_ENDPOINTS) | |||
if ( setup.wIndex > NUM_ENDPOINTS ) | |||
{ | |||
// TODO: do we need to handle IN vs OUT here? | |||
endpoint0_stall(); | |||
@@ -313,17 +313,31 @@ static void usb_setup() | |||
data = reply_buffer; | |||
datalen = 2; | |||
break; | |||
case 0x0102: // CLEAR_FEATURE (endpoint) | |||
case 0x0100: // CLEAR_FEATURE (device) | |||
case 0x0101: // CLEAR_FEATURE (interface) | |||
// TODO: Currently ignoring, perhaps useful? -HaaTa | |||
endpoint0_stall(); | |||
return; | |||
case 0x0102: // CLEAR_FEATURE (interface) | |||
i = setup.wIndex & 0x7F; | |||
if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) | |||
{ | |||
// TODO: do we need to handle IN vs OUT here? | |||
endpoint0_stall(); | |||
return; | |||
} | |||
(*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; | |||
//(*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; | |||
// TODO: do we need to clear the data toggle here? | |||
break; | |||
//break; | |||
// FIXME: Clearing causes keyboard to freeze, likely an invalid clear | |||
// XXX: Ignoring seems to work, though this may not be the ideal behaviour -HaaTa | |||
endpoint0_stall(); | |||
return; | |||
case 0x0300: // SET_FEATURE (device) | |||
case 0x0301: // SET_FEATURE (interface) | |||
// TODO: Currently ignoring, perhaps useful? -HaaTa | |||
endpoint0_stall(); | |||
return; | |||
case 0x0302: // SET_FEATURE (endpoint) | |||
i = setup.wIndex & 0x7F; | |||
if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) |
@@ -1,7 +1,7 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2013 PJRC.COM, LLC. | |||
* Modifications by Jacob Alexander 2013-2014 | |||
* Modifications by Jacob Alexander 2013-2015 | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
@@ -120,6 +120,23 @@ void usb_keyboard_send() | |||
{ | |||
// Send boot keyboard interrupt packet(s) | |||
case 0: | |||
// USB Boot Mode debug output | |||
if ( Output_DebugMode ) | |||
{ | |||
dbug_msg("Boot USB: "); | |||
printHex_op( USBKeys_Modifiers, 2 ); | |||
print(" "); | |||
printHex( 0 ); | |||
print(" "); | |||
printHex_op( USBKeys_Keys[0], 2 ); | |||
printHex_op( USBKeys_Keys[1], 2 ); | |||
printHex_op( USBKeys_Keys[2], 2 ); | |||
printHex_op( USBKeys_Keys[3], 2 ); | |||
printHex_op( USBKeys_Keys[4], 2 ); | |||
printHex_op( USBKeys_Keys[5], 2 ); | |||
print( NL ); | |||
} | |||
// Boot Mode | |||
*tx_buf++ = USBKeys_Modifiers; | |||
*tx_buf++ = 0; | |||
@@ -133,9 +150,21 @@ void usb_keyboard_send() | |||
// Send NKRO keyboard interrupts packet(s) | |||
case 1: | |||
if ( Output_DebugMode ) | |||
{ | |||
dbug_msg("NKRO USB: "); | |||
} | |||
// Check system control keys | |||
if ( USBKeys_Changed & USBKeyChangeState_System ) | |||
{ | |||
if ( Output_DebugMode ) | |||
{ | |||
print("SysCtrl["); | |||
printHex_op( USBKeys_SysCtrl, 2 ); | |||
print( "] " NL ); | |||
} | |||
*tx_buf++ = 0x02; // ID | |||
*tx_buf = USBKeys_SysCtrl; | |||
tx_packet->len = 2; | |||
@@ -148,6 +177,13 @@ void usb_keyboard_send() | |||
// Check consumer control keys | |||
if ( USBKeys_Changed & USBKeyChangeState_Consumer ) | |||
{ | |||
if ( Output_DebugMode ) | |||
{ | |||
print("ConsCtrl["); | |||
printHex_op( USBKeys_ConsCtrl, 2 ); | |||
print( "] " NL ); | |||
} | |||
*tx_buf++ = 0x03; // ID | |||
*tx_buf++ = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); | |||
*tx_buf = (uint8_t)(USBKeys_ConsCtrl >> 8); | |||
@@ -161,6 +197,24 @@ void usb_keyboard_send() | |||
// Standard HID Keyboard | |||
if ( USBKeys_Changed ) | |||
{ | |||
// USB NKRO Debug output | |||
if ( Output_DebugMode ) | |||
{ | |||
printHex_op( USBKeys_Modifiers, 2 ); | |||
print(" "); | |||
for ( uint8_t c = 0; c < 6; c++ ) | |||
printHex_op( USBKeys_Keys[ c ], 2 ); | |||
print(" "); | |||
for ( uint8_t c = 6; c < 20; c++ ) | |||
printHex_op( USBKeys_Keys[ c ], 2 ); | |||
print(" "); | |||
printHex_op( USBKeys_Keys[20], 2 ); | |||
print(" "); | |||
for ( uint8_t c = 21; c < 27; c++ ) | |||
printHex_op( USBKeys_Keys[ c ], 2 ); | |||
print( NL ); | |||
} | |||
tx_packet->len = 0; | |||
// Modifiers |
@@ -61,6 +61,7 @@ | |||
// ----- Function Declarations ----- | |||
void cliFunc_kbdProtocol( char* args ); | |||
void cliFunc_outputDebug( char* args ); | |||
void cliFunc_readLEDs ( char* args ); | |||
void cliFunc_sendKeys ( char* args ); | |||
void cliFunc_setKeys ( char* args ); | |||
@@ -72,6 +73,7 @@ void cliFunc_setMod ( char* args ); | |||
// Output Module command dictionary | |||
CLIDict_Entry( kbdProtocol, "Keyboard Protocol Mode: 0 - Boot, 1 - OS/NKRO Mode" ); | |||
CLIDict_Entry( outputDebug, "Toggle Output Debug mode." ); | |||
CLIDict_Entry( readLEDs, "Read LED byte:" NL "\t\t1 NumLck, 2 CapsLck, 4 ScrlLck, 16 Kana, etc." ); | |||
CLIDict_Entry( sendKeys, "Send the prepared list of USB codes and modifier byte." ); | |||
CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." ); | |||
@@ -79,6 +81,7 @@ CLIDict_Entry( setMod, "Set the modfier byte:" NL "\t\t1 LCtrl, 2 LShft, 4 | |||
CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { | |||
CLIDict_Item( kbdProtocol ), | |||
CLIDict_Item( outputDebug ), | |||
CLIDict_Item( readLEDs ), | |||
CLIDict_Item( sendKeys ), | |||
CLIDict_Item( setKeys ), | |||
@@ -129,6 +132,11 @@ USBKeyChangeState USBKeys_Changed = USBKeyChangeState_None; | |||
// 0 is often used to show that a USB cable is not plugged in (but has power) | |||
uint8_t Output_Available = 0; | |||
// Debug control variable for Output modules | |||
// 0 - Debug disabled (default) | |||
// 1 - Debug enabled | |||
uint8_t Output_DebugMode = 0; | |||
// ----- Capabilities ----- | |||
@@ -211,7 +219,10 @@ void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t * | |||
// Only send keypresses if press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
{ | |||
USBKeys_ConsCtrl = 0; | |||
return; | |||
} | |||
// Set consumer control code | |||
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | |||
@@ -242,7 +253,10 @@ void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *a | |||
// Only send keypresses if press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
{ | |||
USBKeys_SysCtrl = 0; | |||
return; | |||
} | |||
// Set system control code | |||
USBKeys_SysCtrl = args[0]; | |||
@@ -584,6 +598,24 @@ void cliFunc_kbdProtocol( char* args ) | |||
} | |||
void cliFunc_outputDebug( char* args ) | |||
{ | |||
// Parse number from argument | |||
// NOTE: Only first argument is used | |||
char* arg1Ptr; | |||
char* arg2Ptr; | |||
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr ); | |||
// Default to 1 if no argument is given | |||
Output_DebugMode = 1; | |||
if ( arg1Ptr[0] != '\0' ) | |||
{ | |||
Output_DebugMode = (uint16_t)numToInt( arg1Ptr ); | |||
} | |||
} | |||
void cliFunc_readLEDs( char* args ) | |||
{ | |||
print( NL ); |
@@ -81,6 +81,8 @@ extern USBKeyChangeState USBKeys_Changed; | |||
extern uint8_t Output_Available; // 0 - Output module not fully functional, 1 - Output module working | |||
extern uint8_t Output_DebugMode; // 0 - Debug disabled, 1 - Debug enabled | |||
// ----- Capabilities ----- |
@@ -1,14 +0,0 @@ | |||
Name = usbMuxUartCapabilities; | |||
Version = 0.1; | |||
Author = "HaaTa (Jacob Alexander) 2014"; | |||
KLL = 0.3; | |||
# Modified Date | |||
Date = 2014-09-28; | |||
# Capabilties available to the usbMuxUart output module | |||
consCtrlOut => Output_consCtrlSend_capability( consCode : 2 ); | |||
sysCtrlOut => Output_sysCtrlSend_capability( sysCode : 1 ); | |||
usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 ); | |||
@@ -33,10 +33,10 @@ | |||
// USB Includes | |||
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) | |||
#elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) | |||
#include <uartOut/arm/uart_serial.h> | |||
#include <pjrcUSB/arm/usb_dev.h> | |||
#include <pjrcUSB/arm/usb_keyboard.h> | |||
#include <pjrcUSB/arm/usb_serial.h> | |||
#include <arm/uart_serial.h> | |||
#include <arm/usb_dev.h> | |||
#include <arm/usb_keyboard.h> | |||
#include <arm/usb_serial.h> | |||
#endif | |||
// Local Includes | |||
@@ -135,10 +135,69 @@ USBKeyChangeState USBKeys_Changed = USBKeyChangeState_None; | |||
// 0 is often used to show that a USB cable is not plugged in (but has power) | |||
uint8_t Output_Available = 0; | |||
// Debug control variable for Output modules | |||
// 0 - Debug disabled (default) | |||
// 1 - Debug enabled | |||
uint8_t Output_DebugMode = 0; | |||
// ----- Capabilities ----- | |||
// Set Boot Keyboard Protocol | |||
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Output_kbdProtocolBoot()"); | |||
return; | |||
} | |||
// Only set if necessary | |||
if ( USBKeys_Protocol == 0 ) | |||
return; | |||
// TODO Analog inputs | |||
// Only set on key press | |||
if ( stateType != 0x01 ) | |||
return; | |||
// Flush the key buffers | |||
Output_flushBuffers(); | |||
// Set the keyboard protocol to Boot Mode | |||
USBKeys_Protocol = 0; | |||
} | |||
// Set NKRO Keyboard Protocol | |||
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Output_kbdProtocolNKRO()"); | |||
return; | |||
} | |||
// Only set if necessary | |||
if ( USBKeys_Protocol == 1 ) | |||
return; | |||
// TODO Analog inputs | |||
// Only set on key press | |||
if ( stateType != 0x01 ) | |||
return; | |||
// Flush the key buffers | |||
Output_flushBuffers(); | |||
// Set the keyboard protocol to NKRO Mode | |||
USBKeys_Protocol = 1; | |||
} | |||
// Sends a Consumer Control code to the USB Output buffer | |||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
@@ -374,6 +433,20 @@ void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *a | |||
// ----- Functions ----- | |||
// Flush Key buffers | |||
void Output_flushBuffers() | |||
{ | |||
// Zero out USBKeys_Keys array | |||
for ( uint8_t c = 0; c < USB_NKRO_BITFIELD_SIZE_KEYS; c++ ) | |||
USBKeys_Keys[ c ] = 0; | |||
// Zero out other key buffers | |||
USBKeys_ConsCtrl = 0; | |||
USBKeys_Modifiers = 0; | |||
USBKeys_SysCtrl = 0; | |||
} | |||
// USB Module Setup | |||
inline void Output_setup() | |||
{ |
@@ -80,6 +80,8 @@ extern USBKeyChangeState USBKeys_Changed; | |||
extern uint8_t Output_Available; // 0 - Output module not fully functional, 1 - Output module working | |||
extern uint8_t Output_DebugMode; // 0 - Debug disabled, 1 - Debug enabled | |||
// ----- Capabilities ----- | |||
@@ -88,6 +90,10 @@ void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t * | |||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
// Configuration capabilities | |||
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
// ----- Functions ----- | |||
@@ -95,6 +101,8 @@ void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *a | |||
void Output_setup(); | |||
void Output_send(); | |||
void Output_flushBuffers(); | |||
void Output_firmwareReload(); | |||
void Output_softReset(); | |||
@@ -23,6 +23,12 @@ set( Module_SRCS | |||
output_com.c | |||
) | |||
# Remove duplicate output_com.c files from pjrcUSB and uartOut | |||
list ( REMOVE_ITEM Output_SRCS | |||
Output/pjrcUSB/output_com.c | |||
Output/uartOut/output_com.c | |||
) | |||
### | |||
# Compiler Family Compatibility |
@@ -9,8 +9,9 @@ Teensy 3.0/3.1, McHCK). | |||
Linux is the ideal build environment (preferably recent'ish). In the near | |||
future I'll make available an Arch Linux VM for building/manufacturing tests. | |||
Building on Mac should be ok for 99% of users with Macports (haven't tried | |||
Brew). The dfu Bootloader will not build correctly with the old version of | |||
Building on Mac should be ok for 99% of users with Macports or Homebrew. For | |||
Homebrew, use `brew tap PX4/homebrew-px4` to get the arm-none-eabi-gcc installer. | |||
The dfu Bootloader will not build correctly with the old version of | |||
arm-none-eabi-gcc that Macports currently has (4.7.3). This is due to a bug | |||
with lto (link time optimizations) which makes the resulting binary too big to | |||
fit on the chip (must be less than 4096 Bytes). | |||
@@ -58,7 +59,7 @@ ARM Specific (Teensy 3.0/3.1, Infinity Keyboard, McHCK) | |||
- Arch Linux / Mac Ports | |||
- arm-none-eabi-gcc | |||
- arm-none-eaby-binutils | |||
- arm-none-eabi-binutils | |||
- Windows (https://launchpad.net/gcc-arm-embedded/+download) | |||
- gcc-arm-none-eabi (win32.zip) | |||
@@ -262,6 +263,112 @@ There are also CMake options for temporarily selecting modules. But it's | |||
easier to just edit the file. e.g. `cmake -DScanModuleOverride=<module name>`. | |||
Keymap Configuration | |||
-------------------- | |||
This is where you define the layout for your keyboard. | |||
Currently, the only way to define kebyoard layouts is using [KLL](https://www.overleaf.com/read/zzqbdwqjfwwf). | |||
KLL is built up of 3 different kinds of keymaps in total. | |||
The BaseMap, DefaultMap and PartialMaps. | |||
For each type of keymap, it is possible to combine multiple .kll files together to create new ones using | |||
the compiler. The order of the files matter, as the right-most file will overwrite any setting in the | |||
previous files. | |||
> NOTE: Each keymap is done after the entire file is processed. This means that within the file the order | |||
> of assignment doesa *not* matter (if you assign the same thing twice, then yes the most recent one | |||
> takes priority). | |||
BaseMap defines what the keyboard can do. This includes specific capabilities of the keyboard (such as USB), | |||
the mapping of Scan Codes to USB Codes and any specific configurations for the keyboard. | |||
In general, the BaseMap rarely needs to be changed. Usually only when adding a new keyboard to the firmware | |||
does the Basemap need any modification. | |||
The BaseMap is what both DefaultMap and PartialMaps are based upon. This allows for a common reference | |||
when defining custom keymappings. | |||
> NOTE: Don't use defaultMap.kll to change your layouts. This will work, but they will not be portable. | |||
The DefaultMap is the normal state of the keyboard, i.e. your default layer. | |||
Using the BaseMap as a base, the DefaultMap is a modification of the BaseMap to what the keyboard should do. | |||
Since the DefaultMap uses USB Code to USB Code translations, this means that keymaps used for one keyboard | |||
will work with another keyboard. | |||
For example, I use Colemak, so this means I only have to define Colemak once for every keyboard that supports | |||
the kiibohd firmware. This is possible because every BaseMap defines the keyboard as a US ANSI like keyboard | |||
layout. | |||
The DefaultMap can also be thought of as Layer 0. | |||
PartialMaps are optional keymaps that can be "stacked" on top of the DefaultMap. | |||
They can be dynamically swapped out using the layer control capabilities: | |||
- layerLatch( `<layer number>` ) | |||
- layerLock( `<layer number>` ) | |||
- layerShift( `<layer number>` ) | |||
layerShift is usually what you want as it works just like a standard shift key. | |||
layerLock is similar to the CapsLock key. While layerLatch is a latch, where only the next key you press | |||
will use that layer (e.g. stickykeys). | |||
A unique aspect of KLL layers is that it's a true stack of layers. | |||
When a layer is activated, only the keys that are specified by the layer will change. | |||
This means, if you define a layer that only sets `CapsLock -> LCtrl` and `LCtrl->Capslock` only those keys | |||
will change when you active the layer. All the other keys will use the layer that is "underneath" to | |||
lookup the keypress (usually the DefaultMap). | |||
This means that you can combine .kll files statically using the compiler or dynamically using the firmware. | |||
You can set the max number of layers by changing the `stateWordSize` define in one of your kll files. | |||
By default it is set to 8 in Macro/PartialMap/capabilities.kll. This means you can have up to 256 layers | |||
total (this includes the DefaultMap). | |||
You can increase this number to either 16 or 32 (this will use more Flash and RAM btw) which will give you | |||
2^16 and 2^32 possible layers respectively (65 535 and 4 294 967 295). | |||
```cmake | |||
### | |||
# Keymap Configuration (do not include the .kll extension) | |||
# | |||
#| Do not include the .kll extension | |||
#| * BaseMap maps the native keyboard scan codes to USB Codes so the layout is compatible with all other layouts | |||
#| * DefaultMap allows the default keymap to be modified from the BaseMap | |||
#| * PartialMaps is a set of dynamically set layers (there is no limit, but too many may use up too much RAM...) | |||
#| BaseMap generally does not need to be changed from "defaultMap" | |||
#| | |||
#| Syntax: | |||
#| myMap | |||
#| * defines a single .kll layout file, double-quotes are needed to distinguish between layers | |||
#| "myMap specialLayer" | |||
#| * defines myMap to be the main layout, then replace specialLayers on top of it | |||
#| | |||
#| - Only for PartialMaps - | |||
#| "myMap specialLayer" "myMap colemak" dvorak | |||
#| * As before, but also generates a second layer at index 2 and third at index 3 | |||
#| | |||
#| NOTE: Remember to add key(s) to enable each Partial Layer | |||
#| NOTE2: Layers are always based up the BaseMap (which should be an ANSI-like mapping) | |||
#| NOTE3: Compiler looks in kll/layouts and the build directory for layout files (precedence on build directory) | |||
##| Set the base keyboard .kll map, defaults to "defaultMap" if not found | |||
##| Looks in Scan/<Module Name> for the available BaseMaps | |||
set( BaseMap "defaultMap" | |||
CACHE STRING "KLL BaseMap/Scancode Keymapping" ) | |||
##| Layer additonal .kll maps on the BaseMap, layers are in order from 1st to nth | |||
##| Can be set to "" | |||
set( DefaultMap "md1Overlay stdFuncMap" | |||
CACHE STRING "KLL DefaultMap" ) | |||
##| ParitalMaps available on top of the BaseMap. See above for syntax on specifying multiple layers vs. layering | |||
##| Can be set to "" | |||
set( PartialMaps "hhkbpro2" | |||
CACHE STRING "KLL PartialMaps/Layer Definitions" ) | |||
``` | |||
Linux Building | |||
-------------- | |||
@@ -0,0 +1,34 @@ | |||
Name = MatrixArmCapabilities; | |||
Version = 0.1; | |||
Author = "HaaTa (Jacob Alexander) 2015"; | |||
KLL = 0.3a; | |||
# Modified Date | |||
Date = 2015-02-28; | |||
# Defines available to the MatrixArm sub-module | |||
# This debounce scheme uses a rolling counter for press/unpress on each key | |||
# Each counter is incremented if pressed/unpressed and the opposite counter is divided by 2 | |||
# Using the default division threshold (0xFFFF), there are approximately 13 cycles in a perfect cycle | |||
# If debounce is actually necessary, this will increase (better switches will debounce faster) | |||
# | |||
# The maximum threshold is 0xFFFFFFFF, which will give around ~32 -> 36 cycles per perfect cycle | |||
# Using a threshold higher than 0xFFFF will require 32 bit variables, and double the ram usage. | |||
DebounceDivThreshold => DebounceDivThreshold_define; | |||
DebounceDivThreshold = 0xFFFF; # Default debounce | |||
#DebounceDivThreshold = 0xFFFFFFFF; # Max debounce | |||
# This defines how often the matrix is scanned | |||
# By, default the key matrix is scanned once per macro processing loop | |||
# For fast uCs and bouncy switches, this can be non-ideal | |||
# 0 - Bit-shift of 0 | |||
# 1 - Bit-shift of 1 (i.e. divide by 2) | |||
# 2 - Bit-shift of 2 (i.e. divide by 4) | |||
# 3 - Bit-shift of 3 (i.e. divide by 8) | |||
# etc. | |||
# Depending on the architecture, this is either a maximum of 16 or 32 | |||
# Increasing this value will increase switch latency | |||
DebounceThrottleDiv => DebounceThrottleDiv_define; | |||
DebounceThrottleDiv = 0; # Default | |||
#DebounceThrottleDiv = 2; # /4 divider | |||
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2014 by Jacob Alexander | |||
/* Copyright (C) 2014-2015 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 | |||
@@ -26,6 +26,7 @@ | |||
// Project Includes | |||
#include <cli.h> | |||
#include <kll.h> | |||
#include <led.h> | |||
#include <print.h> | |||
#include <macro.h> | |||
@@ -38,6 +39,14 @@ | |||
// ----- Defines ----- | |||
#if ( DebounceThrottleDiv_define > 0 ) | |||
nat_ptr_t Matrix_divCounter = 0; | |||
#endif | |||
// ----- Function Declarations ----- | |||
// CLI Functions | |||
@@ -191,7 +200,7 @@ void Matrix_setup() | |||
Matrix_scanArray[ item ].prevState = KeyState_Off; | |||
Matrix_scanArray[ item ].curState = KeyState_Off; | |||
Matrix_scanArray[ item ].activeCount = 0; | |||
Matrix_scanArray[ item ].inactiveCount = 0xFFFF; // Start at 'off' steady state | |||
Matrix_scanArray[ item ].inactiveCount = DebounceDivThreshold_define; // Start at 'off' steady state | |||
} | |||
// Clear scan stats counters | |||
@@ -232,6 +241,15 @@ void Matrix_keyPositionDebug( KeyPosition pos ) | |||
// NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters) | |||
void Matrix_scan( uint16_t scanNum ) | |||
{ | |||
#if ( DebounceThrottleDiv_define > 0 ) | |||
// Scan-rate throttling | |||
// By scanning using a divider, the scan rate slowed down | |||
// DebounceThrottleDiv_define == 1 means -> /2 or half scan rate | |||
// This helps with bouncy switches on fast uCs | |||
if ( !( Matrix_divCounter++ & (1 << ( DebounceThrottleDiv_define - 1 )) ) ) | |||
return; | |||
#endif | |||
// Increment stats counters | |||
if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum; | |||
if ( scanNum == 0 ) | |||
@@ -275,14 +293,14 @@ void Matrix_scan( uint16_t scanNum ) | |||
if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) ) | |||
{ | |||
// Only update if not going to wrap around | |||
if ( state->activeCount < 0xFFFF ) state->activeCount += 1; | |||
if ( state->activeCount < DebounceDivThreshold_define ) state->activeCount += 1; | |||
state->inactiveCount >>= 1; | |||
} | |||
// Signal Not Detected | |||
else | |||
{ | |||
// Only update if not going to wrap around | |||
if ( state->inactiveCount < 0xFFFF ) state->inactiveCount += 1; | |||
if ( state->inactiveCount < DebounceDivThreshold_define ) state->inactiveCount += 1; | |||
state->activeCount >>= 1; | |||
} | |||
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2014 by Jacob Alexander | |||
/* Copyright (C) 2014-2015 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 | |||
@@ -24,6 +24,23 @@ | |||
// ----- Includes ----- | |||
// KLL Generated Defines | |||
#include <kll_defs.h> | |||
// ----- Defines ----- | |||
#if ( DebounceDivThreshold_define < 0xFF + 1 ) | |||
#define DebounceCounter uint8_t | |||
#elif ( DebounceDivThreshold_define < 0xFFFF + 1 ) | |||
#define DebounceCounter uint16_t | |||
#elif ( DebounceDivThreshold_define < 0xFFFFFFFF + 1 ) | |||
#define DebounceCounter uint32_t | |||
#else | |||
#error "Debounce threshold is too high... 32 bit max. Check .kll defines." | |||
#endif | |||
// ----- Enums ----- | |||
@@ -110,10 +127,10 @@ typedef struct GPIO_Pin { | |||
// Debounce Element | |||
typedef struct KeyState { | |||
KeyPosition prevState; | |||
KeyPosition curState; | |||
uint16_t activeCount; | |||
uint16_t inactiveCount; | |||
KeyPosition prevState; | |||
KeyPosition curState; | |||
DebounceCounter activeCount; | |||
DebounceCounter inactiveCount; | |||
} KeyState; | |||