/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
print( NL ); | print( NL ); | ||||
print( " \033[1mRevision:\033[0m " CLI_Revision NL ); | print( " \033[1mRevision:\033[0m " CLI_Revision NL ); | ||||
print( " \033[1mBranch:\033[0m " CLI_Branch 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[1mRepo Origin:\033[0m " CLI_RepoOrigin NL ); | ||||
print( " \033[1mCommit Date:\033[0m " CLI_CommitDate NL ); | print( " \033[1mCommit Date:\033[0m " CLI_CommitDate NL ); | ||||
print( " \033[1mCommit Author:\033[0m " CLI_CommitAuthor NL ); | print( " \033[1mCommit Author:\033[0m " CLI_CommitAuthor NL ); |
# 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 | |||||
) | |||||
###| CMAKE Kiibohd Controller Source Configurator |### | ###| 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 | # Released into the Public Domain | ||||
# | # | ||||
#| Convert the .ELF into a .bin to load onto the McHCK | #| Convert the .ELF into a .bin to load onto the McHCK | ||||
#| Then sign using dfu-suffix (requries dfu-util) | |||||
if ( DEFINED DFU ) | if ( DEFINED DFU ) | ||||
# dfu-suffix is required to sign the dfu binary | |||||
find_package ( DFUSuffix ) | |||||
set( TARGET_BIN ${TARGET}.dfu.bin ) | 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 () | endif () | ||||
###| CMAKE Kiibohd Controller KLL Configurator |### | ###| 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 | # Released into the Public Domain | ||||
# | # | ||||
#| KLL_DEPENDS is used to build a dependency tree for kll.py, this way when files are changed, kll.py gets re-run | #| 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 () | endforeach () | ||||
#| If set BaseMap cannot be found, use default map | #| If set BaseMap cannot be found, use default map | ||||
# | # | ||||
#| KLL Options | #| 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 | #| 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} | add_custom_command ( OUTPUT ${kll_outputname} | ||||
COMMAND ${kll_cmd} | COMMAND ${kll_cmd} | ||||
DEPENDS ${KLL_DEPENDS} | DEPENDS ${KLL_DEPENDS} | ||||
COMMENT "Generating KLL Layout" | 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 | #| Append generated file to required sources so it becomes a dependency in the main build | ||||
set ( SRCS ${SRCS} ${kll_outputname} ) | set ( SRCS ${SRCS} ${kll_outputname} ) | ||||
###| CMAKE Kiibohd Controller Source Configurator |### | ###| 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 | # Released into the Public Domain | ||||
# | # | ||||
PathPrepend ( Module_SRCS ${ModulePath} ${Module_SRCS} ) | PathPrepend ( Module_SRCS ${ModulePath} ${Module_SRCS} ) | ||||
# Check the current scope to see if a sub-module added some source files | # 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 | # 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 .h files | ||||
add_definitions ( -I${ModuleFullPath} ) | add_definitions ( -I${ModuleFullPath} ) | ||||
endif () | endif () | ||||
endforeach () | 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}_SRCS ${${ModuleType}_SRCS} PARENT_SCOPE ) | ||||
set ( ${ModuleType}Module_KLL ${${ModuleType}Module_KLL} PARENT_SCOPE ) | |||||
endfunction () | endfunction () | ||||
# | # | ||||
#| Manufacturer name | #| Manufacturer name | ||||
set( MANUFACTURER "Kiibohd" ) | |||||
set ( MANUFACTURER "Kiibohd" ) | |||||
#| Serial Number | #| Serial Number | ||||
#| Modified | #| Modified | ||||
#| Takes a bit of work to extract the "M " using CMake, and not using it if there are no modifications | #| 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} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
OUTPUT_VARIABLE Git_Modified_INFO | OUTPUT_VARIABLE Git_Modified_INFO | ||||
ERROR_QUIET | ERROR_QUIET | ||||
OUTPUT_STRIP_TRAILING_WHITESPACE | 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 ) | 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 () | 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 | #| Branch | ||||
execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD | execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD | ||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
) | ) | ||||
#| Date | #| Date | ||||
execute_process( COMMAND ${GIT_EXECUTABLE} show -s --format=%ci | |||||
execute_process ( COMMAND ${GIT_EXECUTABLE} show -s --format=%ci | |||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
OUTPUT_VARIABLE Git_Date_INFO | OUTPUT_VARIABLE Git_Date_INFO | ||||
ERROR_QUIET | ERROR_QUIET | ||||
) | ) | ||||
#| Commit Author and Email | #| 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} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
OUTPUT_VARIABLE Git_Commit_Author | OUTPUT_VARIABLE Git_Commit_Author | ||||
ERROR_QUIET | ERROR_QUIET | ||||
) | ) | ||||
#| Commit Revision | #| 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} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
OUTPUT_VARIABLE Git_Commit_Revision | OUTPUT_VARIABLE Git_Commit_Revision | ||||
ERROR_QUIET | ERROR_QUIET | ||||
) | ) | ||||
#| Origin URL | #| 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} | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} | ||||
OUTPUT_VARIABLE Git_Origin_URL | OUTPUT_VARIABLE Git_Origin_URL | ||||
ERROR_QUIET | ERROR_QUIET | ||||
) | ) | ||||
#| Build Date | #| Build Date | ||||
execute_process( COMMAND "date" "+%Y-%m-%d %T %z" | |||||
execute_process ( COMMAND "date" "+%Y-%m-%d %T %z" | |||||
OUTPUT_VARIABLE Build_Date | OUTPUT_VARIABLE Build_Date | ||||
ERROR_QUIET | ERROR_QUIET | ||||
OUTPUT_STRIP_TRAILING_WHITESPACE | OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
) | ) | ||||
#| Last Commit Date | #| 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 | #| Uses CMake variables to include as defines | ||||
#| Primarily for USB configuration | #| 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 | # Source Defines | ||||
# | # | ||||
set( SRCS | |||||
set ( SRCS | |||||
${MAIN_SRCS} | ${MAIN_SRCS} | ||||
${COMPILER_SRCS} | ${COMPILER_SRCS} | ||||
${Scan_SRCS} | ${Scan_SRCS} | ||||
) | ) | ||||
#| Directories to include by default | #| 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} ) | |||||
# ctag Generation | # ctag Generation | ||||
# | # | ||||
if( CTAGS_EXECUTABLE ) | |||||
if ( CTAGS_EXECUTABLE ) | |||||
# Populate list of directories for ctags to parse | # Populate list of directories for ctags to parse | ||||
# NOTE: Doesn't support dots in the folder names... | # 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 | # Generate the ctags | ||||
execute_process( COMMAND ctags ${CTAG_PATHS} | |||||
execute_process ( COMMAND ctags ${CTAG_PATHS} | |||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
) | ) | ||||
endif() | |||||
endif () | |||||
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
#define CLI_Revision "@Git_Commit_Revision@" | #define CLI_Revision "@Git_Commit_Revision@" | ||||
#define CLI_Branch "@Git_Branch_INFO@" | #define CLI_Branch "@Git_Branch_INFO@" | ||||
#define CLI_ModifiedStatus "@Git_Modified_Status@" | #define CLI_ModifiedStatus "@Git_Modified_Status@" | ||||
#define CLI_ModifiedFiles "@Git_Modified_Files@" | |||||
#define CLI_RepoOrigin "@Git_Origin_URL@" | #define CLI_RepoOrigin "@Git_Origin_URL@" | ||||
#define CLI_CommitDate "@Git_Date_INFO@" | #define CLI_CommitDate "@Git_Date_INFO@" | ||||
#define CLI_CommitAuthor @Git_Commit_Author@ | #define CLI_CommitAuthor @Git_Commit_Author@ |
if [[ "$SERIAL_PORT" != "" ]] && [[ -e "$SERIAL_PORT" ]]; then | 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" | echo "NOTE: This may fail if the uC is in a bad state or does not support remote flashing" | ||||
printf "reload\r" > $SERIAL_PORT | printf "reload\r" > $SERIAL_PORT | ||||
sleep 1 | |||||
sleep 2 | |||||
fi | fi | ||||
# Load via dfu-util | # Load via dfu-util |
/* 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 | * 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 | * it under the terms of the GNU General Public License as published by | ||||
uint16_t macroStepCounter = 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 ]; | TriggerGuide macroTriggerListBuffer[ MaxScanCode ]; | ||||
uint8_t macroTriggerListBufferSize = 0; | uint8_t macroTriggerListBufferSize = 0; | ||||
var_uint_t macroTriggerListLayerCache[ MaxScanCode ]; | |||||
// Pending Trigger Macro Index List | // Pending Trigger Macro Index List | ||||
// * Any trigger macros that need processing from a previous macro processing loop | // * Any trigger macros that need processing from a previous macro processing loop | ||||
// Looks up the trigger list for the given scan code (from the active layer) | // Looks up the trigger list for the given scan code (from the active layer) | ||||
// NOTE: Calling function must handle the NULL pointer case | // 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 | // If no trigger macro is defined at the given layer, fallthrough to the next layer | ||||
for ( uint16_t layerIndex = 0; layerIndex < macroLayerIndexStackSize; layerIndex++ ) | for ( uint16_t layerIndex = 0; layerIndex < macroLayerIndexStackSize; layerIndex++ ) | ||||
{ | { | ||||
&& scanCode >= layer->first | && scanCode >= layer->first | ||||
&& *map[ scanCode - layer->first ] != 0 ) | && *map[ scanCode - layer->first ] != 0 ) | ||||
{ | { | ||||
// Set the layer cache | |||||
macroTriggerListLayerCache[ scanCode ] = macroLayerIndexStack[ layerIndex ]; | |||||
return map[ scanCode - layer->first ]; | return map[ scanCode - layer->first ]; | ||||
} | } | ||||
} | } | ||||
&& scanCode >= layer->first | && scanCode >= layer->first | ||||
&& *map[ scanCode - layer->first ] != 0 ) | && *map[ scanCode - layer->first ] != 0 ) | ||||
{ | { | ||||
// Set the layer cache to default map | |||||
macroTriggerListLayerCache[ scanCode ] = 0; | |||||
return map[ scanCode - layer->first ]; | return map[ scanCode - layer->first ]; | ||||
} | } | ||||
uint8_t latch_expire = macroTriggerListBuffer[ key ].state == 0x03; | uint8_t latch_expire = macroTriggerListBuffer[ key ].state == 0x03; | ||||
// Lookup Trigger List | // 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 | // Number of Triggers in list | ||||
nat_ptr_t triggerListSize = triggerList[0]; | nat_ptr_t triggerListSize = triggerList[0]; |
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
#define KEY_UP 0x52 | #define KEY_UP 0x52 | ||||
#define KEY_NUM_LOCK 0x53 | #define KEY_NUM_LOCK 0x53 | ||||
#define KEYPAD_SLASH 0x54 | #define KEYPAD_SLASH 0x54 | ||||
#define KEYPAD_ASTERIX 0x55 | |||||
#define KEYPAD_ASTERISK 0x55 | |||||
#define KEYPAD_MINUS 0x56 | #define KEYPAD_MINUS 0x56 | ||||
#define KEYPAD_PLUS 0x57 | #define KEYPAD_PLUS 0x57 | ||||
#define KEYPAD_ENTER 0x58 | #define KEYPAD_ENTER 0x58 |
data = reply_buffer; | data = reply_buffer; | ||||
break; | break; | ||||
case 0x0082: // GET_STATUS (endpoint) | 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? | // TODO: do we need to handle IN vs OUT here? | ||||
endpoint0_stall(); | endpoint0_stall(); | ||||
data = reply_buffer; | data = reply_buffer; | ||||
datalen = 2; | datalen = 2; | ||||
break; | 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; | i = setup.wIndex & 0x7F; | ||||
if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) | if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) | ||||
{ | { | ||||
// TODO: do we need to handle IN vs OUT here? | |||||
endpoint0_stall(); | endpoint0_stall(); | ||||
return; | 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? | // 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) | case 0x0302: // SET_FEATURE (endpoint) | ||||
i = setup.wIndex & 0x7F; | i = setup.wIndex & 0x7F; | ||||
if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) | if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | * 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 | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
{ | { | ||||
// Send boot keyboard interrupt packet(s) | // Send boot keyboard interrupt packet(s) | ||||
case 0: | 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 | // Boot Mode | ||||
*tx_buf++ = USBKeys_Modifiers; | *tx_buf++ = USBKeys_Modifiers; | ||||
*tx_buf++ = 0; | *tx_buf++ = 0; | ||||
// Send NKRO keyboard interrupts packet(s) | // Send NKRO keyboard interrupts packet(s) | ||||
case 1: | case 1: | ||||
if ( Output_DebugMode ) | |||||
{ | |||||
dbug_msg("NKRO USB: "); | |||||
} | |||||
// Check system control keys | // Check system control keys | ||||
if ( USBKeys_Changed & USBKeyChangeState_System ) | if ( USBKeys_Changed & USBKeyChangeState_System ) | ||||
{ | { | ||||
if ( Output_DebugMode ) | |||||
{ | |||||
print("SysCtrl["); | |||||
printHex_op( USBKeys_SysCtrl, 2 ); | |||||
print( "] " NL ); | |||||
} | |||||
*tx_buf++ = 0x02; // ID | *tx_buf++ = 0x02; // ID | ||||
*tx_buf = USBKeys_SysCtrl; | *tx_buf = USBKeys_SysCtrl; | ||||
tx_packet->len = 2; | tx_packet->len = 2; | ||||
// Check consumer control keys | // Check consumer control keys | ||||
if ( USBKeys_Changed & USBKeyChangeState_Consumer ) | if ( USBKeys_Changed & USBKeyChangeState_Consumer ) | ||||
{ | { | ||||
if ( Output_DebugMode ) | |||||
{ | |||||
print("ConsCtrl["); | |||||
printHex_op( USBKeys_ConsCtrl, 2 ); | |||||
print( "] " NL ); | |||||
} | |||||
*tx_buf++ = 0x03; // ID | *tx_buf++ = 0x03; // ID | ||||
*tx_buf++ = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); | *tx_buf++ = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); | ||||
*tx_buf = (uint8_t)(USBKeys_ConsCtrl >> 8); | *tx_buf = (uint8_t)(USBKeys_ConsCtrl >> 8); | ||||
// Standard HID Keyboard | // Standard HID Keyboard | ||||
if ( USBKeys_Changed ) | 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; | tx_packet->len = 0; | ||||
// Modifiers | // Modifiers |
// ----- Function Declarations ----- | // ----- Function Declarations ----- | ||||
void cliFunc_kbdProtocol( char* args ); | void cliFunc_kbdProtocol( char* args ); | ||||
void cliFunc_outputDebug( char* args ); | |||||
void cliFunc_readLEDs ( char* args ); | void cliFunc_readLEDs ( char* args ); | ||||
void cliFunc_sendKeys ( char* args ); | void cliFunc_sendKeys ( char* args ); | ||||
void cliFunc_setKeys ( char* args ); | void cliFunc_setKeys ( char* args ); | ||||
// Output Module command dictionary | // Output Module command dictionary | ||||
CLIDict_Entry( kbdProtocol, "Keyboard Protocol Mode: 0 - Boot, 1 - OS/NKRO Mode" ); | 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( 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( 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." ); | CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." ); | ||||
CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { | CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { | ||||
CLIDict_Item( kbdProtocol ), | CLIDict_Item( kbdProtocol ), | ||||
CLIDict_Item( outputDebug ), | |||||
CLIDict_Item( readLEDs ), | CLIDict_Item( readLEDs ), | ||||
CLIDict_Item( sendKeys ), | CLIDict_Item( sendKeys ), | ||||
CLIDict_Item( setKeys ), | CLIDict_Item( setKeys ), | ||||
// 0 is often used to show that a USB cable is not plugged in (but has power) | // 0 is often used to show that a USB cable is not plugged in (but has power) | ||||
uint8_t Output_Available = 0; | uint8_t Output_Available = 0; | ||||
// Debug control variable for Output modules | |||||
// 0 - Debug disabled (default) | |||||
// 1 - Debug enabled | |||||
uint8_t Output_DebugMode = 0; | |||||
// ----- Capabilities ----- | // ----- Capabilities ----- | ||||
// Only send keypresses if press or hold state | // Only send keypresses if press or hold state | ||||
if ( stateType == 0x00 && state == 0x03 ) // Release state | if ( stateType == 0x00 && state == 0x03 ) // Release state | ||||
{ | |||||
USBKeys_ConsCtrl = 0; | |||||
return; | return; | ||||
} | |||||
// Set consumer control code | // Set consumer control code | ||||
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | ||||
// Only send keypresses if press or hold state | // Only send keypresses if press or hold state | ||||
if ( stateType == 0x00 && state == 0x03 ) // Release state | if ( stateType == 0x00 && state == 0x03 ) // Release state | ||||
{ | |||||
USBKeys_SysCtrl = 0; | |||||
return; | return; | ||||
} | |||||
// Set system control code | // Set system control code | ||||
USBKeys_SysCtrl = args[0]; | USBKeys_SysCtrl = args[0]; | ||||
} | } | ||||
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 ) | void cliFunc_readLEDs( char* args ) | ||||
{ | { | ||||
print( NL ); | print( NL ); |
extern uint8_t Output_Available; // 0 - Output module not fully functional, 1 - Output module working | 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 ----- | // ----- Capabilities ----- |
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 ); | |||||
// USB Includes | // USB Includes | ||||
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) | #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) | ||||
#elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) | #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 | #endif | ||||
// Local Includes | // Local Includes | ||||
// 0 is often used to show that a USB cable is not plugged in (but has power) | // 0 is often used to show that a USB cable is not plugged in (but has power) | ||||
uint8_t Output_Available = 0; | uint8_t Output_Available = 0; | ||||
// Debug control variable for Output modules | |||||
// 0 - Debug disabled (default) | |||||
// 1 - Debug enabled | |||||
uint8_t Output_DebugMode = 0; | |||||
// ----- Capabilities ----- | // ----- 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 | // Sends a Consumer Control code to the USB Output buffer | ||||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
// ----- Functions ----- | // ----- 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 | // USB Module Setup | ||||
inline void Output_setup() | inline void Output_setup() | ||||
{ | { |
extern uint8_t Output_Available; // 0 - Output module not fully functional, 1 - Output module working | 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 ----- | // ----- Capabilities ----- | ||||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | 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 ); | 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 ----- | // ----- Functions ----- | ||||
void Output_setup(); | void Output_setup(); | ||||
void Output_send(); | void Output_send(); | ||||
void Output_flushBuffers(); | |||||
void Output_firmwareReload(); | void Output_firmwareReload(); | ||||
void Output_softReset(); | void Output_softReset(); | ||||
output_com.c | 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 | # Compiler Family Compatibility |
Linux is the ideal build environment (preferably recent'ish). In the near | 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. | 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 | 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 | with lto (link time optimizations) which makes the resulting binary too big to | ||||
fit on the chip (must be less than 4096 Bytes). | fit on the chip (must be less than 4096 Bytes). | ||||
- Arch Linux / Mac Ports | - Arch Linux / Mac Ports | ||||
- arm-none-eabi-gcc | - arm-none-eabi-gcc | ||||
- arm-none-eaby-binutils | |||||
- arm-none-eabi-binutils | |||||
- Windows (https://launchpad.net/gcc-arm-embedded/+download) | - Windows (https://launchpad.net/gcc-arm-embedded/+download) | ||||
- gcc-arm-none-eabi (win32.zip) | - gcc-arm-none-eabi (win32.zip) | ||||
easier to just edit the file. e.g. `cmake -DScanModuleOverride=<module name>`. | 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 | Linux Building | ||||
-------------- | -------------- | ||||
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 | |||||
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
// Project Includes | // Project Includes | ||||
#include <cli.h> | #include <cli.h> | ||||
#include <kll.h> | |||||
#include <led.h> | #include <led.h> | ||||
#include <print.h> | #include <print.h> | ||||
#include <macro.h> | #include <macro.h> | ||||
// ----- Defines ----- | |||||
#if ( DebounceThrottleDiv_define > 0 ) | |||||
nat_ptr_t Matrix_divCounter = 0; | |||||
#endif | |||||
// ----- Function Declarations ----- | // ----- Function Declarations ----- | ||||
// CLI Functions | // CLI Functions | ||||
Matrix_scanArray[ item ].prevState = KeyState_Off; | Matrix_scanArray[ item ].prevState = KeyState_Off; | ||||
Matrix_scanArray[ item ].curState = KeyState_Off; | Matrix_scanArray[ item ].curState = KeyState_Off; | ||||
Matrix_scanArray[ item ].activeCount = 0; | 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 | // Clear scan stats counters | ||||
// NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters) | // NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters) | ||||
void Matrix_scan( uint16_t scanNum ) | 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 | // Increment stats counters | ||||
if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum; | if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum; | ||||
if ( scanNum == 0 ) | if ( scanNum == 0 ) | ||||
if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) ) | if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) ) | ||||
{ | { | ||||
// Only update if not going to wrap around | // 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; | state->inactiveCount >>= 1; | ||||
} | } | ||||
// Signal Not Detected | // Signal Not Detected | ||||
else | else | ||||
{ | { | ||||
// Only update if not going to wrap around | // 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; | state->activeCount >>= 1; | ||||
} | } | ||||
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
// ----- Includes ----- | // ----- 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 ----- | // ----- Enums ----- | ||||
// Debounce Element | // Debounce Element | ||||
typedef struct KeyState { | typedef struct KeyState { | ||||
KeyPosition prevState; | |||||
KeyPosition curState; | |||||
uint16_t activeCount; | |||||
uint16_t inactiveCount; | |||||
KeyPosition prevState; | |||||
KeyPosition curState; | |||||
DebounceCounter activeCount; | |||||
DebounceCounter inactiveCount; | |||||
} KeyState; | } KeyState; | ||||