diff --git a/examples/Devices/gHeavy/ButterStick/.kaleidoscope-builder.conf b/examples/Devices/gHeavy/ButterStick/.kaleidoscope-builder.conf
new file mode 100644
index 00000000..c6e2f96f
--- /dev/null
+++ b/examples/Devices/gHeavy/ButterStick/.kaleidoscope-builder.conf
@@ -0,0 +1,2 @@
+DEFAULT_SKETCH="ButterStick"
+BOARD="gheavy_butterstick"
diff --git a/examples/Devices/gHeavy/ButterStick/ButterStick.ino b/examples/Devices/gHeavy/ButterStick/ButterStick.ino
new file mode 100644
index 00000000..35cf5aff
--- /dev/null
+++ b/examples/Devices/gHeavy/ButterStick/ButterStick.ino
@@ -0,0 +1,42 @@
+/* -*- mode: c++ -*-
+ * kaleidoscope::device::gheavy::ButterStick -- gHeavy ButterStick hardware support for Kaleidoscope
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "Kaleidoscope.h"
+
+enum {
+ _DEFAULT
+};
+
+
+/* *INDENT-OFF* */
+KEYMAPS(
+ [_DEFAULT] = KEYMAP(
+ Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Y, Key_U, Key_I, Key_O, Key_P,
+ Key_A, Key_S, Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Semicolon
+ )
+);
+/* *INDENT-ON* */
+
+void setup() {
+ Kaleidoscope.setup();
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/examples/Devices/gHeavy/ButterStick/Makefile b/examples/Devices/gHeavy/ButterStick/Makefile
new file mode 100644
index 00000000..996bde98
--- /dev/null
+++ b/examples/Devices/gHeavy/ButterStick/Makefile
@@ -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
diff --git a/src/Kaleidoscope-Hardware-gHeavy-ButterStick.h b/src/Kaleidoscope-Hardware-gHeavy-ButterStick.h
new file mode 100644
index 00000000..82d7c678
--- /dev/null
+++ b/src/Kaleidoscope-Hardware-gHeavy-ButterStick.h
@@ -0,0 +1,21 @@
+/* -*- mode: c++ -*-
+ * kaleidoscope::device::gheavy::ButterStick -- gHeavy ButterStick hardware support for Kaleidoscope
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "kaleidoscope/device/gheavy/ButterStick.h"
diff --git a/src/kaleidoscope/device/gheavy/ButterStick.cpp b/src/kaleidoscope/device/gheavy/ButterStick.cpp
new file mode 100644
index 00000000..016d1f02
--- /dev/null
+++ b/src/kaleidoscope/device/gheavy/ButterStick.cpp
@@ -0,0 +1,71 @@
+/* -*- mode: c++ -*-
+ * kaleidoscope::device::gheavy::ButterStick -- gHeavy ButterStick hardware support for Kaleidoscope
+ * Copyright (C) 2020 Keyboard.io, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 .
+ */
+
+#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
+#ifdef ARDUINO_AVR_GHEAVY_BUTTERSTICK
+
+#include "kaleidoscope/Runtime.h"
+#include "kaleidoscope/driver/keyscanner/Base_Impl.h"
+
+// Here, we set up aliases to the device's KeyScanner and KeyScannerProps
+// in the global namespace within the scope of this file. We'll use these
+// aliases to simplify some template initialization code below.
+using KeyScannerProps = typename kaleidoscope::device::gheavy::ButterStickProps::KeyScannerProps;
+using KeyScanner = typename kaleidoscope::device::gheavy::ButterStickProps::KeyScanner;
+
+namespace kaleidoscope {
+namespace device {
+namespace gheavy {
+
+// `KeyScannerProps` here refers to the alias set up above. We do not need to
+// prefix the `matrix_rows` and `matrix_columns` names within the array
+// declaration, because those are resolved within the context of the class, so
+// the `matrix_rows` in `KeyScannerProps::matrix_row_pins[matrix_rows]` gets
+// resolved as `KeyScannerProps::matrix_rows`.
+const uint8_t KeyScannerProps::matrix_rows;
+const uint8_t KeyScannerProps::matrix_columns;
+constexpr uint8_t KeyScannerProps::matrix_row_pins[matrix_rows];
+constexpr uint8_t KeyScannerProps::matrix_col_pins[matrix_columns];
+
+// Resolving is a bit different in case of templates, however: the name of the
+// array is resolved within the scope of the namespace and the class, but the
+// array size is not - because it is a template. Therefore, we need a fully
+// qualified name there - or an alias in the global scope, which we set up just
+// above.
+template<> uint16_t KeyScanner::previousKeyState_[KeyScannerProps::matrix_rows] = {};
+template<> uint16_t KeyScanner::keyState_[KeyScannerProps::matrix_rows] = {};
+template<> uint16_t KeyScanner::masks_[KeyScannerProps::matrix_rows] = {};
+template<> uint8_t KeyScanner::debounce_matrix_[KeyScannerProps::matrix_rows][KeyScannerProps::matrix_columns] = {};
+
+// We set up the TIMER1 interrupt vector here. Due to dependency reasons, this
+// cannot be in a header-only driver, and must be placed here.
+//
+// Timer1 is responsible for setting a property on the KeyScanner, which will
+// tell it to do a scan. We use this to make sure that scans happen at roughly
+// the intervals we want. We do the scan outside of the interrupt scope for
+// practical reasons: guarding every codepath against interrupts that can be
+// reached from the scan is far too tedious, for very little gain.
+ISR(TIMER1_OVF_vect) {
+ Runtime.device().keyScanner().do_scan_ = true;
+}
+
+} // namespace gheavy
+} // namespace device
+} // namespace kaleidoscope
+
+#endif
+#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
diff --git a/src/kaleidoscope/device/gheavy/ButterStick.h b/src/kaleidoscope/device/gheavy/ButterStick.h
new file mode 100644
index 00000000..44071944
--- /dev/null
+++ b/src/kaleidoscope/device/gheavy/ButterStick.h
@@ -0,0 +1,74 @@
+/* -*- mode: c++ -*-
+ * kaleidoscope::device::gheavy::ButterStick -- gHeavy ButterStick hardware support for Kaleidoscope
+ * Copyright (C) 2020 Keyboard.io, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#ifdef ARDUINO_AVR_GHEAVY_BUTTERSTICK
+
+#define KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND 1
+
+#include
+
+#include "kaleidoscope/driver/keyscanner/ATmega.h"
+#include "kaleidoscope/driver/bootloader/avr/FLIP.h"
+#include "kaleidoscope/device/ATmega32U4Keyboard.h"
+
+namespace kaleidoscope {
+namespace device {
+namespace gheavy {
+
+struct ButterStickProps : kaleidoscope::device::ATmega32U4KeyboardProps {
+ struct KeyScannerProps : public kaleidoscope::driver::keyscanner::ATmegaProps {
+ static constexpr uint8_t matrix_rows = 2;
+ static constexpr uint8_t matrix_columns = 10;
+ typedef MatrixAddr KeyAddr;
+#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
+ static constexpr uint8_t matrix_row_pins[matrix_rows] = { PIN_F4, PIN_F5 };
+ static constexpr uint8_t matrix_col_pins[matrix_columns] = { PIN_B0, PIN_B1, PIN_B2, PIN_B3, PIN_B4, PIN_B5, PIN_B6, PIN_B7, PIN_C6, PIN_C7 };
+#endif // KALEIDOSCOPE_VIRTUAL_BUILD
+ };
+ typedef kaleidoscope::driver::keyscanner::ATmega KeyScanner;
+ typedef kaleidoscope::driver::bootloader::avr::FLIP Bootloader;
+ static constexpr const char *short_name = "ButterStick";
+};
+
+#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
+class ButterStick: public kaleidoscope::device::ATmega32U4Keyboard {};
+#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
+/* 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 ButterStick;
+
+#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
+
+#define PER_KEY_DATA(dflt, \
+ R0C0, R0C1, R0C2, R0C3, R0C4, R0C5, R0C6, R0C7, R0C8, R0C9, \
+ R1C0, R1C1, R1C2, R1C3, R1C4, R1C5, R1C6, R1C7, R1C8, R1C9 \
+ ) \
+ R0C9, R0C8, R0C7, R0C6, R0C5, R0C4, R0C3, R0C2, R0C1, R0C0, \
+ R1C9, R1C8, R1C7, R1C6, R1C5, R1C4, R1C3, R1C2, R1C1, R1C0
+} // namespace gheavy
+} // namespace device
+
+EXPORT_DEVICE(kaleidoscope::device::gheavy::ButterStick)
+
+} // namespace kaleidoscope
+
+#endif