plugin/FlashHelper: New plugin for firmware-assisted flashing

This introduces a new plugin - `FlashHelper` - to aid with firmware-assisted
flashing. During the flashing process, this plugin can temporarily disable the
`Prog` key.

Addresses the firmware part of keyboardio/Chrysalis#509.

Signed-off-by: Gergely Nagy <algernon@keyboard.io>
pull/837/head
Gergely Nagy 5 years ago
parent c097a21bfd
commit c917acb8a1
No known key found for this signature in database
GPG Key ID: AC1E90BAC433F68F

@ -0,0 +1,71 @@
# FlashHelper
A number of keyboards supported by Kaleidoscope need a key held during reset to
enter bootloader mode. While held, any action mapped to the key will take
effect, which is something we may want to avoid in this special case. This
plugin is here to help with that: when asked via [Focus](FocusSerial.md), it
will ignore any events on the `Prog` key for a short while (or until asked to
resume).
## Using the plugin
Using the plugin is simple: after including the header, enable the plugin
(preferably before enabling any other plugin that handles key events).
We also need `Focus` enabled, to take full advantage of the plugin.
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-FocusSerial.h>
#include <Kaleidoscope-FlashHelper.h>
KALEIDOSCOPE_INIT_PLUGINS(Focus, FlashHelper);
void setup() {
Kaleidoscope.setup();
}
```
The plugin relies on the device descriptor having set a `Prog` key.
## Plugin methods
The plugin provides the `FlashHelper` object, which has the following methods:
### `.setTimeout(timeout)`
### `.getTimeout()`
Set or get the time (in seconds) to wait before re-enabling the Prog key, after
the helper has been activated.
The timer defaults to **10 seconds**.
### `.activate()`
### `.deactivate()`
### `.isActive()`
Activate, deactivate, or check the status of the flashing helper, respectively.
## Focus commands
The plugin provides two Focus commands: `flash.prepare` and `flash.resume`.
### `flash.prepare`
Prepare for flashing, by disabling the previously configured `Prog` key for a
few seconds, or until explicitly asked to resume. If the keyboard resets
meanwhile, then preparation is automatically concluded.
### `flash.resume`
Resume normal key event handling, and deactivate the helper plugin.
## Dependencies
* [Kaleidoscope-FocusSerial](FocusSerial.md)
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting started with the plugin.
[plugin:example]: ../../examples/Features/FlashHelper/FlashHelper.ino

@ -0,0 +1,52 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FlashHelper -- Firmware-assisted flashing
* Copyright (C) 2020 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-FocusSerial.h>
#include <Kaleidoscope-FlashHelper.h>
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(
Key_0, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
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,
Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
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_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_skip),
)
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(Focus, FlashHelper);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,55 @@
# This stub makefile for a Kaleidoscope example pulls in all the targets
# required to build the example
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SKETCHBOOK_DIR ?= $(HOME)/Documents/Arduino
PACKAGE_DIR ?= $(HOME)/Library/Arduino15
else
SKETCHBOOK_DIR ?= $(HOME)/Arduino
PACKAGE_DIR ?= $(HOME)/.arduino15
endif
ARDUINO_INSTALLED_ENV=$(shell ls -dt $(PACKAGE_DIR)/packages/keyboardio/hardware/avr 2>/dev/null |head -n 1)
MANUALLY_INSTALLED_ENV=$(shell ls -dt $(SKETCHBOOK_DIR)/hardware/keyboardio/avr 2>/dev/null |head -n 1)
ifneq ("$(wildcard $(ARDUINO_INSTALLED_ENV)/boards.txt)","")
ifneq ("$(wildcard $(MANUALLY_INSTALLED_ENV)/boards.txt)","")
$(info ***************************************************************************)
$(info It appears that you have installed two copies of Kaleidoscope. One copy was)
$(info installed using Arduino's "Board Manager", while the other was installed by)
$(info hand, probably using "git".)
$(info )
$(info This will likely cause some trouble as you try to build keyboard firmware)
$(info using Kaleidoscope. You may want to remove either: )
$(info )
$(info $(PACKAGE_DIR)/packages/keyboardio/ which was installed using Arduino)
$(info )
$(info or)
$(info )
$(info $(SKETCHBOOK_DIR)/hardware/keyboardio/ which was installed by hand.)
$(info )
$(info ***************************************************************************)
$(info )
endif
BOARD_HARDWARE_PATH = $(ARDUINO_INSTALLED_ENV)
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= build-tools/makefiles/
KALEIDOSCOPE_BUILDER_DIR ?= $(ARDUINO_INSTALLED_ENV)/libraries/Kaleidoscope/bin/
endif
BOARD_HARDWARE_PATH ?= $(SKETCHBOOK_DIR)/hardware
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= keyboardio/avr/build-tools/makefiles/
include $(BOARD_HARDWARE_PATH)/$(KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR)/rules.mk

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FlashHelper -- Firmware-assisted flashing
* Copyright (C) 2020 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <kaleidoscope/plugin/FlashHelper.h>

@ -27,17 +27,29 @@
#include "kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h"
#include "kaleidoscope/driver/storage/AVREEPROM.h"
#define ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_) \
struct BOARD_##Props : kaleidoscope::device::ATmega32U4KeyboardProps { \
struct KeyScannerProps \
: public kaleidoscope::driver::keyscanner::ATmegaProps \
{ \
ATMEGA_KEYSCANNER_PROPS(ROW_PIN_LIST(ROW_PINS_), \
COL_PIN_LIST(COL_PINS_)); \
}; \
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; \
typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \
static constexpr const char *short_name = NAME_; \
//#define PROG_KEY(...) __VA_ARGS__
//#define NO_PROG_KEY PROG_KEY(KeyScannerProps::KeyAddr::invalid_state)
#define PROG_KEY(...) \
static constexpr uint8_t prog_key_addresses[] = { \
KeyScannerProps::KeyAddr(__VA_ARGS__).toInt() \
}
#define NO_PROG_KEY \
static constexpr uint8_t prog_key_addresses[] = {}
#define ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_, PROG_KEY_) \
struct BOARD_##Props : kaleidoscope::device::ATmega32U4KeyboardProps { \
struct KeyScannerProps \
: public kaleidoscope::driver::keyscanner::ATmegaProps \
{ \
ATMEGA_KEYSCANNER_PROPS(ROW_PIN_LIST(ROW_PINS_), \
COL_PIN_LIST(COL_PINS_)); \
}; \
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; \
typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \
static constexpr const char *short_name = NAME_; \
PROG_KEY_; \
};
#define ATMEGA32U4_DEVICE(BOARD_) \
@ -47,21 +59,21 @@
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_) \
ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, \
FORWARD(ROW_PINS_), FORWARD(COL_PINS_)) \
#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_, PROG_KEY_) \
ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, \
FORWARD(ROW_PINS_), FORWARD(COL_PINS_), FORWARD(PROG_KEY_)) \
ATMEGA32U4_DEVICE(BOARD_)
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_) \
ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, \
FORWARD(ROW_PINS_), FORWARD(COL_PINS_)) \
/* Device definition omitted for virtual device builds. \
* We need to forward declare the device name, though, as there are \
* some legacy extern references to boards whose definition \
* depends on this. \
*/ \
#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, NAME_, ROW_PINS_, COL_PINS_, PROG_KEY_) \
ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, NAME_, \
FORWARD(ROW_PINS_), FORWARD(COL_PINS_), FORWARD(PROG_KEY_)) \
/* Device definition omitted for virtual device builds. \
* We need to forward declare the device name, though, as there are \
* some legacy extern references to boards whose definition \
* depends on this. \
*/ \
class BOARD_;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD

@ -64,6 +64,7 @@ struct BaseProps {
typedef kaleidoscope::driver::storage::BaseProps StorageProps;
typedef kaleidoscope::driver::storage::None Storage;
static constexpr const char *short_name = USB_PRODUCT;
static constexpr const uint8_t prog_key_addresses[] = {};
};
template<typename _DeviceProps>
@ -107,6 +108,13 @@ class Base {
return matrix_columns * matrix_rows;
}
static constexpr auto progKeyAddresses() {
return Props::prog_key_addresses;
}
static constexpr uint8_t numProgKeys() {
return sizeof(Props::prog_key_addresses) / sizeof(uint8_t);
}
/**
* Returns the HID driver used by the keyboard.
*/

@ -172,6 +172,9 @@ struct RaiseProps : kaleidoscope::device::BaseProps {
typedef RaiseSideFlasherProps SideFlasherProps;
typedef kaleidoscope::util::flasher::KeyboardioI2CBootloader<SideFlasherProps> SideFlasher;
static constexpr const char *short_name = "raise";
static constexpr uint8_t prog_key_addresses[] = {
KeyScannerProps::KeyAddr(0, 0).toInt()
};
};
class Raise: public kaleidoscope::device::Base<RaiseProps> {

@ -122,6 +122,9 @@ struct Model01Props : public kaleidoscope::device::ATmega32U4KeyboardProps {
typedef Model01KeyScanner KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "kbio01";
static constexpr uint8_t prog_key_addresses[] = {
KeyScannerProps::KeyAddr(0, 0).toInt()
};
};
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD

@ -31,7 +31,8 @@ namespace olkb {
ATMEGA32U4_KEYBOARD(
Planck, HalfKay, "planck",
ROW_PIN_LIST({ PIN_D0, PIN_D5, PIN_B5, PIN_B6 }),
COL_PIN_LIST({ PIN_F1, PIN_F0, PIN_B0, PIN_C7, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_D4, PIN_D6, PIN_B4, PIN_D7 })
COL_PIN_LIST({ PIN_F1, PIN_F0, PIN_B0, PIN_C7, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_D4, PIN_D6, PIN_B4, PIN_D7 }),
NO_PROG_KEY
);
#define PER_KEY_DATA(dflt, \

@ -39,16 +39,17 @@ ATMEGA32U4_KEYBOARD(
Atreus, HalfKay, "atreus",
#ifdef KALEIDOSCOPE_HARDWARE_ATREUS_PINOUT_ASTAR
ROW_PIN_LIST({PIN_D0, PIN_D1, PIN_D3, PIN_D2}),
COL_PIN_LIST({PIN_D7, PIN_C6, PIN_B5, PIN_B4, PIN_E6, PIN_D4, PIN_B6, PIN_F6, PIN_F7, PIN_D6, PIN_B7})
COL_PIN_LIST({PIN_D7, PIN_C6, PIN_B5, PIN_B4, PIN_E6, PIN_D4, PIN_B6, PIN_F6, PIN_F7, PIN_D6, PIN_B7}),
#endif
#ifdef KALEIDOSCOPE_HARDWARE_ATREUS_PINOUT_ASTAR_DOWN
ROW_PIN_LIST({PIN_D0, PIN_D1, PIN_D3, PIN_D2}),
COL_PIN_LIST({PIN_B7, PIN_D6, PIN_F7, PIN_F6, PIN_B6, PIN_D4, PIN_E6, PIN_B4, PIN_B5, PIN_C6, PIN_D7})
COL_PIN_LIST({PIN_B7, PIN_D6, PIN_F7, PIN_F6, PIN_B6, PIN_D4, PIN_E6, PIN_B4, PIN_B5, PIN_C6, PIN_D7}),
#endif
#ifdef KALEIDOSCOPE_HARDWARE_ATREUS_PINOUT_LEGACY_TEENSY2
ROW_PIN_LIST({PIN_D0, PIN_D1, PIN_D2, PIN_D3}),
COL_PIN_LIST({PIN_F6, PIN_F5, PIN_F4, PIN_B7, PIN_B6, PIN_B5, PIN_B4, PIN_B3, PIN_B2, PIN_B1, PIN_B0})
COL_PIN_LIST({PIN_F6, PIN_F5, PIN_F4, PIN_B7, PIN_B6, PIN_B5, PIN_B4, PIN_B3, PIN_B2, PIN_B1, PIN_B0}),
#endif
NO_PROG_KEY
);
#define PER_KEY_DATA(dflt, \

@ -32,7 +32,8 @@ namespace technomancy {
ATMEGA32U4_KEYBOARD(
Atreus2, Caterina, "atreus",
ROW_PIN_LIST({PIN_F6, PIN_F5, PIN_F4, PIN_F1}),
COL_PIN_LIST({PIN_F7, PIN_E2, PIN_C7, PIN_C6, PIN_B6, PIN_B5, PIN_D7, PIN_D6, PIN_D4, PIN_D5, PIN_D3, PIN_D2})
COL_PIN_LIST({PIN_F7, PIN_E2, PIN_C7, PIN_C6, PIN_B6, PIN_B5, PIN_D7, PIN_D6, PIN_D4, PIN_D5, PIN_D3, PIN_D2}),
PROG_KEY(3, 0)
);
#define PER_KEY_DATA(dflt, \

@ -0,0 +1,82 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FlashHelper -- Firmware-assisted flashing
* Copyright (C) 2020 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Kaleidoscope-FlashHelper.h>
#include <Kaleidoscope-FocusSerial.h>
#include "kaleidoscope/key_events.h"
namespace kaleidoscope {
namespace plugin {
uint8_t FlashHelper::timeout_ = 10;
uint32_t FlashHelper::start_time_;
bool FlashHelper::is_active_;
EventHandlerResult FlashHelper::onFocusEvent(const char *command) {
if (::Focus.handleHelp(command, PSTR("flash.prepare\nflash.resume")))
return EventHandlerResult::OK;
if (strncmp_P(command, PSTR("flash."), 6) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 6, PSTR("prepare")) == 0) {
activate();
return EventHandlerResult::EVENT_CONSUMED;
}
if (strcmp_P(command + 6, PSTR("resume")) == 0) {
deactivate();
return EventHandlerResult::EVENT_CONSUMED;
}
return EventHandlerResult::OK;
}
EventHandlerResult FlashHelper::beforeEachCycle() {
if (!isActive())
goto end;
if (!Runtime.hasTimeExpired(start_time_, (uint16_t)(timeout_ * 1000)))
goto end;
deactivate();
end:
return EventHandlerResult::OK;
}
EventHandlerResult FlashHelper::onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr, uint8_t key_state) {
if (!isActive())
return EventHandlerResult::OK;
const auto progKeys = Runtime.device().progKeyAddresses();
const uint8_t progKeyNum = Runtime.device().numProgKeys();
for (int8_t i = 0; i < progKeyNum; i++) {
if (key_addr.toInt() == progKeys[i]) {
return EventHandlerResult::EVENT_CONSUMED;
}
}
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::FlashHelper FlashHelper;

@ -0,0 +1,60 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FlashHelper -- Firmware-assisted flashing
* Copyright (C) 2020 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kaleidoscope/Runtime.h"
namespace kaleidoscope {
namespace plugin {
class FlashHelper: public kaleidoscope::Plugin {
public:
FlashHelper() {}
static void setTimeout(uint8_t timeout) {
timeout_ = timeout;
}
static uint8_t getTimeout() {
return timeout_;
}
static void activate() {
is_active_ = true;
start_time_ = Runtime.millisAtCycleStart();
}
static void deactivate() {
is_active_ = false;
}
static bool isActive() {
return is_active_;
}
EventHandlerResult onFocusEvent(const char *command);
EventHandlerResult onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr, uint8_t key_state);
EventHandlerResult beforeEachCycle();
private:
static bool is_active_;
static uint8_t timeout_;
static uint32_t start_time_;
};
}
}
extern kaleidoscope::plugin::FlashHelper FlashHelper;
Loading…
Cancel
Save