Merge pull request #1088 from keyboardio/f/keyboardio-model-100-hacked-up-for-basic-usb

With this PR and a release of our GD32 Arduino core, basic Model 100 functionality works
pull/1094/head
Jesse Vincent 3 years ago committed by GitHub
commit d6b7d7d4c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,7 +12,7 @@ endif
DEFAULT_GOAL: smoke-sketches DEFAULT_GOAL: smoke-sketches
setup: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt $(ARDUINO_CLI_PATH) $(ARDUINO_DIRECTORIES_DATA)/arduino-cli.yaml install-arduino-core-avr setup: $(ARDUINO_CLI_PATH) $(ARDUINO_DIRECTORIES_DATA)/arduino-cli.yaml install-arduino-core-avr install-arduino-core-kaleidoscope $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt
@: @:
@ -27,9 +27,22 @@ $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt:
$(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt:
git clone -c core.symlinks=true --recurse-submodules=":(exclude)avr/libraries/Kaleidoscope" --recurse-submodules=build-tools --recurse-submodules=toolchain --recurse-submodules=avr/libraries/ git://github.com/keyboardio/Kaleidoscope-Bundle-Keyboardio $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio git clone -c core.symlinks=true \
rm -d $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope --recurse-submodules=":(exclude)avr/libraries/Kaleidoscope" \
--recurse-submodules=":(exclude)gd32/libraries/Kaleidoscope" \
--recurse-submodules=avr/libraries/ \
--recurse-submodules=gd32/ \
--recurse-submodules=gd32/libraries/ \
git://github.com/keyboardio/Kaleidoscope-Bundle-Keyboardio \
$(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio
-rm -d $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope
ln -s $(KALEIDOSCOPE_DIR) $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope ln -s $(KALEIDOSCOPE_DIR) $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope
git clone -c core.symlinks=true \
--recurse-submodules=":(exclude)libraries/Kaleidoscope" \
--recurse-submodules=libraries/ \
git://github.com/keyboardio/ArduinoCore-GD32-Keyboardio $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/gd32
-rm -d $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/gd32/libraries/Kaleidoscope
ln -s $(KALEIDOSCOPE_DIR) $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/gd32/libraries/Kaleidoscope
simulator-tests: simulator-tests:
$(MAKE) -C tests all $(MAKE) -C tests all

@ -164,6 +164,7 @@ arduino-update-cores:
install-arduino-core-kaleidoscope: arduino-update-cores install-arduino-core-kaleidoscope: arduino-update-cores
$(QUIET) $(ARDUINO_CLI) core install "keyboardio:avr" $(QUIET) $(ARDUINO_CLI) core install "keyboardio:avr"
$(QUIET) $(ARDUINO_CLI) core install "keyboardio:gd32"
install-arduino-core-avr: arduino-update-cores install-arduino-core-avr: arduino-update-cores
$(QUIET) $(ARDUINO_CLI) core install "arduino:avr" $(QUIET) $(ARDUINO_CLI) core install "arduino:avr"

@ -209,12 +209,21 @@ ensure-device-port-defined:
echo ;\ echo ;\
exit -1;fi exit -1;fi
flash: ensure-device-port-defined ifneq ($(FQBN),)
fqbn_arg = --fqbn $(FQBN)
endif
ifneq ($(KALEIDOSCOPE_DEVICE_PORT),)
port_arg = --port $(KALEIDOSCOPE_DEVICE_PORT)
endif
flash:
$(info $(unescaped_flashing_instructions)) $(info $(unescaped_flashing_instructions))
$(info ) $(info )
$(info When you're ready to proceed, press 'Enter'.) $(info When you're ready to proceed, press 'Enter'.)
$(info ) $(info )
@$(shell read _) @$(shell read _)
$(QUIET) $(ARDUINO_CLI) upload --fqbn $(FQBN) \ $(QUIET) $(ARDUINO_CLI) upload $(fqbn_arg) \
--input-dir "${OUTPUT_PATH}" \ --input-dir "${OUTPUT_PATH}" \
--port $(KALEIDOSCOPE_DEVICE_PORT) $(ARDUINO_VERBOSE) $(port_arg) $(ARDUINO_VERBOSE)

@ -0,0 +1,48 @@
# This makefile for a Kaleidoscope sketch pulls in all the targets
# required to build the example
ifneq ($(KALEIDOSCOPE_DIR),)
search_path += $(KALEIDOSCOPE_DIR)
endif
ifneq ($(ARDUINO_DIRECTORIES_USER),)
search_path += $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope
endif
ifeq ($(shell uname -s),Darwin)
search_path += $(HOME)/Documents/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
else
search_path += $(HOME)/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
endif
sketch_makefile := etc/makefiles/sketch.mk
$(foreach candidate, $(search_path), $(if $(wildcard $(candidate)/$(sketch_makefile)), $(eval ks_dir ?= $(candidate))))
ifneq ($(ks_dir),)
$(info Using Kaleidoscope from $(ks_dir))
export KALEIDOSCOPE_DIR := $(ks_dir)
include $(ks_dir)/$(sketch_makefile)
else
$(info I can't find your Kaleidoscope installation.)
$(info )
$(info I tried looking in:)
$(info )
$(foreach candidate, $(search_path), $(info $(candidate)))
$(info )
$(info The easiest way to fix this is to set the 'KALEIDOSCOPE_DIR' environment)
$(info variable to the location of your Kaleidoscope directory.)
endif
null-target:
$(info You should never see this message)
@:

@ -0,0 +1,571 @@
// -*- mode: c++ -*-
// Copyright 2016 Keyboardio, inc. <jesse@keyboard.io>
// See "LICENSE" for license details
#ifndef BUILD_INFORMATION
#define BUILD_INFORMATION "locally built on " __DATE__ " at " __TIME__
#endif
/**
* These #include directives pull in the Kaleidoscope firmware core,
* as well as the Kaleidoscope plugins we use in the Model 100's firmware
*/
// The Kaleidoscope core
#include "Kaleidoscope.h"
// Support for storing the keymap in EEPROM
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h"
// Support for communicating with the host via a simple Serial protocol
//#include "Kaleidoscope-FocusSerial.h"
// Support for keys that move the mouse
#include "Kaleidoscope-MouseKeys.h"
// Support for macros
#include "Kaleidoscope-Macros.h"
// Support for controlling the keyboard's LEDs
#include "Kaleidoscope-LEDControl.h"
// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode
#include "Kaleidoscope-NumPad.h"
// Support for the "Boot greeting" effect, which pulses the 'LED' button for 10s
// when the keyboard is connected to a computer (or that computer is powered on)
#include "Kaleidoscope-LEDEffect-BootGreeting.h"
// Support for LED modes that set all LEDs to a single color
#include "Kaleidoscope-LEDEffect-SolidColor.h"
// Support for an LED mode that makes all the LEDs 'breathe'
#include "Kaleidoscope-LEDEffect-Breathe.h"
// Support for an LED mode that makes a red pixel chase a blue pixel across the keyboard
#include "Kaleidoscope-LEDEffect-Chase.h"
// Support for LED modes that pulse the keyboard's LED in a rainbow pattern
#include "Kaleidoscope-LEDEffect-Rainbow.h"
// Support for an LED mode that lights up the keys as you press them
#include "Kaleidoscope-LED-Stalker.h"
// Support for an LED mode that prints the keys you press in letters 4px high
#include "Kaleidoscope-LED-AlphaSquare.h"
// Support for shared palettes for other plugins, like Colormap below
#include "Kaleidoscope-LED-Palette-Theme.h"
// Support for an LED mode that lets one configure per-layer color maps
#include "Kaleidoscope-Colormap.h"
// Support for Keyboardio's internal keyboard testing mode
#include "Kaleidoscope-HardwareTestMode.h"
// Support for host power management (suspend & wakeup)
#include "Kaleidoscope-HostPowerManagement.h"
// Support for magic combos (key chords that trigger an action)
#include "Kaleidoscope-MagicCombo.h"
// Support for USB quirks, like changing the key state report protocol
#include "Kaleidoscope-USB-Quirks.h"
/** This 'enum' is a list of all the macros used by the Model 100's firmware
* The names aren't particularly important. What is important is that each
* is unique.
*
* These are the names of your macros. They'll be used in two places.
* The first is in your keymap definitions. There, you'll use the syntax
* `M(MACRO_NAME)` to mark a specific keymap position as triggering `MACRO_NAME`
*
* The second usage is in the 'switch' statement in the `macroAction` function.
* That switch statement actually runs the code associated with a macro when
* a macro key is pressed.
*/
enum { MACRO_VERSION_INFO,
MACRO_ANY
};
/** The Model 100's key layouts are defined as 'keymaps'. By default, there are three
* keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad"
* keymap.
*
* Each keymap is defined as a list using the 'KEYMAP_STACKED' macro, built
* of first the left hand's layout, followed by the right hand's layout.
*
* Keymaps typically consist mostly of `Key_` definitions. There are many, many keys
* defined as part of the USB HID Keyboard specification. You can find the names
* (if not yet the explanations) for all the standard `Key_` defintions offered by
* Kaleidoscope in these files:
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keyboard.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_consumerctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_sysctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keymaps.h
*
* Additional things that should be documented here include
* using ___ to let keypresses fall through to the previously active layer
* using XXX to mark a keyswitch as 'blocked' on this layer
* using ShiftToLayer() and LockLayer() keys to change the active keymap.
* keeping NUM and FN consistent and accessible on all layers
*
* The PROG key is special, since it is how you indicate to the board that you
* want to flash the firmware. However, it can be remapped to a regular key.
* When the keyboard boots, it first looks to see whether the PROG key is held
* down; if it is, it simply awaits further flashing instructions. If it is
* not, it continues loading the rest of the firmware and the keyboard
* functions normally, with whatever binding you have set to PROG. More detail
* here: https://community.keyboard.io/t/how-the-prog-key-gets-you-into-the-bootloader/506/8
*
* The "keymaps" data structure is a list of the keymaps compiled into the firmware.
* The order of keymaps in the list is important, as the ShiftToLayer(#) and LockLayer(#)
* macros switch to key layers based on this list.
*
*
* A key defined as 'ShiftToLayer(FUNCTION)' will switch to FUNCTION while held.
* Similarly, a key defined as 'LockLayer(NUMPAD)' will switch to NUMPAD when tapped.
*/
/**
* Layers are "0-indexed" -- That is the first one is layer 0. The second one is layer 1.
* The third one is layer 2.
* This 'enum' lets us use names like QWERTY, FUNCTION, and NUMPAD in place of
* the numbers 0, 1 and 2.
*
*/
enum { PRIMARY, NUMPAD, FUNCTION }; // layers
/**
* To change your keyboard's layout from QWERTY to DVORAK or COLEMAK, comment out the line
*
* #define PRIMARY_KEYMAP_QWERTY
*
* by changing it to
*
* // #define PRIMARY_KEYMAP_QWERTY
*
* Then uncomment the line corresponding to the layout you want to use.
*
*/
#define PRIMARY_KEYMAP_QWERTY
// #define PRIMARY_KEYMAP_DVORAK
// #define PRIMARY_KEYMAP_COLEMAK
// #define PRIMARY_KEYMAP_CUSTOM
/* This comment temporarily turns off astyle's indent enforcement
* so we can make the keymaps actually resemble the physical key layout better
*/
// *INDENT-OFF*
KEYMAPS(
#if defined (PRIMARY_KEYMAP_QWERTY)
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#elif defined (PRIMARY_KEYMAP_DVORAK)
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Backtick, Key_Quote, Key_Comma, Key_Period, Key_P, Key_Y, Key_Tab,
Key_PageUp, Key_A, Key_O, Key_E, Key_U, Key_I,
Key_PageDown, Key_Semicolon, Key_Q, Key_J, Key_K, Key_X, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_F, Key_G, Key_C, Key_R, Key_L, Key_Slash,
Key_D, Key_H, Key_T, Key_N, Key_S, Key_Minus,
Key_RightAlt, Key_B, Key_M, Key_W, Key_V, Key_Z, Key_Equals,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#elif defined (PRIMARY_KEYMAP_COLEMAK)
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Backtick, Key_Q, Key_W, Key_F, Key_P, Key_G, Key_Tab,
Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_D,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_J, Key_L, Key_U, Key_Y, Key_Semicolon, Key_Equals,
Key_H, Key_N, Key_E, Key_I, Key_O, Key_Quote,
Key_RightAlt, Key_K, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#elif defined (PRIMARY_KEYMAP_CUSTOM)
// Edit this keymap to make a custom layout
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#else
#error "No default keymap defined. You should make sure that you have a line like '#define PRIMARY_KEYMAP_QWERTY' in your sketch"
#endif
[NUMPAD] = KEYMAP_STACKED
(___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___,
M(MACRO_VERSION_INFO), ___, Key_7, Key_8, Key_9, Key_KeypadSubtract, ___,
___, ___, Key_4, Key_5, Key_6, Key_KeypadAdd, ___,
___, Key_1, Key_2, Key_3, Key_Equals, ___,
___, ___, Key_0, Key_Period, Key_KeypadMultiply, Key_KeypadDivide, Key_Enter,
___, ___, ___, ___,
___),
[FUNCTION] = KEYMAP_STACKED
(___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, Key_CapsLock,
Key_Tab, ___, Key_mouseUp, ___, Key_mouseBtnR, Key_mouseWarpEnd, Key_mouseWarpNE,
Key_Home, Key_mouseL, Key_mouseDn, Key_mouseR, Key_mouseBtnL, Key_mouseWarpNW,
Key_End, Key_PrintScreen, Key_Insert, ___, Key_mouseBtnM, Key_mouseWarpSW, Key_mouseWarpSE,
___, Key_Delete, ___, ___,
___,
Consumer_ScanPreviousTrack, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
Consumer_PlaySlashPause, Consumer_ScanNextTrack, Key_LeftCurlyBracket, Key_RightCurlyBracket, Key_LeftBracket, Key_RightBracket, Key_F12,
Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
Key_PcApplication, Consumer_Mute, Consumer_VolumeDecrement, Consumer_VolumeIncrement, ___, Key_Backslash, Key_Pipe,
___, ___, Key_Enter, ___,
___)
) // KEYMAPS(
/* Re-enable astyle's indent enforcement */
// *INDENT-ON*
/** versionInfoMacro handles the 'firmware version info' macro
* When a key bound to the macro is pressed, this macro
* prints out the firmware build information as virtual keystrokes
*/
static void versionInfoMacro(uint8_t key_state) {
if (keyToggledOn(key_state)) {
Macros.type(PSTR("Keyboardio Model 100 - Kaleidoscope "));
Macros.type(PSTR(BUILD_INFORMATION));
}
}
/** anyKeyMacro is used to provide the functionality of the 'Any' key.
*
* When the 'any key' macro is toggled on, a random alphanumeric key is
* selected. While the key is held, the function generates a synthetic
* keypress event repeating that randomly selected key.
*
*/
static void anyKeyMacro(KeyEvent &event) {
if (keyToggledOn(event.state)) {
event.key.setKeyCode(Key_A.getKeyCode() + (uint8_t)(millis() % 36));
event.key.setFlags(0);
}
}
/** macroAction dispatches keymap events that are tied to a macro
to that macro. It takes two uint8_t parameters.
The first is the macro being called (the entry in the 'enum' earlier in this file).
The second is the state of the keyswitch. You can use the keyswitch state to figure out
if the key has just been toggled on, is currently pressed or if it's just been released.
The 'switch' statement should have a 'case' for each entry of the macro enum.
Each 'case' statement should call out to a function to handle the macro in question.
*/
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
switch (macro_id) {
case MACRO_VERSION_INFO:
versionInfoMacro(event.state);
break;
case MACRO_ANY:
anyKeyMacro(event);
break;
}
return MACRO_NONE;
}
// These 'solid' color effect definitions define a rainbow of
// LED color modes calibrated to draw 500mA or less on the
// Keyboardio Model 100.
static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0);
static kaleidoscope::plugin::LEDSolidColor solidOrange(140, 70, 0);
static kaleidoscope::plugin::LEDSolidColor solidYellow(130, 100, 0);
static kaleidoscope::plugin::LEDSolidColor solidGreen(0, 160, 0);
static kaleidoscope::plugin::LEDSolidColor solidBlue(0, 70, 130);
static kaleidoscope::plugin::LEDSolidColor solidIndigo(0, 0, 170);
static kaleidoscope::plugin::LEDSolidColor solidViolet(130, 0, 120);
/** toggleLedsOnSuspendResume toggles the LEDs off when the host goes to sleep,
* and turns them back on when it wakes up.
*/
void toggleLedsOnSuspendResume(kaleidoscope::plugin::HostPowerManagement::Event event) {
switch (event) {
case kaleidoscope::plugin::HostPowerManagement::Suspend:
LEDControl.disable();
break;
case kaleidoscope::plugin::HostPowerManagement::Resume:
LEDControl.enable();
break;
case kaleidoscope::plugin::HostPowerManagement::Sleep:
break;
}
}
/** hostPowerManagementEventHandler dispatches power management events (suspend,
* resume, and sleep) to other functions that perform action based on these
* events.
*/
void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event) {
toggleLedsOnSuspendResume(event);
}
/** This 'enum' is a list of all the magic combos used by the Model 100's
* firmware The names aren't particularly important. What is important is that
* each is unique.
*
* These are the names of your magic combos. They will be used by the
* `USE_MAGIC_COMBOS` call below.
*/
enum {
// Toggle between Boot (6-key rollover; for BIOSes and early boot) and NKRO
// mode.
COMBO_TOGGLE_NKRO_MODE,
// Enter test mode
COMBO_ENTER_TEST_MODE
};
/** Wrappers, to be used by MagicCombo. **/
/**
* This simply toggles the keyboard protocol via USBQuirks, and wraps it within
* a function with an unused argument, to match what MagicCombo expects.
*/
static void toggleKeyboardProtocol(uint8_t combo_index) {
USBQuirks.toggleKeyboardProtocol();
}
/**
* This enters the hardware test mode
*/
static void enterHardwareTestMode(uint8_t combo_index) {
HardwareTestMode.runTests();
}
/** Magic combo list, a list of key combo and action pairs the firmware should
* recognise.
*/
USE_MAGIC_COMBOS({.action = toggleKeyboardProtocol,
// Left Fn + Esc + Shift
.keys = { R3C6, R2C6, R3C7 }
}, {
.action = enterHardwareTestMode,
// Left Fn + Prog + LED
.keys = { R3C6, R0C0, R0C6 }
});
// First, tell Kaleidoscope which plugins you want to use.
// The order can be important. For example, LED effects are
// added in the order they're listed here.
KALEIDOSCOPE_INIT_PLUGINS(
// The EEPROMSettings & EEPROMKeymap plugins make it possible to have an
// editable keymap in EEPROM.
EEPROMSettings,
EEPROMKeymap,
// Focus allows bi-directional communication with the host, and is the
// interface through which the keymap in EEPROM can be edited.
//Focus,
// FocusSettingsCommand adds a few Focus commands, intended to aid in
// changing some settings of the keyboard, such as the default layer (via the
// `settings.defaultLayer` command)
//FocusSettingsCommand,
// FocusEEPROMCommand adds a set of Focus commands, which are very helpful in
// both debugging, and in backing up one's EEPROM contents.
// FocusEEPROMCommand,
// The boot greeting effect pulses the LED button for 10 seconds after the
// keyboard is first connected
BootGreetingEffect,
// The hardware test mode, which can be invoked by tapping Prog, LED and the
// left Fn button at the same time.
HardwareTestMode,
// LEDControl provides support for other LED modes
LEDControl,
// We start with the LED effect that turns off all the LEDs.
LEDOff,
// The rainbow effect changes the color of all of the keyboard's keys at the same time
// running through all the colors of the rainbow.
LEDRainbowEffect,
// The rainbow wave effect lights up your keyboard with all the colors of a rainbow
// and slowly moves the rainbow across your keyboard
LEDRainbowWaveEffect,
// The chase effect follows the adventure of a blue pixel which chases a red pixel across
// your keyboard. Spoiler: the blue pixel never catches the red pixel
LEDChaseEffect,
// These static effects turn your keyboard's LEDs a variety of colors
solidRed, solidOrange, solidYellow, solidGreen, solidBlue, solidIndigo, solidViolet,
// The breathe effect slowly pulses all of the LEDs on your keyboard
LEDBreatheEffect,
// The AlphaSquare effect prints each character you type, using your
// keyboard's LEDs as a display
AlphaSquareEffect,
// The stalker effect lights up the keys you've pressed recently
StalkerEffect,
// The LED Palette Theme plugin provides a shared palette for other plugins,
// like Colormap below
LEDPaletteTheme,
// The Colormap effect makes it possible to set up per-layer colormaps
ColormapEffect,
// The numpad plugin is responsible for lighting up the 'numpad' mode
// with a custom LED effect
NumPad,
// The macros plugin adds support for macros
Macros,
// The MouseKeys plugin lets you add keys to your keymap which move the mouse.
MouseKeys,
// The HostPowerManagement plugin allows us to turn LEDs off when then host
// goes to sleep, and resume them when it wakes up.
HostPowerManagement,
// The MagicCombo plugin lets you use key combinations to trigger custom
// actions - a bit like Macros, but triggered by pressing multiple keys at the
// same time.
MagicCombo,
// The USBQuirks plugin lets you do some things with USB that we aren't
// comfortable - or able - to do automatically, but can be useful
// nevertheless. Such as toggling the key report protocol between Boot (used
// by BIOSes) and Report (NKRO).
USBQuirks
);
/** The 'setup' function is one of the two standard Arduino sketch functions.
* It's called when your keyboard first powers up. This is where you set up
* Kaleidoscope and any plugins.
*/
void setup() {
// First, call Kaleidoscope's internal setup function
Kaleidoscope.setup();
// While we hope to improve this in the future, the NumPad plugin
// needs to be explicitly told which keymap layer is your numpad layer
NumPad.numPadLayer = NUMPAD;
// We configure the AlphaSquare effect to use RED letters
AlphaSquare.color = CRGB(255, 0, 0);
// We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
// This draws more than 500mA, but looks much nicer than a dimmer effect
LEDRainbowEffect.brightness(255);
LEDRainbowWaveEffect.brightness(255);
// Set the action key the test mode should listen for to Left Fn
HardwareTestMode.setActionKey(R3C6);
// The LED Stalker mode has a few effects. The one we like is called
// 'BlazingTrail'. For details on other options, see
// https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md
StalkerEffect.variant = STALKER(BlazingTrail);
// We want to make sure that the firmware starts with LED effects off
// This avoids over-taxing devices that don't have a lot of power to share
// with USB devices
LEDOff.activate();
// To make the keymap editable without flashing new firmware, we store
// additional layers in EEPROM. For now, we reserve space for five layers. If
// one wants to use these layers, just set the default layer to one in EEPROM,
// by using the `settings.defaultLayer` Focus command, or by using the
// `keymap.onlyCustom` command to use EEPROM layers only.
//EEPROMKeymap.setup(5);
// We need to tell the Colormap plugin how many layers we want to have custom
// maps for. To make things simple, we set it to five layers, which is how
// many editable layers we have (see above).
//ColormapEffect.max_layers(5);
}
/** loop is the second of the standard Arduino sketch functions.
* As you might expect, it runs in a loop, never exiting.
*
* For Kaleidoscope-based keyboard firmware, you usually just want to
* call Kaleidoscope.loop(); and not do anything custom here.
*/
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,6 @@
{
"cpu": {
"fqbn": "keyboardio:gd32:keyboardio_model_100",
"port": ""
}
}

@ -15,16 +15,16 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef ARDUINO_GD32_keyboardio_model_100 #ifdef ARDUINO_keyboardio_model_100
#include "Arduino.h" // for PROGMEM #include "Arduino.h" // for PROGMEM
#include "kaleidoscope/device/keyboardio/Model100.h" // for Model100LEDDriver... #include "kaleidoscope/device/keyboardio/Model100.h" // for Model100LEDDriver...
#include "kaleidoscope/key_events.h" #include "kaleidoscope/key_events.h"
#include "kaleidoscope/driver/keyscanner/Base_Impl.h" #include "kaleidoscope/driver/keyscanner/Base_Impl.h"
#include "Wire.h"
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#include <KeyboardioHID.h>
#include <avr/wdt.h>
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
namespace kaleidoscope { namespace kaleidoscope {
@ -48,14 +48,13 @@ driver::keyboardio::Model100Side Model100Hands::leftHand(0);
driver::keyboardio::Model100Side Model100Hands::rightHand(3); driver::keyboardio::Model100Side Model100Hands::rightHand(3);
void Model100Hands::setup(void) { void Model100Hands::setup(void) {
// This lets the keyboard pull up to 1.6 amps from the host. delay(100);
// That violates the USB spec. But it sure is pretty looking pinMode(PB9, OUTPUT_OPEN_DRAIN);
DDRE |= _BV(6); digitalWrite(PB9, LOW);
PORTE &= ~_BV(6); delay(105); // TODO remove this when we remove it from the attiny code
Wire.begin();
Wire.setClock(400000);
// Set B4, the overcurrent check to an input with an internal pull-up
DDRB &= ~_BV(4); // set bit, input
PORTB &= ~_BV(4); // set bit, enable pull-up resistor
} }
/********* LED Driver *********/ /********* LED Driver *********/
@ -103,7 +102,6 @@ cRGB Model100LEDDriver::getCrgbAt(uint8_t i) {
void Model100LEDDriver::syncLeds() { void Model100LEDDriver::syncLeds() {
if (!isLEDChanged) if (!isLEDChanged)
return; return;
// LED Data is stored in four "banks" for each side // LED Data is stored in four "banks" for each side
// We send it all at once to make it look nicer. // We send it all at once to make it look nicer.
// We alternate left and right hands because otherwise // We alternate left and right hands because otherwise
@ -125,10 +123,6 @@ void Model100LEDDriver::syncLeds() {
isLEDChanged = false; isLEDChanged = false;
} }
boolean Model100LEDDriver::ledPowerFault() {
// TODO remove - obsolete
}
/********* Key scanner *********/ /********* Key scanner *********/
driver::keyboardio::keydata_t Model100KeyScanner::leftHandState; driver::keyboardio::keydata_t Model100KeyScanner::leftHandState;
@ -137,16 +131,26 @@ driver::keyboardio::keydata_t Model100KeyScanner::previousLeftHandState;
driver::keyboardio::keydata_t Model100KeyScanner::previousRightHandState; driver::keyboardio::keydata_t Model100KeyScanner::previousRightHandState;
void Model100KeyScanner::enableScannerPower(void) { void Model100KeyScanner::enableScannerPower(void) {
// Turn on the switched 5V network.
// make sure this happens at least 100ms after USB connect
// to satisfy inrush limits
//
pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PB9, LOW);
}
void Model100KeyScanner::disableScannerPower(void) {
// Turn on power to the 5V net // Turn on power to the 5V net
// //
pinMode(PC13, OUTPUT_OPEN_DRAIN); pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PC13, LOW); digitalWrite(PB9, HIGH);
} }
void Model100KeyScanner::setup() { void Model100KeyScanner::setup() {
wdt_disable();
delay(100);
enableScannerPower(); enableScannerPower();
delay(250);
} }
void Model100KeyScanner::readMatrix() { void Model100KeyScanner::readMatrix() {
@ -228,6 +232,7 @@ uint8_t Model100KeyScanner::previousPressedKeyswitchCount() {
/********* Hardware plugin *********/ /********* Hardware plugin *********/
void Model100::setup() { void Model100::setup() {
Model100KeyScanner::setup();
Model100Hands::setup(); Model100Hands::setup();
kaleidoscope::device::Base<Model100Props>::setup(); kaleidoscope::device::Base<Model100Props>::setup();
} }

@ -17,7 +17,11 @@
#pragma once #pragma once
#ifdef ARDUINO_GD32_keyboardio_model_100 #ifdef ARDUINO_keyboardio_model_100
#ifndef EEPROM_EMULATION_SIZE
#define EEPROM_EMULATION_SIZE 4096
#endif
#include <Arduino.h> #include <Arduino.h>
@ -29,17 +33,24 @@ struct cRGB {
uint8_t r; uint8_t r;
}; };
#include "kaleidoscope/device/ATmega32U4Keyboard.h"
#include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/keyscanner/Base.h"
#include "kaleidoscope/driver/storage/GD32Flash.h"
#include "kaleidoscope/driver/keyboardio/Model100Side.h" #include "kaleidoscope/driver/keyboardio/Model100Side.h"
#include "kaleidoscope/driver/led/Base.h" #include "kaleidoscope/driver/led/Base.h"
#include "kaleidoscope/device/Base.h"
#include "kaleidoscope/driver/hid/Keyboardio.h"
#include "kaleidoscope/driver/bootloader/gd32/Base.h" #include "kaleidoscope/driver/bootloader/gd32/Base.h"
namespace kaleidoscope { namespace kaleidoscope {
namespace device { namespace device {
namespace keyboardio { namespace keyboardio {
struct Model100StorageProps: public kaleidoscope::driver::storage::GD32FlashProps {
static constexpr uint16_t length = EEPROM_EMULATION_SIZE;
};
struct Model100LEDDriverProps : public kaleidoscope::driver::led::BaseProps { struct Model100LEDDriverProps : public kaleidoscope::driver::led::BaseProps {
static constexpr uint8_t led_count = 64; static constexpr uint8_t led_count = 64;
static constexpr uint8_t key_led_map[] PROGMEM = { static constexpr uint8_t key_led_map[] PROGMEM = {
@ -60,7 +71,6 @@ class Model100LEDDriver : public kaleidoscope::driver::led::Base<Model100LEDDriv
static uint8_t getBrightness(); static uint8_t getBrightness();
static void enableHighPowerLeds(); static void enableHighPowerLeds();
static boolean ledPowerFault();
private: private:
static bool isLEDChanged; static bool isLEDChanged;
@ -101,16 +111,23 @@ class Model100KeyScanner : public kaleidoscope::driver::keyscanner::Base<Model10
static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos); static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos);
static void enableScannerPower(); static void enableScannerPower();
static void disableScannerPower();
}; };
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100KeyScanner; class Model100KeyScanner;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
struct Model100Props : public kaleidoscope::device::BaseKeyboardProps { struct Model100Props : public kaleidoscope::device::BaseProps {
typedef kaleidoscope::driver::hid::KeyboardioProps HIDProps;
typedef kaleidoscope::driver::hid::Keyboardio<HIDProps> HID;
typedef Model100LEDDriverProps LEDDriverProps; typedef Model100LEDDriverProps LEDDriverProps;
typedef Model100LEDDriver LEDDriver; typedef Model100LEDDriver LEDDriver;
typedef Model100KeyScannerProps KeyScannerProps; typedef Model100KeyScannerProps KeyScannerProps;
typedef Model100KeyScanner KeyScanner; typedef Model100KeyScanner KeyScanner;
typedef Model100StorageProps StorageProps;
typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage;
typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader; typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader;
static constexpr const char *short_name = "kbio100"; static constexpr const char *short_name = "kbio100";
}; };

@ -24,10 +24,8 @@
#include <Arduino.h> #include <Arduino.h>
#include "Model100Side.h" #include "Model100Side.h"
#include <Wire.h>
extern "C" { #include <utility/twi.h>
#include "kaleidoscope/device/keyboardio/twi.h"
}
#include "kaleidoscope/driver/color/GammaCorrection.h" #include "kaleidoscope/driver/color/GammaCorrection.h"
@ -43,9 +41,7 @@ uint8_t twi_uninitialized = 1;
Model100Side::Model100Side(byte setAd01) { Model100Side::Model100Side(byte setAd01) {
ad01 = setAd01; ad01 = setAd01;
addr = SCANNER_I2C_ADDR_BASE | ad01; addr = SCANNER_I2C_ADDR_BASE | ad01;
if (twi_uninitialized--) { markDeviceUnavailable();
twi_init();
}
} }
// Returns the relative controller addresss. The expected range is 0-3 // Returns the relative controller addresss. The expected range is 0-3
@ -72,8 +68,7 @@ uint8_t Model100Side::controllerAddress() {
// https://www.arduino.cc/en/Reference/WireEndTransmission // https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model100Side::setKeyscanInterval(byte delay) { byte Model100Side::setKeyscanInterval(byte delay) {
uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay}; uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
return result; return result;
} }
@ -103,34 +98,84 @@ int Model100Side::readLEDSPIFrequency() {
// https://www.arduino.cc/en/Reference/WireEndTransmission // https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model100Side::setLEDSPIFrequency(byte frequency) { byte Model100Side::setLEDSPIFrequency(byte frequency) {
uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency}; uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
return result; return result;
} }
// GD32 I2C implements timeouts which will cause a stall when a device does not answer.
// This method will verify that the device is around and ready to talk.
bool Model100Side::isDeviceAvailable() {
return true;
// if the counter is zero, that's the special value that means "we know it's there"
if (unavailable_device_check_countdown_ == 0) {
return true;
}
int Model100Side::readRegister(uint8_t cmd) { // if the time to check counter is 1, check for the device
byte return_value = 0; else if (--unavailable_device_check_countdown_ == 0) {
uint8_t wire_result;
Wire.beginTransmission(addr);
wire_result = Wire.endTransmission();
//if the check succeeds
if (wire_result == 0) {
// unavailable_device_check_countdown_ = 0; // TODO this is already true
return true;
} else {
// set the time to check counter to max
unavailable_device_check_countdown_ = UNAVAILABLE_DEVICE_COUNTDOWN_MAX;
return false;
}
} else {
// we've decremented the counter, but it's not time to probe for the device yet.
return false;
}
uint8_t data[] = {cmd}; }
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
void Model100Side::markDeviceUnavailable() {
unavailable_device_check_countdown_ = 1; // We think there was a comms problem. Check on the next cycle
}
uint8_t Model100Side::writeData(uint8_t *data, uint8_t length) {
if (isDeviceAvailable() == false) {
return 1;
}
Wire.beginTransmission(addr);
Wire.write(data, length);
uint8_t result = Wire.endTransmission();
if (result) {
markDeviceUnavailable();
}
return result;
}
int Model100Side::readRegister(uint8_t cmd) {
byte return_value = 0;
uint8_t data[] = {cmd};
uint8_t result = writeData(data, ELEMENTS(data));
delayMicroseconds(15); // We may be able to drop this in the future // If the setup failed, return. This means there was a problem asking for the register
if (result) {
return -1;
}
delayMicroseconds(50); // TODO We may be able to drop this in the future
// but will need to verify with correctly // but will need to verify with correctly
// sized pull-ups on both the left and right // sized pull-ups on both the left and right
// hands' i2c SDA and SCL lines // hands' i2c SDA and SCL lines
uint8_t rxBuffer[1]; uint8_t rxBuffer[1] = {0};
// perform blocking read into buffer // perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true);
if (read > 0) { Wire.requestFrom(addr, 1); // request 1 byte from the keyscanner
return rxBuffer[0]; if (Wire.available()) {
return Wire.read();
} else { } else {
markDeviceUnavailable();
return -1; return -1;
} }
@ -139,20 +184,28 @@ int Model100Side::readRegister(uint8_t cmd) {
// gives information on the key that was just pressed or released. // gives information on the key that was just pressed or released.
bool Model100Side::readKeys() { bool Model100Side::readKeys() {
if (isDeviceAvailable() == false) {
return false;
}
uint8_t rxBuffer[5]; uint8_t row_counter = 0;
// perform blocking read into buffer // perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true); uint8_t read = 0;
if (rxBuffer[0] == TWI_REPLY_KEYDATA) { uint8_t bytes_returned = 0;
keyData.rows[0] = rxBuffer[1]; bytes_returned = Wire.requestFrom(addr, 5); // request 5 bytes from the keyscanner
keyData.rows[1] = rxBuffer[2]; if (bytes_returned < 5) {
keyData.rows[2] = rxBuffer[3];
keyData.rows[3] = rxBuffer[4];
return true;
} else {
return false; return false;
} }
if (Wire.available()) {
read = Wire.read();
if (TWI_REPLY_KEYDATA == read) {
while (Wire.available()) {
keyData.rows[row_counter++] = Wire.read();
}
return true;
}
}
return false;
} }
keydata_t Model100Side::getKeyData() { keydata_t Model100Side::getKeyData() {
@ -166,7 +219,6 @@ void Model100Side::sendLEDData() {
} }
} }
auto constexpr gamma8 = kaleidoscope::driver::color::gamma_correction;
void Model100Side::sendLEDBank(byte bank) { void Model100Side::sendLEDBank(byte bank) {
uint8_t data[LED_BYTES_PER_BANK + 1]; uint8_t data[LED_BYTES_PER_BANK + 1];
@ -182,28 +234,28 @@ void Model100Side::sendLEDBank(byte bank) {
else else
c = 0; c = 0;
data[i + 1] = pgm_read_byte(&gamma8[c]); data[i + 1] = c;
} }
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setAllLEDsTo(cRGB color) { void Model100Side::setAllLEDsTo(cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO, uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO,
pgm_read_byte(&gamma8[color.b]), color.b,
pgm_read_byte(&gamma8[color.g]), color.g,
pgm_read_byte(&gamma8[color.r]) color.r
}; };
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setOneLEDTo(byte led, cRGB color) { void Model100Side::setOneLEDTo(byte led, cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO, uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO,
led, led,
pgm_read_byte(&gamma8[color.b]), color.b,
pgm_read_byte(&gamma8[color.g]), color.g,
pgm_read_byte(&gamma8[color.r]) color.r
}; };
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }

@ -78,9 +78,12 @@ class Model100Side {
void setAllLEDsTo(cRGB color); void setAllLEDsTo(cRGB color);
keydata_t getKeyData(); keydata_t getKeyData();
bool readKeys(); bool readKeys();
LEDData_t ledData; LEDData_t ledData;
uint8_t controllerAddress();
uint8_t controllerAddress();
bool isDeviceAvailable();
void markDeviceUnavailable();
void setBrightness(uint8_t brightness) { void setBrightness(uint8_t brightness) {
brightness_adjustment_ = 255 - brightness; brightness_adjustment_ = 255 - brightness;
} }
@ -93,9 +96,14 @@ class Model100Side {
int addr; int addr;
int ad01; int ad01;
keydata_t keyData; keydata_t keyData;
// a value of 0 is "device seen" - anything else is how many cycles before we should
// check for the device
uint16_t unavailable_device_check_countdown_ = 0;
static const uint16_t UNAVAILABLE_DEVICE_COUNTDOWN_MAX = 0x00FFU;
byte nextLEDBank = 0; byte nextLEDBank = 0;
void sendLEDBank(byte bank); void sendLEDBank(byte bank);
int readRegister(uint8_t cmd); int readRegister(uint8_t cmd);
uint8_t writeData(uint8_t* data, uint8_t length);
}; };
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100Side; class Model100Side;

Loading…
Cancel
Save