Skip to content

Commit 9158661

Browse files
authored
Merge pull request #735 from CapeLeidokos/pr_keymap_exploration
Added a template hook that enables compile-time sketch exploration
2 parents edb30f5 + a538328 commit 9158661

File tree

17 files changed

+890
-27
lines changed

17 files changed

+890
-27
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# This stub makefile for a Kaleidoscope example pulls in all the targets
2+
# required to build the example
3+
4+
UNAME_S := $(shell uname -s)
5+
6+
ifeq ($(UNAME_S),Darwin)
7+
SKETCHBOOK_DIR ?= $(HOME)/Documents/Arduino
8+
PACKAGE_DIR ?= $(HOME)/Library/Arduino15
9+
else
10+
SKETCHBOOK_DIR ?= $(HOME)/Arduino
11+
PACKAGE_DIR ?= $(HOME)/.arduino15
12+
endif
13+
14+
15+
ARDUINO_INSTALLED_ENV=$(shell ls -dt $(PACKAGE_DIR)/packages/keyboardio/hardware/avr 2>/dev/null |head -n 1)
16+
MANUALLY_INSTALLED_ENV=$(shell ls -dt $(SKETCHBOOK_DIR)/hardware/keyboardio/avr 2>/dev/null |head -n 1)
17+
18+
19+
20+
ifneq ("$(wildcard $(ARDUINO_INSTALLED_ENV)/boards.txt)","")
21+
22+
ifneq ("$(wildcard $(MANUALLY_INSTALLED_ENV)/boards.txt)","")
23+
24+
$(info ***************************************************************************)
25+
$(info It appears that you have installed two copies of Kaleidoscope. One copy was)
26+
$(info installed using Arduino's "Board Manager", while the other was installed by)
27+
$(info hand, probably using "git".)
28+
$(info )
29+
$(info This will likely cause some trouble as you try to build keyboard firmware)
30+
$(info using Kaleidoscope. You may want to remove either: )
31+
$(info )
32+
$(info $(PACKAGE_DIR)/packages/keyboardio/ which was installed using Arduino)
33+
$(info )
34+
$(info or)
35+
$(info )
36+
$(info $(SKETCHBOOK_DIR)/hardware/keyboardio/ which was installed by hand.)
37+
$(info )
38+
$(info ***************************************************************************)
39+
$(info )
40+
41+
endif
42+
43+
BOARD_HARDWARE_PATH = $(ARDUINO_INSTALLED_ENV)
44+
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= build-tools/makefiles/
45+
KALEIDOSCOPE_BUILDER_DIR ?= $(ARDUINO_INSTALLED_ENV)/libraries/Kaleidoscope/bin/
46+
47+
48+
49+
endif
50+
51+
52+
BOARD_HARDWARE_PATH ?= $(SKETCHBOOK_DIR)/hardware
53+
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= keyboardio/avr/build-tools/makefiles/
54+
55+
include $(BOARD_HARDWARE_PATH)/$(KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR)/rules.mk
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/* -*- mode: c++ -*-
2+
* Basic -- A very basic Kaleidoscope example
3+
* Copyright (C) 2018 Keyboard.io, Inc.
4+
*
5+
* This program is free software: you can redistribute it and/or modify it under
6+
* the terms of the GNU General Public License as published by the Free Software
7+
* Foundation, version 3.
8+
*
9+
* This program is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12+
* details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with
15+
* this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include "Kaleidoscope.h"
19+
20+
21+
// This example demonstrates how a plugin can gather information about
22+
// the keymap at compile time, e.g. to adapt its behavior, safe resources, ...
23+
24+
/* *INDENT-OFF* */
25+
KEYMAPS(
26+
[0] = KEYMAP_STACKED
27+
(
28+
Key_NoKey, Key_1, Key_1, Key_1, Key_4, Key_5, Key_NoKey,
29+
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
30+
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
31+
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
32+
33+
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
34+
Key_NoKey,
35+
36+
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
37+
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
38+
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
39+
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
40+
41+
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
42+
Key_NoKey
43+
),
44+
)
45+
/* *INDENT-ON* */
46+
47+
using namespace kaleidoscope::sketch_exploration;
48+
49+
class BPlugin : public kaleidoscope::Plugin {};
50+
class CPlugin : public kaleidoscope::Plugin {};
51+
52+
// A simple plugin that defines just one hook.
53+
//
54+
class APlugin : public kaleidoscope::Plugin {
55+
56+
public:
57+
APlugin() : has_key_1_{false} {}
58+
59+
template<typename _Sketch>
60+
kaleidoscope::EventHandlerResult exploreSketch() {
61+
62+
// Static keymap exploration
63+
64+
typedef typename _Sketch::StaticKeymap K;
65+
66+
// Important: Always make sure to call _Sketch::StaticKeymap's methods
67+
// in a constexpr context. This is done by
68+
// passing their value to a constexpr temporary variable.
69+
70+
constexpr uint8_t n_key_1 = K::collect(NumKeysEqual{Key_1});
71+
static_assert(n_key_1 == 3, "Error determining key count");
72+
73+
constexpr bool has_key_1 = K::collect(HasKey{Key_1});
74+
static_assert(has_key_1, "Error querying key existence");
75+
has_key_1_ = has_key_1; // Assign the temporary that was computed
76+
// at compile time.
77+
78+
constexpr Key max_key = K::collect(MaxKeyRaw{});
79+
static_assert(max_key.getRaw() > 0, "");
80+
81+
static_assert(K::getKey(0 /*layer*/, KeyAddr{2, 3}) == Key_D,
82+
"Key lookup failed");
83+
84+
constexpr auto n_layers = K::nLayers();
85+
constexpr auto layer_size = K::layerSize();
86+
87+
// Plugin exploration
88+
//
89+
// Use macros ENTRY_TYPE, ENRTY_IS_LAST, PLUGIN_POSITION,
90+
// PLUGIN_IS_REGISTERED and NUM_OCCURRENCES to retreive information
91+
// about the plugins that are registered in the sketch.
92+
93+
typedef typename _Sketch::Plugins P;
94+
95+
static_assert(std::is_same<ENTRY_TYPE(P, 0), APlugin>::value, "");
96+
static_assert(std::is_same<ENTRY_TYPE(P, 1), BPlugin>::value, "");
97+
98+
static_assert(P::size == 3, "");
99+
100+
static_assert(!ENRTY_IS_LAST(P, 0), "");
101+
static_assert(!ENRTY_IS_LAST(P, 1), "");
102+
static_assert(ENRTY_IS_LAST(P, 2), "");
103+
104+
static_assert(PLUGIN_POSITION(P, APlugin) == 0, "");
105+
static_assert(PLUGIN_POSITION(P, BPlugin) == 1, "");
106+
static_assert(PLUGIN_POSITION(P, CPlugin) == -1, "");
107+
108+
static_assert(PLUGIN_IS_REGISTERED(P, APlugin) == true, "");
109+
static_assert(PLUGIN_IS_REGISTERED(P, BPlugin) == true, "");
110+
static_assert(PLUGIN_IS_REGISTERED(P, CPlugin) == false, "");
111+
112+
static_assert(NUM_OCCURRENCES(P, APlugin) == 2, "");
113+
static_assert(NUM_OCCURRENCES(P, BPlugin) == 1, "");
114+
static_assert(NUM_OCCURRENCES(P, CPlugin) == 0, "");
115+
116+
return kaleidoscope::EventHandlerResult::OK;
117+
}
118+
119+
private:
120+
121+
bool has_key_1_;
122+
};
123+
124+
APlugin a_plugin1, a_plugin2;
125+
BPlugin b_plugin;
126+
127+
KALEIDOSCOPE_INIT_PLUGINS(
128+
a_plugin1,
129+
b_plugin,
130+
a_plugin2
131+
)
132+
133+
void setup() {
134+
Kaleidoscope.setup();
135+
}
136+
137+
void loop() {
138+
Kaleidoscope.loop();
139+
}

src/kaleidoscope/Kaleidoscope.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Kaleidoscope_::setup(void) {
3636
// properly.
3737
device().serialPort().begin(9600);
3838

39+
kaleidoscope::sketch_exploration::pluginsExploreSketch();
3940
kaleidoscope::Hooks::onSetup();
4041

4142
device().setup();

src/kaleidoscope/Kaleidoscope.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ static constexpr DEPRECATED(LED_COUNT) uint8_t LED_COUNT = kaleidoscope_internal
5959
#include "kaleidoscope/key_events.h"
6060
#include "kaleidoscope/hid.h"
6161
#include "kaleidoscope/layers.h"
62+
#include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h"
6263
#include "kaleidoscope/macro_map.h"
6364
#include "kaleidoscope_internal/event_dispatch.h"
6465
#include "kaleidoscope_internal/LEDModeManager.h"

src/kaleidoscope/event_handlers.h

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@
7676
// kaleidoscope::EventHandlerResult::EVENT_CONSUMED. To enable this
7777
// pass the abortable flag value _ABORTABLE, _NOT_ABORTABLE otherwise.
7878
//
79+
// template parameter type list:
80+
// The hook's template type list in parenthesis, with a trailing comma.
81+
// e.g. (, typename _T1, typename _T2)
82+
// Pass empty parenthesis if the hook is non templatized.
83+
//
84+
// template parameters:
85+
// The hook's template parameters in parenthesis, with a trailing comma.
86+
// The template parameter names must match the template type list.
87+
// e.g. (, _T1, _T2)
88+
// Pass empty parenthesis if the hook is non templatized.
89+
//
90+
// dummy template arguments:
91+
// Supply a list of already defined dummy types that could realistically
92+
// be used to instantiate the template hook. Those types are only used
93+
// during hook method signature checks.
94+
// Please add parenthesis and a trailing comma.
95+
// e.g. (, int, int)
96+
// Pass empty parenthesis if the hook is non templatized.
97+
//
7998
// call signature:
8099
// The type of arguments passed to the handlers as a comma separated
81100
// list in brackets. Every parameter must be named.
@@ -93,12 +112,21 @@
93112
" uint8_t keyState)\n" __NL__ \
94113
"instead."
95114

115+
namespace kaleidoscope {
116+
117+
// This dummy class can be used as dummy template argument to
118+
// be passed in the definition of template hooks.
119+
//
120+
class SignatureCheckDummy {};
121+
} // namespace kaleidoscope
122+
96123
#define _FOR_EACH_EVENT_HANDLER(OPERATION, ...) __NL__ \
97124
__NL__ \
98125
OPERATION(onSetup, __NL__ \
99126
1, __NL__ \
100127
_CURRENT_IMPLEMENTATION, __NL__ \
101128
_NOT_ABORTABLE, __NL__ \
129+
(),(),(), /* non template */ __NL__ \
102130
(),(), ##__VA_ARGS__) __NL__ \
103131
__NL__ \
104132
/* Called at the very start of each cycle, before gathering */ __NL__ \
@@ -107,6 +135,7 @@
107135
1, __NL__ \
108136
_CURRENT_IMPLEMENTATION, __NL__ \
109137
_NOT_ABORTABLE, __NL__ \
138+
(),(),(), /* non template */ __NL__ \
110139
(), (), ##__VA_ARGS__) __NL__ \
111140
__NL__ \
112141
/* DEPRECATED */ __NL__ \
@@ -121,6 +150,7 @@
121150
1, __NL__ \
122151
DEPRECATED(ON_KEYSWITCH_EVENT_HANDLER_V1), __NL__ \
123152
_ABORTABLE, __NL__ \
153+
(),(),(), /* non template */ __NL__ \
124154
(Key &mappedKey, byte row, byte col, uint8_t keyState), __NL__ \
125155
(mappedKey, row, col, keyState), ##__VA_ARGS__) __NL__ \
126156
__NL__ \
@@ -135,6 +165,7 @@
135165
2, __NL__ \
136166
_CURRENT_IMPLEMENTATION, __NL__ \
137167
_ABORTABLE, __NL__ \
168+
(),(),(), /* non template */ __NL__ \
138169
(Key &mappedKey, KeyAddr key_addr, uint8_t keyState), __NL__ \
139170
(mappedKey, key_addr, keyState), ##__VA_ARGS__) __NL__ \
140171
__NL__ \
@@ -150,6 +181,7 @@
150181
1, __NL__ \
151182
_CURRENT_IMPLEMENTATION, __NL__ \
152183
_ABORTABLE, __NL__ \
184+
(),(),(), /* non template */ __NL__ \
153185
(const char *command), __NL__ \
154186
(command), ##__VA_ARGS__) __NL__ \
155187
__NL__ \
@@ -160,6 +192,7 @@
160192
1, __NL__ \
161193
_CURRENT_IMPLEMENTATION, __NL__ \
162194
_NOT_ABORTABLE, __NL__ \
195+
(),(),(), /* non template */ __NL__ \
163196
(), (), ##__VA_ARGS__) __NL__ \
164197
/* Called when the LED mode changes. If one needs to know what */ __NL__ \
165198
/* from and what to the mode changed, they should track that */ __NL__ \
@@ -168,6 +201,7 @@
168201
1, __NL__ \
169202
_CURRENT_IMPLEMENTATION, __NL__ \
170203
_NOT_ABORTABLE, __NL__ \
204+
(),(),(), /* non template */ __NL__ \
171205
(), (), ##__VA_ARGS__) __NL__ \
172206
/* Called before reporting our state to the host. This is the */ __NL__ \
173207
/* last point in a cycle where a plugin can alter what gets */ __NL__ \
@@ -176,6 +210,7 @@
176210
1, __NL__ \
177211
_CURRENT_IMPLEMENTATION, __NL__ \
178212
_NOT_ABORTABLE, __NL__ \
213+
(),(),(), /* non template */ __NL__ \
179214
(),(),##__VA_ARGS__) __NL__ \
180215
__NL__ \
181216
/* Called at the very end of a cycle, after everything's */ __NL__ \
@@ -184,7 +219,20 @@
184219
1, __NL__ \
185220
_CURRENT_IMPLEMENTATION, __NL__ \
186221
_NOT_ABORTABLE, __NL__ \
187-
(),(),##__VA_ARGS__)
222+
(),(),(), /* non template */ __NL__ \
223+
(),(),##__VA_ARGS__) __NL__ \
224+
__NL__ \
225+
/* Called before setup to enable plugins at compile time */ __NL__ \
226+
/* to explore the sketch. */ __NL__ \
227+
OPERATION(exploreSketch , __NL__ \
228+
1, __NL__ \
229+
_CURRENT_IMPLEMENTATION, __NL__ \
230+
_NOT_ABORTABLE, __NL__ \
231+
(,typename _Sketch), __NL__ \
232+
(,_Sketch), __NL__ \
233+
(,kaleidoscope::SignatureCheckDummy), __NL__ \
234+
(), __NL__ \
235+
(),##__VA_ARGS__)
188236

189237
// The following function macro lists event handler/hook method names and
190238
// available versions. It is used to auto-generate code that is
@@ -237,4 +285,8 @@
237285
__NL__ \
238286
START(afterEachCycle, 1) __NL__ \
239287
OP(afterEachCycle, 1) __NL__ \
240-
END(afterEachCycle, 1)
288+
END(afterEachCycle, 1) __NL__ \
289+
__NL__ \
290+
START(exploreSketch, 1) __NL__ \
291+
OP(exploreSketch, 1) __NL__ \
292+
END(exploreSketch, 1)

src/kaleidoscope/hooks.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ namespace kaleidoscope {
3131

3232
#define INSTANTIATE_WEAK_HOOK_FUNCTION( \
3333
HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \
34-
SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) __NL__ \
34+
SHOULD_ABORT_ON_CONSUMED_EVENT, \
35+
TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \
36+
SIGNATURE, ARGS_LIST) __NL__ \
3537
__NL__ \
38+
MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \
3639
__attribute__((weak)) __NL__ \
3740
EventHandlerResult Hooks::HOOK_NAME SIGNATURE { __NL__ \
3841
return EventHandlerResult::OK; __NL__ \
@@ -42,4 +45,18 @@ _FOR_EACH_EVENT_HANDLER(INSTANTIATE_WEAK_HOOK_FUNCTION)
4245

4346
#undef INSTANTIATE_WEAK_HOOK_FUNCTION
4447

48+
namespace sketch_exploration {
49+
class Sketch;
50+
}
51+
52+
// Make sure that there is no undefined symbol if KALEIDOSCOPE_INIT_PLUGINS(...)
53+
// is not invoked in the user's sketch.
54+
//
55+
template<>
56+
__attribute__((weak))
57+
EventHandlerResult Hooks::exploreSketch
58+
<sketch_exploration::Sketch>() {
59+
return EventHandlerResult::OK;
60+
};
61+
4562
} // namespace kaleidoscope

0 commit comments

Comments
 (0)