From 92842cc40810bfda4e37877e98929a2b419c1bfe Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 22 Nov 2019 12:48:54 +0100 Subject: [PATCH 01/26] Improved ATmega class naming The MCU family is called `ATmega`. not `ATMega`, so correct all occurrences of it, while we still can. Also renamed `kaleidoscope::driver::keyscanner::AVR` to `kaleidoscope::driver::keyscanner::ATmega`. As a side-effect, this fixes compilation under the Arduino IDE, which defines `AVR` as a symbol. Signed-off-by: Gergely Nagy --- ...ega32U4Keyboard.h => ATmega32U4Keyboard.h} | 25 ++++++++++--------- src/kaleidoscope/device/ez/ErgoDox.h | 6 ++--- src/kaleidoscope/device/kbdfans/KBD4x.cpp | 2 +- src/kaleidoscope/device/kbdfans/KBD4x.h | 14 +++++------ src/kaleidoscope/device/keyboardio/Imago.cpp | 4 +-- src/kaleidoscope/device/keyboardio/Imago.h | 14 +++++------ src/kaleidoscope/device/keyboardio/Model01.h | 6 ++--- src/kaleidoscope/device/olkb/Planck.cpp | 2 +- src/kaleidoscope/device/olkb/Planck.h | 3 +-- .../device/softhruf/Splitography.cpp | 2 +- .../device/softhruf/Splitography.h | 14 +++++------ .../device/technomancy/Atreus.cpp | 2 +- src/kaleidoscope/device/technomancy/Atreus.h | 3 +-- .../device/technomancy/Atreus2.cpp | 2 +- src/kaleidoscope/device/technomancy/Atreus2.h | 3 +-- .../driver/keyscanner/{AVR.h => ATmega.h} | 24 +++++++++--------- .../driver/mcu/{ATMega32U4.h => ATmega32U4.h} | 6 ++--- ...4EEPROMProps.h => ATmega32U4EEPROMProps.h} | 4 +-- 18 files changed, 67 insertions(+), 69 deletions(-) rename src/kaleidoscope/device/{ATMega32U4Keyboard.h => ATmega32U4Keyboard.h} (64%) rename src/kaleidoscope/driver/keyscanner/{AVR.h => ATmega.h} (92%) rename src/kaleidoscope/driver/mcu/{ATMega32U4.h => ATmega32U4.h} (91%) rename src/kaleidoscope/driver/storage/{ATMega32U4EEPROMProps.h => ATmega32U4EEPROMProps.h} (84%) diff --git a/src/kaleidoscope/device/ATMega32U4Keyboard.h b/src/kaleidoscope/device/ATmega32U4Keyboard.h similarity index 64% rename from src/kaleidoscope/device/ATMega32U4Keyboard.h rename to src/kaleidoscope/device/ATmega32U4Keyboard.h index f3cc8882d2..b0d66feade 100644 --- a/src/kaleidoscope/device/ATMega32U4Keyboard.h +++ b/src/kaleidoscope/device/ATmega32U4Keyboard.h @@ -1,5 +1,5 @@ /* -*- mode: c++ -*- - * device::ATMega32U4Keyboard -- Generic ATMega32U4 keyboard base class + * device::ATmega32U4Keyboard -- Generic ATmega32U4 keyboard base class * Copyright (C) 2019 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify @@ -22,31 +22,32 @@ #include #include "kaleidoscope/device/Base.h" -#include "kaleidoscope/driver/mcu/ATMega32U4.h" -#include "kaleidoscope/driver/storage/ATMega32U4EEPROMProps.h" +#include "kaleidoscope/driver/mcu/ATmega32U4.h" +#include "kaleidoscope/driver/keyscanner/ATmega.h" +#include "kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h" #include "kaleidoscope/driver/storage/AVREEPROM.h" #define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, ROW_PINS_, COL_PINS_) \ - struct BOARD_##Props : kaleidoscope::device::ATMega32U4KeyboardProps { \ - struct KeyScannerProps : public kaleidoscope::driver::keyscanner::AVRProps { \ - AVR_KEYSCANNER_PROPS(ROW_PIN_LIST(ROW_PINS_), COL_PIN_LIST(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::AVR KeyScanner; \ + typedef kaleidoscope::driver::keyscanner::ATmega KeyScanner; \ typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \ }; \ - class BOARD_: public kaleidoscope::device::ATMega32U4Keyboard {}; + class BOARD_: public kaleidoscope::device::ATmega32U4Keyboard {}; namespace kaleidoscope { namespace device { -struct ATMega32U4KeyboardProps : kaleidoscope::device::BaseProps { - typedef kaleidoscope::driver::mcu::ATMega32U4 MCU; - typedef kaleidoscope::driver::storage::ATMega32U4EEPROMProps StorageProps; +struct ATmega32U4KeyboardProps : kaleidoscope::device::BaseProps { + typedef kaleidoscope::driver::mcu::ATmega32U4 MCU; + typedef kaleidoscope::driver::storage::ATmega32U4EEPROMProps StorageProps; typedef kaleidoscope::driver::storage::AVREEPROM Storage; }; template -class ATMega32U4Keyboard : public kaleidoscope::device::Base<_DeviceProps> { +class ATmega32U4Keyboard : public kaleidoscope::device::Base<_DeviceProps> { public: auto serialPort() -> decltype(Serial) & { return Serial; diff --git a/src/kaleidoscope/device/ez/ErgoDox.h b/src/kaleidoscope/device/ez/ErgoDox.h index fe2aaee593..34bee12756 100644 --- a/src/kaleidoscope/device/ez/ErgoDox.h +++ b/src/kaleidoscope/device/ez/ErgoDox.h @@ -41,20 +41,20 @@ struct cRGB { #include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/bootloader/avr/HalfKay.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { namespace ez { -struct ErgoDoxProps : public kaleidoscope::device::ATMega32U4KeyboardProps { +struct ErgoDoxProps : public kaleidoscope::device::ATmega32U4KeyboardProps { struct KeyScannerProps : kaleidoscope::driver::keyscanner::BaseProps { KEYSCANNER_PROPS(14, 6); }; typedef kaleidoscope::driver::bootloader::avr::HalfKay Bootloader; }; -class ErgoDox : public kaleidoscope::device::ATMega32U4Keyboard { +class ErgoDox : public kaleidoscope::device::ATmega32U4Keyboard { public: ErgoDox(void) {} diff --git a/src/kaleidoscope/device/kbdfans/KBD4x.cpp b/src/kaleidoscope/device/kbdfans/KBD4x.cpp index 7664dd68d8..7657edc521 100644 --- a/src/kaleidoscope/device/kbdfans/KBD4x.cpp +++ b/src/kaleidoscope/device/kbdfans/KBD4x.cpp @@ -23,7 +23,7 @@ namespace kaleidoscope { namespace device { namespace kbdfans { -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE } } diff --git a/src/kaleidoscope/device/kbdfans/KBD4x.h b/src/kaleidoscope/device/kbdfans/KBD4x.h index b18b8bd1f5..a47c277cfa 100644 --- a/src/kaleidoscope/device/kbdfans/KBD4x.h +++ b/src/kaleidoscope/device/kbdfans/KBD4x.h @@ -23,26 +23,26 @@ #include -#include "kaleidoscope/driver/keyscanner/AVR.h" +#include "kaleidoscope/driver/keyscanner/ATmega.h" #include "kaleidoscope/driver/bootloader/avr/FLIP.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { namespace kbdfans { -struct KBD4xProps : kaleidoscope::device::ATMega32U4KeyboardProps { - struct KeyScannerProps : public kaleidoscope::driver::keyscanner::AVRProps { - AVR_KEYSCANNER_PROPS( +struct KBD4xProps : kaleidoscope::device::ATmega32U4KeyboardProps { + struct KeyScannerProps : public kaleidoscope::driver::keyscanner::ATmegaProps { + ATMEGA_KEYSCANNER_PROPS( ROW_PIN_LIST({ PIN_D0, PIN_D1, PIN_D2, PIN_D3 }), COL_PIN_LIST({ PIN_F0, PIN_F1, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_B3, PIN_B1, PIN_B0, PIN_D5, PIN_B7, PIN_C7 }) ); }; - typedef kaleidoscope::driver::keyscanner::AVR KeyScanner; + typedef kaleidoscope::driver::keyscanner::ATmega KeyScanner; typedef kaleidoscope::driver::bootloader::avr::FLIP Bootloader; }; -class KBD4x: public kaleidoscope::device::ATMega32U4Keyboard { +class KBD4x: public kaleidoscope::device::ATmega32U4Keyboard { public: KBD4x() { mcu_.disableJTAG(); diff --git a/src/kaleidoscope/device/keyboardio/Imago.cpp b/src/kaleidoscope/device/keyboardio/Imago.cpp index 575d4d96fd..bdbd528601 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.cpp +++ b/src/kaleidoscope/device/keyboardio/Imago.cpp @@ -48,7 +48,7 @@ static constexpr uint8_t LED_REGISTER_DATA1_SIZE = 0xAB; static constexpr uint8_t LED_REGISTER_DATA_LARGEST = LED_REGISTER_DATA0_SIZE; -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE bool ImagoLEDDriver::isLEDChanged = true; cRGB ImagoLEDDriver::led_data[]; @@ -181,7 +181,7 @@ void Imago::setup() { } TWBR = 10; - kaleidoscope::device::ATMega32U4Keyboard::setup(); + kaleidoscope::device::ATmega32U4Keyboard::setup(); } } diff --git a/src/kaleidoscope/device/keyboardio/Imago.h b/src/kaleidoscope/device/keyboardio/Imago.h index 3df5e53c9d..21ea731bbd 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.h +++ b/src/kaleidoscope/device/keyboardio/Imago.h @@ -29,10 +29,10 @@ struct cRGB { #define CRGB(r,g,b) (cRGB){b, g, r} -#include "kaleidoscope/driver/keyscanner/AVR.h" +#include "kaleidoscope/driver/keyscanner/ATmega.h" #include "kaleidoscope/driver/led/Base.h" #include "kaleidoscope/driver/bootloader/avr/Caterina.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { @@ -61,20 +61,20 @@ class ImagoLEDDriver : public kaleidoscope::driver::led::Base KeyScanner; + typedef kaleidoscope::driver::keyscanner::ATmega KeyScanner; typedef ImagoLEDDriverProps LEDDriverProps; typedef ImagoLEDDriver LEDDriver; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader; }; -class Imago: public kaleidoscope::device::ATMega32U4Keyboard { +class Imago: public kaleidoscope::device::ATmega32U4Keyboard { public: void setup(); }; diff --git a/src/kaleidoscope/device/keyboardio/Model01.h b/src/kaleidoscope/device/keyboardio/Model01.h index 889891ed09..55ed599e9b 100644 --- a/src/kaleidoscope/device/keyboardio/Model01.h +++ b/src/kaleidoscope/device/keyboardio/Model01.h @@ -29,7 +29,7 @@ #include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/led/Base.h" #include "kaleidoscope/driver/bootloader/avr/Caterina.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { @@ -93,7 +93,7 @@ class Model01KeyScanner : public kaleidoscope::driver::keyscanner::Base { +class Model01 : public kaleidoscope::device::ATmega32U4Keyboard { public: static void setup(); diff --git a/src/kaleidoscope/device/olkb/Planck.cpp b/src/kaleidoscope/device/olkb/Planck.cpp index eb4d9106fe..66167f53e7 100644 --- a/src/kaleidoscope/device/olkb/Planck.cpp +++ b/src/kaleidoscope/device/olkb/Planck.cpp @@ -23,7 +23,7 @@ namespace kaleidoscope { namespace device { namespace olkb { -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE } } diff --git a/src/kaleidoscope/device/olkb/Planck.h b/src/kaleidoscope/device/olkb/Planck.h index 2fdb7311f8..687d7323aa 100644 --- a/src/kaleidoscope/device/olkb/Planck.h +++ b/src/kaleidoscope/device/olkb/Planck.h @@ -21,9 +21,8 @@ #include -#include "kaleidoscope/driver/keyscanner/AVR.h" #include "kaleidoscope/driver/bootloader/avr/HalfKay.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { diff --git a/src/kaleidoscope/device/softhruf/Splitography.cpp b/src/kaleidoscope/device/softhruf/Splitography.cpp index edf7890645..5d0af017c3 100644 --- a/src/kaleidoscope/device/softhruf/Splitography.cpp +++ b/src/kaleidoscope/device/softhruf/Splitography.cpp @@ -30,7 +30,7 @@ namespace kaleidoscope { namespace device { namespace softhruf { -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE } } diff --git a/src/kaleidoscope/device/softhruf/Splitography.h b/src/kaleidoscope/device/softhruf/Splitography.h index ec20aab224..133ee7377a 100644 --- a/src/kaleidoscope/device/softhruf/Splitography.h +++ b/src/kaleidoscope/device/softhruf/Splitography.h @@ -30,26 +30,26 @@ #include -#include "kaleidoscope/driver/keyscanner/AVR.h" +#include "kaleidoscope/driver/keyscanner/ATmega.h" #include "kaleidoscope/driver/bootloader/avr/FLIP.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { namespace softhruf { -struct SplitographyProps : kaleidoscope::device::ATMega32U4KeyboardProps { - struct KeyScannerProps : public kaleidoscope::driver::keyscanner::AVRProps { - AVR_KEYSCANNER_PROPS( +struct SplitographyProps : kaleidoscope::device::ATmega32U4KeyboardProps { + struct KeyScannerProps : public kaleidoscope::driver::keyscanner::ATmegaProps { + ATMEGA_KEYSCANNER_PROPS( ROW_PIN_LIST({ PIN_D0, PIN_D1, PIN_D2, PIN_D3 }), COL_PIN_LIST({ PIN_F0, PIN_F1, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_C7, PIN_C6, PIN_B6, PIN_B5, PIN_B4, PIN_D7 }) ); }; - typedef kaleidoscope::driver::keyscanner::AVR KeyScanner; + typedef kaleidoscope::driver::keyscanner::ATmega KeyScanner; typedef kaleidoscope::driver::bootloader::avr::FLIP BootLoader; }; -class Splitography: public kaleidoscope::device::ATMega32U4Keyboard { +class Splitography: public kaleidoscope::device::ATmega32U4Keyboard { public: Splitography() { mcu_.disableJTAG(); diff --git a/src/kaleidoscope/device/technomancy/Atreus.cpp b/src/kaleidoscope/device/technomancy/Atreus.cpp index 51e595d429..31e2149905 100644 --- a/src/kaleidoscope/device/technomancy/Atreus.cpp +++ b/src/kaleidoscope/device/technomancy/Atreus.cpp @@ -32,7 +32,7 @@ namespace kaleidoscope { namespace device { namespace technomancy { -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE } } diff --git a/src/kaleidoscope/device/technomancy/Atreus.h b/src/kaleidoscope/device/technomancy/Atreus.h index 09242cccb6..7e7032dd50 100644 --- a/src/kaleidoscope/device/technomancy/Atreus.h +++ b/src/kaleidoscope/device/technomancy/Atreus.h @@ -28,9 +28,8 @@ #include -#include "kaleidoscope/driver/keyscanner/AVR.h" #include "kaleidoscope/driver/bootloader/avr/HalfKay.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { diff --git a/src/kaleidoscope/device/technomancy/Atreus2.cpp b/src/kaleidoscope/device/technomancy/Atreus2.cpp index 5bfb0fc3db..f33261671f 100644 --- a/src/kaleidoscope/device/technomancy/Atreus2.cpp +++ b/src/kaleidoscope/device/technomancy/Atreus2.cpp @@ -24,7 +24,7 @@ namespace kaleidoscope { namespace device { namespace technomancy { -AVR_KEYSCANNER_BOILERPLATE +ATMEGA_KEYSCANNER_BOILERPLATE } } diff --git a/src/kaleidoscope/device/technomancy/Atreus2.h b/src/kaleidoscope/device/technomancy/Atreus2.h index aac16e1c1a..c9ff8324ed 100644 --- a/src/kaleidoscope/device/technomancy/Atreus2.h +++ b/src/kaleidoscope/device/technomancy/Atreus2.h @@ -22,9 +22,8 @@ #include -#include "kaleidoscope/driver/keyscanner/AVR.h" #include "kaleidoscope/driver/bootloader/avr/Caterina.h" -#include "kaleidoscope/device/ATMega32U4Keyboard.h" +#include "kaleidoscope/device/ATmega32U4Keyboard.h" namespace kaleidoscope { namespace device { diff --git a/src/kaleidoscope/driver/keyscanner/AVR.h b/src/kaleidoscope/driver/keyscanner/ATmega.h similarity index 92% rename from src/kaleidoscope/driver/keyscanner/AVR.h rename to src/kaleidoscope/driver/keyscanner/ATmega.h index 1481fc34d3..bf8e8ba399 100644 --- a/src/kaleidoscope/driver/keyscanner/AVR.h +++ b/src/kaleidoscope/driver/keyscanner/ATmega.h @@ -1,5 +1,5 @@ /* -*- mode: c++ -*- - * kaleidoscope::driver::keyscanner::AVR -- AVR-based keyscanner component + * kaleidoscope::driver::keyscanner::ATmega -- AVR ATmega-based keyscanner component * Copyright (C) 2018-2019 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under @@ -29,20 +29,20 @@ #define ROW_PIN_LIST(...) __VA_ARGS__ #define COL_PIN_LIST(...) __VA_ARGS__ -#define AVR_KEYSCANNER_PROPS(ROW_PINS_, COL_PINS_) \ - KEYSCANNER_PROPS(NUM_ARGS(ROW_PINS_), NUM_ARGS(COL_PINS_)); \ +#define ATMEGA_KEYSCANNER_PROPS(ROW_PINS_, COL_PINS_) \ + KEYSCANNER_PROPS(NUM_ARGS(ROW_PINS_), NUM_ARGS(COL_PINS_)); \ static constexpr uint8_t matrix_row_pins[matrix_rows] = ROW_PINS_; \ static constexpr uint8_t matrix_col_pins[matrix_columns] = COL_PINS_; -#define AVR_KEYSCANNER_BOILERPLATE \ +#define ATMEGA_KEYSCANNER_BOILERPLATE \ KEYSCANNER_PROPS_BOILERPLATE(kaleidoscope::Device::KeyScannerProps); \ constexpr uint8_t kaleidoscope::Device::KeyScannerProps::matrix_row_pins[matrix_rows]; \ - constexpr uint8_t kaleidoscope::Device::KeyScannerProps::matrix_col_pins[matrix_columns]; \ - template<> \ + constexpr uint8_t kaleidoscope::Device::KeyScannerProps::matrix_col_pins[matrix_columns]; \ + template<> \ volatile uint16_t kaleidoscope::Device::KeyScanner::previousKeyState_[kaleidoscope::Device::KeyScannerProps::matrix_rows] = {}; \ - template<> \ - volatile uint16_t kaleidoscope::Device::KeyScanner::keyState_[kaleidoscope::Device::KeyScannerProps::matrix_rows] = {}; \ - template<> \ + template<> \ + volatile uint16_t kaleidoscope::Device::KeyScanner::keyState_[kaleidoscope::Device::KeyScannerProps::matrix_rows] = {}; \ + template<> \ uint16_t kaleidoscope::Device::KeyScanner::masks_[kaleidoscope::Device::KeyScannerProps::matrix_rows] = {}; \ template<> \ uint8_t kaleidoscope::Device::KeyScanner::debounce_matrix_[kaleidoscope::Device::KeyScannerProps::matrix_rows][kaleidoscope::Device::KeyScannerProps::matrix_columns] = {}; \ @@ -55,7 +55,7 @@ namespace kaleidoscope { namespace driver { namespace keyscanner { -struct AVRProps: kaleidoscope::driver::keyscanner::BaseProps { +struct ATmegaProps: kaleidoscope::driver::keyscanner::BaseProps { static const uint8_t debounce = 3; /* @@ -67,9 +67,9 @@ struct AVRProps: kaleidoscope::driver::keyscanner::BaseProps { }; template -class AVR : public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> { +class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> { private: - typedef AVR<_KeyScannerProps> ThisType; + typedef ATmega<_KeyScannerProps> ThisType; public: void setup() { diff --git a/src/kaleidoscope/driver/mcu/ATMega32U4.h b/src/kaleidoscope/driver/mcu/ATmega32U4.h similarity index 91% rename from src/kaleidoscope/driver/mcu/ATMega32U4.h rename to src/kaleidoscope/driver/mcu/ATmega32U4.h index 8b52a2d907..ad31c5fb12 100644 --- a/src/kaleidoscope/driver/mcu/ATMega32U4.h +++ b/src/kaleidoscope/driver/mcu/ATmega32U4.h @@ -1,5 +1,5 @@ /* -*- mode: c++ -*- - * driver::MCU::ATMega32U4 -- ATMega32U4 MCU driver for Kaleidoscope + * driver::MCU::ATmega32U4 -- ATmega32U4 MCU driver for Kaleidoscope * Copyright (C) 2019 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under @@ -23,7 +23,7 @@ namespace kaleidoscope { namespace driver { namespace mcu { -class ATMega32U4 : public kaleidoscope::driver::mcu::Base { +class ATmega32U4 : public kaleidoscope::driver::mcu::Base { public: void detachFromHost() { UDCON |= _BV(DETACH); @@ -45,7 +45,7 @@ class ATMega32U4 : public kaleidoscope::driver::mcu::Base { * that's doable, we just have to write the JTD bit into MCUCR twice within * four cycles. These two lines do just that. * - * For more information, see the ATMega16U4/ATMega32U4 datasheet, the + * For more information, see the ATmega16U4/ATmega32U4 datasheet, the * following sections: * - 2.2.7 (PIN Descriptions; PIN F) * - 7.8.7 (On-chip Debug System) diff --git a/src/kaleidoscope/driver/storage/ATMega32U4EEPROMProps.h b/src/kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h similarity index 84% rename from src/kaleidoscope/driver/storage/ATMega32U4EEPROMProps.h rename to src/kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h index 2db9085a59..78fa441108 100644 --- a/src/kaleidoscope/driver/storage/ATMega32U4EEPROMProps.h +++ b/src/kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h @@ -1,5 +1,5 @@ /* -*- mode: c++ -*- - * kaleidoscope::driver::storage::ATMega32U4StorageProps -- Storage driver props for ATMega32U4 + * kaleidoscope::driver::storage::ATmega32U4StorageProps -- Storage driver props for ATmega32U4 * Copyright (C) 2019 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under @@ -23,7 +23,7 @@ namespace kaleidoscope { namespace driver { namespace storage { -struct ATMega32U4EEPROMProps : kaleidoscope::driver::storage::AVREEPROMProps { +struct ATmega32U4EEPROMProps : kaleidoscope::driver::storage::AVREEPROMProps { static constexpr uint16_t length = 1024; }; From 0356318fa8cd63d0c6e82fc0e3f6c7acd9bdb292 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Tue, 19 Nov 2019 11:27:50 +0100 Subject: [PATCH 02/26] Moved stuff over from plugin Kaleidoscope-HardwareVirtual Plugin Kaleidoscope-HardwareVirtual is now obsolete. Everything device related has been incorporated in the core repo as a virtual device in kaleidoscope/devices/virtual. Signed-off-by: Florian Fleissner --- .../virtual/DefaultHIDReportConsumer.cpp | 125 ++++++ .../device/virtual/DefaultHIDReportConsumer.h | 34 ++ src/kaleidoscope/device/virtual/HID.cpp | 94 +++++ src/kaleidoscope/device/virtual/Logging.cpp | 33 ++ src/kaleidoscope/device/virtual/Logging.h | 96 +++++ src/kaleidoscope/device/virtual/Virtual.cpp | 396 ++++++++++++++++++ src/kaleidoscope/device/virtual/Virtual.h | 160 +++++++ 7 files changed, 938 insertions(+) create mode 100644 src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.cpp create mode 100644 src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.h create mode 100644 src/kaleidoscope/device/virtual/HID.cpp create mode 100644 src/kaleidoscope/device/virtual/Logging.cpp create mode 100644 src/kaleidoscope/device/virtual/Logging.h create mode 100644 src/kaleidoscope/device/virtual/Virtual.cpp create mode 100644 src/kaleidoscope/device/virtual/Virtual.h diff --git a/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.cpp b/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.cpp new file mode 100644 index 0000000000..ed2dca6de3 --- /dev/null +++ b/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.cpp @@ -0,0 +1,125 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD + +#include "DefaultHIDReportConsumer.h" +#include "MultiReport/Keyboard.h" +#include "Logging.h" + +#include "virtual_io.h" + +#undef min +#undef max + +#include + +namespace kaleidoscope { + +using namespace logging; + +// For each bit set in 'bitfield', output the corresponding string to 'stream' +#define FOREACHBIT(bitfield, stream, str0, str1, str2, str3, str4, str5, str6, str7) \ + if((bitfield) & 1<<0) stream << str0; \ + if((bitfield) & 1<<1) stream << str1; \ + if((bitfield) & 1<<2) stream << str2; \ + if((bitfield) & 1<<3) stream << str3; \ + if((bitfield) & 1<<4) stream << str4; \ + if((bitfield) & 1<<5) stream << str5; \ + if((bitfield) & 1<<6) stream << str6; \ + if((bitfield) & 1<<7) stream << str7; + +void DefaultHIDReportConsumer::processHIDReport( + uint8_t id, const void *data, int len, int result) { + if (id != HID_REPORTID_NKRO_KEYBOARD) { + log_info("***Ignoring hid report with id = %d\n", id); + return; + } + + const HID_KeyboardReport_Data_t &report_data + = *static_cast(data); + + std::stringstream keypresses; + bool anything = false; + + if (report_data.modifiers) anything = true; + else for (int i = 0; i < KEY_BYTES; i++) if (report_data.keys[i]) { + anything = true; + break; + } + + if (!anything) { + keypresses << "none"; + } else { + FOREACHBIT(report_data.modifiers, keypresses, + "lctrl ", "lshift ", "lalt ", "lgui ", + "rctrl ", "rshift ", "ralt ", "rgui ") + FOREACHBIT(report_data.keys[0], keypresses, + "NO_EVENT ", "ERROR_ROLLOVER ", "POST_FAIL ", "ERROR_UNDEFINED ", + "a ", "b ", "c ", "d ") + FOREACHBIT(report_data.keys[1], keypresses, + "e ", "f ", "g ", "h ", "i ", "j ", "k ", "l ") + FOREACHBIT(report_data.keys[2], keypresses, + "m ", "n ", "o ", "p ", "q ", "r ", "s ", "t ") + FOREACHBIT(report_data.keys[3], keypresses, + "u ", "v ", "w ", "x ", "y ", "z ", "1/! ", "2/@ ") + FOREACHBIT(report_data.keys[4], keypresses, + "3/# ", "4/$ ", "5/% ", "6/^ ", "7/& ", "8/* ", "9/( ", "0/) ") + FOREACHBIT(report_data.keys[5], keypresses, + "enter ", "esc ", "del/bksp ", "tab ", + "space ", "-/_ ", "=/+ ", "[/{ ") + FOREACHBIT(report_data.keys[6], keypresses, + "]/} ", "\\/| ", "#/~ ", ";/: ", "'/\" ", "`/~ ", ",/< ", "./> ") + FOREACHBIT(report_data.keys[7], keypresses, + "//? ", "capslock ", "F1 ", "F2 ", "F3 ", "F4 ", "F5 ", "F6 ") + FOREACHBIT(report_data.keys[8], keypresses, + "F7 ", "F8 ", "F9 ", "F10 ", "F11 ", "F12 ", "prtscr ", "scrolllock ") + FOREACHBIT(report_data.keys[9], keypresses, + "pause ", "ins ", "home ", "pgup ", "del ", "end ", "pgdn ", "r_arrow ") + FOREACHBIT(report_data.keys[10], keypresses, + "l_arrow ", "d_arrow ", "u_arrow ", "numlock ", + "num/ ", "num* ", "num- ", "num+ ") + FOREACHBIT(report_data.keys[11], keypresses, + "numenter ", "num1 ", "num2 ", "num3 ", + "num4 ", "num5 ", "num6 ", "num7 ") + FOREACHBIT(report_data.keys[12], keypresses, + "num8 ", "num9 ", "num0 ", "num. ", "\\/| ", "app ", "power ", "num= ") + FOREACHBIT(report_data.keys[13], keypresses, + "F13 ", "F14 ", "F15 ", "F16 ", "F17 ", "F18 ", "F19 ", "F20 ") + FOREACHBIT(report_data.keys[14], keypresses, + "F21 ", "F22 ", "F23 ", "F24 ", "exec ", "help ", "menu ", "sel ") + FOREACHBIT(report_data.keys[15], keypresses, + "stop ", "again ", "undo ", "cut ", "copy ", "paste ", "find ", "mute ") + FOREACHBIT(report_data.keys[16], keypresses, + "volup ", "voldn ", "capslock_l ", "numlock_l ", + "scrolllock_l ", "num, ", "num= ", "(other) ") + + for (int i = 17; i < KEY_BYTES; i++) { + // A little imprecise, in two ways: + // (1) obviously, "(other)" refers to many distinct keys + // (2) this might undercount the number of "other" keys pressed + // Therefore, if any keys are frequently used, they should be handled above and not via "other" + if (report_data.keys[i]) keypresses << "(other) "; + } + } + + log_info("Sent virtual HID report. Pressed keys: %s\n", keypresses.str().c_str()); + logUSBEvent_keyboard("Keyboard HID report; pressed keys: " + keypresses.str()); +} + +} // namespace kaleidoscope + +#endif // ifdef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.h b/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.h new file mode 100644 index 0000000000..77ce855260 --- /dev/null +++ b/src/kaleidoscope/device/virtual/DefaultHIDReportConsumer.h @@ -0,0 +1,34 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD + +#include + +namespace kaleidoscope { + +class DefaultHIDReportConsumer { + public: + + static void processHIDReport(uint8_t id, const void *data, + int len, int result); +}; + +} // namespace kaleidoscope + +#endif // ifdef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/virtual/HID.cpp b/src/kaleidoscope/device/virtual/HID.cpp new file mode 100644 index 0000000000..cf751f3fed --- /dev/null +++ b/src/kaleidoscope/device/virtual/HID.cpp @@ -0,0 +1,94 @@ +/* + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +// This is a modified version of the original HID.cpp from +// library KeyboardioHID. It replaces all hardware related stuff +// with stub implementations. + +// Include KeyboardioHID's HID.h header +// +#include "HID.h" + +#include "HIDReportObserver.h" + +#if defined(USBCON) + +HID_ &HID() { + static HID_ obj; + return obj; +} + +int HID_::getInterface(uint8_t *interfaceCount) { + *interfaceCount += 1; // uses 1 + return 0; +} + +int HID_::getDescriptor(USBSetup &setup) { + return 1; +} + +uint8_t HID_::getShortName(char *name) { + name[0] = 'v'; + name[1] = 'i'; + name[2] = 'r'; + name[3] = 't'; + name[4] = 'u'; + name[5] = 'a'; + name[6] = 'l'; + return 7; +} + +void HID_::AppendDescriptor(HIDSubDescriptor *node) { + if (!rootNode) { + rootNode = node; + } else { + HIDSubDescriptor *current = rootNode; + + while (current->next) { + current = current->next; + } + + current->next = node; + } + + descriptorSize += node->length; +} + +int HID_::SendReport(uint8_t id, const void *data, int len) { + HIDReportObserver::observeReport(id, data, len, 0); + return 1; +} + +bool HID_::setup(USBSetup &setup) { + return true; +} + +HID_::HID_(void) : PluggableUSBModule(1, 1, epType), + rootNode(NULL), descriptorSize(0), + protocol(HID_REPORT_PROTOCOL), idle(1) { + setReportData.reportId = 0; + setReportData.leds = 0; + epType[0] = EP_TYPE_INTERRUPT_IN; + //PluggableUSB().plug(this); +} + +int HID_::begin(void) { + return 0; +} + +#endif /* if defined(USBCON) */ diff --git a/src/kaleidoscope/device/virtual/Logging.cpp b/src/kaleidoscope/device/virtual/Logging.cpp new file mode 100644 index 0000000000..2acecbbc3f --- /dev/null +++ b/src/kaleidoscope/device/virtual/Logging.cpp @@ -0,0 +1,33 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#include "Logging.h" + +namespace kaleidoscope { +namespace logging { + +static bool __verboseOutputEnabled = true; + +void toggleVerboseOutput(bool state) { + __verboseOutputEnabled = state; +} + +bool verboseOutputEnabled() { + return __verboseOutputEnabled; +} + +} // namespace logging +} // namespace kaleidoscope diff --git a/src/kaleidoscope/device/virtual/Logging.h b/src/kaleidoscope/device/virtual/Logging.h new file mode 100644 index 0000000000..94c592e3ea --- /dev/null +++ b/src/kaleidoscope/device/virtual/Logging.h @@ -0,0 +1,96 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD + +#include "utility" +#include "stdio.h" + +namespace kaleidoscope { +namespace logging { + +extern void toggleVerboseOutput(bool state); +extern bool verboseOutputEnabled(); + +// Please note that we prefer stdio based logging against +// stream based output, to stay compatible with possible future global +// logging functions introduced by Kaleidoscope. Stream +// based logging is not available on the target platform due to restricted +// resources. + +// Below, we use perfect forwarding to pass printf style log messages +// to different printf derivates. gcc warns when the the format string +// is not a literal, which is not the case here due to our forwarding. +// To silence the related warning, which is not desired in our application, +// we disable the format-security diagnostic until the end of this file. + +// Disable diagnostic for literal format strings. +// +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-security" + +#ifdef KALEIDOSCOPE_HARDWARE_VIRTUAL_NO_LOGGING + +template +inline +void log_debug(Args__&&... args) {} + +template +inline +void log_info(Args__&&... args) {} + +#else // #ifdef KALEIDOSCOPE_HARDWARE_VIRTUAL_NO_LOGGING + +template +inline +void log_debug(Args__&&... args) { + if (verboseOutputEnabled()) { + fprintf(stdout, std::forward(args)...); + } +} + +template +inline +void log_info(Args__&&... args) { + if (verboseOutputEnabled()) { + fprintf(stdout, std::forward(args)...); + } +} + +#endif // #ifdef KALEIDOSCOPE_HARDWARE_VIRTUAL_NO_LOGGING + +template +inline +void log_error(Args__&&... args) { + fprintf(stderr, std::forward(args)...); +} + +template +inline +void log_critical(Args__&&... args) { + fprintf(stderr, std::forward(args)...); +} + +} // namespace logging +} // namespace kaleidoscope + +// Re-enable diagnostic for literal format strings. +// +#pragma GCC diagnostic pop + +#endif // ifdef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/virtual/Virtual.cpp b/src/kaleidoscope/device/virtual/Virtual.cpp new file mode 100644 index 0000000000..e0ff4cf639 --- /dev/null +++ b/src/kaleidoscope/device/virtual/Virtual.cpp @@ -0,0 +1,396 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Hardware-Model01 -- Keyboard.io Model01 hardware support for Kaleidoscope + * Copyright (C) 2017-2019 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 . + */ + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD + +#include "kaleidoscope/device/virtual/Virtual.h" +#include "kaleidoscope/device/virtual/DefaultHIDReportConsumer.h" +#include "kaleidoscope/device/virtual/Logging.h" + +#include "kaleidoscope/keyswitch_state.h" +#include "Kaleidoscope.h" + +#include "HIDReportObserver.h" +#include "virtual_io.h" +#include "EEPROM.h" + +#include +#include +#include + +// FIXME: This relates to virtual/cores/arduino/EEPROM.h. +// EEPROM static data must be defined here as only +// the device knows about the EEPROM size. +// +// It might be better to move the EEPROM.h header here as +// well??? + +uint8_t EERef::eeprom_[kaleidoscope::DeviceProps::StorageProps::length]; + +EEPROMClass EEPROM; + +uint16_t EEPROMClass::length() { + return kaleidoscope::DeviceProps::StorageProps::length; +} + +namespace kaleidoscope { +namespace device { +namespace virt { + +using namespace kaleidoscope::logging; + +//############################################################################## +// VirtualKeyScanner +//############################################################################## + +VirtualKeyScanner::VirtualKeyScanner() + : n_pressed_switches_{0}, + n_previously_pressed_switches_{0}, + read_matrix_enabled_{true} { +} + +void VirtualKeyScanner::setup() { + + HIDReportObserver::resetHook(&DefaultHIDReportConsumer::processHIDReport); + + for (auto key_addr : KeyAddr::all()) { + keystates_[key_addr.toInt()] = KeyState::NotPressed; + keystates_prev_[key_addr.toInt()] = KeyState::NotPressed; + mask_[key_addr.toInt()] = false; + } +} + +enum Mode { + M_TAP, + M_DOWN, + M_UP, +}; + +// FIXME: getRCfromPhysicalKey only works for the Model01 with default +// layout. We might want to remove this as the virtual hardware +// intents to simulate any type of keyboard. +// +// static KeyAddr getRCfromPhysicalKey(std::string keyname) { +// if (keyname == "prog") return KeyAddr{0, 0}; +// else if (keyname == "1") return KeyAddr{0, 1}; +// else if (keyname == "2") return KeyAddr{0, 2}; +// else if (keyname == "3") return KeyAddr{0, 3}; +// else if (keyname == "4") return KeyAddr{0, 4}; +// else if (keyname == "5") return KeyAddr{0, 5}; +// else if (keyname == "led") return KeyAddr{0, 6}; +// else if (keyname == "any") return KeyAddr{0, 9}; +// else if (keyname == "6") return KeyAddr{0, 10}; +// else if (keyname == "7") return KeyAddr{0, 11}; +// else if (keyname == "8") return KeyAddr{0, 12}; +// else if (keyname == "9") return KeyAddr{0, 13}; +// else if (keyname == "0") return KeyAddr{0, 14}; +// else if (keyname == "num") return KeyAddr{0, 15}; +// else if (keyname == "`") return KeyAddr{1, 0}; +// else if (keyname == "q") return KeyAddr{1, 1}; +// else if (keyname == "w") return KeyAddr{1, 2}; +// else if (keyname == "e") return KeyAddr{1, 3}; +// else if (keyname == "r") return KeyAddr{1, 4}; +// else if (keyname == "t") return KeyAddr{1, 5}; +// else if (keyname == "tab") return KeyAddr{1, 6}; +// else if (keyname == "enter") return KeyAddr{1, 9}; +// else if (keyname == "y") return KeyAddr{1, 10}; +// else if (keyname == "u") return KeyAddr{1, 11}; +// else if (keyname == "i") return KeyAddr{1, 12}; +// else if (keyname == "o") return KeyAddr{1, 13}; +// else if (keyname == "p") return KeyAddr{1, 14}; +// else if (keyname == "=") return KeyAddr{1, 15}; +// else if (keyname == "pgup") return KeyAddr{2, 0}; +// else if (keyname == "a") return KeyAddr{2, 1}; +// else if (keyname == "s") return KeyAddr{2, 2}; +// else if (keyname == "d") return KeyAddr{2, 3}; +// else if (keyname == "f") return KeyAddr{2, 4}; +// else if (keyname == "g") return KeyAddr{2, 5}; +// else if (keyname == "h") return KeyAddr{2, 10}; +// else if (keyname == "j") return KeyAddr{2, 11}; +// else if (keyname == "k") return KeyAddr{2, 12}; +// else if (keyname == "l") return KeyAddr{2, 13}; +// else if (keyname == ";") return KeyAddr{2, 14}; +// else if (keyname == "'") return KeyAddr{2, 15}; +// else if (keyname == "pgdn") return KeyAddr{3, 0}; +// else if (keyname == "z") return KeyAddr{3, 1}; +// else if (keyname == "x") return KeyAddr{3, 2}; +// else if (keyname == "c") return KeyAddr{3, 3}; +// else if (keyname == "v") return KeyAddr{3, 4}; +// else if (keyname == "b") return KeyAddr{3, 5}; +// else if (keyname == "esc") return KeyAddr{2, 6}; // yes, row 2 +// else if (keyname == "fly") return KeyAddr{2, 9}; // yes, row 2 +// else if (keyname == "n") return KeyAddr{3, 10}; +// else if (keyname == "m") return KeyAddr{3, 11}; +// else if (keyname == ",") return KeyAddr{3, 12}; +// else if (keyname == ".") return KeyAddr{3, 13}; +// else if (keyname == "/") return KeyAddr{3, 14}; +// else if (keyname == "-") return KeyAddr{3, 15}; +// else if (keyname == "lctrl") return KeyAddr{0, 7}; +// else if (keyname == "bksp") return KeyAddr{1, 7}; +// else if (keyname == "cmd") return KeyAddr{2, 7}; +// else if (keyname == "lshift") return KeyAddr{3, 7}; +// else if (keyname == "rshift") return KeyAddr{3, 8}; +// else if (keyname == "alt") return KeyAddr{2, 8}; +// else if (keyname == "space") return KeyAddr{1, 8}; +// else if (keyname == "rctrl") return KeyAddr{0, 8}; +// else if (keyname == "lfn") return KeyAddr{3, 6}; +// else if (keyname == "rfn") return KeyAddr{3, 9}; +// +// return KeyAddr{}; // Invalid key +// } + +void VirtualKeyScanner::readMatrix() { + + if (!read_matrix_enabled_) return; + + std::stringstream sline; + sline << getLineOfInput(anythingHeld()); + Mode mode = M_TAP; + + while (true) { + std::string token; + std::getline(sline, token, ' '); + + if (token == "") break; // end of line + else if (token == "#") break; // skip the rest of the line + else if ((token == "?" || token == "help") && isInteractive()) { + printHelp(); + } else if (token == "Q") { + exit(0); + } else if (token == "T") { + mode = M_TAP; + } else if (token == "D") { + mode = M_DOWN; + } else if (token == "U") { + mode = M_UP; + } else if (token == "C") { + for (auto key_addr : KeyAddr::all()) { + keystates_[key_addr.toInt()] = KeyState::NotPressed; + } + } else { + KeyAddr key_addr; + + if (token.front() == '(' && token.back() == ')') { + size_t commapos = token.find_first_of(','); + + if (commapos == std::string::npos) { + log_error("Bad (r,c) pair: %s\n", token.c_str()); + continue; + } else { + key_addr = KeyAddr( + (uint8_t)std::stoi(token.substr(1, commapos - 1)), + (uint8_t)std::stoi(token.substr(commapos + 1, token.length() - commapos - 1)) + ); + + if (!key_addr.isValid()) { + log_error("Bad coordinates: %s\n", token.c_str()); + continue; + } + } + } else { + // TODO: Is there a device independent + // way to determine KeyAddr from key names? +// key_addr = getRCfromPhysicalKey(token); +// +// if (!key_addr.isValid()) { +// log_error("Unrecognized command: %s\n", token.c_str()); +// continue; +// } + } + + keystates_[key_addr.toInt()] = + (mode == M_DOWN) ? KeyState::Pressed : + (mode == M_UP) ? KeyState::NotPressed : + KeyState::Tap; + } + } +} +void VirtualKeyScanner::actOnMatrixScan() { + + n_pressed_switches_ = 0; + n_previously_pressed_switches_ = 0; + + for (auto key_addr : KeyAddr::all()) { + uint8_t key_state = 0; + + switch (keystates_prev_[key_addr.toInt()]) { + case KeyState::Pressed: + key_state |= WAS_PRESSED; + ++n_previously_pressed_switches_; + break; + + case KeyState::Tap: + log_error("Error: assertion failed, keystates_prev_ should not be KeyState::Tap\n"); + break; + + case KeyState::NotPressed: + default: + /* do nothing */ + break; + } + + switch (keystates_[key_addr.toInt()]) { + case KeyState::Pressed: + case KeyState::Tap: + key_state |= IS_PRESSED; + ++n_pressed_switches_; + break; + + case KeyState::NotPressed: + default: + /* do nothing */ + break; + } + + handleKeyswitchEvent(Key_NoKey, key_addr, key_state); + keystates_prev_[key_addr.toInt()] = keystates_[key_addr.toInt()]; + + if (keystates_[key_addr.toInt()] == KeyState::Tap) { + key_state = WAS_PRESSED & ~IS_PRESSED; + handleKeyswitchEvent(Key_NoKey, key_addr, key_state); + keystates_[key_addr.toInt()] = KeyState::NotPressed; + keystates_prev_[key_addr.toInt()] = KeyState::NotPressed; + } + } +} + +uint8_t VirtualKeyScanner::pressedKeyswitchCount() const { + return n_pressed_switches_; +} +bool VirtualKeyScanner::isKeyswitchPressed(KeyAddr key_addr) const { + if (keystates_[key_addr.toInt()] == KeyState::NotPressed) { + return false; + + } + return true; +} + +uint8_t VirtualKeyScanner::previousPressedKeyswitchCount() const { + return n_previously_pressed_switches_; +} +bool VirtualKeyScanner::wasKeyswitchPressed(KeyAddr key_addr) const { + if (keystates_prev_[key_addr.toInt()] == KeyState::NotPressed) { + return false; + + } + + return true; +} + +void VirtualKeyScanner::maskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) { + log_error("Virtual::maskKey: key_addr invalid\n"); + return; + } + mask_[key_addr.toInt()] = true; +} + +void VirtualKeyScanner::unMaskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) { + log_error("Virtual::unMaskKey: key_addr invalid\n"); + return; + } + mask_[key_addr.toInt()] = false; +} + +bool VirtualKeyScanner::isKeyMasked(KeyAddr key_addr) const { + if (!key_addr.isValid()) { + log_error("Virtual::isKeyMasked: key_addr invalid\n"); + return false; + } + return mask_[key_addr.toInt()]; +} + +void VirtualKeyScanner::setKeystate(KeyAddr keyAddr, KeyState ks) { + keystates_[keyAddr.toInt()] = ks; +} + +VirtualKeyScanner::KeyState VirtualKeyScanner::getKeystate(KeyAddr keyAddr) const { + return keystates_[keyAddr.toInt()]; +} + +bool VirtualKeyScanner::anythingHeld() { + for (auto key_addr : KeyAddr::all()) { + if (keystates_[key_addr.toInt()] == KeyState::Pressed) return true; + } + + return false; +} + +//############################################################################## +// VirtualLEDDriver +//############################################################################## + +void VirtualLEDDriver::setup() { + for (int i = 0; i < led_count; i++) { + led_states_[i] = CRGB(0, 0, 0); + } +} + +void VirtualLEDDriver::syncLeds() { + // log format: red.green.blue where values are written in hex; followed by a space, followed by the next LED + std::stringstream ss; + ss << std::hex; + + for (int i = 0; i < led_count; i++) { + const cRGB state = led_states_[i]; + ss << (unsigned int) state.r << "." << (unsigned int) state.g << "." << (unsigned int) state.b << " "; + } + + ss << std::endl; + logLEDStates(ss.str()); +} + +void VirtualLEDDriver::setCrgbAt(uint8_t i, cRGB color) { + if ((int)i >= (int)led_count) { + log_error("Virtual::setCrgbAt: Index %d out of bounds\n", i); + return; + } + led_states_[i] = color; +} + +cRGB VirtualLEDDriver::getCrgbAt(uint8_t i) const { + if ((int)i >= (int)led_count) { + log_error("Virtual::getCrgbAt: Index %d out of bounds\n", i); + return CRGB(0, 0, 0); + } + return led_states_[i]; +} + +uint8_t VirtualLEDDriver::getLedIndex(uint8_t key_offset) const { + return kaleidoscope::DeviceProps::LEDDriverProps::getLedIndex(key_offset); +} + +} // namespace virt +} // namespace device + + +namespace driver { +namespace led { + +template<> +Base::LEDs +Base::LEDs_{}; + +} // namespace led +} // namespace driver + +} // namespace kaleidoscope + + + +#endif // ifdef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/virtual/Virtual.h b/src/kaleidoscope/device/virtual/Virtual.h new file mode 100644 index 0000000000..4a8800318c --- /dev/null +++ b/src/kaleidoscope/device/virtual/Virtual.h @@ -0,0 +1,160 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Hardware-Model01 -- Keyboard.io Model01 hardware support for Kaleidoscope + * Copyright (C) 2017-2019 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 . + */ + +#pragma once + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD + +#include KALEIDOSCOPE_HARDWARE_H + +#include "kaleidoscope/driver/bootloader/None.h" +#include "kaleidoscope/driver/led/Base.h" + +namespace kaleidoscope { +namespace device { +namespace virt { + +class VirtualKeyScanner + : public kaleidoscope::driver::keyscanner::Base { + private: + + typedef VirtualKeyScanner ThisType; + typedef kaleidoscope::driver::keyscanner::Base ParentType; + + public: + + typedef typename ParentType::KeyAddr KeyAddr; + + enum class KeyState { + Pressed, + NotPressed, + Tap + }; + + static constexpr uint8_t matrix_rows = kaleidoscope::DeviceProps::KeyScannerProps::matrix_rows; + static constexpr uint8_t matrix_columns = kaleidoscope::DeviceProps::KeyScannerProps::matrix_columns; + + VirtualKeyScanner(); + + void setup(); + void readMatrix(); + void scanMatrix() { + this->readMatrix(); + this->actOnMatrixScan(); + } + void actOnMatrixScan(); + + uint8_t pressedKeyswitchCount() const; + bool isKeyswitchPressed(KeyAddr key_addr) const; + + uint8_t previousPressedKeyswitchCount() const; + bool wasKeyswitchPressed(KeyAddr key_addr) const; + + void maskKey(KeyAddr key_addr); + void unMaskKey(KeyAddr key_addr); + bool isKeyMasked(KeyAddr key_addr) const; + + void setEnableReadMatrix(bool state) { + read_matrix_enabled_ = state; + } + + void setKeystate(KeyAddr keyAddr, KeyState ks); + KeyState getKeystate(KeyAddr keyAddr) const; + + private: + + bool anythingHeld(); + + private: + + uint8_t n_pressed_switches_, + n_previously_pressed_switches_; + + bool read_matrix_enabled_; + + KeyState keystates_[matrix_rows * matrix_columns]; + KeyState keystates_prev_[matrix_rows * matrix_columns]; + + bool mask_[matrix_rows * matrix_columns]; +}; + +class VirtualLEDDriver + : public driver::led::Base { + public: + + typedef driver::led::Base + ParentType; + + using typename ParentType::LEDs; + + static constexpr uint8_t led_count = kaleidoscope::DeviceProps::LEDDriverProps::led_count; + + void setup(); + void syncLeds(); + void setCrgbAt(uint8_t i, cRGB color); + cRGB getCrgbAt(uint8_t i) const; + uint8_t getLedIndex(uint8_t key_offset) const; + + private: + + cRGB led_states_[led_count]; +}; + +// This overrides only the drivers and keeps the driver props of +// the physical keyboard. +// +struct VirtualProps : public kaleidoscope::DeviceProps { + typedef typename kaleidoscope::DeviceProps::KeyScannerProps + KeyScannerProps; + typedef VirtualKeyScanner + KeyScanner; + typedef KeyScannerProps::KeyAddr + KeyAddr; + + typedef typename kaleidoscope::DeviceProps::LEDDriverProps + LEDDriverProps; + typedef VirtualLEDDriver + LEDDriver; + + typedef kaleidoscope::driver::mcu::None MCU; + + typedef kaleidoscope::driver::bootloader::None + BootLoader; + + typedef typename kaleidoscope::DeviceProps::StorageProps + StorageProps; + typedef typename kaleidoscope::DeviceProps::Storage + Storage; +}; + +class VirtualDevice + : public kaleidoscope::device::Base { + public: + + auto serialPort() -> decltype(Serial) & { + return Serial; + } +}; + +} // namespace virt +} // namespace device + +typedef device::virt::VirtualDevice Device; + +} // namespace kaleidoscope + +#endif // ifdef KALEIDOSCOPE_VIRTUAL_BUILD From 0cce6ed0a82f18bfd145b752b0f4c51fa5415fca Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 15:35:09 +0100 Subject: [PATCH 03/26] Introduced a build type selection header Up to now, the device header was included by several files via the command This commit introduces a build type selection header kaleidoscope/device/device.h that enables to either directly include the device header or to first include the 'physical' device header and then the 'virtual' device header. This is meant for the virtual device to be able to be defined depending on the properties of the physical device. Signed-off-by: Florian Fleissner --- src/kaleidoscope/Kaleidoscope.h | 2 +- src/kaleidoscope/KeyAddr.h | 2 +- src/kaleidoscope/device/device.h | 23 +++++++++++++++++++++++ src/kaleidoscope/key_events.h | 2 +- src/kaleidoscope/layers.h | 2 +- 5 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/kaleidoscope/device/device.h diff --git a/src/kaleidoscope/Kaleidoscope.h b/src/kaleidoscope/Kaleidoscope.h index 4237c65e20..b588cdd5a0 100644 --- a/src/kaleidoscope/Kaleidoscope.h +++ b/src/kaleidoscope/Kaleidoscope.h @@ -36,7 +36,7 @@ void setup(); #include #include -#include KALEIDOSCOPE_HARDWARE_H +#include "kaleidoscope/device/device.h" #include "kaleidoscope/device/key_indexes.h" #include "kaleidoscope_internal/device.h" #include "kaleidoscope_internal/deprecations.h" diff --git a/src/kaleidoscope/KeyAddr.h b/src/kaleidoscope/KeyAddr.h index 3762b0b5b9..c27c930c5b 100644 --- a/src/kaleidoscope/KeyAddr.h +++ b/src/kaleidoscope/KeyAddr.h @@ -16,6 +16,6 @@ #pragma once -#include KALEIDOSCOPE_HARDWARE_H +#include "kaleidoscope/device/device.h" typedef kaleidoscope::Device::KeyAddr KeyAddr; diff --git a/src/kaleidoscope/device/device.h b/src/kaleidoscope/device/device.h new file mode 100644 index 0000000000..ed16ea934d --- /dev/null +++ b/src/kaleidoscope/device/device.h @@ -0,0 +1,23 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#ifdef KALEIDOSCOPE_VIRTUAL_BUILD +#include "kaleidoscope/device/virtual/Virtual.h" +#else +#include KALEIDOSCOPE_HARDWARE_H +#endif diff --git a/src/kaleidoscope/key_events.h b/src/kaleidoscope/key_events.h index 84945703ce..6de6becd5f 100644 --- a/src/kaleidoscope/key_events.h +++ b/src/kaleidoscope/key_events.h @@ -17,7 +17,7 @@ #pragma once #include -#include KALEIDOSCOPE_HARDWARE_H +#include "kaleidoscope/device/device.h" #include "kaleidoscope/key_defs.h" #include "kaleidoscope/keyswitch_state.h" diff --git a/src/kaleidoscope/layers.h b/src/kaleidoscope/layers.h index 5a94d7c64c..0cf7d19636 100644 --- a/src/kaleidoscope/layers.h +++ b/src/kaleidoscope/layers.h @@ -19,7 +19,7 @@ #include #include "kaleidoscope/key_defs.h" #include "kaleidoscope/keymaps.h" -#include KALEIDOSCOPE_HARDWARE_H +#include "kaleidoscope/device/device.h" #include "kaleidoscope_internal/device.h" // Macro for defining the keymap. This should be used in the sketch From 714e34579e0d9e4909cef3b485f0cc1e8a68c054 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 15:47:55 +0100 Subject: [PATCH 04/26] Disambiguated type name and instance name LEDs Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/Base.h | 2 +- src/kaleidoscope/driver/led/Base.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kaleidoscope/device/Base.h b/src/kaleidoscope/device/Base.h index c965510aae..2e7291bd8c 100644 --- a/src/kaleidoscope/device/Base.h +++ b/src/kaleidoscope/device/Base.h @@ -91,7 +91,7 @@ class Base { static constexpr uint8_t matrix_columns = KeyScannerProps::matrix_columns; static constexpr uint8_t led_count = LEDDriverProps::led_count; static constexpr typename LEDDriver::LEDs &LEDs() { - return LEDDriver::LEDs; + return LEDDriver::LEDs_; } /** diff --git a/src/kaleidoscope/driver/led/Base.h b/src/kaleidoscope/driver/led/Base.h index db82a7476b..3f5cb8dc7c 100644 --- a/src/kaleidoscope/driver/led/Base.h +++ b/src/kaleidoscope/driver/led/Base.h @@ -109,7 +109,7 @@ class Base { constexpr bool isValid(uint8_t index) { return (_LEDDriverProps::led_count > 0 && index < _LEDDriverProps::led_count); } - } LEDs; + } LEDs_; protected: typedef _LEDDriverProps Props_; From c864e78e94c15ac0097fd146bcd6f073474ed4e7 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 16:00:06 +0100 Subject: [PATCH 05/26] Added missing driver accessors Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/Base.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/kaleidoscope/device/Base.h b/src/kaleidoscope/device/Base.h index 2e7291bd8c..fd0407c306 100644 --- a/src/kaleidoscope/device/Base.h +++ b/src/kaleidoscope/device/Base.h @@ -115,6 +115,20 @@ class Base { return noop_serial_; } + /** + * Returns the key scanner used by the keyboard. + */ + KeyScanner &keyScanner() { + return key_scanner_; + } + + /** + * Returns the LED driver + */ + LEDDriver &ledDriver() { + return led_driver_; + } + /** * @defgroup kaleidoscope_hardware_leds Kaleidoscope::Hardware/LEDs * @{ From 4c2e0a7635d555080dbd4dfd2f25df534d2c0464 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Thu, 21 Nov 2019 12:31:47 +0100 Subject: [PATCH 06/26] Focus serial template version of send(...) - call by value Using call by reference in FocusSerial::send(...) and FocusSerial::sendRaw(...) causes linker errors due to undefined symbols if constexpr constants are passed to the methods. This is because if a constexpr value is bound to a reference this is the same as taking the address of the value. Thus, the compiler has to generate an instance. Some constants like e.g. FocusSerial::NEWLINE do not come with an instance. This seems not to cause problems with avr-gcc up to now but generates linker errors during virtual compiles with later gcc versions (e.g. gcc 8.3.0). This change does not incur any additional overhead as all version of FocusSerial's send methods are already inlined, and the templated versions root to the non-template versions of the send methods that only accept call-by-value anyway. Signed-off-by: Florian Fleissner --- src/kaleidoscope/plugin/FocusSerial.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kaleidoscope/plugin/FocusSerial.h b/src/kaleidoscope/plugin/FocusSerial.h index 0b7051f7aa..5a7230c006 100644 --- a/src/kaleidoscope/plugin/FocusSerial.h +++ b/src/kaleidoscope/plugin/FocusSerial.h @@ -45,14 +45,14 @@ class FocusSerial : public kaleidoscope::Plugin { Kaleidoscope.serialPort().print(SEPARATOR); } template - void send(Var v, const Vars&... vars) { + void send(Var v, Vars... vars) { send(v); send(vars...); } void sendRaw() {} template - void sendRaw(Var v, const Vars&... vars) { + void sendRaw(Var v, Vars... vars) { Kaleidoscope.serialPort().print(v); sendRaw(vars...); } From ddf609daa6625e7350361fb2345fe08690c98f29 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Sat, 23 Nov 2019 21:46:38 +0100 Subject: [PATCH 07/26] Key offset to LED index map made LED driver property LED driver properties now can re-define an array for their individual mapping from key offsets to LED indices. This array is both constexpr (can be used at compiletime) and stored in PROGMEM. The latter is used by the LED driver base class to map key offsets to LED ids at runtime. Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/keyboardio/Imago.cpp | 16 ++------------ src/kaleidoscope/device/keyboardio/Imago.h | 10 ++++++++- .../device/keyboardio/Model01.cpp | 13 ++--------- src/kaleidoscope/device/keyboardio/Model01.h | 8 +++++-- src/kaleidoscope/driver/led/Base.h | 22 +++++++++++++++++-- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/kaleidoscope/device/keyboardio/Imago.cpp b/src/kaleidoscope/device/keyboardio/Imago.cpp index bdbd528601..0890c54c28 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.cpp +++ b/src/kaleidoscope/device/keyboardio/Imago.cpp @@ -31,6 +31,8 @@ namespace kaleidoscope { namespace device { namespace keyboardio { +constexpr uint8_t ImagoLEDDriverProps::key_led_map[] PROGMEM; + static constexpr uint8_t CMD_SET_REGISTER = 0xFD; static constexpr uint8_t CMD_WRITE_ENABLE = 0xFE; static constexpr uint8_t WRITE_ENABLE_ONCE = 0b11000101; @@ -53,16 +55,6 @@ ATMEGA_KEYSCANNER_BOILERPLATE bool ImagoLEDDriver::isLEDChanged = true; cRGB ImagoLEDDriver::led_data[]; -#define NOLED 254 - -static constexpr uint8_t key_led_map[5][16] PROGMEM = { - { 104, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 115, 12, 116}, - { 91, 13, NOLED, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 102, 15, 103}, - { 78, 26, 27, 28, 29, 30, 31, NOLED, 33, 34, 35, 36, 37, 89, 38, NOLED}, - { 65, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NOLED, 90}, - { 52, 66, 53, 54, NOLED, 56, 57, 71, 59, NOLED, 61, 62, 63, 64, NOLED, 77} -}; - void ImagoLEDDriver::setup() { setAllPwmTo(0xFF); selectRegister(LED_REGISTER_CONTROL); @@ -96,10 +88,6 @@ void ImagoLEDDriver::setCrgbAt(uint8_t i, cRGB crgb) { led_data[i] = crgb; } -uint8_t ImagoLEDDriver::getLedIndex(uint8_t key_offset) { - return pgm_read_byte(key_led_map + key_offset); -} - cRGB ImagoLEDDriver::getCrgbAt(uint8_t i) { if (!Kaleidoscope.device().LEDs().isValid(i)) return {0, 0, 0}; diff --git a/src/kaleidoscope/device/keyboardio/Imago.h b/src/kaleidoscope/device/keyboardio/Imago.h index 21ea731bbd..380afc32f6 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.h +++ b/src/kaleidoscope/device/keyboardio/Imago.h @@ -38,8 +38,17 @@ namespace kaleidoscope { namespace device { namespace keyboardio { +using kaleidoscope::driver::led::no_led; + struct ImagoLEDDriverProps: public kaleidoscope::driver::led::BaseProps { static constexpr uint8_t led_count = 78; + static constexpr uint8_t key_led_map[/* 5*16 */] PROGMEM = { + 104, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 115, 12, 116, + 91, 13, no_led, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 102, 15, 103, + 78, 26, 27, 28, 29, 30, 31, no_led, 33, 34, 35, 36, 37, 89, 38, no_led, + 65, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, no_led, 90, + 52, 66, 53, 54, no_led, 56, 57, 71, 59, no_led, 61, 62, 63, 64, no_led, 77 + }; }; class ImagoLEDDriver : public kaleidoscope::driver::led::Base { @@ -48,7 +57,6 @@ class ImagoLEDDriver : public kaleidoscope::driver::led::Base= 64) return {0, 0, 0}; diff --git a/src/kaleidoscope/device/keyboardio/Model01.h b/src/kaleidoscope/device/keyboardio/Model01.h index 55ed599e9b..930fe7651f 100644 --- a/src/kaleidoscope/device/keyboardio/Model01.h +++ b/src/kaleidoscope/device/keyboardio/Model01.h @@ -37,6 +37,12 @@ namespace keyboardio { struct Model01LEDDriverProps : public kaleidoscope::driver::led::BaseProps { static constexpr uint8_t led_count = 64; + static constexpr uint8_t key_led_map[] PROGMEM = { + 3, 4, 11, 12, 19, 20, 26, 27, 36, 37, 43, 44, 51, 52, 59, 60, + 2, 5, 10, 13, 18, 21, 25, 28, 35, 38, 42, 45, 50, 53, 58, 61, + 1, 6, 9, 14, 17, 22, 24, 29, 34, 39, 41, 46, 49, 54, 57, 62, + 0, 7, 8, 15, 16, 23, 31, 30, 33, 32, 40, 47, 48, 55, 56, 63, + }; }; class Model01LEDDriver : public kaleidoscope::driver::led::Base { @@ -45,8 +51,6 @@ class Model01LEDDriver : public kaleidoscope::driver::led::Base @@ -43,8 +49,20 @@ class Base { }; return c; } - uint8_t getLedIndex(uint8_t key_offset) { - return 0; + static uint8_t getLedIndex(uint8_t key_offset) { + + // Give the compiler the oportunity to optimize + // for boards without LEDs. + // + if (_LEDDriverProps::led_count == 0) { + return no_led; + } + + if (key_offset >= sizeof(_LEDDriverProps::key_led_map)) { + return no_led; + } + + return pgm_read_byte(&_LEDDriverProps::key_led_map[key_offset]); } static class LEDs { From fddbd75ff89f33a806188340710ca23381458e58 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 25 Nov 2019 15:56:45 +0100 Subject: [PATCH 08/26] New event handler: onLEDModeChange We'd like to be able to run custom code whenever the led mode changes, reliably, without having to resort to checking the mode every cycle. For this purpose, we introduce the `onLEDModeChange()` handler plugins can hook into. It will be called every time `LEDControl.set_mode()` is called, even if that just sets the mode to the currently active one. Signed-off-by: Gergely Nagy --- src/kaleidoscope/event_handlers.h | 12 ++++++++++++ src/kaleidoscope/hooks.h | 5 +++++ src/kaleidoscope/plugin/LEDControl.cpp | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/kaleidoscope/event_handlers.h b/src/kaleidoscope/event_handlers.h index 86c21db974..4bd8b38c33 100644 --- a/src/kaleidoscope/event_handlers.h +++ b/src/kaleidoscope/event_handlers.h @@ -161,6 +161,14 @@ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __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__ \ + /* themselves. */ __NL__ \ + OPERATION(onLEDModeChange, __NL__ \ + 1, __NL__ \ + _CURRENT_IMPLEMENTATION, __NL__ \ + _NOT_ABORTABLE, __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__ \ /* reported to the host. */ __NL__ \ @@ -219,6 +227,10 @@ OP(onLayerChange, 1) __NL__ \ END(onLayerChange, 1) __NL__ \ __NL__ \ + START(onLEDModeChange, 1) __NL__ \ + OP(onLEDModeChange, 1) __NL__ \ + END(onLEDModeChange, 1) __NL__ \ + __NL__ \ START(beforeReportingState, 1) __NL__ \ OP(beforeReportingState, 1) __NL__ \ END(beforeReportingState, 1) __NL__ \ diff --git a/src/kaleidoscope/hooks.h b/src/kaleidoscope/hooks.h index 4e154f49c5..abc6d5f1b4 100644 --- a/src/kaleidoscope/hooks.h +++ b/src/kaleidoscope/hooks.h @@ -33,6 +33,10 @@ extern void handleKeyswitchEvent(kaleidoscope::Key mappedKey, KeyAddr key_addr, DEPRECATED(ROW_COL_FUNC) extern void handleKeyswitchEvent(kaleidoscope::Key mappedKey, byte row, byte col, uint8_t keyState); namespace kaleidoscope { +namespace plugin { +// Forward declaration to enable friend declarations. +class LEDControl; +} // Forward declaration to enable friend declarations. class Layer_; @@ -55,6 +59,7 @@ class Hooks { // and Hooks::afterEachCycle. friend class Kaleidoscope_; friend class ::kaleidoscope::Layer_; + friend class ::kaleidoscope::plugin::LEDControl; // ::handleKeyswitchEvent(...) calls Hooks::onKeyswitchEvent. friend void ::handleKeyswitchEvent(kaleidoscope::Key mappedKey, diff --git a/src/kaleidoscope/plugin/LEDControl.cpp b/src/kaleidoscope/plugin/LEDControl.cpp index 9dc3b931ec..a5390072e9 100644 --- a/src/kaleidoscope/plugin/LEDControl.cpp +++ b/src/kaleidoscope/plugin/LEDControl.cpp @@ -68,6 +68,8 @@ LEDControl::set_mode(uint8_t mode_) { cur_led_mode_ = LEDModeManager::getLEDMode(mode_id); refreshAll(); + + kaleidoscope::Hooks::onLEDModeChange(); } void LEDControl::activate(LEDModeInterface *plugin) { From 9724e2eceaa620eb984a171f4c5c717365e54489 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 25 Nov 2019 16:02:17 +0100 Subject: [PATCH 09/26] plugin/PersistnetLEDMode: Use the new `onLEDModeChange()` hook Signed-off-by: Gergely Nagy --- src/kaleidoscope/plugin/PersistentLEDMode.cpp | 6 +++--- src/kaleidoscope/plugin/PersistentLEDMode.h | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/kaleidoscope/plugin/PersistentLEDMode.cpp b/src/kaleidoscope/plugin/PersistentLEDMode.cpp index 6480143b0a..312dbd856f 100644 --- a/src/kaleidoscope/plugin/PersistentLEDMode.cpp +++ b/src/kaleidoscope/plugin/PersistentLEDMode.cpp @@ -33,8 +33,8 @@ EventHandlerResult PersistentLEDMode::onSetup() { Kaleidoscope.storage().get(settings_base_, cached_mode_index_); // If the index is max, assume an uninitialized EEPROM, and don't set the LED - // mode. We don't change the cached index here, `afterEachCycle()` will do - // that at the end of he cycle anyway. + // mode. We don't change the cached index here, `onLEDModeChange()` will do + // that whenever a led mode change happens. if (cached_mode_index_ != 0xff) return EventHandlerResult::OK; @@ -43,7 +43,7 @@ EventHandlerResult PersistentLEDMode::onSetup() { return EventHandlerResult::OK; } -EventHandlerResult PersistentLEDMode::afterEachCycle() { +EventHandlerResult PersistentLEDMode::onLEDModeChange() { if (cached_mode_index_ == ::LEDControl.get_mode_index()) return EventHandlerResult::OK; diff --git a/src/kaleidoscope/plugin/PersistentLEDMode.h b/src/kaleidoscope/plugin/PersistentLEDMode.h index 511c8939ad..07bc5c31f4 100644 --- a/src/kaleidoscope/plugin/PersistentLEDMode.h +++ b/src/kaleidoscope/plugin/PersistentLEDMode.h @@ -16,11 +16,6 @@ * this program. If not, see . */ -/* NOTE: This plugin is a workaround. It allows us to (optionally) save the LED - * mode to storage, and restore it on next boot, without having a way to hook - * into led mode change events. Once we can hook into that, this plugin shall be - * reworked to use it instead of keeping `afterEachCycle()` busy. */ - #pragma once #include @@ -33,7 +28,7 @@ class PersistentLEDMode: public kaleidoscope::Plugin { PersistentLEDMode() {} EventHandlerResult onSetup(); - EventHandlerResult afterEachCycle(); + EventHandlerResult onLEDModeChange(); private: static uint16_t settings_base_; static uint8_t cached_mode_index_; From 9dea2a6083afa8d64f804dacd762601ba781b64f Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 11 Nov 2019 09:50:29 +0100 Subject: [PATCH 10/26] samd: mcu & bootloader Signed-off-by: Gergely Nagy --- .../driver/bootloader/samd/Bossac.h | 47 +++++++++++++++++++ src/kaleidoscope/driver/mcu/SAMD.h | 43 +++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/kaleidoscope/driver/bootloader/samd/Bossac.h create mode 100644 src/kaleidoscope/driver/mcu/SAMD.h diff --git a/src/kaleidoscope/driver/bootloader/samd/Bossac.h b/src/kaleidoscope/driver/bootloader/samd/Bossac.h new file mode 100644 index 0000000000..fdd48e2f84 --- /dev/null +++ b/src/kaleidoscope/driver/bootloader/samd/Bossac.h @@ -0,0 +1,47 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::bootloader::samd::Bossac -- Driver for the SAMD bootloader + * Copyright (C) 2019 Keyboard.io, Inc + * Copyright (C) 2019 Dygma, 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 . + */ + +#pragma once + +#ifdef ARDUINO_ARCH_SAMD + +#include "kaleidoscope/driver/bootloader/Base.h" + +namespace kaleidoscope { +namespace driver { +namespace bootloader { +namespace samd { + +class Bossac : public kaleidoscope::driver::bootloader::Base { + public: + static void rebootBootloader() { + __attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM]; + + USB->DEVICE.CTRLA.bit.SWRST = 1; + memset(EP, 0, sizeof(EP)); + while (USB->DEVICE.SYNCBUSY.bit.SWRST) {} + USB->DEVICE.DESCADD.reg = (uint32_t)(&EP); + } +}; + +} +} +} +} + +#endif diff --git a/src/kaleidoscope/driver/mcu/SAMD.h b/src/kaleidoscope/driver/mcu/SAMD.h new file mode 100644 index 0000000000..0b8e2fa330 --- /dev/null +++ b/src/kaleidoscope/driver/mcu/SAMD.h @@ -0,0 +1,43 @@ +/* -*- mode: c++ -*- + * driver::mcu::SAMD -- SAMD MCU driver class for Kaleidoscope + * Copyright (C) 2019 Keyboard.io, Inc + * Copyright (C) 2019 Dygma, 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 . + */ + +#pragma once + +#ifdef ARDUINO_ARCH_SAMD + +#include "kaleidoscope/driver/mcu/Base.h" + +namespace kaleidoscope { +namespace driver { +namespace mcu { + +class SAMD : public kaleidoscope::driver::mcu::Base { + public: + void detachFromHost() { + USBDevice.detach(); + } + void attachToHost() { + USBDevice.attach(); + } +}; + +} +} +} + +#endif From 7ab65b94d5326d0b37ab9efa3cd75cff4bd8f578 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Wed, 13 Nov 2019 18:38:54 +0100 Subject: [PATCH 11/26] driver::storage::Flash: FlashAsStorage-based storage component This is a primitive implementation of a `FlashAsStorage` (or rather, `FlashAsEEPROM`)-based storage component. It's based on `FlashAsEEPROM`, because I couldn't find a sane way to push the storage data variable within our template class. At some point, this needs to be reworked, to pull the size from Props, and not use the EEPROM API wrappers. Signed-off-by: Gergely Nagy --- src/kaleidoscope/driver/storage/Flash.h | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/kaleidoscope/driver/storage/Flash.h diff --git a/src/kaleidoscope/driver/storage/Flash.h b/src/kaleidoscope/driver/storage/Flash.h new file mode 100644 index 0000000000..a8dc0617d3 --- /dev/null +++ b/src/kaleidoscope/driver/storage/Flash.h @@ -0,0 +1,80 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::storage::Flash -- Storage driver with Flash backend + * Copyright (C) 2019 Keyboard.io, Inc + * Copyright (C) 2019 Dygma Lab S.L. + * + * 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 . + */ + +/* + * TODO(algernon): This currently uses , making the Props + * struct fairly useless. At some point, we need to figure out a way to do this + * without EEPROM API emulation, and by having the flash data variable somewhere + * within the `storage::Flash` class. + */ + +#pragma once + +#ifdef __SAMD21G18A__ + +#include "kaleidoscope/driver/storage/Base.h" +#include +#include + +// We need to undefine Flash, because `FlashStorage` defines it as a macro, yet, +// we want to use it as a class name. +#undef Flash + +namespace kaleidoscope { +namespace driver { +namespace storage { + +struct FlashProps : kaleidoscope::driver::storage::BaseProps { + static constexpr uint16_t length = EEPROM_EMULATION_SIZE; +}; + +template +class Flash: public kaleidoscope::driver::storage::Base<_StorageProps> { + public: + template + T& get(uint16_t offset, T& t) { + return EEPROM.get(offset, t); + } + + template + const T& put(uint16_t offset, T& t) { + EEPROM.put(offset, t); + } + + uint8_t read(int idx) { + return EEPROM.read(idx); + } + + void write(int idx, uint8_t val) { + EEPROM.write(idx, val); + } + + void update(int idx, uint8_t val) { + EEPROM.update(idx, val); + } + + void commit() { + EEPROM.commit(); + } +}; + +} +} +} + +#endif From f1a92d6fb07262fb47ec22f0b4127ddd0c3d7f05 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Sun, 24 Nov 2019 12:25:17 +0100 Subject: [PATCH 12/26] Added a macro that exports device types Kaleidoscope's device API defines two types to be exported as kaleidoscope::Device and kaleidoscope::DeviceProps. The newly introduced macro EXPORT_DEVICE can be used to export those two type names conveniently. The macro also serves the purpose to only export a type named kaleidoscope::Device in non-virtual device builds. In virtual builds, a homonymous type is exported by the virtual device header Virtual.h. Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/Base.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/kaleidoscope/device/Base.h b/src/kaleidoscope/device/Base.h index fd0407c306..4fb6397ea3 100644 --- a/src/kaleidoscope/device/Base.h +++ b/src/kaleidoscope/device/Base.h @@ -516,3 +516,22 @@ class Base { } } + +// EXPORT_DEVICE exports a device type from a specific namespace to +// the 'kaleidoscope' namespace as type 'Device'. The corresponding +// properties type is also exported as 'DeviceProps'. +// +// Please note that this macro expects to find two types, one referenced +// by the macro argument DEVICE and another one, the properties class +// with the name of the type that is passed as DEVICE prefixed by 'Props', +// e.g. Model01 as device and Model01Props as properties class. +// +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#define EXPORT_DEVICE(DEVICE) \ + typedef DEVICE##Props DeviceProps; \ + typedef DEVICE Device; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#define EXPORT_DEVICE(DEVICE) \ + typedef DEVICE##Props DeviceProps; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD + From c44eccfbdbb5371e2ae28c9196efd84b39284dd1 Mon Sep 17 00:00:00 2001 From: Jesse Vincent Date: Tue, 26 Nov 2019 14:25:32 -0800 Subject: [PATCH 13/26] switch from exporting our own Device typedef to using the new macro that helps the simulator work --- src/kaleidoscope/device/ez/ErgoDox.h | 2 +- src/kaleidoscope/device/kbdfans/KBD4x.h | 2 +- src/kaleidoscope/device/keyboardio/Imago.h | 2 +- src/kaleidoscope/device/keyboardio/Model01.h | 2 +- src/kaleidoscope/device/olkb/Planck.h | 2 +- src/kaleidoscope/device/softhruf/Splitography.h | 2 +- src/kaleidoscope/device/technomancy/Atreus.h | 2 +- src/kaleidoscope/device/technomancy/Atreus2.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/kaleidoscope/device/ez/ErgoDox.h b/src/kaleidoscope/device/ez/ErgoDox.h index 34bee12756..d7b35626b8 100644 --- a/src/kaleidoscope/device/ez/ErgoDox.h +++ b/src/kaleidoscope/device/ez/ErgoDox.h @@ -135,7 +135,7 @@ class ErgoDox : public kaleidoscope::device::ATmega32U4Keyboard { } } -typedef kaleidoscope::device::ez::ErgoDox Device; +EXPORT_DEVICE(kaleidoscope::device::ez::ErgoDox) } diff --git a/src/kaleidoscope/device/kbdfans/KBD4x.h b/src/kaleidoscope/device/kbdfans/KBD4x.h index a47c277cfa..c0a28c6891 100644 --- a/src/kaleidoscope/device/kbdfans/KBD4x.h +++ b/src/kaleidoscope/device/kbdfans/KBD4x.h @@ -63,7 +63,7 @@ class KBD4x: public kaleidoscope::device::ATmega32U4Keyboard { } } -typedef kaleidoscope::device::kbdfans::KBD4x Device; +EXPORT_DEVICE(kaleidoscope::device::kbdfans::KBD4x) } diff --git a/src/kaleidoscope/device/keyboardio/Imago.h b/src/kaleidoscope/device/keyboardio/Imago.h index 380afc32f6..e580cba29d 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.h +++ b/src/kaleidoscope/device/keyboardio/Imago.h @@ -103,7 +103,7 @@ class Imago: public kaleidoscope::device::ATmega32U4Keyboard { } } -typedef kaleidoscope::device::keyboardio::Imago Device; +EXPORT_DEVICE(kaleidoscope::device::keyboardio::Imago) } diff --git a/src/kaleidoscope/device/keyboardio/Model01.h b/src/kaleidoscope/device/keyboardio/Model01.h index 930fe7651f..3733435963 100644 --- a/src/kaleidoscope/device/keyboardio/Model01.h +++ b/src/kaleidoscope/device/keyboardio/Model01.h @@ -115,7 +115,7 @@ class Model01 : public kaleidoscope::device::ATmega32U4Keyboard { } } -typedef kaleidoscope::device::keyboardio::Model01 Device; +EXPORT_DEVICE(kaleidoscope::device::keyboardio::Model01) } diff --git a/src/kaleidoscope/device/olkb/Planck.h b/src/kaleidoscope/device/olkb/Planck.h index 687d7323aa..c56e16b64e 100644 --- a/src/kaleidoscope/device/olkb/Planck.h +++ b/src/kaleidoscope/device/olkb/Planck.h @@ -48,7 +48,7 @@ ATMEGA32U4_KEYBOARD( } } -typedef kaleidoscope::device::olkb::Planck Device; +EXPORT_DEVICE(kaleidoscope::device::olkb::Planck) } diff --git a/src/kaleidoscope/device/softhruf/Splitography.h b/src/kaleidoscope/device/softhruf/Splitography.h index 133ee7377a..19ce037f58 100644 --- a/src/kaleidoscope/device/softhruf/Splitography.h +++ b/src/kaleidoscope/device/softhruf/Splitography.h @@ -87,7 +87,7 @@ class Splitography: public kaleidoscope::device::ATmega32U4Keyboard Date: Wed, 20 Nov 2019 16:13:49 +0100 Subject: [PATCH 14/26] Removed method Virtual::getLedIndex(...) This method is now implemented in the LED driver base class based on the LED driver properties.Removed method Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/virtual/Virtual.cpp | 4 ---- src/kaleidoscope/device/virtual/Virtual.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/kaleidoscope/device/virtual/Virtual.cpp b/src/kaleidoscope/device/virtual/Virtual.cpp index e0ff4cf639..735355751a 100644 --- a/src/kaleidoscope/device/virtual/Virtual.cpp +++ b/src/kaleidoscope/device/virtual/Virtual.cpp @@ -371,10 +371,6 @@ cRGB VirtualLEDDriver::getCrgbAt(uint8_t i) const { return led_states_[i]; } -uint8_t VirtualLEDDriver::getLedIndex(uint8_t key_offset) const { - return kaleidoscope::DeviceProps::LEDDriverProps::getLedIndex(key_offset); -} - } // namespace virt } // namespace device diff --git a/src/kaleidoscope/device/virtual/Virtual.h b/src/kaleidoscope/device/virtual/Virtual.h index 4a8800318c..394cb421c3 100644 --- a/src/kaleidoscope/device/virtual/Virtual.h +++ b/src/kaleidoscope/device/virtual/Virtual.h @@ -107,7 +107,6 @@ class VirtualLEDDriver void syncLeds(); void setCrgbAt(uint8_t i, cRGB color); cRGB getCrgbAt(uint8_t i) const; - uint8_t getLedIndex(uint8_t key_offset) const; private: From b5c9794626c78a6f24303a3c864cfb7efcd25f4e Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 15:54:40 +0100 Subject: [PATCH 15/26] Enabled virtual build for Keyboardio/Model01 The Model01.h required some reordering of header includes and some forward defines of certain types that are used in property classes. Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/ATmega32U4Keyboard.h | 7 +++- .../device/keyboardio/Model01.cpp | 10 ++++-- src/kaleidoscope/device/keyboardio/Model01.h | 35 +++++++++++++++---- src/kaleidoscope/device/keyboardio/twi.c | 2 +- src/kaleidoscope/device/keyboardio/twi.h | 3 ++ src/kaleidoscope/driver/mcu/ATmega32U4.h | 4 +++ 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/kaleidoscope/device/ATmega32U4Keyboard.h b/src/kaleidoscope/device/ATmega32U4Keyboard.h index b0d66feade..2f552440e7 100644 --- a/src/kaleidoscope/device/ATmega32U4Keyboard.h +++ b/src/kaleidoscope/device/ATmega32U4Keyboard.h @@ -17,7 +17,7 @@ #pragma once -#ifdef __AVR__ +#if defined(__AVR__) || defined(KALEIDOSCOPE_VIRTUAL_BUILD) #include #include "kaleidoscope/device/Base.h" @@ -46,6 +46,7 @@ struct ATmega32U4KeyboardProps : kaleidoscope::device::BaseProps { typedef kaleidoscope::driver::storage::AVREEPROM Storage; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD template class ATmega32U4Keyboard : public kaleidoscope::device::Base<_DeviceProps> { public: @@ -53,6 +54,10 @@ class ATmega32U4Keyboard : public kaleidoscope::device::Base<_DeviceProps> { return Serial; } }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +template +class ATmega32U4Keyboard; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } diff --git a/src/kaleidoscope/device/keyboardio/Model01.cpp b/src/kaleidoscope/device/keyboardio/Model01.cpp index b8d1124c8e..ae6ecb62b3 100644 --- a/src/kaleidoscope/device/keyboardio/Model01.cpp +++ b/src/kaleidoscope/device/keyboardio/Model01.cpp @@ -16,11 +16,13 @@ */ #ifdef ARDUINO_AVR_MODEL01 -#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include + +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include #include +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD namespace kaleidoscope { namespace device { @@ -28,6 +30,8 @@ namespace keyboardio { constexpr uint8_t Model01LEDDriverProps::key_led_map[] PROGMEM; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD + /********* Model01Hands *********/ struct Model01Hands { @@ -293,9 +297,9 @@ void Model01::enableHardwareTestMode() { KeyScanner::setKeyscanInterval(2); } +#endif + } } } - -#endif #endif diff --git a/src/kaleidoscope/device/keyboardio/Model01.h b/src/kaleidoscope/device/keyboardio/Model01.h index 3733435963..ceac5c5dbf 100644 --- a/src/kaleidoscope/device/keyboardio/Model01.h +++ b/src/kaleidoscope/device/keyboardio/Model01.h @@ -21,15 +21,24 @@ #include -#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h" -#include "KeyboardioScanner.h" - #define CRGB(r,g,b) (cRGB){b, g, r} +struct cRGB { + uint8_t b; + uint8_t g; + uint8_t r; +}; + +#include "kaleidoscope/device/ATmega32U4Keyboard.h" + #include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/led/Base.h" +#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h" #include "kaleidoscope/driver/bootloader/avr/Caterina.h" -#include "kaleidoscope/device/ATmega32U4Keyboard.h" + +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#include "KeyboardioScanner.h" +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD namespace kaleidoscope { namespace device { @@ -45,6 +54,7 @@ struct Model01LEDDriverProps : public kaleidoscope::driver::led::BaseProps { }; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class Model01LEDDriver : public kaleidoscope::driver::led::Base { public: static void syncLeds(); @@ -57,11 +67,15 @@ class Model01LEDDriver : public kaleidoscope::driver::led::Base { private: typedef Model01KeyScanner ThisType; @@ -96,8 +110,11 @@ class Model01KeyScanner : public kaleidoscope::driver::keyscanner::Base { public: static void setup(); @@ -112,8 +131,10 @@ class Model01 : public kaleidoscope::device::ATmega32U4Keyboard { static void enableHardwareTestMode(); }; -} -} +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD + +} // namespace keyboardio +} // namespace device EXPORT_DEVICE(kaleidoscope::device::keyboardio::Model01) diff --git a/src/kaleidoscope/device/keyboardio/twi.c b/src/kaleidoscope/device/keyboardio/twi.c index 38fe7e598f..8b5416e0b1 100644 --- a/src/kaleidoscope/device/keyboardio/twi.c +++ b/src/kaleidoscope/device/keyboardio/twi.c @@ -18,7 +18,7 @@ Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts */ -#ifdef __AVR__ +#if defined(__AVR__) && !defined(KALEIDOSCOPE_VIRTUAL_BUILD) #define ENABLE_TWI_SLAVE_MODE 0 diff --git a/src/kaleidoscope/device/keyboardio/twi.h b/src/kaleidoscope/device/keyboardio/twi.h index e375351960..5b22cc40cb 100644 --- a/src/kaleidoscope/device/keyboardio/twi.h +++ b/src/kaleidoscope/device/keyboardio/twi.h @@ -21,6 +21,8 @@ #ifndef twi_h #define twi_h +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD + #include //#define ATMEGA8 @@ -52,5 +54,6 @@ void twi_reply(uint8_t); void twi_stop(void); void twi_releaseBus(void); +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #endif #endif diff --git a/src/kaleidoscope/driver/mcu/ATmega32U4.h b/src/kaleidoscope/driver/mcu/ATmega32U4.h index ad31c5fb12..2a15fafdda 100644 --- a/src/kaleidoscope/driver/mcu/ATmega32U4.h +++ b/src/kaleidoscope/driver/mcu/ATmega32U4.h @@ -23,6 +23,7 @@ namespace kaleidoscope { namespace driver { namespace mcu { +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class ATmega32U4 : public kaleidoscope::driver::mcu::Base { public: void detachFromHost() { @@ -62,6 +63,9 @@ class ATmega32U4 : public kaleidoscope::driver::mcu::Base { void setup() {} }; +#else +typedef Base ATmega32U4; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } From 57e7fe59b17d088332ec253b23feabd5e9d0ad15 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 21:48:42 +0100 Subject: [PATCH 16/26] Enabled virtual build for ez/ErgoDox Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/ez/ErgoDox.cpp | 2 ++ src/kaleidoscope/device/ez/ErgoDox.h | 9 +++++++-- src/kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.cpp | 2 ++ src/kaleidoscope/device/ez/ErgoDox/i2cmaster.cpp | 2 ++ src/kaleidoscope/driver/bootloader/avr/Caterina.h | 6 ++++++ src/kaleidoscope/driver/bootloader/avr/FLIP.cpp | 2 ++ src/kaleidoscope/driver/bootloader/avr/FLIP.h | 6 ++++++ src/kaleidoscope/driver/bootloader/avr/HalfKay.h | 6 ++++++ 8 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/kaleidoscope/device/ez/ErgoDox.cpp b/src/kaleidoscope/device/ez/ErgoDox.cpp index 1d6c528c19..38dd0f1bd9 100644 --- a/src/kaleidoscope/device/ez/ErgoDox.cpp +++ b/src/kaleidoscope/device/ez/ErgoDox.cpp @@ -24,6 +24,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_ERGODOX #include @@ -232,3 +233,4 @@ uint8_t ErgoDox::pressedKeyswitchCount() { kaleidoscope::device::ez::ErgoDox &ErgoDox = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/ez/ErgoDox.h b/src/kaleidoscope/device/ez/ErgoDox.h index d7b35626b8..c706b27ff6 100644 --- a/src/kaleidoscope/device/ez/ErgoDox.h +++ b/src/kaleidoscope/device/ez/ErgoDox.h @@ -29,8 +29,6 @@ #include -#include "kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.h" - #include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h" struct cRGB { @@ -42,6 +40,9 @@ struct cRGB { #include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/bootloader/avr/HalfKay.h" #include "kaleidoscope/device/ATmega32U4Keyboard.h" +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#include "kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.h" +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD namespace kaleidoscope { namespace device { @@ -54,6 +55,7 @@ struct ErgoDoxProps : public kaleidoscope::device::ATmega32U4KeyboardProps { typedef kaleidoscope::driver::bootloader::avr::HalfKay Bootloader; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class ErgoDox : public kaleidoscope::device::ATmega32U4Keyboard { public: ErgoDox(void) {} @@ -93,6 +95,9 @@ class ErgoDox : public kaleidoscope::device::ATmega32U4Keyboard { static void debounceRow(uint8_t change, uint8_t row); static void readMatrixRow(uint8_t row); }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +class ErgoDox; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define PER_KEY_DATA_STACKED(dflt, \ /* left hand, spatial positions */ \ diff --git a/src/kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.cpp b/src/kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.cpp index 660171c5ef..649710e5e4 100644 --- a/src/kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.cpp +++ b/src/kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.cpp @@ -23,6 +23,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_ERGODOX #include "kaleidoscope/device/ez/ErgoDox/ErgoDoxScanner.h" @@ -171,3 +172,4 @@ ErgoDoxScanner::reattachExpanderOnError() { } #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.cpp b/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.cpp index 71400b84b3..abc105c141 100644 --- a/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.cpp +++ b/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.cpp @@ -7,6 +7,7 @@ * Usage: API compatible with I2C Software Library i2cmaster.h **************************************************************************/ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_ERGODOX #include @@ -201,3 +202,4 @@ unsigned char i2c_readNak(void) { }/* i2c_readNak */ #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/driver/bootloader/avr/Caterina.h b/src/kaleidoscope/driver/bootloader/avr/Caterina.h index 7006c51211..1d45939c89 100644 --- a/src/kaleidoscope/driver/bootloader/avr/Caterina.h +++ b/src/kaleidoscope/driver/bootloader/avr/Caterina.h @@ -17,7 +17,9 @@ #pragma once +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include "kaleidoscope/driver/bootloader/Base.h" namespace kaleidoscope { @@ -25,6 +27,7 @@ namespace driver { namespace bootloader { namespace avr { +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class Caterina : public kaleidoscope::driver::bootloader::Base { public: static void rebootBootloader() { @@ -49,6 +52,9 @@ class Caterina : public kaleidoscope::driver::bootloader::Base { // happens before the watchdog reboots us } }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +class Caterina; +#endif // #ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } diff --git a/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp b/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp index 4ab4485f8d..fcb86068c4 100644 --- a/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp +++ b/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp @@ -15,6 +15,7 @@ * this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include #ifdef KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND @@ -74,3 +75,4 @@ void FLIP::rebootBootloader() { } #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/driver/bootloader/avr/FLIP.h b/src/kaleidoscope/driver/bootloader/avr/FLIP.h index bc79d59f67..29af58c107 100644 --- a/src/kaleidoscope/driver/bootloader/avr/FLIP.h +++ b/src/kaleidoscope/driver/bootloader/avr/FLIP.h @@ -17,11 +17,13 @@ #pragma once +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include #ifndef KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND #error To use the FLIP bootloader driver, KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND *must* be defined prior to including this header! #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include "kaleidoscope/driver/bootloader/Base.h" @@ -30,10 +32,14 @@ namespace driver { namespace bootloader { namespace avr { +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class FLIP : public kaleidoscope::driver::bootloader::Base { public: static void rebootBootloader(); }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +class FLIP; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } diff --git a/src/kaleidoscope/driver/bootloader/avr/HalfKay.h b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h index 651db242c3..7386122f62 100644 --- a/src/kaleidoscope/driver/bootloader/avr/HalfKay.h +++ b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h @@ -17,7 +17,9 @@ #pragma once +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include "kaleidoscope/driver/bootloader/Base.h" namespace kaleidoscope { @@ -25,6 +27,7 @@ namespace driver { namespace bootloader { namespace avr { +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class HalfKay : public kaleidoscope::driver::bootloader::Base { public: // To reset a Teensy with the HalfKay bootloader, we need to disable all @@ -65,6 +68,9 @@ class HalfKay : public kaleidoscope::driver::bootloader::Base { asm volatile("jmp 0x7E00"); } }; +#else +class HalfKay; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } From b6fd6b02f5755c01a2eab5c0cd3b308a80a6e531 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 22:23:22 +0100 Subject: [PATCH 17/26] Enabled virtual build for KBDFans/KBD4x Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/avr/pins_and_ports.h | 16 ++++++++++++---- src/kaleidoscope/device/kbdfans/KBD4x.cpp | 2 ++ src/kaleidoscope/device/kbdfans/KBD4x.h | 4 ++++ .../driver/bootloader/avr/Caterina.h | 3 ++- src/kaleidoscope/driver/bootloader/avr/FLIP.h | 3 ++- src/kaleidoscope/driver/bootloader/avr/HalfKay.h | 3 ++- src/kaleidoscope/driver/keyscanner/ATmega.h | 15 +++++++++++++++ 7 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/kaleidoscope/device/avr/pins_and_ports.h b/src/kaleidoscope/device/avr/pins_and_ports.h index ba42f7ba9c..d2d566ccf2 100644 --- a/src/kaleidoscope/device/avr/pins_and_ports.h +++ b/src/kaleidoscope/device/avr/pins_and_ports.h @@ -21,7 +21,7 @@ #pragma once -#ifndef __ASSEMBLER__ +#if !defined(__ASSEMBLER__) && !defined(KALEIDOSCOPE_VIRTUAL_BUILD) #include #endif #define PORT_SHIFTER 4 // this may be 4 for all AVR chips @@ -55,13 +55,22 @@ #define PINC_ADDRESS 0x3 #define PINB_ADDRESS 0x6 #define PINA_ADDRESS 0x9 -#else +#elif !defined(KALEIDOSCOPE_VIRTUAL_BUILD) #error "Pins are not defined" #endif /* I/O pins */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin) - +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#define PINDEF(port, pin) 0 +#define PORTA +#define PORTB +#define PORTC +#define PORTD +#define PORTE +#define PORTF +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef PORTA #define PIN_A0 PINDEF(A, 0) @@ -124,7 +133,6 @@ #define PIN_F7 PINDEF(F, 7) #endif - /* converting pins to ports */ enum { PIN_OFFSET, DDR_OFFSET, PORT_OFFSET}; diff --git a/src/kaleidoscope/device/kbdfans/KBD4x.cpp b/src/kaleidoscope/device/kbdfans/KBD4x.cpp index 7657edc521..788100cb86 100644 --- a/src/kaleidoscope/device/kbdfans/KBD4x.cpp +++ b/src/kaleidoscope/device/kbdfans/KBD4x.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_KBD4X #include @@ -32,3 +33,4 @@ ATMEGA_KEYSCANNER_BOILERPLATE kaleidoscope::device::kbdfans::KBD4x &KBD4x = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/kbdfans/KBD4x.h b/src/kaleidoscope/device/kbdfans/KBD4x.h index c0a28c6891..d5d83d373a 100644 --- a/src/kaleidoscope/device/kbdfans/KBD4x.h +++ b/src/kaleidoscope/device/kbdfans/KBD4x.h @@ -42,6 +42,7 @@ struct KBD4xProps : kaleidoscope::device::ATmega32U4KeyboardProps { typedef kaleidoscope::driver::bootloader::avr::FLIP Bootloader; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class KBD4x: public kaleidoscope::device::ATmega32U4Keyboard { public: KBD4x() { @@ -49,6 +50,9 @@ class KBD4x: public kaleidoscope::device::ATmega32U4Keyboard { mcu_.disableClockDivision(); } }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +class KBD4x; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define PER_KEY_DATA(dflt, \ R0C0, R0C1, R0C2, R0C3, R0C4, R0C5, R0C6, R0C7, R0C8, R0C9, R0C10, R0C11, \ diff --git a/src/kaleidoscope/driver/bootloader/avr/Caterina.h b/src/kaleidoscope/driver/bootloader/avr/Caterina.h index 1d45939c89..52447cb57d 100644 --- a/src/kaleidoscope/driver/bootloader/avr/Caterina.h +++ b/src/kaleidoscope/driver/bootloader/avr/Caterina.h @@ -20,6 +20,7 @@ #ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#include "kaleidoscope/driver/bootloader/None.h" #include "kaleidoscope/driver/bootloader/Base.h" namespace kaleidoscope { @@ -53,7 +54,7 @@ class Caterina : public kaleidoscope::driver::bootloader::Base { } }; #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD -class Caterina; +typedef bootloader::None Caterina; #endif // #ifndef KALEIDOSCOPE_VIRTUAL_BUILD } diff --git a/src/kaleidoscope/driver/bootloader/avr/FLIP.h b/src/kaleidoscope/driver/bootloader/avr/FLIP.h index 29af58c107..c4e993e198 100644 --- a/src/kaleidoscope/driver/bootloader/avr/FLIP.h +++ b/src/kaleidoscope/driver/bootloader/avr/FLIP.h @@ -25,6 +25,7 @@ #endif #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#include "kaleidoscope/driver/bootloader/None.h" #include "kaleidoscope/driver/bootloader/Base.h" namespace kaleidoscope { @@ -38,7 +39,7 @@ class FLIP : public kaleidoscope::driver::bootloader::Base { static void rebootBootloader(); }; #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD -class FLIP; +typedef bootloader::None FLIP; #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } diff --git a/src/kaleidoscope/driver/bootloader/avr/HalfKay.h b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h index 7386122f62..ae8d126832 100644 --- a/src/kaleidoscope/driver/bootloader/avr/HalfKay.h +++ b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h @@ -20,6 +20,7 @@ #ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#include "kaleidoscope/driver/bootloader/None.h" #include "kaleidoscope/driver/bootloader/Base.h" namespace kaleidoscope { @@ -69,7 +70,7 @@ class HalfKay : public kaleidoscope::driver::bootloader::Base { } }; #else -class HalfKay; +typedef bootloader::None HalfKay; #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } diff --git a/src/kaleidoscope/driver/keyscanner/ATmega.h b/src/kaleidoscope/driver/keyscanner/ATmega.h index bf8e8ba399..8db7eaf882 100644 --- a/src/kaleidoscope/driver/keyscanner/ATmega.h +++ b/src/kaleidoscope/driver/keyscanner/ATmega.h @@ -22,17 +22,26 @@ #include "kaleidoscope/macro_helpers.h" #include "kaleidoscope/driver/keyscanner/Base.h" +#include "kaleidoscope/driver/keyscanner/None.h" + #include "kaleidoscope/device/avr/pins_and_ports.h" +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #include +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define ROW_PIN_LIST(...) __VA_ARGS__ #define COL_PIN_LIST(...) __VA_ARGS__ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define ATMEGA_KEYSCANNER_PROPS(ROW_PINS_, COL_PINS_) \ KEYSCANNER_PROPS(NUM_ARGS(ROW_PINS_), NUM_ARGS(COL_PINS_)); \ static constexpr uint8_t matrix_row_pins[matrix_rows] = ROW_PINS_; \ static constexpr uint8_t matrix_col_pins[matrix_columns] = COL_PINS_; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +#define ATMEGA_KEYSCANNER_PROPS(ROW_PINS_, COL_PINS_) \ + KEYSCANNER_PROPS(NUM_ARGS(ROW_PINS_), NUM_ARGS(COL_PINS_)); +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define ATMEGA_KEYSCANNER_BOILERPLATE \ KEYSCANNER_PROPS_BOILERPLATE(kaleidoscope::Device::KeyScannerProps); \ @@ -66,6 +75,8 @@ struct ATmegaProps: kaleidoscope::driver::keyscanner::BaseProps { static constexpr uint8_t matrix_col_pins[] = {}; }; + +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD template class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> { private: @@ -233,6 +244,10 @@ class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> { } } }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +template +class ATmega : public keyscanner::None {}; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD } } From 9d4641a21860898921e64197aba755c6187b13ba Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 22:36:02 +0100 Subject: [PATCH 18/26] Enabled virtual build for OLKB/Planck Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/ATmega32U4Keyboard.h | 44 ++++++++++++++++---- src/kaleidoscope/device/olkb/Planck.cpp | 2 + src/kaleidoscope/driver/storage/AVREEPROM.h | 2 +- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/kaleidoscope/device/ATmega32U4Keyboard.h b/src/kaleidoscope/device/ATmega32U4Keyboard.h index 2f552440e7..2570a859a0 100644 --- a/src/kaleidoscope/device/ATmega32U4Keyboard.h +++ b/src/kaleidoscope/device/ATmega32U4Keyboard.h @@ -27,16 +27,44 @@ #include "kaleidoscope/driver/storage/ATmega32U4EEPROMProps.h" #include "kaleidoscope/driver/storage/AVREEPROM.h" -#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, 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 KeyScanner; \ - typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \ - }; \ +#define ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, 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 KeyScanner;\ + typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \ + }; + +#define ATMEGA32U4_DEVICE(BOARD_) \ class BOARD_: public kaleidoscope::device::ATmega32U4Keyboard {}; +#define FORWARD(...) __VA_ARGS__ + +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD + +#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, ROW_PINS_, COL_PINS_) \ + ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, \ + FORWARD(ROW_PINS_), FORWARD(COL_PINS_)) \ + ATMEGA32U4_DEVICE(BOARD_) + +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD + +#define ATMEGA32U4_KEYBOARD(BOARD_, BOOTLOADER_, ROW_PINS_, COL_PINS_) \ + ATMEGA32U4_DEVICE_PROPS(BOARD_, BOOTLOADER_, \ + 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. \ + */ \ + class BOARD_; + +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD + namespace kaleidoscope { namespace device { diff --git a/src/kaleidoscope/device/olkb/Planck.cpp b/src/kaleidoscope/device/olkb/Planck.cpp index 66167f53e7..889a255f5c 100644 --- a/src/kaleidoscope/device/olkb/Planck.cpp +++ b/src/kaleidoscope/device/olkb/Planck.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_PLANCK #include @@ -32,3 +33,4 @@ ATMEGA_KEYSCANNER_BOILERPLATE kaleidoscope::device::olkb::Planck &Planck = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/driver/storage/AVREEPROM.h b/src/kaleidoscope/driver/storage/AVREEPROM.h index 9871a084cf..691d0e685a 100644 --- a/src/kaleidoscope/driver/storage/AVREEPROM.h +++ b/src/kaleidoscope/driver/storage/AVREEPROM.h @@ -17,7 +17,7 @@ #pragma once -#ifdef __AVR__ +#if defined(__AVR__) || defined(KALEIDOSCOPE_VIRTUAL_BUILD) #include "kaleidoscope/driver/storage/Base.h" #include From 7599ad44d988cdeab0d67e19fb17df90420db7cf Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 22:38:53 +0100 Subject: [PATCH 19/26] Enabled virtual build for SOFTHRUF/Splitography Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/softhruf/Splitography.cpp | 2 ++ src/kaleidoscope/device/softhruf/Splitography.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/kaleidoscope/device/softhruf/Splitography.cpp b/src/kaleidoscope/device/softhruf/Splitography.cpp index 5d0af017c3..cf7f55a2be 100644 --- a/src/kaleidoscope/device/softhruf/Splitography.cpp +++ b/src/kaleidoscope/device/softhruf/Splitography.cpp @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_SPLITOGRAPHY #include @@ -39,3 +40,4 @@ ATMEGA_KEYSCANNER_BOILERPLATE kaleidoscope::device::softhruf::Splitography &Splitography = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD diff --git a/src/kaleidoscope/device/softhruf/Splitography.h b/src/kaleidoscope/device/softhruf/Splitography.h index 19ce037f58..230ace3075 100644 --- a/src/kaleidoscope/device/softhruf/Splitography.h +++ b/src/kaleidoscope/device/softhruf/Splitography.h @@ -49,12 +49,16 @@ struct SplitographyProps : kaleidoscope::device::ATmega32U4KeyboardProps { typedef kaleidoscope::driver::bootloader::avr::FLIP BootLoader; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class Splitography: public kaleidoscope::device::ATmega32U4Keyboard { public: Splitography() { mcu_.disableJTAG(); } }; +#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD +class Splitography; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define PER_KEY_DATA(dflt, \ r0c0 ,r0c1 ,r0c2 ,r0c3 ,r0c4 ,r0c5 ,r0c6 ,r0c7 ,r0c8 ,r0c9 ,r0c10 ,r0c11 \ From fb64771e52741d4a13e4b1b27a32ac7b0307d322 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 22:40:16 +0100 Subject: [PATCH 20/26] Enabled virtual build for Technomancy/Atreus Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/technomancy/Atreus.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kaleidoscope/device/technomancy/Atreus.cpp b/src/kaleidoscope/device/technomancy/Atreus.cpp index 31e2149905..23a9cc5146 100644 --- a/src/kaleidoscope/device/technomancy/Atreus.cpp +++ b/src/kaleidoscope/device/technomancy/Atreus.cpp @@ -24,6 +24,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_ATREUS #include @@ -41,3 +42,4 @@ ATMEGA_KEYSCANNER_BOILERPLATE kaleidoscope::device::technomancy::Atreus &Atreus = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD From 7e5a2d0ddca40cfc32758f0dbb3c48f050b87b94 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 22:42:54 +0100 Subject: [PATCH 21/26] Enabled virtual build for Technomancy/Atreus2 Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/technomancy/Atreus2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kaleidoscope/device/technomancy/Atreus2.cpp b/src/kaleidoscope/device/technomancy/Atreus2.cpp index f33261671f..5b8475d7c5 100644 --- a/src/kaleidoscope/device/technomancy/Atreus2.cpp +++ b/src/kaleidoscope/device/technomancy/Atreus2.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifdef ARDUINO_AVR_ATREUS2 #include @@ -33,3 +34,4 @@ ATMEGA_KEYSCANNER_BOILERPLATE kaleidoscope::device::technomancy::Atreus2 &Atreus2 = kaleidoscope_internal::device; #endif +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD From a114f3c1a43362158e42ad5a2765bc7a2bb5412d Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 20 Nov 2019 23:29:23 +0100 Subject: [PATCH 22/26] Enabled virtual build for Keyboardio/Imago Signed-off-by: Florian Fleissner --- src/kaleidoscope/device/keyboardio/Imago.cpp | 4 ++++ src/kaleidoscope/device/keyboardio/Imago.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/kaleidoscope/device/keyboardio/Imago.cpp b/src/kaleidoscope/device/keyboardio/Imago.cpp index 0890c54c28..d840ba397a 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.cpp +++ b/src/kaleidoscope/device/keyboardio/Imago.cpp @@ -33,6 +33,8 @@ namespace keyboardio { constexpr uint8_t ImagoLEDDriverProps::key_led_map[] PROGMEM; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD + static constexpr uint8_t CMD_SET_REGISTER = 0xFD; static constexpr uint8_t CMD_WRITE_ENABLE = 0xFE; static constexpr uint8_t WRITE_ENABLE_ONCE = 0b11000101; @@ -172,6 +174,8 @@ void Imago::setup() { kaleidoscope::device::ATmega32U4Keyboard::setup(); } +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD + } } } diff --git a/src/kaleidoscope/device/keyboardio/Imago.h b/src/kaleidoscope/device/keyboardio/Imago.h index e580cba29d..03ff9337c1 100644 --- a/src/kaleidoscope/device/keyboardio/Imago.h +++ b/src/kaleidoscope/device/keyboardio/Imago.h @@ -51,6 +51,7 @@ struct ImagoLEDDriverProps: public kaleidoscope::driver::led::BaseProps { }; }; +#ifndef KALEIDOSCOPE_VIRTUAL_BUILD class ImagoLEDDriver : public kaleidoscope::driver::led::Base { public: static void setup(); @@ -68,6 +69,9 @@ class ImagoLEDDriver : public kaleidoscope::driver::led::Base { public: void setup(); }; +#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #define PER_KEY_DATA(dflt, \ R0C0, R0C1, R0C2, R0C3, R0C4, R0C5, R0C6, R0C7, R0C8, R0C9, R0C10, R0C11, R0C12, R0C13, R0C14, R0C15, \ From 686044264e8815ffd1bf769e52e6ae6318753102 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 27 Nov 2019 11:36:43 +0100 Subject: [PATCH 23/26] Made the keymap a constexpr array This enables compile time exploration of the keymap from all code that is part of the sketch's compilation unit. Signed-off-by: Florian Fleissner --- src/kaleidoscope/layers.cpp | 2 +- src/kaleidoscope/layers.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kaleidoscope/layers.cpp b/src/kaleidoscope/layers.cpp index ac59b49b38..f3efb80e78 100644 --- a/src/kaleidoscope/layers.cpp +++ b/src/kaleidoscope/layers.cpp @@ -33,7 +33,7 @@ __attribute__((weak)) uint8_t layer_count = 0; __attribute__((weak)) -extern const Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] = {}; +extern constexpr Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] = {}; namespace kaleidoscope { uint32_t Layer_::layer_state_; diff --git a/src/kaleidoscope/layers.h b/src/kaleidoscope/layers.h index 0cf7d19636..aaa6762f8a 100644 --- a/src/kaleidoscope/layers.h +++ b/src/kaleidoscope/layers.h @@ -26,7 +26,7 @@ // file (*.ino) to define the keymap[] array that holds the user's // layers. It also computes the number of layers in that keymap. #define KEYMAPS(layers...) __NL__ \ - const Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] PROGMEM = { layers }; __NL__ \ + constexpr Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] PROGMEM = { layers }; __NL__ \ uint8_t layer_count __NL__ \ = sizeof(keymaps_linear) / sizeof(*keymaps_linear); __NL__ \ __NL__ \ From 7aa2c0e8596bd18412990067ebb5ee2ac6902f84 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 27 Nov 2019 11:45:53 +0100 Subject: [PATCH 24/26] Enabled templated hook methods Hook methods can now be templated. A template parameter type list, a list of template parameters and a list of dummy template arguments have been added to the macro arguments used in _FOR_EACH_EVENT_HANDLER. Non-template hooks pass empty parenthesis for the three newly introduced macro arguments. Signed-off-by: Florian Fleissner --- src/kaleidoscope/event_handlers.h | 36 ++++++++++++++ src/kaleidoscope/hooks.cpp | 5 +- src/kaleidoscope/hooks.h | 5 +- src/kaleidoscope/macro_helpers.h | 49 +++++++++++++++++++ src/kaleidoscope_internal/LEDModeManager.h | 4 +- src/kaleidoscope_internal/event_dispatch.h | 36 +++++++++----- .../eventhandler_signature_check.h | 11 +++-- .../type_traits/has_method.h | 11 +++-- 8 files changed, 136 insertions(+), 21 deletions(-) diff --git a/src/kaleidoscope/event_handlers.h b/src/kaleidoscope/event_handlers.h index 4bd8b38c33..b35985d78f 100644 --- a/src/kaleidoscope/event_handlers.h +++ b/src/kaleidoscope/event_handlers.h @@ -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. @@ -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__ \ @@ -107,6 +135,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (), (), ##__VA_ARGS__) __NL__ \ __NL__ \ /* DEPRECATED */ __NL__ \ @@ -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__ \ @@ -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__ \ @@ -150,6 +181,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (const char *command), __NL__ \ (command), ##__VA_ARGS__) __NL__ \ __NL__ \ @@ -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__ \ @@ -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__ \ @@ -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__ \ @@ -184,6 +219,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (),(),##__VA_ARGS__) // The following function macro lists event handler/hook method names and diff --git a/src/kaleidoscope/hooks.cpp b/src/kaleidoscope/hooks.cpp index ac25c44cec..9ad71c5075 100644 --- a/src/kaleidoscope/hooks.cpp +++ b/src/kaleidoscope/hooks.cpp @@ -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__ \ diff --git a/src/kaleidoscope/hooks.h b/src/kaleidoscope/hooks.h index abc6d5f1b4..012196ccec 100644 --- a/src/kaleidoscope/hooks.h +++ b/src/kaleidoscope/hooks.h @@ -72,8 +72,11 @@ class Hooks { #define DEFINE_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__ \ static EventHandlerResult HOOK_NAME SIGNATURE; _FOR_EACH_EVENT_HANDLER(DEFINE_WEAK_HOOK_FUNCTION) diff --git a/src/kaleidoscope/macro_helpers.h b/src/kaleidoscope/macro_helpers.h index c056bf25a8..eeb50a244c 100644 --- a/src/kaleidoscope/macro_helpers.h +++ b/src/kaleidoscope/macro_helpers.h @@ -52,6 +52,8 @@ #define GLUE3(A, B, C) A##B##C #define GLUE4(A, B, C, D) A##B##C##D +#define UNWRAP(...) __VA_ARGS__ + // Allow for the creation of verbose messages in static_asserts // #define VERBOSE_STATIC_ASSERT_HEADER \ @@ -142,3 +144,50 @@ int array[] = { A, B, RESTRICT_ARGS_COUNT(C, 3, B_MACRO, ##__VA_ARGS__) }; /* Count the args in a list */ #define NUM_ARGS(...) (sizeof((int[])__VA_ARGS__)/sizeof(int)) + +// Macro MAKE_TEMPLATE_SIGNATURE(...) wraps arguments 2..last in a template +// signature like 'template' only if it is passed more +// than one argument. Otherwise it generates an empty string. +// +#define MAKE_TEMPLATE_SIGNATURE(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(MAKE_TEMPLATE_SIGNATURE_, UNUSED,##__VA_ARGS__) +#define MAKE_TEMPLATE_SIGNATURE_0(...) +#define MAKE_TEMPLATE_SIGNATURE_1(...) template<__VA_ARGS__> + +// Macro ADD_TEMPLATE_BRACES(...) wraps arguments 2..last in angle brackets +// only if it is passed more than one argument. Otherwise it generates an +// empty string. +// +#define ADD_TEMPLATE_BRACES(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(ADD_TEMPLATE_BRACES_, UNUSED,##__VA_ARGS__) +#define ADD_TEMPLATE_BRACES_0(...) +#define ADD_TEMPLATE_BRACES_1(...) <__VA_ARGS__> + +// Macro TEMPLATE_KEYWORD(...) generates the 'template' keyword only if it is +// passed more than one argument. +// +#define TEMPLATE_KEYWORD(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(TEMPLATE_KEYWORD_, UNUSED,##__VA_ARGS__) +#define TEMPLATE_KEYWORD_0(...) +#define TEMPLATE_KEYWORD_1(...) template + +// Helper macros for template parameter list treatment + +#define GLUE2_AUX(...) GLUE2(__VA_ARGS__) + +#define TEST1(UNUSED, A, B, C, D, \ + E, F, G, H, \ + I, J, K, L, \ + M, N, O, P, \ + Q, ...) Q +#define TEST(...) TEST1(__VA_ARGS__) +#define CHOICE(UNUSED, ...) ,##__VA_ARGS__, 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 0 +#define SELECT_ON_EMPTY_SIGNATURE(MACRO_BASE_NAME, UNUSED, ...) \ + GLUE2_AUX( \ + MACRO_BASE_NAME, \ + TEST(CHOICE(1,##__VA_ARGS__)) \ + )(__VA_ARGS__) diff --git a/src/kaleidoscope_internal/LEDModeManager.h b/src/kaleidoscope_internal/LEDModeManager.h index 2c93fccd35..a1277f7875 100644 --- a/src/kaleidoscope_internal/LEDModeManager.h +++ b/src/kaleidoscope_internal/LEDModeManager.h @@ -82,7 +82,9 @@ inline void registerLEDModeActivated(Bool2Type, // Noop } -DEFINE_HAS_METHOD_TRAITS(Plugin, registerLEDModeActivated, void, (uint8_t led_mode_id)) +DEFINE_HAS_METHOD_TRAITS(Plugin, + /* registerLEDModeActivated not templated */ (), (), + registerLEDModeActivated, void, (uint8_t led_mode_id)) // A templated implementation of LEDModeFactoryFunc. // diff --git a/src/kaleidoscope_internal/event_dispatch.h b/src/kaleidoscope_internal/event_dispatch.h index a93a024fcd..4186c6ae2b 100644 --- a/src/kaleidoscope_internal/event_dispatch.h +++ b/src/kaleidoscope_internal/event_dispatch.h @@ -38,6 +38,7 @@ #include "kaleidoscope/hooks.h" #include "kaleidoscope_internal/eventhandler_signature_check.h" #include "kaleidoscope/event_handlers.h" +#include "kaleidoscope_internal/keymap_exploration.h" // Some words about the design of hook routing: // @@ -79,40 +80,48 @@ #define _REGISTER_EVENT_HANDLER( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) __NL__ \ __NL__ \ namespace kaleidoscope_internal { __NL__ \ __NL__ \ template __NL__ \ + typename Plugin__ __NL__ \ + UNWRAP TMPL_PARAM_TYPE_LIST /* may evaluate empty */ __NL__ \ + , typename... Args__> __NL__ \ struct _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) { __NL__ \ static DEPRECATION_TAG kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &plugin, Args__&&... hook_args) { __NL__ \ - return plugin.HOOK_NAME(hook_args...); __NL__ \ + return plugin.TEMPLATE_KEYWORD(UNWRAP TMPL_PARAM_LIST) HOOK_NAME __NL__ \ + ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + (hook_args...); __NL__ \ } __NL__ \ }; __NL__ \ __NL__ \ /* This specialization is used for those hooks that a plugin does not __NL__ \ * implement. __NL__ \ */ __NL__ \ - template __NL__ \ + template __NL__ \ struct _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) __NL__ \ - { __NL__ \ + { __NL__ \ static kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &/*plugin*/, Args__&&... /*hook_args*/) { __NL__ \ return kaleidoscope::EventHandlerResult::OK; __NL__ \ } __NL__ \ }; __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ struct _NAME4(EventHandler_, HOOK_NAME, _v, HOOK_VERSION) { __NL__ \ __NL__ \ static bool shouldAbortOnConsumedEvent() { __NL__ \ return SHOULD_ABORT_ON_CONSUMED_EVENT; __NL__ \ } __NL__ \ __NL__ \ - template __NL__ \ + template __NL__ \ static kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &plugin, Args__&&... hook_args) { __NL__ \ __NL__ \ @@ -129,8 +138,9 @@ typedef _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) __NL__ \ < __NL__ \ derived_implements_hook, __NL__ \ - Plugin__, __NL__ \ - Args__... __NL__ \ + Plugin__ __NL__ \ + UNWRAP TMPL_PARAM_LIST __NL__ \ + , Args__... __NL__ \ > Caller; __NL__ \ __NL__ \ return Caller::call(plugin, hook_args...); __NL__ \ @@ -141,11 +151,13 @@ __NL__ \ namespace kaleidoscope { __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ EventHandlerResult Hooks::HOOK_NAME SIGNATURE { __NL__ \ return kaleidoscope_internal::EventDispatcher::template __NL__ \ apply __NL__ \ - ARGS_LIST; __NL__ \ + ::_NAME4(EventHandler_, HOOK_NAME, _v, HOOK_VERSION) __NL__ \ + ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + >ARGS_LIST; __NL__ \ } __NL__ \ __NL__ \ } diff --git a/src/kaleidoscope_internal/eventhandler_signature_check.h b/src/kaleidoscope_internal/eventhandler_signature_check.h index 97ac9c891b..5fdf3c31ef 100644 --- a/src/kaleidoscope_internal/eventhandler_signature_check.h +++ b/src/kaleidoscope_internal/eventhandler_signature_check.h @@ -92,13 +92,17 @@ template struct #define _DEFINE_IMPLEMENTATION_CHECK_CLASS_SPECIALIZATION( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) \ \ /* We use the generalized traits class found in header has_method.h __NL__ \ * to do check if a plugin defines a hook method with a specific __NL__ \ * signature. __NL__ \ */ __NL__ \ - DEFINE_HAS_METHOD_TRAITS(GLUE2(Plugin, HOOK_VERSION), HOOK_NAME, __NL__ \ + DEFINE_HAS_METHOD_TRAITS(GLUE2(Plugin, HOOK_VERSION), __NL__ \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, __NL__ \ + HOOK_NAME, __NL__ \ kaleidoscope::EventHandlerResult, __NL__ \ SIGNATURE) __NL__ \ __NL__ \ @@ -107,7 +111,8 @@ template struct */ __NL__ \ template __NL__ \ struct HookVersionImplemented_##HOOK_NAME __NL__ \ - : public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME) __NL__ \ + : public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME) __NL__ \ + __NL__ \ {}; #define _PREPARE_EVENT_HANDLER_SIGNATURE_CHECK_START(HOOK_NAME, ...) \ diff --git a/src/kaleidoscope_internal/type_traits/has_method.h b/src/kaleidoscope_internal/type_traits/has_method.h index 3051deca09..11431ced21 100644 --- a/src/kaleidoscope_internal/type_traits/has_method.h +++ b/src/kaleidoscope_internal/type_traits/has_method.h @@ -18,13 +18,15 @@ #include "kaleidoscope/macro_helpers.h" -#define DEFINE_HAS_METHOD_TRAITS(PREFIX, METHOD_NAME, \ +#define DEFINE_HAS_METHOD_TRAITS(PREFIX, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, \ + METHOD_NAME, \ RETURN_TYPE, ARGUMENTS) \ __NL__ \ /* This traits checks if a class of type Class__ __NL__ \ * implements a method with given signature. __NL__ \ */ __NL__ \ - template __NL__ \ + template __NL__ \ struct GLUE3(PREFIX, _HasMethod_, METHOD_NAME) __NL__ \ { __NL__ \ /* Define a pointer to member function with the correct __NL__ \ @@ -55,7 +57,10 @@ * (SFINAE = substitution failure is not an error) __NL__ \ * and the test(...) overload is used instead. __NL__ \ */ __NL__ \ - static_cast(&ClassAux__::METHOD_NAME), bool{} __NL__ \ + static_cast( __NL__ \ + &ClassAux__::TEMPLATE_KEYWORD(UNWRAP TMPL_PARAM_LIST) __NL__ \ + METHOD_NAME ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + ), bool{} __NL__ \ ) __NL__ \ test(int /* unused */) __NL__ \ { __NL__ \ From a538328ba2f702595abb3b203868942467cf83b5 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Thu, 28 Nov 2019 18:42:15 +0100 Subject: [PATCH 25/26] Added sketch exploration This commit adds a new template hook exploreSketch() that allows plugins to efficiently obtain compile-time known information about the sketch. The hook is called before setup and is passed a _Sketch template parameter that wraps two more types Plugins and StaticKeymap, whose static constexpr methods can be used to explore the registered plugins and the static keymap. Signed-off-by: Florian Fleissner --- examples/Internal/Sketch_Exploration/Makefile | 55 ++++ .../Sketch_Exploration/Sketch_Exploration.ino | 139 ++++++++++ src/kaleidoscope/Kaleidoscope.cpp | 1 + src/kaleidoscope/Kaleidoscope.h | 1 + src/kaleidoscope/event_handlers.h | 20 +- src/kaleidoscope/hooks.cpp | 14 + src/kaleidoscope/hooks.h | 5 + src/kaleidoscope/layers.h | 5 +- src/kaleidoscope_internal/event_dispatch.h | 6 +- .../sketch_exploration/keymap_exploration.h | 256 ++++++++++++++++++ .../sketch_exploration/plugin_exploration.h | 185 +++++++++++++ .../sketch_exploration/sketch_exploration.h | 71 +++++ 12 files changed, 753 insertions(+), 5 deletions(-) create mode 100644 examples/Internal/Sketch_Exploration/Makefile create mode 100644 examples/Internal/Sketch_Exploration/Sketch_Exploration.ino create mode 100644 src/kaleidoscope_internal/sketch_exploration/keymap_exploration.h create mode 100644 src/kaleidoscope_internal/sketch_exploration/plugin_exploration.h create mode 100644 src/kaleidoscope_internal/sketch_exploration/sketch_exploration.h diff --git a/examples/Internal/Sketch_Exploration/Makefile b/examples/Internal/Sketch_Exploration/Makefile new file mode 100644 index 0000000000..996bde9889 --- /dev/null +++ b/examples/Internal/Sketch_Exploration/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/examples/Internal/Sketch_Exploration/Sketch_Exploration.ino b/examples/Internal/Sketch_Exploration/Sketch_Exploration.ino new file mode 100644 index 0000000000..443a9cd76e --- /dev/null +++ b/examples/Internal/Sketch_Exploration/Sketch_Exploration.ino @@ -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 . + */ + +#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 + 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::value, ""); + static_assert(std::is_same::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(); +} diff --git a/src/kaleidoscope/Kaleidoscope.cpp b/src/kaleidoscope/Kaleidoscope.cpp index 02a7aaafd1..2ce2dfca22 100644 --- a/src/kaleidoscope/Kaleidoscope.cpp +++ b/src/kaleidoscope/Kaleidoscope.cpp @@ -36,6 +36,7 @@ Kaleidoscope_::setup(void) { // properly. device().serialPort().begin(9600); + kaleidoscope::sketch_exploration::pluginsExploreSketch(); kaleidoscope::Hooks::onSetup(); device().setup(); diff --git a/src/kaleidoscope/Kaleidoscope.h b/src/kaleidoscope/Kaleidoscope.h index b588cdd5a0..9b7dbe53dd 100644 --- a/src/kaleidoscope/Kaleidoscope.h +++ b/src/kaleidoscope/Kaleidoscope.h @@ -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" diff --git a/src/kaleidoscope/event_handlers.h b/src/kaleidoscope/event_handlers.h index b35985d78f..6b13f4de2f 100644 --- a/src/kaleidoscope/event_handlers.h +++ b/src/kaleidoscope/event_handlers.h @@ -220,7 +220,19 @@ class SignatureCheckDummy {}; _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ (),(),(), /* non template */ __NL__ \ - (),(),##__VA_ARGS__) + (),(),##__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 @@ -273,4 +285,8 @@ class SignatureCheckDummy {}; __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) diff --git a/src/kaleidoscope/hooks.cpp b/src/kaleidoscope/hooks.cpp index 9ad71c5075..929aa8e8ca 100644 --- a/src/kaleidoscope/hooks.cpp +++ b/src/kaleidoscope/hooks.cpp @@ -45,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 +() { + return EventHandlerResult::OK; +}; + } // namespace kaleidoscope diff --git a/src/kaleidoscope/hooks.h b/src/kaleidoscope/hooks.h index 012196ccec..5ea358c108 100644 --- a/src/kaleidoscope/hooks.h +++ b/src/kaleidoscope/hooks.h @@ -41,6 +41,10 @@ class LEDControl; // Forward declaration to enable friend declarations. class Layer_; +namespace sketch_exploration { +void pluginsExploreSketch(); +} // namespace sketch_exploration + // The reason why the hook routing entry point functions live within // class Hooks and not directly within a namespace is, that we want // to restrict who is allowed to trigger hooks, mainly to prevent @@ -60,6 +64,7 @@ class Hooks { friend class Kaleidoscope_; friend class ::kaleidoscope::Layer_; friend class ::kaleidoscope::plugin::LEDControl; + friend void ::kaleidoscope::sketch_exploration::pluginsExploreSketch(); // ::handleKeyswitchEvent(...) calls Hooks::onKeyswitchEvent. friend void ::handleKeyswitchEvent(kaleidoscope::Key mappedKey, diff --git a/src/kaleidoscope/layers.h b/src/kaleidoscope/layers.h index aaa6762f8a..c4e258bc45 100644 --- a/src/kaleidoscope/layers.h +++ b/src/kaleidoscope/layers.h @@ -21,6 +21,7 @@ #include "kaleidoscope/keymaps.h" #include "kaleidoscope/device/device.h" #include "kaleidoscope_internal/device.h" +#include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h" // Macro for defining the keymap. This should be used in the sketch // file (*.ino) to define the keymap[] array that holds the user's @@ -33,7 +34,9 @@ /* This deprecated compatibility wrapper is removed by the linker if __NL__ \ it is not accessed nowhere. __NL__ \ */ __NL__ \ - kaleidoscope::internal::Keymaps2DInterface keymaps; + kaleidoscope::internal::Keymaps2DInterface keymaps; __NL__ \ + __NL__ \ + _INIT_SKETCH_EXPLORATION extern uint8_t layer_count; diff --git a/src/kaleidoscope_internal/event_dispatch.h b/src/kaleidoscope_internal/event_dispatch.h index 4186c6ae2b..be51e7aa40 100644 --- a/src/kaleidoscope_internal/event_dispatch.h +++ b/src/kaleidoscope_internal/event_dispatch.h @@ -38,7 +38,7 @@ #include "kaleidoscope/hooks.h" #include "kaleidoscope_internal/eventhandler_signature_check.h" #include "kaleidoscope/event_handlers.h" -#include "kaleidoscope_internal/keymap_exploration.h" +#include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h" // Some words about the design of hook routing: // @@ -214,4 +214,6 @@ __NL__ \ /* This generates a PROGMEM array-kind-of data structure that contains */ __NL__ \ /* LEDModeFactory entries */ __NL__ \ - _INIT_LED_MODE_MANAGER(__VA_ARGS__) + _INIT_LED_MODE_MANAGER(__VA_ARGS__) __NL__ \ + __NL__ \ + _INIT_PLUGIN_EXPLORATION(__VA_ARGS__) diff --git a/src/kaleidoscope_internal/sketch_exploration/keymap_exploration.h b/src/kaleidoscope_internal/sketch_exploration/keymap_exploration.h new file mode 100644 index 0000000000..2f3ef23bfd --- /dev/null +++ b/src/kaleidoscope_internal/sketch_exploration/keymap_exploration.h @@ -0,0 +1,256 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#include "kaleidoscope/key_defs.h" + +namespace kaleidoscope { +namespace sketch_exploration { + +// A simple keymap adaptor class that makes the keymap conveniently accessible. +// at compiletime. +// +template +class KeymapAdaptor { + private: + + const Key(&keymap_)[_n_layers][_layer_size]; + + public: + + static constexpr uint8_t n_layers = _n_layers; + static constexpr uint8_t layer_size = _layer_size; + + constexpr KeymapAdaptor(const Key(&keymap)[_n_layers][_layer_size]) + : keymap_{keymap} + {} + + constexpr Key getKey(uint8_t layer, uint8_t offset) { + return keymap_[layer][offset]; + } + constexpr Key getKey(uint8_t layer, KeyAddr key_addr) { + return this->getKey(layer, key_addr.toInt()); + } +}; + +// This class implements compile time keymap traversal. +// +// Every key is visited an the _Accumulation functor decides on how +// the key's value affects the overal return value (accumulation). +// +template +class AccumulationHelper : public KeymapAdaptor<_n_layers, _layer_size> { + private: + + const _Accumulation &op_; + + private: + + typedef typename _Accumulation::ResultType ResultType; + + constexpr ResultType accumulateOnLayer(uint8_t layer, uint8_t offset) { + return (offset >= _layer_size) + ? op_.init_value + : op_.apply(this->getKey(layer, offset), + this->accumulateOnLayer(layer, offset + 1)); + } + + constexpr ResultType accumulate(uint8_t layer) { + return (layer >= _n_layers) + ? op_.init_value + : op_.apply(this->accumulateOnLayer(layer, 0), + this->accumulate(layer + 1)); + } + + public: + + typedef KeymapAdaptor<_n_layers, _layer_size> ParentType; + + constexpr AccumulationHelper(const Key(&keymap)[_n_layers][_layer_size], + const _Accumulation &op) + : ParentType{keymap}, + op_{op} + {} + + constexpr ResultType apply() { + return this->accumulate(0); + } +}; + +// Accumulation functors to be used with the KeymapInterface's collect +// method. +// +// Plugins can implement their own functors to request other types of +// information + +struct MaxKeyRaw { + typedef Key ResultType; + static constexpr ResultType init_value = 0; + + constexpr ResultType apply(Key k1, Key k2) { + return (k1 > k2) ? k1 : k2; + } +}; + +struct NumKeysEqual { + typedef uint8_t ResultType; + static constexpr ResultType init_value = 0; + + constexpr NumKeysEqual(Key k) : k_{k} {} + + constexpr ResultType apply(Key test_key, ResultType r) { + return (test_key == k_) ? r + 1 : r; + } + constexpr ResultType apply(ResultType r1, ResultType r2) { + return r1 + r2; + } + + Key k_; +}; + +struct HasKey { + typedef bool ResultType; + static constexpr ResultType init_value = false; + + constexpr HasKey(Key k) : k_{k} {} + + constexpr ResultType apply(Key test_key, ResultType r) { + return (test_key == k_) ? true : r; + } + constexpr ResultType apply(ResultType r1, ResultType r2) { + return r1 || r2; + } + + Key k_; +}; + +// This class is actually defined and implemented in _INIT_KEYMAP_EXPLORATION +// which is invoked by KALEIDOSCOPE_INIT_PLUGINS +// +class KeymapInterface; + +extern void pluginsExploreSketch(); + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// Read carefully +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// +// About compile-time-only functions (COMPILE_TIME_USE_ONLY) +// +// On Harvard architecture an array like the Kaleidoscope keymap +// that is declared 'constexpr PROGMEM' must either be accessed +// by a runtime function through functions like pgm_read_byte +// or at compile time with ordinary array access. Using normal array +// access at run-time will cause a memory access failures as the MCU +// will try to read from SRAM instead of PROGMEM. +// +// There are some functions that are therefore restricted to compile-time +// use and will fail if instantiated by the compiler. There is no language +// inherent means to prevent the latter. Therefore, we flag all such functions +// as +// +// COMPILE_TIME_USE_ONLY +// +// Call such functions consistently as +// +// constexpr auto val = aCompileTimeOnlyFunction(...); +// +// This ensures that they can not be instantiated and called at runtime. +// +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// This macro defines a Sketch interface class that is passed to the +// exploreSketch<_Sketch>(...)-hook. +// +#define _INIT_KEYMAP_EXPLORATION \ + namespace kaleidoscope { \ + namespace sketch_exploration { \ + class StaticKeymap \ + { \ + private: \ + \ + template \ + static constexpr auto accumulationHelper( \ + const Key (&keymap)[_n_layers][_layer_size], \ + const _Accumulation &op) \ + -> AccumulationHelper<_n_layers, _layer_size, _Accumulation> \ + { \ + return AccumulationHelper<_n_layers, _layer_size, \ + _Accumulation>{keymap, op}; \ + } \ + \ + template \ + static constexpr auto accumulationHelper(const _Accumulation &op) \ + -> decltype(accumulationHelper(::keymaps_linear, op)) \ + { \ + return accumulationHelper(::keymaps_linear, op); \ + } \ + \ + template \ + static constexpr auto keymapAdaptor( \ + const Key (&keymap)[_n_layers][_layer_size]) \ + -> KeymapAdaptor<_n_layers, _layer_size> \ + { \ + return KeymapAdaptor<_n_layers, _layer_size>{keymap}; \ + } \ + \ + static constexpr auto keymapAdaptor() \ + -> decltype(keymapAdaptor(::keymaps_linear)) \ + { \ + return keymapAdaptor(::keymaps_linear); \ + } \ + \ + public: \ + \ + /* COMPILE_TIME_USE_ONLY (see explanation above) \ + * \ + * The collect function visits all keys in the keymap and generates \ + * a result based on the requirements that are defined by the \ + * _Accumulation functor op. \ + * \ + * This approach is necessary as there is currently (c++11) no \ + * language feature available that would enable compile time iterative \ + * traversal of arrays like the keymap. \ + * \ + * Examples for an accumulation could e.g. be the number of occurences \ + * of a specific key or if a key is present at all... \ + */ \ + template \ + static constexpr auto collect(const _Accumulation &op) \ + -> typename _Accumulation::ResultType \ + { \ + return accumulationHelper(op).apply(); \ + } \ + \ + /* COMPILE_TIME_USE_ONLY (see explanation above) \ + */ \ + static constexpr Key getKey(uint8_t layer, KeyAddr key_addr) { \ + return keymapAdaptor().getKey(layer, key_addr); \ + } \ + \ + static constexpr uint8_t nLayers() { \ + return keymapAdaptor().n_layers; \ + } \ + static constexpr uint8_t layerSize() { \ + return keymapAdaptor().layer_size; \ + } \ + }; \ + } /* namespace sketch_exploration */ \ + } /* namespace kaleidoscope */ + +} // namespace sketch_exploration +} // namespace kaleidoscope diff --git a/src/kaleidoscope_internal/sketch_exploration/plugin_exploration.h b/src/kaleidoscope_internal/sketch_exploration/plugin_exploration.h new file mode 100644 index 0000000000..afb20bb6b2 --- /dev/null +++ b/src/kaleidoscope_internal/sketch_exploration/plugin_exploration.h @@ -0,0 +1,185 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#include "kaleidoscope_internal/type_traits/type_traits" + +namespace kaleidoscope { +namespace sketch_exploration { + +struct EmptyPluginTypeList { + typedef void Plugin; + typedef EmptyPluginTypeList Next; + static constexpr int size = 0; + static constexpr bool is_last = true; +}; + +template +struct BareType { + typedef typename std::remove_const < + typename std::remove_reference<_T>::type + >::type Type; +}; + +template +struct PluginTypeList { + typedef typename BareType<_Plugin>::Type Plugin; + + static constexpr int id = _id; + + typedef PluginTypeList < _id + 1, _MorePlugins... > Next; + + static constexpr int size = 1 + Next::size; + static constexpr bool is_last = false; +}; + +template +struct PluginTypeList<_id, _Plugin> { + typedef typename BareType<_Plugin>::Type Plugin; + + static constexpr int id = _id; + + typedef EmptyPluginTypeList Next; + + static constexpr int size = 1; + static constexpr bool is_last = true; +}; + +template +auto makePluginTypeList(const _Plugins&...p) -> PluginTypeList<0, _Plugins...> {} + +template +struct Entry { + typedef typename Entry < _PluginTypeList, _id - 1 >::Next::Plugin Type; + typedef typename Entry < _PluginTypeList, _id - 1 >::Next::Next Next; + + static constexpr int id = Entry < _PluginTypeList, _id - 1 >::id + 1; + static_assert(id == _id, ""); + + static constexpr bool is_last = Entry < _PluginTypeList, _id - 1 >::Next::is_last; +}; + +template +struct Entry<_PluginTypeList, 0> { + typedef typename _PluginTypeList::Plugin Type; + typedef typename _PluginTypeList::Next Next; + + static constexpr int id = 0; + static constexpr bool is_last = _PluginTypeList::is_last; +}; + +template +struct OccurrencesAux { + static constexpr int value = + (std::is_same::Type, _WantedPlugin>::value) + ? OccurrencesAux < _PluginTypeList, _WantedPlugin, _id - 1 >::value + 1 + : OccurrencesAux < _PluginTypeList, _WantedPlugin, _id - 1 >::value; +}; + +template +struct OccurrencesAux<_PluginTypeList, _WantedPlugin, 0> { + static constexpr int value + = (std::is_same::Type, _WantedPlugin>::value) + ? 1 + : 0; +}; + +template +struct Occurrences + : public OccurrencesAux < _PluginTypeList, _WantedPlugin, _PluginTypeList::size - 1 > {}; + +template +struct PluginPositionAux { + static constexpr int value = + (PluginPositionAux < _PluginTypeList, _WantedPlugin, _id - 1 >::value != -1) + ? PluginPositionAux < _PluginTypeList, _WantedPlugin, _id - 1 >::value + : (std::is_same::Type, _WantedPlugin>::value) + ? _id + : -1; +}; + +template +struct PluginPositionAux<_PluginTypeList, _WantedPlugin, 0> { + static constexpr int value + = (std::is_same::Type, _WantedPlugin>::value) + ? 0 + : -1; +}; + +template +struct PluginPosition + : public PluginPositionAux < _PluginTypeList, _WantedPlugin, _PluginTypeList::size - 1 > {}; + +template +struct IsRegistered { + static constexpr bool value + = (PluginPosition<_PluginTypeList, _WantedPlugin>::value != -1); +}; + +template +struct Plugins__ { + + static constexpr int size = _PluginTypeList::size; + + // C++11 does not allow for template specialization to havven + // in non-namespace scope. Thus, we define those templates + // in namespace scope and then using declare their types here. + // + template + using Entry = Entry<_PluginTypeList, _id>; + + template + using Position = PluginPosition<_PluginTypeList, _PluginType>; + + template + using IsRegistered = IsRegistered<_PluginTypeList, _PluginType>; + + template + using Occurrences = Occurrences<_PluginTypeList, _PluginType>; +}; + +} // namespace sketch_exploration +} // namespace kaleidoscope + +#define _FIX_PLUGIN_TYPE_AND_NAME_AMBIGUITIES(T) T + +#define _INIT_PLUGIN_EXPLORATION(...) \ + \ + /* We have to define this type list in global namespace as some plugins \ + * exhibit ambiguities between their type name and the name of \ + * their global instance :( \ + */ \ + typedef decltype( \ + kaleidoscope::sketch_exploration::makePluginTypeList( __VA_ARGS__) \ + ) Kaleidoscope_SketchExploration__ConcretePluginTypeList; \ + \ + namespace kaleidoscope { \ + namespace sketch_exploration { \ + class Plugins : public Plugins__< \ + Kaleidoscope_SketchExploration__ConcretePluginTypeList> {}; \ + } /* namespace sketch_exploration */ \ + } /* namespace kaleidoscope */ + +// Convenience macro that deal with the ugly typedef and typename stuff... +// +#define ENTRY_TYPE(PLUGINS, ID) \ + typename PLUGINS::template Entry::Type + +#define ENRTY_IS_LAST(PLUGINS, ID) PLUGINS::template Entry::is_last +#define PLUGIN_POSITION(PLUGINS, TYPE) PLUGINS::template Position::value +#define PLUGIN_IS_REGISTERED(PLUGINS, TYPE) PLUGINS::template IsRegistered::value +#define NUM_OCCURRENCES(PLUGINS, TYPE) PLUGINS::template Occurrences::value diff --git a/src/kaleidoscope_internal/sketch_exploration/sketch_exploration.h b/src/kaleidoscope_internal/sketch_exploration/sketch_exploration.h new file mode 100644 index 0000000000..9fd9b5adbe --- /dev/null +++ b/src/kaleidoscope_internal/sketch_exploration/sketch_exploration.h @@ -0,0 +1,71 @@ +/* Kaleidoscope - Firmware for computer input devices + * Copyright (C) 2013-2019 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 . + */ + +#pragma once + +#include "kaleidoscope_internal/sketch_exploration/keymap_exploration.h" +#include "kaleidoscope_internal/sketch_exploration/plugin_exploration.h" + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// Read carefully +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// +// About compile-time-only functions (COMPILE_TIME_USE_ONLY) +// +// On Harvard architecture an array like the Kaleidoscope keymap +// that is declared 'constexpr PROGMEM' must either be accessed +// by a runtime function through functions like pgm_read_byte +// or at compile time with ordinary array access. Using normal array +// access at run-time will cause a memory access failures as the MCU +// will try to read from SRAM instead of PROGMEM. +// +// There are some functions that are therefore restricted to compile-time +// use and will fail if instantiated by the compiler. There is no language +// inherent means to prevent the latter. Therefore, we flag all such functions +// as +// +// COMPILE_TIME_USE_ONLY +// +// Call such functions consistently as +// +// constexpr auto val = aCompileTimeOnlyFunction(...); +// +// This ensures that they can not be instantiated and called at runtime. +// +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// This macro defines a Sketch interface class that is passed to the +// exploreSketch<_Sketch>(...)-hook. +// +#define _INIT_SKETCH_EXPLORATION \ + \ + _INIT_KEYMAP_EXPLORATION \ + \ + namespace kaleidoscope { \ + namespace sketch_exploration { \ + \ + class Plugins; \ + \ + struct Sketch { \ + typedef sketch_exploration::StaticKeymap StaticKeymap; \ + typedef sketch_exploration::Plugins Plugins; \ + }; \ + \ + void pluginsExploreSketch() { \ + Hooks::exploreSketch(); \ + } \ + } /* namespace sketch_exploration */ \ + } /* namespace kaleidoscope */ From 2c5f4a78a23cc247338c7996b43ab34731928941 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 29 Nov 2019 12:55:40 +0100 Subject: [PATCH 26/26] New device: Dygma Raise This implements a new device plugin, to drive the Dygma Raise. A few helpers are also introduces, which are used by the Raise only for now, but are generic enough so that eventually, other boards may use them too. Signed-off-by: Gergely Nagy --- src/Kaleidoscope-Hardware-Dygma-Raise.h | 21 + src/kaleidoscope/device/dygma/Raise.cpp | 515 ++++++++++++++++++ src/kaleidoscope/device/dygma/Raise.h | 272 +++++++++ src/kaleidoscope/device/dygma/raise/Focus.cpp | 133 +++++ src/kaleidoscope/device/dygma/raise/Focus.h | 42 ++ src/kaleidoscope/device/dygma/raise/Hand.cpp | 254 +++++++++ src/kaleidoscope/device/dygma/raise/Hand.h | 105 ++++ .../device/dygma/raise/SideFlash.h | 84 +++ src/kaleidoscope/device/dygma/raise/TWI.cpp | 99 ++++ src/kaleidoscope/device/dygma/raise/TWI.h | 49 ++ .../driver/color/GammaCorrection.h | 47 ++ src/kaleidoscope/util/crc16.h | 94 ++++ src/kaleidoscope/util/flasher/Base.h | 60 ++ .../util/flasher/KeyboardioI2CBootloader.h | 226 ++++++++ 14 files changed, 2001 insertions(+) create mode 100644 src/Kaleidoscope-Hardware-Dygma-Raise.h create mode 100644 src/kaleidoscope/device/dygma/Raise.cpp create mode 100644 src/kaleidoscope/device/dygma/Raise.h create mode 100644 src/kaleidoscope/device/dygma/raise/Focus.cpp create mode 100644 src/kaleidoscope/device/dygma/raise/Focus.h create mode 100644 src/kaleidoscope/device/dygma/raise/Hand.cpp create mode 100644 src/kaleidoscope/device/dygma/raise/Hand.h create mode 100644 src/kaleidoscope/device/dygma/raise/SideFlash.h create mode 100644 src/kaleidoscope/device/dygma/raise/TWI.cpp create mode 100644 src/kaleidoscope/device/dygma/raise/TWI.h create mode 100644 src/kaleidoscope/driver/color/GammaCorrection.h create mode 100644 src/kaleidoscope/util/crc16.h create mode 100644 src/kaleidoscope/util/flasher/Base.h create mode 100644 src/kaleidoscope/util/flasher/KeyboardioI2CBootloader.h diff --git a/src/Kaleidoscope-Hardware-Dygma-Raise.h b/src/Kaleidoscope-Hardware-Dygma-Raise.h new file mode 100644 index 0000000000..f87b9f878a --- /dev/null +++ b/src/Kaleidoscope-Hardware-Dygma-Raise.h @@ -0,0 +1,21 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 "kaleidoscope/device/dygma/Raise.h" diff --git a/src/kaleidoscope/device/dygma/Raise.cpp b/src/kaleidoscope/device/dygma/Raise.cpp new file mode 100644 index 0000000000..45f134b7a7 --- /dev/null +++ b/src/kaleidoscope/device/dygma/Raise.cpp @@ -0,0 +1,515 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 ARDUINO_SAMD_RAISE + +#include +#include +#include +#include +#include + +#include "kaleidoscope/util/crc16.h" +#include "kaleidoscope/driver/color/GammaCorrection.h" + +#define I2C_CLOCK_KHZ 200 +#define I2C_FLASH_CLOCK_KHZ 100 // flashing doesn't work reliably at higher clock speeds + +#define SIDE_POWER 1 // side power switch pa10 + +#define LAYOUT_ISO 0 +#define LAYOUT_ANSI 1 + +namespace kaleidoscope { +namespace device { +namespace dygma { + +/********* RaiseHands *********/ + +struct RaiseHands { + static raise::Hand leftHand; + static raise::Hand rightHand; + + static void setup(); + static void initializeSides(); + + static uint8_t layout; + + static void setSidePower(bool power); + static bool getSidePower() { + return side_power_; + } + + static void keyscanInterval(uint16_t interval); + static uint16_t keyscanInterval() { + return keyscan_interval_; + } + + private: + static uint16_t keyscan_interval_; + static bool side_power_; + static uint16_t settings_base_; + static constexpr uint8_t iso_only_led_ = 19; +}; + +raise::Hand RaiseHands::leftHand(0); +raise::Hand RaiseHands::rightHand(1); +uint8_t RaiseHands::layout; +bool RaiseHands::side_power_; +uint16_t RaiseHands::settings_base_; +uint16_t RaiseHands::keyscan_interval_ = 50; + +void RaiseHands::setSidePower(bool power) { + digitalWrite(SIDE_POWER, power ? HIGH : LOW); + side_power_ = power; +} + +void RaiseHands::setup() { + settings_base_ = ::EEPROMSettings.requestSlice(sizeof(keyscan_interval_)); + + // If keyscan is max, assume that EEPROM is uninitialized, and store the + // defaults. + uint16_t interval; + Kaleidoscope.storage().get(settings_base_, interval); + if (interval == 0xffff) { + Kaleidoscope.storage().put(settings_base_, keyscan_interval_); + Kaleidoscope.storage().commit(); + } + Kaleidoscope.storage().get(settings_base_, keyscan_interval_); +} + +void RaiseHands::keyscanInterval(uint16_t interval) { + leftHand.setKeyscanInterval(interval); + rightHand.setKeyscanInterval(interval); + keyscan_interval_ = interval; + Kaleidoscope.storage().put(settings_base_, keyscan_interval_); + Kaleidoscope.storage().commit(); +} + +void RaiseHands::initializeSides() { + // key scan interval from eeprom + leftHand.setKeyscanInterval(keyscan_interval_); + rightHand.setKeyscanInterval(keyscan_interval_); + + // get ANSI/ISO at every side replug + uint8_t l_layout = leftHand.readLayout(); + uint8_t r_layout = rightHand.readLayout(); + + // setup layout variable, this will affect led mapping - defaults to ISO if + // nothing reported + // FIXME + if (l_layout == 1 || r_layout == 1) + layout = 1; + else + layout = 0; + + /* + * if the neuron starts up with no sides connected, it will assume ISO. This + * turns on an extra LED (hardware LED 19 on left side). If an ANSI left is + * then plugged in, the keyboard will switch to ANSI, but LED 19 can't get + * wiped because the ANSI LED map doesn't include this LED. It will be driven + * from the SLED1735's memory with the same colour as before, which causes + * weird looking colours to come on on other seemingly unrelated keys. So: on + * a replug, set LED 19 to off to be safe. + */ + leftHand.led_data.leds[iso_only_led_] = {0, 0, 0}; + + // get activated LED plugin to refresh + ::LEDControl.refreshAll(); +} + +/********* LED Driver *********/ + +bool RaiseLEDDriver::isLEDChangedNeuron; +uint8_t RaiseLEDDriver::isLEDChangedLeft[LED_BANKS]; +uint8_t RaiseLEDDriver::isLEDChangedRight[LED_BANKS]; +cRGB RaiseLEDDriver::neuronLED; +constexpr uint8_t RaiseLEDDriver::led_map[][RaiseLEDDriverProps::led_count + 1]; + +constexpr uint8_t RaiseLEDDriverProps::key_led_map[]; + +void RaiseLEDDriver::syncLeds() { + // left and right sides + for (uint8_t i = 0; i < LED_BANKS; i ++) { + // only send the banks that have changed - try to improve jitter performance + if (isLEDChangedLeft[i]) { + RaiseHands::leftHand.sendLEDBank(i); + isLEDChangedLeft[i] = false; + } + if (isLEDChangedRight[i]) { + RaiseHands::rightHand.sendLEDBank(i); + isLEDChangedRight[i] = false; + } + } + + if (isLEDChangedNeuron) { + updateNeuronLED(); + isLEDChangedNeuron = false; + } +} + +void RaiseLEDDriver::updateNeuronLED() { + static constexpr struct { + uint8_t r, g, b; + } pins = { 3, 5, 4 }; + auto constexpr gamma8 = kaleidoscope::driver::color::gamma_correction; + + // invert as these are common anode, and make sure we reach 65535 to be able + // to turn fully off. + analogWrite(pins.r, ((256 - pgm_read_byte(&gamma8[neuronLED.r])) << 8) - 1); + analogWrite(pins.g, ((256 - pgm_read_byte(&gamma8[neuronLED.g])) << 8) - 1); + analogWrite(pins.b, ((256 - pgm_read_byte(&gamma8[neuronLED.b])) << 8) - 1); +} + +void RaiseLEDDriver::setCrgbAt(uint8_t i, cRGB crgb) { + // prevent reading off the end of the led_map array + if (i >= Props_::led_count) + return; + + // neuron LED + if (i == Props_::led_count - 1) { + isLEDChangedNeuron |= !(neuronLED.r == crgb.r && + neuronLED.g == crgb.g && + neuronLED.b == crgb.b); + neuronLED = crgb; + return; + } + + // get the SLED index + uint8_t sled_num = led_map[RaiseHands::layout][i]; + if (sled_num < LEDS_PER_HAND) { + cRGB oldColor = RaiseHands::leftHand.led_data.leds[sled_num]; + RaiseHands::leftHand.led_data.leds[sled_num] = crgb; + isLEDChangedLeft[uint8_t(sled_num / 8)] |= !(oldColor.r == crgb.r && + oldColor.g == crgb.g && + oldColor.b == crgb.b); + } else if (sled_num < 2 * LEDS_PER_HAND) { + cRGB oldColor = RaiseHands::rightHand.led_data.leds[sled_num - LEDS_PER_HAND]; + RaiseHands::rightHand.led_data.leds[sled_num - LEDS_PER_HAND] = crgb; + isLEDChangedRight[uint8_t((sled_num - LEDS_PER_HAND) / 8)] |= + !(oldColor.r == crgb.r && + oldColor.g == crgb.g && + oldColor.b == crgb.b); + } else { + // TODO(anyone): + // how do we want to handle debugging assertions about crazy user + // code that would overwrite other memory? + } +} + +cRGB RaiseLEDDriver::getCrgbAt(uint8_t i) { + if (i >= Props_::led_count) + return {0, 0, 0}; + + uint8_t sled_num = led_map[RaiseHands::layout][i]; + if (sled_num < LEDS_PER_HAND) { + return RaiseHands::leftHand.led_data.leds[sled_num]; + } else if (sled_num < 2 * LEDS_PER_HAND) { + return RaiseHands::rightHand.led_data.leds[sled_num - LEDS_PER_HAND]; + } else { + return {0, 0, 0}; + } +} + +void RaiseLEDDriver::setup() { + pinMode(SIDE_POWER, OUTPUT); + RaiseHands::setSidePower(false); + + // arduino zero analogWrite(255) isn't fully on as its actually working with a + // 16bit counter and the mapping is a bit shift. + // so change to 16 bit resolution to avoid the mapping and do the mapping + // ourselves in updateHubleLED() to ensure LEDs can be set fully off + analogWriteResolution(16); + updateNeuronLED(); + + delay(10); + RaiseHands::setSidePower(true); + delay(500); // wait for sides to power up and finish bootloader +} + +/********* Key scanner *********/ + +raise::keydata_t RaiseKeyScanner::leftHandState; +raise::keydata_t RaiseKeyScanner::rightHandState; +raise::keydata_t RaiseKeyScanner::previousLeftHandState; +raise::keydata_t RaiseKeyScanner::previousRightHandState; +raise::keydata_t RaiseKeyScanner::leftHandMask; +raise::keydata_t RaiseKeyScanner::rightHandMask; +bool RaiseKeyScanner::lastLeftOnline; +bool RaiseKeyScanner::lastRightOnline; + +void RaiseKeyScanner::readMatrix() { + previousLeftHandState = leftHandState; + previousRightHandState = rightHandState; + + if (RaiseHands::leftHand.readKeys()) { + leftHandState = RaiseHands::leftHand.getKeyData(); + // if ANSI, then swap r3c0 and r3c1 to match the PCB + if (RaiseHands::layout == LAYOUT_ANSI) + // only swap if bits are different + if ((leftHandState.rows[3] & (1 << 0)) ^ leftHandState.rows[3] & (1 << 1)) { + leftHandState.rows[3] ^= (1 << 0); // flip the bit + leftHandState.rows[3] ^= (1 << 1); // flip the bit + } + } + + if (RaiseHands::rightHand.readKeys()) { + rightHandState = RaiseHands::rightHand.getKeyData(); + // if ANSI, then swap r1c0 and r2c0 to match the PCB + if (RaiseHands::layout == LAYOUT_ANSI) + if ((rightHandState.rows[1] & (1 << 0)) ^ rightHandState.rows[2] & (1 << 0)) { + rightHandState.rows[1] ^= (1 << 0); + rightHandState.rows[2] ^= (1 << 0); + } + } + + // if a side has just been replugged, initialise it + if ((RaiseHands::leftHand.online && !lastLeftOnline) || + (RaiseHands::rightHand.online && !lastRightOnline)) + RaiseHands::initializeSides(); + + // if a side has just been unplugged, wipe its state + if (!RaiseHands::leftHand.online && lastLeftOnline) + leftHandState.all = 0; + + if (!RaiseHands::rightHand.online && lastRightOnline) + rightHandState.all = 0; + + // store previous state of whether the sides are plugged in + lastLeftOnline = RaiseHands::leftHand.online; + lastRightOnline = RaiseHands::rightHand.online; +} + +void RaiseKeyScanner::actOnMatrixScan() { + for (byte row = 0; row < Props_::matrix_rows; row++) { + for (byte col = 0; col < Props_::matrix_columns; col++) { + uint8_t keynum = (row * Props_::matrix_rows) + (col); + uint8_t keyState; + + // left + keyState = (bitRead(previousLeftHandState.all, keynum) << 0) | + (bitRead(leftHandState.all, keynum) << 1); + if (keyState) + ThisType::handleKeyswitchEvent(Key_NoKey, KeyAddr(row, col), keyState); + + // right + keyState = (bitRead(previousRightHandState.all, keynum) << 0) | + (bitRead(rightHandState.all, keynum) << 1); + if (keyState) + ThisType::handleKeyswitchEvent(Key_NoKey, KeyAddr(row, (Props_::matrix_columns - 1) - col), keyState); + } + } +} + +void RaiseKeyScanner::scanMatrix() { + readMatrix(); + actOnMatrixScan(); +} + +void RaiseKeyScanner::maskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) + return; + + auto row = key_addr.row(); + auto col = key_addr.col(); + + if (col >= Props_::left_columns) { + rightHandMask.rows[row] |= 1 << (Props_::right_columns - (col - Props_::left_columns)); + } else { + leftHandMask.rows[row] |= 1 << (Props_::right_columns - col); + } +} + +void RaiseKeyScanner::unMaskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) + return; + + auto row = key_addr.row(); + auto col = key_addr.col(); + + if (col >= Props_::left_columns) { + rightHandMask.rows[row] &= ~(1 << (Props_::right_columns - (col - Props_::left_columns))); + } else { + leftHandMask.rows[row] &= ~(1 << (Props_::right_columns - col)); + } +} + +bool RaiseKeyScanner::isKeyMasked(KeyAddr key_addr) { + if (!key_addr.isValid()) + return false; + + auto row = key_addr.row(); + auto col = key_addr.col(); + + if (col >= 8) { + return rightHandMask.rows[row] & (1 << (7 - (col - 8))); + } else { + return leftHandMask.rows[row] & (1 << (7 - col)); + } +} + +void RaiseKeyScanner::maskHeldKeys() { + memcpy(leftHandMask.rows, leftHandState.rows, sizeof(leftHandMask)); + memcpy(rightHandMask.rows, rightHandState.rows, sizeof(rightHandMask)); +} + +bool RaiseKeyScanner::isKeyswitchPressed(KeyAddr key_addr) { + auto row = key_addr.row(); + auto col = key_addr.col(); + + if (col >= Props_::left_columns) { + return (bitRead(rightHandState.rows[row], (Props_::matrix_columns - 1) - col) != 0); + } else { + return (bitRead(leftHandState.rows[row], col) != 0); + } +} + +bool RaiseKeyScanner::wasKeyswitchPressed(KeyAddr key_addr) { + auto row = key_addr.row(); + auto col = key_addr.col(); + + if (col >= Props_::left_columns) { + return (bitRead(previousRightHandState.rows[row], (Props_::matrix_columns - 1) - col) != 0); + } else { + return (bitRead(previousLeftHandState.rows[row], col) != 0); + } +} + +uint8_t RaiseKeyScanner::pressedKeyswitchCount() { + return __builtin_popcountl(leftHandState.all) + __builtin_popcountl(rightHandState.all); +} + +uint8_t RaiseKeyScanner::previousPressedKeyswitchCount() { + return __builtin_popcountl(previousLeftHandState.all) + __builtin_popcountl(previousRightHandState.all); +} + +void RaiseKeyScanner::setKeyscanInterval(uint8_t interval) { + RaiseHands::leftHand.setKeyscanInterval(interval); + RaiseHands::rightHand.setKeyscanInterval(interval); +} + +void RaiseKeyScanner::setup() { + static constexpr uint8_t keyscanner_pins[] = { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 + }; + for (int i = 0; i < sizeof(keyscanner_pins); i++) { + pinMode(keyscanner_pins[i], OUTPUT); + digitalWrite(keyscanner_pins[i], LOW); + } +} + +void RaiseKeyScanner::reset() { + leftHandState.all = 0; + rightHandState.all = 0; + kaleidoscope::hid::releaseAllKeys(); + kaleidoscope::hid::sendKeyboardReport(); +} + +/********* Hardware plugin *********/ +void Raise::setup() { + RaiseHands::setup(); + KeyScanner::setup(); + LEDDriver::setup(); + + // initialise Wire of scanner - have to do this here to avoid problem with + // static object intialisation ordering + Wire.begin(); + Wire.setClock(I2C_CLOCK_KHZ * 1000); + + RaiseHands::initializeSides(); +} + +void Raise::side::prepareForFlash() { + Wire.end(); + + setPower(LOW); + // also turn off i2c pins to stop attiny from getting enough current through i2c to stay on + pinMode(SCL, OUTPUT); + pinMode(SDA, OUTPUT); + digitalWrite(SCL, false); + digitalWrite(SDA, false); + + // wipe key states, to prevent accidental key repeats + RaiseKeyScanner::reset(); + + setPower(HIGH); + + Wire.begin(); + Wire.setClock(I2C_FLASH_CLOCK_KHZ * 1000); + // wait for side bootloader to be ready + delay(100); +} + +uint8_t Raise::side::getPower() { + return RaiseHands::getSidePower(); +} +void Raise::side::setPower(uint8_t power) { + RaiseHands::setSidePower(power); +} + +uint8_t Raise::side::leftVersion() { + return RaiseHands::leftHand.readVersion(); +} +uint8_t Raise::side::rightVersion() { + return RaiseHands::rightHand.readVersion(); +} + +uint8_t Raise::side::leftCRCErrors() { + return RaiseHands::leftHand.crc_errors(); +} +uint8_t Raise::side::rightCRCErrors() { + return RaiseHands::rightHand.crc_errors(); +} + +uint8_t Raise::side::leftSLEDVersion() { + return RaiseHands::leftHand.readSLEDVersion(); +} +uint8_t Raise::side::rightSLEDVersion() { + return RaiseHands::rightHand.readSLEDVersion(); +} + +uint8_t Raise::side::leftSLEDCurrent() { + return RaiseHands::leftHand.readSLEDCurrent(); +} +uint8_t Raise::side::rightSLEDCurrent() { + return RaiseHands::rightHand.readSLEDCurrent(); +} +void Raise::side::setSLEDCurrent(uint8_t current) { + RaiseHands::rightHand.setSLEDCurrent(current); + RaiseHands::leftHand.setSLEDCurrent(current); +} + +Raise::settings::Layout Raise::settings::layout() { + return RaiseHands::layout == LAYOUT_ANSI ? Layout::ANSI : Layout::ISO; +} +uint8_t Raise::settings::joint() { + return RaiseHands::rightHand.readJoint(); +} + +uint16_t Raise::settings::keyscanInterval() { + return RaiseHands::keyscanInterval(); +} +void Raise::settings::keyscanInterval(uint16_t interval) { + RaiseHands::keyscanInterval(interval); +} + +} +} +} + +#endif diff --git a/src/kaleidoscope/device/dygma/Raise.h b/src/kaleidoscope/device/dygma/Raise.h new file mode 100644 index 0000000000..1edfbced8e --- /dev/null +++ b/src/kaleidoscope/device/dygma/Raise.h @@ -0,0 +1,272 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 + +#ifdef ARDUINO_SAMD_RAISE +#include + +#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h" +#include "kaleidoscope/device/dygma/raise/Hand.h" + +#define CRGB(r,g,b) (cRGB){b, g, r} + +#include "kaleidoscope/driver/keyscanner/Base.h" +#include "kaleidoscope/driver/led/Base.h" +#include "kaleidoscope/driver/bootloader/samd/Bossac.h" +#include "kaleidoscope/driver/storage/Flash.h" +#include "kaleidoscope/device/Base.h" +#include "kaleidoscope/util/flasher/KeyboardioI2CBootloader.h" + +namespace kaleidoscope { +namespace device { +namespace dygma { + +// LHK = Left Hand Keys +#define LHK 33 + +using kaleidoscope::driver::led::no_led; + +struct RaiseLEDDriverProps : public kaleidoscope::driver::led::BaseProps { + static constexpr uint8_t led_count = 132; + static constexpr uint8_t key_led_map[] = { + // ISO & ANSI (ANSI has no LED at 20, but this key can never be pressed so we can have just one map). + 0, 1, 2, 3, 4, 5, 6, no_led, no_led, 6 + LHK, 5 + LHK, 4 + LHK, 3 + LHK, 2 + LHK, 1 + LHK, 0 + LHK, + 7, 8, 9, 10, 11, 12, no_led, no_led, 14 + LHK, 13 + LHK, 12 + LHK, 11 + LHK, 10 + LHK, 9 + LHK, 8 + LHK, 7 + LHK, + 13, 14, 15, 16, 17, 18, no_led, no_led, no_led, 21 + LHK, 20 + LHK, 19 + LHK, 18 + LHK, 17 + LHK, 16 + LHK, 15 + LHK, + 19, 20, 21, 22, 23, 24, 25, no_led, no_led, no_led, 27 + LHK, 26 + LHK, 25 + LHK, 24 + LHK, 23 + LHK, 22 + LHK, + 26, 27, 28, 29, 30, no_led, 31, 32, 35 + LHK, 34 + LHK, 33 + LHK, 32 + LHK, 31 + LHK, 30 + LHK, 29 + LHK, 28 + LHK + }; +}; +#undef LHK + +class RaiseLEDDriver : public kaleidoscope::driver::led::Base { + public: + static void setup(); + + static void syncLeds(); + static void setCrgbAt(uint8_t i, cRGB crgb); + static cRGB getCrgbAt(uint8_t i); + + static void updateNeuronLED(); + private: + static bool isLEDChangedNeuron; + static uint8_t isLEDChangedLeft[LED_BANKS]; + static uint8_t isLEDChangedRight[LED_BANKS]; + static cRGB neuronLED; + + static constexpr uint8_t lph = LEDS_PER_HAND; + // led_count + 1, to account for the Neuron's LED. The last one is the + // Neuron's LED, never send that to SLED. + static constexpr uint8_t led_map[][RaiseLEDDriverProps::led_count + 1] = { + // ISO + { + // left side - 33 keys includes LP + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 68, 69, + + // right side - 36 keys includes LP + 0 + LPH, 1 + LPH, 2 + LPH, 3 + LPH, 4 + LPH, 5 + LPH, 6 + LPH, 7 + LPH, 8 + LPH, 9 + LPH, 10 + LPH, 11 + LPH, 12 + LPH, 13 + LPH, 14 + LPH, 15 + LPH, 16 + LPH, 17 + LPH, 18 + LPH, 19 + LPH, + 20 + LPH, 21 + LPH, 22 + LPH, 23 + LPH, 24 + LPH, 25 + LPH, 26 + LPH, 27 + LPH, 28 + LPH, 29 + LPH, 30 + LPH, 31 + LPH, 32 + LPH, 33 + LPH, 68 + LPH, 69 + LPH, + + // left under glow - 30 + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + + // right underglow - 32 + 34 + LPH, 35 + LPH, 36 + LPH, 37 + LPH, 38 + LPH, 39 + LPH, 40 + LPH, 41 + LPH, 42 + LPH, 43 + LPH, 44 + LPH, 45 + LPH, 46 + LPH, 47 + LPH, 48 + LPH, 49 + LPH, 50 + LPH, 51 + LPH, + 52 + LPH, 53 + LPH, 54 + LPH, 55 + LPH, 56 + LPH, 57 + LPH, 58 + LPH, 59 + LPH, 60 + LPH, 61 + LPH, 62 + LPH, 63 + LPH, 64 + LPH, 65 + LPH, 0xff + }, + // ANSI + { + // left side - 32 keys includes LP: key 19 is missing for ANSI layout + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 0xff, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 68, 69, + + // right side - 36 keys includes LP + 0 + LPH, 1 + LPH, 2 + LPH, 3 + LPH, 4 + LPH, 5 + LPH, 6 + LPH, 15 + LPH, 8 + LPH, 9 + LPH, 10 + LPH, 11 + LPH, 12 + LPH, 13 + LPH, 14 + LPH, 7 + LPH, 16 + LPH, 17 + LPH, 18 + LPH, 19 + LPH, + 20 + LPH, 21 + LPH, 22 + LPH, 23 + LPH, 24 + LPH, 25 + LPH, 26 + LPH, 27 + LPH, 28 + LPH, 29 + LPH, 30 + LPH, 31 + LPH, 32 + LPH, 33 + LPH, 68 + LPH, 69 + LPH, + + // left under glow - 30 + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + + // right underglow - 32 + 34 + LPH, 35 + LPH, 36 + LPH, 37 + LPH, 38 + LPH, 39 + LPH, 40 + LPH, 41 + LPH, 42 + LPH, 43 + LPH, 44 + LPH, 45 + LPH, 46 + LPH, 47 + LPH, 48 + LPH, 49 + LPH, 50 + LPH, 51 + LPH, + 52 + LPH, 53 + LPH, 54 + LPH, 55 + LPH, 56 + LPH, 57 + LPH, 58 + LPH, 59 + LPH, 60 + LPH, 61 + LPH, 62 + LPH, 63 + LPH, 64 + LPH, 65 + LPH, 0xff + } + }; +}; + +struct RaiseKeyScannerProps : public kaleidoscope::driver::keyscanner::BaseProps { + KEYSCANNER_PROPS(5, 16); + static constexpr uint8_t left_columns = 8; + static constexpr uint8_t right_columns = matrix_columns - left_columns; +}; + +class RaiseKeyScanner : public kaleidoscope::driver::keyscanner::Base { + private: + typedef RaiseKeyScanner ThisType; + typedef RaiseKeyScannerProps Props_; + public: + static void setup(); + static void scanMatrix(); + static void readMatrix(); + static void actOnMatrixScan(); + + static void maskKey(KeyAddr key_addr); + static void unMaskKey(KeyAddr key_addr); + static bool isKeyMasked(KeyAddr key_addr); + static void maskHeldKeys(); + + static bool isKeyswitchPressed(KeyAddr key_addr); + static uint8_t pressedKeyswitchCount(); + + static bool wasKeyswitchPressed(KeyAddr key_addr); + static uint8_t previousPressedKeyswitchCount(); + + static void setKeyscanInterval(uint8_t interval); + + static void reset(); + + protected: + static raise::keydata_t leftHandState; + static raise::keydata_t rightHandState; + static raise::keydata_t previousLeftHandState; + static raise::keydata_t previousRightHandState; + + static raise::keydata_t leftHandMask; + static raise::keydata_t rightHandMask; + + static bool lastLeftOnline; + static bool lastRightOnline; +}; + +struct RaiseStorageProps : public kaleidoscope::driver::storage::FlashProps { + static constexpr uint16_t length = EEPROM_EMULATION_SIZE; +}; + +struct RaiseSideFlasherProps : public kaleidoscope::util::flasher::BaseProps {}; + +struct RaiseProps : kaleidoscope::device::BaseProps { + typedef RaiseLEDDriverProps LEDDriverProps; + typedef RaiseLEDDriver LEDDriver; + typedef RaiseKeyScannerProps KeyScannerProps; + typedef RaiseKeyScanner KeyScanner; + typedef RaiseStorageProps StorageProps; + typedef kaleidoscope::driver::storage::Flash Storage; + typedef kaleidoscope::driver::bootloader::samd::Bossac BootLoader; + + typedef RaiseSideFlasherProps SideFlasherProps; + typedef kaleidoscope::util::flasher::KeyboardioI2CBootloader SideFlasher; +}; + +class Raise: public kaleidoscope::device::Base { + private: + static RaiseProps::SideFlasher SideFlasher; + public: + static void setup(); + + auto serialPort() -> decltype(SerialUSB) & { + return SerialUSB; + } + + auto sideFlasher() -> decltype(SideFlasher) & { + return SideFlasher; + } + + struct side { + uint8_t getPower(); + void setPower(uint8_t power); + + uint8_t leftVersion(); + uint8_t rightVersion(); + + uint8_t leftCRCErrors(); + uint8_t rightCRCErrors(); + + uint8_t leftSLEDVersion(); + uint8_t rightSLEDVersion(); + + uint8_t leftSLEDCurrent(); + uint8_t rightSLEDCurrent(); + void setSLEDCurrent(uint8_t current); + + void prepareForFlash(); + + // Side bootloader addresses + static constexpr uint8_t left_boot_address = 0x50; + static constexpr uint8_t right_boot_address = 0x51; + } side; + + struct settings { + enum class Layout { + ISO, + ANSI + }; + Layout layout(); + uint8_t joint(); + + uint16_t keyscanInterval(); + void keyscanInterval(uint16_t interval); + } settings; +}; + + +} +} + +typedef kaleidoscope::device::dygma::Raise Device; + +} + +#define PER_KEY_DATA(dflt, \ + r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \ + r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \ + r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \ + r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \ + r4c0, r4c1, r4c2, r4c3, r4c4, r4c10, r4c11, r4c12, r4c13, r4c14, r4c15, \ + r4c6, r4c7, r4c8, r4c9 \ + ) \ + \ + r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, dflt, dflt, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \ + r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, dflt, dflt, r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \ + r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, dflt, dflt, dflt, r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \ + r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, dflt, dflt, dflt, r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \ + r4c0, r4c1, r4c2, r4c3, r4c4, dflt, r4c6, r4c7, r4c8, r4c9, r4c10, r4c11, r4c12, r4c13, r4c14, r4c15 + + +#define PER_KEY_DATA_STACKED(dflt, \ + r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, \ + r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, \ + r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, \ + r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, \ + r4c0, r4c1, r4c2, r4c3, r4c4, \ + r4c6, r4c7, \ + \ + r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \ + r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \ + r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \ + r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \ + r4c10, r4c11, r4c12, r4c13, r4c14, r4c15, \ + r4c8, r4c9 \ + ) \ + \ + r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, dflt, dflt, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \ + r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, dflt, dflt, r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \ + r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, dflt, dflt, dflt, r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \ + r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, dflt, dflt, dflt, r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \ + r4c0, r4c1, r4c2, r4c3, r4c4, dflt, r4c6, r4c7, r4c8, r4c9, r4c10, r4c11, r4c12, r4c13, r4c14, r4c15 + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/Focus.cpp b/src/kaleidoscope/device/dygma/raise/Focus.cpp new file mode 100644 index 0000000000..137ac9d3c8 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/Focus.cpp @@ -0,0 +1,133 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 ARDUINO_SAMD_RAISE + +#include +#include +#include "kaleidoscope/device/dygma/raise/Focus.h" + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +#ifndef RAISE_FIRMWARE_VERSION +#define RAISE_FIRMWARE_VERSION "" +#endif + +EventHandlerResult Focus::onFocusEvent(const char *command) { + if (::Focus.handleHelp(command, PSTR("hardware.version\nhardware.side_power\nhardware.side_ver\nhardware.sled_ver\nhardware.sled_current\nhardware.layout\nhardware.joint\nhardware.keyscan\nhardware.crc_errors\nhardware.firmware"))) + return EventHandlerResult::OK; + + if (strncmp_P(command, PSTR("hardware."), 9) != 0) + return EventHandlerResult::OK; + + if (strcmp_P(command + 9, PSTR("version")) == 0) { + ::Focus.send("Dygma Raise"); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("firmware")) == 0) { + ::Focus.send(RAISE_FIRMWARE_VERSION); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("side_power")) == 0) + if (::Focus.isEOL()) { + ::Focus.send(Kaleidoscope.device().side.getPower()); + return EventHandlerResult::EVENT_CONSUMED; + } else { + uint8_t power; + ::Focus.read(power); + Kaleidoscope.device().side.setPower(power); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("side_ver")) == 0) { + ::Focus.send("left:"); + ::Focus.send(Kaleidoscope.device().side.leftVersion()); + ::Focus.send("\nright:"); + ::Focus.send(Kaleidoscope.device().side.rightVersion()); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("crc_errors")) == 0) { + ::Focus.send("left:"); + ::Focus.send(Kaleidoscope.device().side.leftCRCErrors()); + ::Focus.send("\nright:"); + ::Focus.send(Kaleidoscope.device().side.rightCRCErrors()); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("sled_ver")) == 0) { + ::Focus.send("left:"); + ::Focus.send(Kaleidoscope.device().side.leftSLEDVersion()); + ::Focus.send("\nright:"); + ::Focus.send(Kaleidoscope.device().side.rightSLEDVersion()); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("sled_current")) == 0) + if (::Focus.isEOL()) { + ::Focus.send("left:"); + ::Focus.send(Kaleidoscope.device().side.leftSLEDCurrent()); + ::Focus.send("\nright:"); + ::Focus.send(Kaleidoscope.device().side.rightSLEDCurrent()); + return EventHandlerResult::EVENT_CONSUMED; + } else { + uint8_t current; + ::Focus.read(current); + Kaleidoscope.device().side.setSLEDCurrent(current); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("layout")) == 0) { + static const auto ANSI = Kaleidoscope.device().settings.Layout::ANSI; + ::Focus.send(Kaleidoscope.device().settings.layout() == ANSI ? "ANSI" : "ISO"); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("joint")) == 0) { + ::Focus.send(Kaleidoscope.device().settings.joint()); + return EventHandlerResult::EVENT_CONSUMED; + } + + if (strcmp_P(command + 9, PSTR("keyscan")) == 0) { + if (::Focus.isEOL()) { + ::Focus.send(Kaleidoscope.device().settings.keyscanInterval()); + return EventHandlerResult::EVENT_CONSUMED; + } else { + uint8_t keyscan; + ::Focus.read(keyscan); + Kaleidoscope.device().settings.keyscanInterval(keyscan); + return EventHandlerResult::EVENT_CONSUMED; + } + } + + return EventHandlerResult::OK; +} + +} +} +} +} + +kaleidoscope::device::dygma::raise::Focus RaiseFocus; + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/Focus.h b/src/kaleidoscope/device/dygma/raise/Focus.h new file mode 100644 index 0000000000..9601147ed4 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/Focus.h @@ -0,0 +1,42 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 + +#ifdef ARDUINO_SAMD_RAISE + +#include + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +class Focus : public kaleidoscope::Plugin { + public: + EventHandlerResult onFocusEvent(const char *command); +}; + +} +} +} +} + +extern kaleidoscope::device::dygma::raise::Focus RaiseFocus; + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/Hand.cpp b/src/kaleidoscope/device/dygma/raise/Hand.cpp new file mode 100644 index 0000000000..33d9b38786 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/Hand.cpp @@ -0,0 +1,254 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 ARDUINO_SAMD_RAISE + +#include +#include "Hand.h" + +#include "kaleidoscope/driver/color/GammaCorrection.h" + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +#define TWI_CMD_NONE 0x00 +#define TWI_CMD_VERSION 0x01 +#define TWI_CMD_KEYSCAN_INTERVAL 0x02 +#define TWI_CMD_LED_SET_ALL_TO 0x03 +#define TWI_CMD_LED_SET_ONE_TO 0x04 +#define TWI_CMD_COLS_USE_PULLUPS 0x05 +#define TWI_CMD_LED_SPI_FREQUENCY 0x06 +#define TWI_CMD_LED_GLOBAL_BRIGHTNESS 0x07 + +#define TWI_CMD_SLED_STATUS 0x08 +#define TWI_CMD_LED_OPEN 0x09 +#define TWI_CMD_LED_SHORT 0x0A +#define TWI_CMD_JOINED 0x0B +#define TWI_CMD_LAYOUT 0x0C +#define TWI_CMD_SLED_CURRENT 0x0D +#define TWI_CMD_SLED_SELF_TEST 0x0E + +#define LED_SPI_FREQUENCY_4MHZ 0x07 +#define LED_SPI_FREQUENCY_2MHZ 0x06 +#define LED_SPI_FREQUENCY_1MHZ 0x05 +#define LED_SPI_FREQUENCY_512KHZ 0x04 +#define LED_SPI_FREQUENCY_256KHZ 0x03 +#define LED_SPI_FREQUENCY_128KHZ 0x02 +#define LED_SPI_FREQUENCY_64KHZ 0x01 +#define LED_SPI_OFF 0x00 + +// 512KHZ seems to be the sweet spot in early testing +// so make it the default +#define LED_SPI_FREQUENCY_DEFAULT LED_SPI_FREQUENCY_512KHZ + +#define TWI_CMD_LED_BASE 0x80 + +#define TWI_REPLY_NONE 0x00 +#define TWI_REPLY_KEYDATA 0x01 + +#define ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) + +// Returns the relative controller addresss. The expected range is 0-3 +uint8_t Hand::controllerAddress() { + return ad01_; +} + +// Sets the keyscan interval. We currently do three reads. +// before declaring a key event debounced. +// +// Takes an integer value representing a counter. +// +// 0 - 0.1-0.25ms +// 1 - 0.125ms +// 10 - 0.35ms +// 25 - 0.8ms +// 50 - 1.6ms +// 100 - 3.15ms +// +// You should think of this as the _minimum_ keyscan interval. +// LED updates can cause a bit of jitter. +// +// returns the Wire.endTransmission code (0 = success) +// https://www.arduino.cc/en/Reference/WireEndTransmission +byte Hand::setKeyscanInterval(byte delay) { + uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay}; + return twi_.writeTo(data, ELEMENTS(data)); +} + +// returns -1 on error, otherwise returns the scanner version integer +int Hand::readVersion() { + return readRegister(TWI_CMD_VERSION); +} + +// returns -1 on error, otherwise returns the sled version integer +int Hand::readSLEDVersion() { + return readRegister(TWI_CMD_SLED_STATUS); +} +// returns -1 on error, otherwise returns the sled current settings +int Hand::readSLEDCurrent() { + return readRegister(TWI_CMD_SLED_CURRENT); +} + +byte Hand::setSLEDCurrent(byte current) { + uint8_t data[] = {TWI_CMD_SLED_CURRENT, current}; + return twi_.writeTo(data, ELEMENTS(data)); +} + +// returns -1 on error, otherwise returns the scanner keyscan interval +int Hand::readKeyscanInterval() { + return readRegister(TWI_CMD_KEYSCAN_INTERVAL); +} + +// returns -1 on error, otherwise returns the layout (ANSI/ISO) setting +int Hand::readLayout() { + return readRegister(TWI_CMD_LAYOUT); +} + +// returns -1 on error, otherwise returns the LED SPI Frequncy +int Hand::readLEDSPIFrequency() { + return readRegister(TWI_CMD_LED_SPI_FREQUENCY); +} + +// Set the LED SPI Frequency. See wire-protocol-constants.h for +// values. +// +// returns the Wire.endTransmission code (0 = success) +// https://www.arduino.cc/en/Reference/WireEndTransmission +byte Hand::setLEDSPIFrequency(byte frequency) { + uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency}; + return twi_.writeTo(data, ELEMENTS(data)); +} + +// returns -1 on error, otherwise returns the value of the hall sensor integer +int Hand::readJoint() { + byte return_value = 0; + + uint8_t data[] = {TWI_CMD_JOINED}; + uint8_t result = twi_.writeTo(data, ELEMENTS(data)); + if (result != 0) + return -1; + + // needs to be long enough for the slave to respond + delayMicroseconds(40); + + uint8_t rxBuffer[2]; + + // perform blocking read into buffer + uint8_t read = twi_.readFrom(rxBuffer, ELEMENTS(rxBuffer)); + if (read == 2) { + return rxBuffer[0] + (rxBuffer[1] << 8); + } else { + return -1; + } +} + +int Hand::readRegister(uint8_t cmd) { + byte return_value = 0; + + uint8_t data[] = {cmd}; + uint8_t result = twi_.writeTo(data, ELEMENTS(data)); + if (result != 0) + return -1; + + // needs to be long enough for the slave to respond + delayMicroseconds(40); + + uint8_t rxBuffer[1]; + + // perform blocking read into buffer + uint8_t read = twi_.readFrom(rxBuffer, ELEMENTS(rxBuffer)); + if (read > 0) { + return rxBuffer[0]; + } else { + return -1; + } +} + +// gives information on the key that was just pressed or released. +bool Hand::readKeys() { + uint8_t rxBuffer[6] = {0, 0, 0, 0, 0, 0}; + + // perform blocking read into buffer + uint8_t result = twi_.readFrom(rxBuffer, ELEMENTS(rxBuffer)); + // if result isn't 6? this can happens if slave nacks while trying to read + Hand::online = (result == 6) ? true : false; + + if (result != 6) + // could also try reset pressed keys here + return false; + + if (rxBuffer[0] == TWI_REPLY_KEYDATA) { + key_data_.rows[0] = rxBuffer[1]; + key_data_.rows[1] = rxBuffer[2]; + key_data_.rows[2] = rxBuffer[3]; + key_data_.rows[3] = rxBuffer[4]; + key_data_.rows[4] = rxBuffer[5]; + return true; + } else { + return false; + } +} + +keydata_t Hand::getKeyData() { + return key_data_; +} + +void Hand::sendLEDData() { + sendLEDBank(next_led_bank_++); + if (next_led_bank_ == LED_BANKS) { + next_led_bank_ = 0; + } +} + +auto constexpr gamma8 = kaleidoscope::driver::color::gamma_correction; + +void Hand::sendLEDBank(uint8_t bank) { + uint8_t data[LED_BYTES_PER_BANK + 1]; // + 1 for the update LED command itself + data[0] = TWI_CMD_LED_BASE + bank; + for (uint8_t i = 0 ; i < LED_BYTES_PER_BANK; i++) { + data[i + 1] = pgm_read_byte(&gamma8[led_data.bytes[bank][i]]); + } + uint8_t result = twi_.writeTo(data, ELEMENTS(data)); +} + +void Hand::setAllLEDsTo(cRGB color) { + uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO, + pgm_read_byte(&gamma8[color.r]), + pgm_read_byte(&gamma8[color.g]), + pgm_read_byte(&gamma8[color.b]) + }; + twi_.writeTo(data, ELEMENTS(data)); +} + +void Hand::setOneLEDTo(byte led, cRGB color) { + uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO, + led, + pgm_read_byte(&gamma8[color.r]), + pgm_read_byte(&gamma8[color.g]), + pgm_read_byte(&gamma8[color.b]) + }; + twi_.writeTo(data, ELEMENTS(data)); +} + +} +} +} +} +#endif diff --git a/src/kaleidoscope/device/dygma/raise/Hand.h b/src/kaleidoscope/device/dygma/raise/Hand.h new file mode 100644 index 0000000000..d82f23c926 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/Hand.h @@ -0,0 +1,105 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 + +#ifdef ARDUINO_SAMD_RAISE + +#include +#include "TWI.h" + +struct cRGB { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +#define LED_BANKS 9 + +#define LEDS_PER_HAND 72 +#define LPH LEDS_PER_HAND +#define LEDS_PER_BANK 8 +#define LED_BYTES_PER_BANK (sizeof(cRGB) * LEDS_PER_BANK) + +typedef union { + cRGB leds[LEDS_PER_HAND]; + byte bytes[LED_BANKS][LED_BYTES_PER_BANK]; +} LEDData_t; + +// return what bank the led is in +#define LED_TO_BANK(led) (led / LEDS_PER_BANK) + +typedef union { + uint8_t rows[5]; + uint64_t all; +} keydata_t; + +class Hand { + public: + Hand(byte ad01) : ad01_(ad01), twi_(i2c_addr_base_ | ad01) {} + + int readVersion(); + int readSLEDVersion(); + int readSLEDCurrent(); + byte setSLEDCurrent(byte current); + int readJoint(); + int readLayout(); + + byte setKeyscanInterval(byte delay); + int readKeyscanInterval(); + + byte setLEDSPIFrequency(byte frequency); + int readLEDSPIFrequency(); + + bool moreKeysWaiting(); + void sendLEDData(); + void sendLEDBank(uint8_t bank); + void setOneLEDTo(byte led, cRGB color); + void setAllLEDsTo(cRGB color); + keydata_t getKeyData(); + bool readKeys(); + uint8_t controllerAddress(); + uint8_t crc_errors() { + return twi_.crc_errors(); + } + + LEDData_t led_data; + bool online = false; + + private: + int ad01_; + TWI twi_; + keydata_t key_data_; + uint8_t next_led_bank_ = 0; + + static constexpr uint8_t i2c_addr_base_ = 0x58; + + int readRegister(uint8_t cmd); +}; + +} +} +} +} + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/SideFlash.h b/src/kaleidoscope/device/dygma/raise/SideFlash.h new file mode 100644 index 0000000000..f5b74b037b --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/SideFlash.h @@ -0,0 +1,84 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 + +#ifdef ARDUINO_SAMD_RAISE + +#include + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +template +class SideFlash : public kaleidoscope::Plugin { + private: + _Firmware firmware; + public: + EventHandlerResult onFocusEvent(const char *command) { + if (::Focus.handleHelp(command, PSTR("hardware.flash_left_side\nhardware.flash_right_side\nhardware.verify_left_side\nhardware.verify_right_side"))) + return EventHandlerResult::OK; + + if (strncmp_P(command, PSTR("hardware."), 9) != 0) + return EventHandlerResult::OK; + + auto sideFlasher = Kaleidoscope.device().sideFlasher(); + uint8_t left_boot_address = Kaleidoscope.device().side.left_boot_address; + uint8_t right_boot_address = Kaleidoscope.device().side.right_boot_address; + enum { + FLASH, + VERIFY + } sub_command; + uint8_t address = 0; + + if (strcmp_P(command + 9, PSTR("flash_left_side")) == 0) { + sub_command = FLASH; + address = left_boot_address; + } else if (strcmp_P(command + 9, PSTR("flash_right_side")) == 0) { + sub_command = FLASH; + address = right_boot_address; + } else if (strcmp_P(command + 9, PSTR("verify_left_side")) == 0) { + sub_command = VERIFY; + address = left_boot_address; + } else if (strcmp_P(command + 9, PSTR("verify_right_side")) == 0) { + sub_command = VERIFY; + address = right_boot_address; + } else { + return EventHandlerResult::OK; + } + + bool result; + Kaleidoscope.device().side.prepareForFlash(); + if (sub_command == FLASH) + result = sideFlasher.flash(address, firmware); + else + result = sideFlasher.verify(address, firmware); + ::Focus.send(result); + + return EventHandlerResult::EVENT_CONSUMED; + } +}; + +} +} +} +} + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/TWI.cpp b/src/kaleidoscope/device/dygma/raise/TWI.cpp new file mode 100644 index 0000000000..15fae04cb9 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/TWI.cpp @@ -0,0 +1,99 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 ARDUINO_SAMD_RAISE + +#include + +#include "TWI.h" +#include "kaleidoscope/util/crc16.h" + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +uint8_t TWI::writeTo(uint8_t *data, size_t length) { + Wire.beginTransmission(addr_); + + // calc cksum + uint16_t crc16 = 0xffff; + uint8_t *buffer = data; + for (uint8_t i = 0; i < length; i++) { + crc16 = _crc_ccitt_update(crc16, *buffer); + buffer++; + } + + // make cksum high byte and low byte + uint8_t crc_bytes[2]; + crc_bytes[0] = crc16 >> 8; + crc_bytes[1] = crc16; + + if (!Wire.write(data, length)) return 1; + if (!Wire.write(crc_bytes, 2)) return 1; + if (Wire.endTransmission(true) != 0) return 1; + return 0; +} + +uint8_t TWI::readFrom(uint8_t* data, size_t length) { + uint8_t counter = 0; + uint32_t timeout; + uint8_t *buffer = data; + + if (!Wire.requestFrom(addr_, length + 2, true)) { // + 2 for the cksum + // in case slave is not responding - return 0 (0 length of received data). + return 0; + } + while (counter < length) { + *data = Wire.read(); + data++; + counter++; + } + + uint16_t crc16 = 0xffff; + uint16_t rx_cksum = (Wire.read() << 8) + Wire.read(); + for (uint8_t i = 0; i < length; i++) { + crc16 = _crc_ccitt_update(crc16, *buffer); + buffer++; + } + + // check received CRC16 + if (crc16 != rx_cksum) { + crc_errors_++; + return 0; + } + + return length; +} + +void TWI::disable() { + Wire.end(); +} + +void TWI::init(uint16_t clock_khz) { + Wire.begin(); + Wire.setClock(clock_khz * 1000); +} + + +} +} +} +} + +#endif diff --git a/src/kaleidoscope/device/dygma/raise/TWI.h b/src/kaleidoscope/device/dygma/raise/TWI.h new file mode 100644 index 0000000000..5d96abb2d4 --- /dev/null +++ b/src/kaleidoscope/device/dygma/raise/TWI.h @@ -0,0 +1,49 @@ +/* -*- mode: c++ -*- + * kaleidoscope::device::dygma::Raise -- Kaleidoscope device plugin for Dygma Raise + * Copyright (C) 2017-2019 Keyboard.io, Inc + * Copyright (C) 2017-2019 Dygma Lab S.L. + * + * 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 ARDUINO_SAMD_RAISE + +#include + +namespace kaleidoscope { +namespace device { +namespace dygma { +namespace raise { + +class TWI { + public: + TWI(int addr) : addr_(addr), crc_errors_(0) {}; + + uint8_t writeTo(uint8_t *data, size_t length); + uint8_t readFrom(uint8_t* data, size_t length); + void disable(); + void init(uint16_t clock_khz); + uint8_t crc_errors() { + return crc_errors_; + } + + private: + int addr_; + uint8_t crc_errors_; +}; + +} +} +} +} +#endif diff --git a/src/kaleidoscope/driver/color/GammaCorrection.h b/src/kaleidoscope/driver/color/GammaCorrection.h new file mode 100644 index 0000000000..f11137e315 --- /dev/null +++ b/src/kaleidoscope/driver/color/GammaCorrection.h @@ -0,0 +1,47 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::led::Gamma -- Gamma correction table + * Copyright (C) 2017-2019 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 . + */ + +#pragma once + +#include + +namespace kaleidoscope { +namespace driver { +namespace color { + +const uint8_t PROGMEM gamma_correction[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, + 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, + 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, + 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, + 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, + 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114, + 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142, + 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175, + 177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, + 215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255 +}; + +} +} +} diff --git a/src/kaleidoscope/util/crc16.h b/src/kaleidoscope/util/crc16.h new file mode 100644 index 0000000000..92cdb77a86 --- /dev/null +++ b/src/kaleidoscope/util/crc16.h @@ -0,0 +1,94 @@ +// CRC compatibility, adapted from the C-only comments here: +// http://svn.savannah.nongnu.org/viewvc/trunk/avr-libc/include/util/crc16.h?revision=933&root=avr-libc&view=markup + +/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef _UTIL_CRC16_H_ +#define _UTIL_CRC16_H_ + +#include + +static inline uint16_t _crc16_update(uint16_t crc, uint8_t data) __attribute__((always_inline, unused)); +static inline uint16_t _crc16_update(uint16_t crc, uint8_t data) { + unsigned int i; + + crc ^= data; + for (i = 0; i < 8; ++i) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xA001; + } else { + crc = (crc >> 1); + } + } + return crc; +} + +static inline uint16_t _crc_xmodem_update(uint16_t crc, uint8_t data) __attribute__((always_inline, unused)); +static inline uint16_t _crc_xmodem_update(uint16_t crc, uint8_t data) { + unsigned int i; + + crc = crc ^ ((uint16_t)data << 8); + for (i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc = (crc << 1) ^ 0x1021; + } else { + crc <<= 1; + } + } + return crc; +} + +static inline uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data) __attribute__((always_inline, unused)); +static inline uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data) { + data ^= (crc & 255); + data ^= data << 4; + + return ((((uint16_t)data << 8) | (crc >> 8)) ^ (uint8_t)(data >> 4) + ^ ((uint16_t)data << 3)); +} + +static inline uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data) __attribute__((always_inline, unused)); +static inline uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data) { + unsigned int i; + + crc = crc ^ data; + for (i = 0; i < 8; i++) { + if (crc & 0x01) { + crc = (crc >> 1) ^ 0x8C; + } else { + crc >>= 1; + } + } + return crc; +} + +#endif + diff --git a/src/kaleidoscope/util/flasher/Base.h b/src/kaleidoscope/util/flasher/Base.h new file mode 100644 index 0000000000..753c0ef6de --- /dev/null +++ b/src/kaleidoscope/util/flasher/Base.h @@ -0,0 +1,60 @@ +/* -*- mode: c++ -*- + * kaleidoscope::util::flasher::Base -- Base flasher utility class + * Copyright (C) 2019 Keyboard.io, Inc + * Copyright (C) 2019 Dygma Lab S.L. + * + * 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 + +namespace kaleidoscope { +namespace util { +namespace flasher { + +struct BaseProps { + static constexpr uint8_t page_size = 64; + static constexpr uint8_t frame_size = 16; + static constexpr uint8_t blank = 0xff; + static constexpr uint8_t delay = 1; + + static struct { + static constexpr uint8_t page_address = 0x01; + static constexpr uint8_t continue_page = 0x02; + static constexpr uint8_t execute = 0x03; + static constexpr uint8_t erase_program = 0x04; + static constexpr uint8_t get_version_and_crc = 0x06; + } command; +}; + +template +class Base { + public: + Base() {} + + template + static uint8_t flash(uint8_t address, T& firmware) { + return 0; + } + template + static uint8_t verify(uint8_t address, T& firmware) { + return 0; + } + static uint8_t command(uint8_t address, uint8_t command) { + return 0; + } +}; + +} +} +} diff --git a/src/kaleidoscope/util/flasher/KeyboardioI2CBootloader.h b/src/kaleidoscope/util/flasher/KeyboardioI2CBootloader.h new file mode 100644 index 0000000000..88f789bceb --- /dev/null +++ b/src/kaleidoscope/util/flasher/KeyboardioI2CBootloader.h @@ -0,0 +1,226 @@ +/* -*- mode: c++ -*- + * kaleidoscope::util::flasher::KeyboardioI2CBootloader -- Flasher for Keyboardio's I2C Bootloader + * Copyright (C) 2019 Keyboard.io, Inc + * Copyright (C) 2019 Dygma Lab S.L. + * + * 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 + +// TODO(@algernon): We should support AVR here, too. +#ifdef __SAMD21G18A__ + +#include + +#include "kaleidoscope/util/flasher/Base.h" +#include "kaleidoscope/util/crc16.h" + +namespace kaleidoscope { +namespace util { +namespace flasher { + +template +class KeyboardioI2CBootloader: kaleidoscope::util::flasher::Base<_Props> { + public: + template + static bool flash(uint8_t address, T& firmware) { + if (!verify(address, firmware)) { + return false; + } + + if (!erase_program(address)) { + return false; + } + if (!write_firmware(address, firmware)) { + return false; + } + if (!verify_firmware(address, firmware)) { + return false; + } + + return command(address, _Props::command.execute) == 0 ? true : false; + } + + template + static bool verify(uint8_t address, T& firmware) { + CRCAndVersion crc_and_version = get_version(address, firmware); + return (crc_and_version.version != 0xff) && (crc_and_version.crc != 0xffff); + } + + static uint8_t command(uint8_t address, uint8_t command) { + Wire.beginTransmission(address); + Wire.write(command); + Wire.write(0x00); + uint8_t result = Wire.endTransmission(); + return result; + } + + private: + struct CRCAndVersion { + uint8_t version; + uint16_t crc; + }; + + static uint8_t read_crc16(uint8_t addr, + CRCAndVersion *crc_and_version, + uint16_t offset, uint16_t length) { + uint8_t result; + + Wire.beginTransmission(addr); + Wire.write(_Props::command.get_version_and_crc); + Wire.write(offset & 0xff); // addr (lo) + Wire.write(offset >> 8); // addr (hi) + Wire.write(length & 0xff); // len (lo) + Wire.write(length >> 8); // len (hi) + result = Wire.endTransmission(false); + if (result != 0) { + return result; + } + + // wait for cksum to be calculated - takes about 20ms + delay(100); + + Wire.requestFrom(addr, 3); + uint8_t v = Wire.read(); + crc_and_version->version = v; + if (Wire.available() == 0) { + return 0xFF; + } + uint8_t crc16_lo = Wire.read(); + if (Wire.available() == 0) { + return 0xFF; + } + uint8_t crc16_hi = Wire.read(); + while (Wire.available()) { + uint8_t c = Wire.read(); + } + crc_and_version->crc = (crc16_hi << 8) | crc16_lo; + return result; + } + + template + static CRCAndVersion get_version(uint8_t addr, T& firmware) { + static CRCAndVersion crc_and_version = {0xff, 0xff}; + + // This here to resolve some weird I2C startup bug. + // Usually in the RHS, get_version fails with the I2C master writing the + // address and the CRC request (0x06), the CRC parameters are never written + // doing a read first seems to let things settle in a way that allows the + // right to respond correctly + Wire.requestFrom(addr, (uint8_t) 3); + while (Wire.available()) { + // throw away the info, as cksum calculation request has yet to be issued. + Wire.read(); + } + + int result = read_crc16(addr, &crc_and_version, + firmware.offsets[0] + 4, + firmware.length - 4); + return crc_and_version; + } + + static bool erase_program(uint8_t addr) { + Wire.beginTransmission(addr); + Wire.write(_Props::command.erase_program); + uint8_t result = Wire.endTransmission(); + + // wait for erase + delay(1000); + + return result != 0; + } + + template + static bool write_firmware(uint8_t addr, T& firmware) { + uint8_t result; + uint8_t o = 0; + + for (uint16_t i = 0; i < firmware.length; i += _Props::page_size) { + Wire.beginTransmission(addr); + Wire.write(_Props::command.page_address); + Wire.write(firmware.offsets[o] & 0xff); + Wire.write(firmware.offsets[o] >> 8); + result = Wire.endTransmission(); + delay(_Props::delay); + + // got something other than ACK. Start over. + if (result != 0) { + return false; + } + + // transmit each frame separately + for (uint8_t frame = 0; frame < _Props::page_size / _Props::frame_size; frame++) { + Wire.beginTransmission(addr); + Wire.write(_Props::command.continue_page); + uint16_t crc16 = 0xffff; + for (uint8_t j = frame * _Props::frame_size; + j < (frame + 1) * _Props::frame_size; + j++) { + if (i + j < firmware.length) { + uint8_t b = pgm_read_byte(&firmware.data[i + j]); + Wire.write(b); + crc16 = _crc16_update(crc16, b); + } else { + Wire.write(_Props::blank); + crc16 = _crc16_update(crc16, _Props::blank); + } + } + // write the CRC16, little end first + Wire.write(crc16 & 0xff); + Wire.write(crc16 >> 8); + Wire.write(0x00); // dummy end uint8_t + result = Wire.endTransmission(); + // got something other than NACK. Start over. + if (result != 3) { + return false; + } + delay(_Props::delay); + } + o++; + } + return true; + } + + template + static bool verify_firmware(uint8_t addr, T& firmware) { + uint8_t result = 3; + CRCAndVersion crc_and_version; + + while (result != 0) { + // skip the first 4 uint8_ts, are they were probably overwritten by the + // reset vector preservation + result = read_crc16(addr, &crc_and_version, + firmware.offsets[0] + 4, firmware.length - 4); + if (result != 0) { + delay(100); + continue; + } + } + + // calculate our own CRC16 + uint16_t check_crc16 = 0xffff; + for (uint16_t i = 4; i < firmware.length; i++) { + check_crc16 = _crc16_update(check_crc16, pgm_read_byte(&(firmware.data[i]))); + } + + return crc_and_version.crc == check_crc16; + } + +}; + +} +} +} + +#endif