diff --git a/fake-gtest/src/googletest.h b/fake-gtest/src/googletest.h deleted file mode 100644 index 02cab892..00000000 --- a/fake-gtest/src/googletest.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "gtest/gtest.h" -#include "gmock/gmock.h" diff --git a/src/kaleidoscope/testing/observer/Observer.h b/src/kaleidoscope/testing/observer/Observer.h deleted file mode 100644 index cc389a82..00000000 --- a/src/kaleidoscope/testing/observer/Observer.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- mode: c++ -*- - * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) - * - * 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 . - */ - -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - -#pragma once - -//#include "./Logging.h" -#include -#define LOG(x) std::cout - -#include "HID-Settings.h" -#include "HIDReportObserver.h" -#include "kaleidoscope/testing/reports/KeyboardReport.h" - -namespace kaleidoscope { -namespace testing { - -class Observer { - public: - Observer() { - HIDReportObserver::resetHook( - std::bind(&Observer::ProcessHidReport, this)); - } - - void Clear() { - mouse_reports_.clear(); - boot_keyboard_reports_.clear(); - absolute_mouse_reports_.clear(); - keyboard_reports_.clear(); - } - - void ProcessHidReport(uint8_t id, const void* data, int len, int result) { - switch (id) { - case HID_REPORTID_MOUSE: { - ProcessReport(MouseReport{data}); - break; - } - case HID_REPORTID_KEYBOARD: { - ProcessReport(BootKeyboardReport{data}); - break; - } - case HID_REPORTID_GAMEPAD: - case HID_REPORTID_CONSUMERCONTROL: - case HID_REPORTID_SYSTEMCONTROL: { - // TODO: React appropriately to these. - LOG(INFO) << "Ignoring HID report with id = " << id; - break; - } - case HID_REPORTID_MOUSE_ABSOLUTE: { - ProcessReport(AbsoluteMouseReport{data}); - break; - } - case HID_REPORTID_NKRO_KEYBOARD: { - ProcessReport(KeyboardReport{data}); - break; - } - default: - LOG(ERROR) << "Encountered unknown HID report with id = " << id; - } - } - - const std::vector& KeyboardReports() const { - return keyboard_reports_; - } - - const KeyboardReport& KeyboardReports(size_t i) const { - return keyboard_reports_.at(i); - } - - private: - template - void ProcessReport(const R& report) { - observer_.RecordReport(report); - } - - template - void RecordReport(const R& report); - - std::vector keyboard_reports_; -}; - -template <> -void Observer::RecordReport(const KeyboardReport& report) { - keyboard_reports_.push_back(report); -} - -} // namespace testing -} // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/testing/Makefile b/testing/Makefile index 086e7866..47fb4d9b 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -1,9 +1,19 @@ +LIB_DIR?=${PWD}/lib TEST_DIRS=$(dir $(wildcard */*_test.cpp)) -Makefile: ${TEST_DIRS} +Makefile: build-libs ${TEST_DIRS} @: +build-libs: googletest common + @: + +googletest: FORCE + cd googletest && $(MAKE) + +common: FORCE + cd common && env LIB_DIR="${LIB_DIR}" $(MAKE) + %: FORCE - cd "$@" && $(MAKE) + if [ -f "$@/Makefile" ]; then cd "$@"; $(MAKE); fi -.PHONY: FORCE +.PHONY: FORCE googletest build-libs diff --git a/src/kaleidoscope/testing/reports/KeyboardReport.cpp b/testing/common/KeyboardReport.cpp similarity index 84% rename from src/kaleidoscope/testing/reports/KeyboardReport.cpp rename to testing/common/KeyboardReport.cpp index 5781e404..6974f43f 100644 --- a/src/kaleidoscope/testing/reports/KeyboardReport.cpp +++ b/testing/common/KeyboardReport.cpp @@ -14,7 +14,7 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD +#include "testing/common/KeyboardReport.h" #include @@ -29,9 +29,9 @@ KeyboardReport::KeyboardReport(const void* data) { std::vector KeyboardReport::ActiveKeycodes() const { std::vector active_keys; - for (uint8_t i = 0; i <= HID_LAST_KEY; ++k) { - uint8_t bit = 1 << (uint8_t(k) % 8); - uint8_t key_code = report_data_.keys[k/8] & bit; + for (uint8_t i = 0; i <= HID_LAST_KEY; ++i) { + uint8_t bit = 1 << (uint8_t(i) % 8); + uint8_t key_code = report_data_.keys[i/8] & bit; if (key_code) active_keys.push_back(i); } return active_keys; @@ -39,5 +39,3 @@ std::vector KeyboardReport::ActiveKeycodes() const { } // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/testing/reports/KeyboardReport.h b/testing/common/KeyboardReport.h similarity index 93% rename from src/kaleidoscope/testing/reports/KeyboardReport.h rename to testing/common/KeyboardReport.h index 3341c5a3..92be4ec4 100644 --- a/src/kaleidoscope/testing/reports/KeyboardReport.h +++ b/testing/common/KeyboardReport.h @@ -14,10 +14,11 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - #pragma once +#include +#include + #include "MultiReport/Keyboard.h" namespace kaleidoscope { @@ -39,5 +40,3 @@ class KeyboardReport { } // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/testing/common/Makefile b/testing/common/Makefile new file mode 100644 index 00000000..bbe9e4cd --- /dev/null +++ b/testing/common/Makefile @@ -0,0 +1,35 @@ +LIB_DIR ?= ${PWD}/lib +OBJ_DIR ?= ${PWD}/obj + + +CXX_FILES=$(wildcard *.cpp) +LIB_FILE=common.a +OBJ_FILES=$(patsubst %.cpp,${OBJ_DIR}/%.o,$(CXX_FILES)) + +Makefile: ${LIB_DIR}/${LIB_FILE} + @: + +${LIB_DIR}/${LIB_FILE}: ${OBJ_FILES} + mkdir -p "${LIB_DIR}" + ar rcs "${LIB_DIR}/${LIB_FILE}" ${OBJ_FILES} + +${OBJ_DIR}/%.o: %.cpp + @echo "compile $@" + mkdir -p "${OBJ_DIR}" + g++ -o "$@" -c \ + -I../.. \ + -I../../src \ + -I../../../../../virtual/cores/arduino \ + -I../../../Kaleidoscope-HIDAdaptor-KeyboardioHID/src \ + -I../../../KeyboardioHID/src \ + -I../../testing/googletest/googlemock/include \ + -I../../testing/googletest/googletest/include \ + -DARDUINO=10607 \ + -DARDUINO_AVR_MODEL01 \ + '-DKALEIDOSCOPE_HARDWARE_H="Kaleidoscope-Hardware-Model01.h"' \ + -DKALEIDOSCOPE_VIRTUAL_BUILD=1 \ + -DKEYBOARDIOHID_BUILD_WITHOUT_HID=1 \ + -DUSBCON=dummy \ + -DARDUINO_ARCH_AVR=1 \ + '-DUSB_PRODUCT="Model 01"' \ + $< diff --git a/src/kaleidoscope/sim/Sim.cpp b/testing/common/Simulator.cpp similarity index 78% rename from src/kaleidoscope/sim/Sim.cpp rename to testing/common/Simulator.cpp index 158a7425..725219f4 100644 --- a/src/kaleidoscope/sim/Sim.cpp +++ b/testing/common/Simulator.cpp @@ -14,25 +14,25 @@ * this program. If not, see . */ -#include "kaleidoscope/sim/Sim.h" #include "Kaleidoscope.h" +#include "testing/common/Simulator.h" namespace kaleidoscope { -namespace sim { +namespace testing { -void Sim::RunCycle() { +void Simulator::RunCycle() { Kaleidoscope.loop(); } -void Sim::RunCycles(size_t n) { +void Simulator::RunCycles(size_t n) { for (size_t i = 0; i < n; ++i) RunCycle(); } -void Sim::Press(uint8_t row, uint8_t, col) { +void Simulator::Press(uint8_t row, uint8_t col) { Kaleidoscope.device().keyScanner().setKeystate( KeyAddr{row, col}, - Kaleidoscope::Device::Props::keyScanner::KeyState::Pressed); + kaleidoscope::Device::Props::KeyScanner::KeyState::Pressed); } -} // namespace sim +} // namespace testing } // namespace kaleidoscope diff --git a/src/kaleidoscope/sim/Sim.h b/testing/common/Simulator.h similarity index 83% rename from src/kaleidoscope/sim/Sim.h rename to testing/common/Simulator.h index a16cf42c..5604faea 100644 --- a/src/kaleidoscope/sim/Sim.h +++ b/testing/common/Simulator.h @@ -14,20 +14,22 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - #pragma once +#include +#include + namespace kaleidoscope { -namespace sim { +namespace testing { -class Sim { +class Simulator { public: void RunCycle(); + void RunCycles(size_t n); + void Press(uint8_t row, uint8_t col); + void Release(uint8_t row, uint8_t col); }; -} // namespace sim +} // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/testing/common/State.cpp b/testing/common/State.cpp new file mode 100644 index 00000000..8ead9cb5 --- /dev/null +++ b/testing/common/State.cpp @@ -0,0 +1,79 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) + * + * 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 . + */ + +#include "testing/common/State.h" + +#include "testing/common/fix-macros.h" + +// TODO(epan): Add proper logging. +#include +#define LOG(x) std::cout + +namespace kaleidoscope { +namespace testing { + +State::State() { + HIDReportObserver::resetHook( + [this](uint8_t id, const void* data, int len, int result) { + this->ProcessHidReport(id, data, len, result); + }); +} + +void State::Clear() { + keyboard_reports_.clear(); +} + +void State::ProcessHidReport( + uint8_t id, const void* data, int len, int result) { + switch (id) { + case HID_REPORTID_MOUSE: { + LOG(ERROR) << "Dropped MouseReport: unimplemented"; + break; + } + case HID_REPORTID_KEYBOARD: { + LOG(ERROR) << "Dropped BootKeyboardReport: unimplemented"; + break; + } + case HID_REPORTID_GAMEPAD: + case HID_REPORTID_CONSUMERCONTROL: + case HID_REPORTID_SYSTEMCONTROL: { + // TODO: React appropriately to these. + LOG(INFO) << "Ignoring HID report with id = " << id; + break; + } + case HID_REPORTID_MOUSE_ABSOLUTE: { + LOG(ERROR) << "Dropped AbsoluteMouseReport: unimplemented"; + break; + } + case HID_REPORTID_NKRO_KEYBOARD: { + ProcessReport(KeyboardReport{data}); + break; + } + default: + LOG(ERROR) << "Encountered unknown HID report with id = " << id; + } +} + +const std::vector& State::KeyboardReports() const { + return keyboard_reports_; +} + +const KeyboardReport& State::KeyboardReports(size_t i) const { + return keyboard_reports_.at(i); +} + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/common/State.h b/testing/common/State.h new file mode 100644 index 00000000..7376544b --- /dev/null +++ b/testing/common/State.h @@ -0,0 +1,58 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) + * + * 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 . + */ + +#pragma once + +#include +#include +#include + +#include "HID-Settings.h" +#include "HIDReportObserver.h" +#include "testing/common/KeyboardReport.h" + +namespace kaleidoscope { +namespace testing { + +class State { + public: + State(); + + void Clear(); + + void ProcessHidReport(uint8_t id, const void* data, int len, int result); + + const std::vector& KeyboardReports() const; + const KeyboardReport& KeyboardReports(size_t i) const; + + private: + template + void ProcessReport(const R& report); + + std::vector keyboard_reports_; +}; + +/* + * Implementation + */ + +template <> +void State::ProcessReport(const KeyboardReport& report) { + keyboard_reports_.push_back(report); +} + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/common/VirtualDeviceTest.cpp b/testing/common/VirtualDeviceTest.cpp new file mode 100644 index 00000000..267ebf7d --- /dev/null +++ b/testing/common/VirtualDeviceTest.cpp @@ -0,0 +1,38 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) + * + * 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 . + */ + +#include "testing/common/VirtualDeviceTest.h" + +namespace kaleidoscope { +namespace testing { + +void VirtualDeviceTest::RunCycle() { + state_.Clear(); + sim_.RunCycle(); +} + +void VirtualDeviceTest::RunCycles(size_t n) { + if (n == 0) return; + state_.Clear(); + sim_.RunCycles(n); +} + +const State& VirtualDeviceTest::Result() const { + return state_; +} + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/common/VirtualDeviceTest.h b/testing/common/VirtualDeviceTest.h index f92f9449..0a76ddf3 100644 --- a/testing/common/VirtualDeviceTest.h +++ b/testing/common/VirtualDeviceTest.h @@ -14,39 +14,33 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - #pragma once -#include "setup-googletest.h" +#include + +#include "testing/common/Simulator.h" +#include "testing/common/State.h" -#include "HID-Settings.h" -#include "kaleidoscope/sim/Sim.h" -#include "kaleidoscope/testing/observer/Observer.h" +// Out of order because `fix-macros.h` clears the preprocessor environment for +// gtest and gmock. +#include "testing/common/fix-macros.h" +#include "gtest/gtest.h" namespace kaleidoscope { namespace testing { class VirtualDeviceTest : public ::testing::Test { protected: - void RunCycle() { - observer_.Clear(); - sim_.RunCycle(); - } - void RunCycles(size_t n) { - if (n == 0) return; - observer_.Clear(); - sim_.RunCycles(n); - } - Observer& Result() { return observer_; } - - Sim sim_; + void RunCycle(); + void RunCycles(size_t n); + + const State& Result() const; + + Simulator sim_; private: - Observer observer_; + State state_; }; } // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/fake-gtest/src/setup-googletest.h b/testing/common/fix-macros.h similarity index 88% rename from fake-gtest/src/setup-googletest.h rename to testing/common/fix-macros.h index 69eaa5c3..2940f996 100644 --- a/fake-gtest/src/setup-googletest.h +++ b/testing/common/fix-macros.h @@ -14,9 +14,9 @@ * this program. If not, see . */ -// Fake file to trick arduino-builder into working. - -#pragma once +// We intentionally omit `#pragma once` since we need to set up macros per +// compilation unit. +// #pragma once #undef min #undef max @@ -24,9 +24,6 @@ #undef U #undef TEST -#include "gtest/gtest.h" -#include "gmock/gmock.h" - #define SETUP_GOOGLETEST() \ void executeTestFunction() { \ setup(); /* setup Kaleidoscope */ \ diff --git a/testing/common/matchers.h b/testing/common/matchers.h index 179fbf33..afb98528 100644 --- a/testing/common/matchers.h +++ b/testing/common/matchers.h @@ -14,11 +14,14 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - #pragma once -#include "setup-googletest.h" +#include "kaleidoscope/key_defs.h" + +// Out of order because `fix-macros.h` clears the preprocessor environment for +// gtest and gmock. +#include "testing/common/fix-macros.h" +#include "gmock/gmock.h" namespace kaleidoscope { namespace testing { @@ -27,5 +30,3 @@ auto ContainsKey(Key key) { return ::testing::Contains(key.getKeyCode()); } } // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/testing/hello-simulator/Makefile b/testing/hello-simulator/Makefile index 824a9279..d77a2fe9 100644 --- a/testing/hello-simulator/Makefile +++ b/testing/hello-simulator/Makefile @@ -23,10 +23,12 @@ ${OBJ_DIR}/%.o: %.cpp @echo "compile $@" mkdir -p "${OBJ_DIR}" g++ -o "$@" -c \ + -I../.. \ -I../../src \ -I../../../../../virtual/cores/arduino \ -I../../../Kaleidoscope-HIDAdaptor-KeyboardioHID/src \ -I../../../KeyboardioHID/src \ + -I../../testing/googletest/googlemock/include \ -I../../testing/googletest/googletest/include \ -DARDUINO=10607 \ -DARDUINO_AVR_MODEL01 \ diff --git a/testing/kaleidoscope/Makefile b/testing/kaleidoscope/Makefile new file mode 100644 index 00000000..d77a2fe9 --- /dev/null +++ b/testing/kaleidoscope/Makefile @@ -0,0 +1,47 @@ +BIN_DIR=bin +LIB_DIR=lib +OBJ_DIR=obj + +SKETCH_FILE=$(wildcard *.ino) +BIN_FILE=$(subst .ino,,$(SKETCH_FILE)) +LIB_FILE=${BIN_FILE}-latest.a + +TEST_FILES=$(wildcard *_test.cpp) +TEST_OBJS=$(patsubst %.cpp,${OBJ_DIR}/%.o,$(TEST_FILES)) + +run: ${BIN_DIR}/${BIN_FILE} + @echo "run" + "./${BIN_DIR}/${BIN_FILE}" -t + +${BIN_DIR}/${BIN_FILE}: ${TEST_OBJS} FORCE + @echo "link" + mkdir -p "${BIN_DIR}" "${LIB_DIR}" + env LIBONLY=yes LOCAL_CFLAGS='"-I$(PWD)"' OUTPUT_PATH="$(PWD)/$(LIB_DIR)" VERBOSE=1 $(MAKE) -f delegate.mk + g++ -o "${BIN_DIR}/${BIN_FILE}" -lpthread -g -w -lm -lXtst -lX11 ${TEST_OBJS} "${LIB_DIR}/${LIB_FILE}" -L"$(PWD)/../googletest/lib" -lgtest -lgmock + +${OBJ_DIR}/%.o: %.cpp + @echo "compile $@" + mkdir -p "${OBJ_DIR}" + g++ -o "$@" -c \ + -I../.. \ + -I../../src \ + -I../../../../../virtual/cores/arduino \ + -I../../../Kaleidoscope-HIDAdaptor-KeyboardioHID/src \ + -I../../../KeyboardioHID/src \ + -I../../testing/googletest/googlemock/include \ + -I../../testing/googletest/googletest/include \ + -DARDUINO=10607 \ + -DARDUINO_AVR_MODEL01 \ + '-DKALEIDOSCOPE_HARDWARE_H="Kaleidoscope-Hardware-Model01.h"' \ + -DKALEIDOSCOPE_VIRTUAL_BUILD=1 \ + -DKEYBOARDIOHID_BUILD_WITHOUT_HID=1 \ + -DUSBCON=dummy \ + -DARDUINO_ARCH_AVR=1 \ + '-DUSB_PRODUCT="Model 01"' \ + $< + +clean: FORCE + rm -rf "${BIN_DIR}" "${LIB_DIR}" "${OBJ_DIR}" + +.PHONY: FORCE + diff --git a/testing/kaleidoscope/delegate.mk b/testing/kaleidoscope/delegate.mk new file mode 100644 index 00000000..c170e383 --- /dev/null +++ b/testing/kaleidoscope/delegate.mk @@ -0,0 +1,73 @@ +# This stub makefile for a Kaleidoscope plugin pulls in +# all targets from the Kaleidoscope-Plugin library + +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/build-tools/makefiles/ + +# If Kaleidoscope's Arduino libraries cannot be found, e.g. because +# they reside outside of SKETCHBOOK_DIR, we fall back to assuming that +# the hardware directory can be determined in relation to the position of +# this Makefile. +ifeq ("$(wildcard $(BOARD_HARDWARE_PATH)/keyboardio/build-tools/makefiles/rules.mk)","") + # Determine the path of this Makefile + MKFILE_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + BOARD_HARDWARE_PATH = $(MKFILE_DIR)/../../../../../.. +endif + +ifeq ("$(wildcard $(BOARD_HARDWARE_PATH)/keyboardio/build-tools/makefiles/rules.mk)","") +$(info ***************************************************************************) +$(info Unable to autodetect a proper BOARD_HARDWARE_PATH. Please define it manually.) +$(info ***************************************************************************) +$(info ) +endif + +include $(BOARD_HARDWARE_PATH)/$(KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR)/rules.mk + diff --git a/testing/kaleidoscope/tests.h b/testing/kaleidoscope/simulator_test.cpp similarity index 75% rename from testing/kaleidoscope/tests.h rename to testing/kaleidoscope/simulator_test.cpp index b928b68d..71b1c076 100644 --- a/testing/kaleidoscope/tests.h +++ b/testing/kaleidoscope/simulator_test.cpp @@ -14,15 +14,16 @@ * this program. If not, see . */ -#ifdef KALEIDOSCOPE_VIRTUAL_BUILD - -#pragma once +#include "kaleidoscope/key_defs_keyboard.h" -#include "setup-googletest.h" +// Out of order because `fix-macros.h` clears the preprocessor environment for +// gtest and gmock. +#include "testing/common/fix-macros.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" -#include "kaleidoscope/key_defs_keyboard.h" -#include "../common/matchers.h" -#include "../common/VirtualDeviceTest.h" +#include "testing/common/matchers.h" +#include "testing/common/VirtualDeviceTest.h" SETUP_GOOGLETEST(); @@ -40,17 +41,15 @@ TEST_F(KeyboardReports, KeysActiveWhenPressed) { EXPECT_EQ(Result().KeyboardReports().size(), 1); EXPECT_THAT( - Result().KeyboardReports(0).ActiveKeyCodes(), + Result().KeyboardReports(0).ActiveKeycodes(), ContainsKey(Key_A)); sim_.Release(2, 1); // A RunCycles(2); - EXPECT_THAT(Result().KeyboardReports().size(), IsEmpty()); + EXPECT_THAT(Result().KeyboardReports(), IsEmpty()); } } // namespace } // namespace testing } // namespace kaleidoscope - -#endif // KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/testing/kaleidoscope/sketch.ino b/testing/kaleidoscope/sketch.ino new file mode 100644 index 00000000..c35a7555 --- /dev/null +++ b/testing/kaleidoscope/sketch.ino @@ -0,0 +1,537 @@ +// -*- mode: c++ -*- +// Copyright 2016 Keyboardio, inc. +// See "LICENSE" for license details + +#ifndef BUILD_INFORMATION +#define BUILD_INFORMATION "locally built" +#endif + + +/** + * These #include directives pull in the Kaleidoscope firmware core, + * as well as the Kaleidoscope plugins we use in the Model 01'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 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 01'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 01'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/key_defs_keyboard.h + * https://github.com/keyboardio/Kaleidoscope/blob/master/src/key_defs_consumerctl.h + * https://github.com/keyboardio/Kaleidoscope/blob/master/src/key_defs_sysctl.h + * https://github.com/keyboardio/Kaleidoscope/blob/master/src/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_COLEMAK +// #define PRIMARY_KEYMAP_DVORAK +// #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 keyState) { + if (keyToggledOn(keyState)) { + Macros.type(PSTR("Keyboardio Model 01 - 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(uint8_t keyState) { + static Key lastKey; + bool toggledOn = false; + if (keyToggledOn(keyState)) { + lastKey.setKeyCode(Key_A.getKeyCode() + (uint8_t)(millis() % 36)); + toggledOn = true; + } + + if (keyIsPressed(keyState)) + Kaleidoscope.hid().keyboard().pressKey(lastKey, toggledOn); +} + + +/** 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 macroIndex, uint8_t keyState) { + switch (macroIndex) { + + case MACRO_VERSION_INFO: + versionInfoMacro(keyState); + break; + + case MACRO_ANY: + anyKeyMacro(keyState); + 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 01. + +static constexpr uint8_t solid_red_level = 160; +static kaleidoscope::plugin::LEDSolidColor solidRed(solid_red_level, 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); +} + +/** A tiny wrapper, 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(); +} + +/** 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 } + }); + +// 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 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(150); + LEDRainbowWaveEffect.brightness(150); + + // 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/doc/plugin/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(); +}