Skip to content

Commit

Permalink
Merge pull request #735 from CapeLeidokos/pr_keymap_exploration
Browse files Browse the repository at this point in the history
Added a template hook that enables compile-time sketch exploration
  • Loading branch information
obra authored Dec 4, 2019
2 parents edb30f5 + a538328 commit 9158661
Show file tree
Hide file tree
Showing 17 changed files with 890 additions and 27 deletions.
55 changes: 55 additions & 0 deletions examples/Internal/Sketch_Exploration/Makefile
Original file line number Diff line number Diff line change
@@ -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
139 changes: 139 additions & 0 deletions examples/Internal/Sketch_Exploration/Sketch_Exploration.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* -*- mode: c++ -*-
* Basic -- A very basic Kaleidoscope example
* Copyright (C) 2018 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"


// This example demonstrates how a plugin can gather information about
// the keymap at compile time, e.g. to adapt its behavior, safe resources, ...

/* *INDENT-OFF* */
KEYMAPS(
[0] = KEYMAP_STACKED
(
Key_NoKey, Key_1, Key_1, Key_1, 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_NoKey,

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_NoKey
),
)
/* *INDENT-ON* */

using namespace kaleidoscope::sketch_exploration;

class BPlugin : public kaleidoscope::Plugin {};
class CPlugin : public kaleidoscope::Plugin {};

// A simple plugin that defines just one hook.
//
class APlugin : public kaleidoscope::Plugin {

public:
APlugin() : has_key_1_{false} {}

template<typename _Sketch>
kaleidoscope::EventHandlerResult exploreSketch() {

// Static keymap exploration

typedef typename _Sketch::StaticKeymap K;

// Important: Always make sure to call _Sketch::StaticKeymap's methods
// in a constexpr context. This is done by
// passing their value to a constexpr temporary variable.

constexpr uint8_t n_key_1 = K::collect(NumKeysEqual{Key_1});
static_assert(n_key_1 == 3, "Error determining key count");

constexpr bool has_key_1 = K::collect(HasKey{Key_1});
static_assert(has_key_1, "Error querying key existence");
has_key_1_ = has_key_1; // Assign the temporary that was computed
// at compile time.

constexpr Key max_key = K::collect(MaxKeyRaw{});
static_assert(max_key.getRaw() > 0, "");

static_assert(K::getKey(0 /*layer*/, KeyAddr{2, 3}) == Key_D,
"Key lookup failed");

constexpr auto n_layers = K::nLayers();
constexpr auto layer_size = K::layerSize();

// Plugin exploration
//
// Use macros ENTRY_TYPE, ENRTY_IS_LAST, PLUGIN_POSITION,
// PLUGIN_IS_REGISTERED and NUM_OCCURRENCES to retreive information
// about the plugins that are registered in the sketch.

typedef typename _Sketch::Plugins P;

static_assert(std::is_same<ENTRY_TYPE(P, 0), APlugin>::value, "");
static_assert(std::is_same<ENTRY_TYPE(P, 1), BPlugin>::value, "");

static_assert(P::size == 3, "");

static_assert(!ENRTY_IS_LAST(P, 0), "");
static_assert(!ENRTY_IS_LAST(P, 1), "");
static_assert(ENRTY_IS_LAST(P, 2), "");

static_assert(PLUGIN_POSITION(P, APlugin) == 0, "");
static_assert(PLUGIN_POSITION(P, BPlugin) == 1, "");
static_assert(PLUGIN_POSITION(P, CPlugin) == -1, "");

static_assert(PLUGIN_IS_REGISTERED(P, APlugin) == true, "");
static_assert(PLUGIN_IS_REGISTERED(P, BPlugin) == true, "");
static_assert(PLUGIN_IS_REGISTERED(P, CPlugin) == false, "");

static_assert(NUM_OCCURRENCES(P, APlugin) == 2, "");
static_assert(NUM_OCCURRENCES(P, BPlugin) == 1, "");
static_assert(NUM_OCCURRENCES(P, CPlugin) == 0, "");

return kaleidoscope::EventHandlerResult::OK;
}

private:

bool has_key_1_;
};

APlugin a_plugin1, a_plugin2;
BPlugin b_plugin;

KALEIDOSCOPE_INIT_PLUGINS(
a_plugin1,
b_plugin,
a_plugin2
)

void setup() {
Kaleidoscope.setup();
}

void loop() {
Kaleidoscope.loop();
}
1 change: 1 addition & 0 deletions src/kaleidoscope/Kaleidoscope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Kaleidoscope_::setup(void) {
// properly.
device().serialPort().begin(9600);

kaleidoscope::sketch_exploration::pluginsExploreSketch();
kaleidoscope::Hooks::onSetup();

device().setup();
Expand Down
1 change: 1 addition & 0 deletions src/kaleidoscope/Kaleidoscope.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static constexpr DEPRECATED(LED_COUNT) uint8_t LED_COUNT = kaleidoscope_internal
#include "kaleidoscope/key_events.h"
#include "kaleidoscope/hid.h"
#include "kaleidoscope/layers.h"
#include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h"
#include "kaleidoscope/macro_map.h"
#include "kaleidoscope_internal/event_dispatch.h"
#include "kaleidoscope_internal/LEDModeManager.h"
Expand Down
56 changes: 54 additions & 2 deletions src/kaleidoscope/event_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@
// kaleidoscope::EventHandlerResult::EVENT_CONSUMED. To enable this
// pass the abortable flag value _ABORTABLE, _NOT_ABORTABLE otherwise.
//
// template parameter type list:
// The hook's template type list in parenthesis, with a trailing comma.
// e.g. (, typename _T1, typename _T2)
// Pass empty parenthesis if the hook is non templatized.
//
// template parameters:
// The hook's template parameters in parenthesis, with a trailing comma.
// The template parameter names must match the template type list.
// e.g. (, _T1, _T2)
// Pass empty parenthesis if the hook is non templatized.
//
// dummy template arguments:
// Supply a list of already defined dummy types that could realistically
// be used to instantiate the template hook. Those types are only used
// during hook method signature checks.
// Please add parenthesis and a trailing comma.
// e.g. (, int, int)
// Pass empty parenthesis if the hook is non templatized.
//
// call signature:
// The type of arguments passed to the handlers as a comma separated
// list in brackets. Every parameter must be named.
Expand All @@ -93,12 +112,21 @@
" uint8_t keyState)\n" __NL__ \
"instead."

namespace kaleidoscope {

// This dummy class can be used as dummy template argument to
// be passed in the definition of template hooks.
//
class SignatureCheckDummy {};
} // namespace kaleidoscope

#define _FOR_EACH_EVENT_HANDLER(OPERATION, ...) __NL__ \
__NL__ \
OPERATION(onSetup, __NL__ \
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(),(), ##__VA_ARGS__) __NL__ \
__NL__ \
/* Called at the very start of each cycle, before gathering */ __NL__ \
Expand All @@ -107,6 +135,7 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(), (), ##__VA_ARGS__) __NL__ \
__NL__ \
/* DEPRECATED */ __NL__ \
Expand All @@ -121,6 +150,7 @@
1, __NL__ \
DEPRECATED(ON_KEYSWITCH_EVENT_HANDLER_V1), __NL__ \
_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(Key &mappedKey, byte row, byte col, uint8_t keyState), __NL__ \
(mappedKey, row, col, keyState), ##__VA_ARGS__) __NL__ \
__NL__ \
Expand All @@ -135,6 +165,7 @@
2, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(Key &mappedKey, KeyAddr key_addr, uint8_t keyState), __NL__ \
(mappedKey, key_addr, keyState), ##__VA_ARGS__) __NL__ \
__NL__ \
Expand All @@ -150,6 +181,7 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(const char *command), __NL__ \
(command), ##__VA_ARGS__) __NL__ \
__NL__ \
Expand All @@ -160,6 +192,7 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(), (), ##__VA_ARGS__) __NL__ \
/* Called when the LED mode changes. If one needs to know what */ __NL__ \
/* from and what to the mode changed, they should track that */ __NL__ \
Expand All @@ -168,6 +201,7 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(), (), ##__VA_ARGS__) __NL__ \
/* Called before reporting our state to the host. This is the */ __NL__ \
/* last point in a cycle where a plugin can alter what gets */ __NL__ \
Expand All @@ -176,6 +210,7 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),(), /* non template */ __NL__ \
(),(),##__VA_ARGS__) __NL__ \
__NL__ \
/* Called at the very end of a cycle, after everything's */ __NL__ \
Expand All @@ -184,7 +219,20 @@
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(),(),##__VA_ARGS__)
(),(),(), /* non template */ __NL__ \
(),(),##__VA_ARGS__) __NL__ \
__NL__ \
/* Called before setup to enable plugins at compile time */ __NL__ \
/* to explore the sketch. */ __NL__ \
OPERATION(exploreSketch , __NL__ \
1, __NL__ \
_CURRENT_IMPLEMENTATION, __NL__ \
_NOT_ABORTABLE, __NL__ \
(,typename _Sketch), __NL__ \
(,_Sketch), __NL__ \
(,kaleidoscope::SignatureCheckDummy), __NL__ \
(), __NL__ \
(),##__VA_ARGS__)

// The following function macro lists event handler/hook method names and
// available versions. It is used to auto-generate code that is
Expand Down Expand Up @@ -237,4 +285,8 @@
__NL__ \
START(afterEachCycle, 1) __NL__ \
OP(afterEachCycle, 1) __NL__ \
END(afterEachCycle, 1)
END(afterEachCycle, 1) __NL__ \
__NL__ \
START(exploreSketch, 1) __NL__ \
OP(exploreSketch, 1) __NL__ \
END(exploreSketch, 1)
19 changes: 18 additions & 1 deletion src/kaleidoscope/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ namespace kaleidoscope {

#define INSTANTIATE_WEAK_HOOK_FUNCTION( \
HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \
SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) __NL__ \
SHOULD_ABORT_ON_CONSUMED_EVENT, \
TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \
SIGNATURE, ARGS_LIST) __NL__ \
__NL__ \
MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \
__attribute__((weak)) __NL__ \
EventHandlerResult Hooks::HOOK_NAME SIGNATURE { __NL__ \
return EventHandlerResult::OK; __NL__ \
Expand All @@ -42,4 +45,18 @@ _FOR_EACH_EVENT_HANDLER(INSTANTIATE_WEAK_HOOK_FUNCTION)

#undef INSTANTIATE_WEAK_HOOK_FUNCTION

namespace sketch_exploration {
class Sketch;
}

// Make sure that there is no undefined symbol if KALEIDOSCOPE_INIT_PLUGINS(...)
// is not invoked in the user's sketch.
//
template<>
__attribute__((weak))
EventHandlerResult Hooks::exploreSketch
<sketch_exploration::Sketch>() {
return EventHandlerResult::OK;
};

} // namespace kaleidoscope
Loading

0 comments on commit 9158661

Please sign in to comment.