diff --git a/src/kaleidoscope/Hardware.h b/src/kaleidoscope/Hardware.h new file mode 100644 index 00000000..35a303a4 --- /dev/null +++ b/src/kaleidoscope/Hardware.h @@ -0,0 +1,271 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Hardware -- Kaleidoscope Hardware Base class + * Copyright (C) 2017, 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 . + */ + +/** @file kaleidoscope/Hardware.h + * Base class for Kaleidoscope hardware libraries. + */ + +#pragma once + +#ifndef CRGB +#error cRGB and CRGB *must* be defined before including this header! +#endif + +/* All hardware libraries must define the following macros: + * HARDWARE_IMPLEMENTATION - the name of your public object conforming to + * the 'class Hardware' interface below. + * CRGB(r,g,b) - explained below + */ + +/** + * Forward declaration of the cRGB structure. + * + * The base class does not define the cRGB structure, that is left up to the + * individual Hardware libraries. We do a forward declaration here, because the + * base hardware has methods that depend on a cRGB structure. + * + * The structure will need to have at least three members: r, g, and b - + * compilation will fail otherwise. + * + * Despite its name, the members do not need to be in the order r g b -- most + * likely they will be in an order that is convenient for the hardware. So + * initializing a cRGB with a struct literal will give surprising results for any + * colors where r, g, and b do not have the same value. Each Hardware library + * defines a CRGB(r,g,b) macro which returns a literal cRGB with the given values. + */ +typedef struct cRGB cRGB; + +namespace kaleidoscope { +/** Kaleidoscope Hardware base class. + * Essential methods all hardware libraries must implement. + */ +class Hardware { + public: + /** + * @defgroup kaleidoscope_hardware_leds Kaleidoscope::Hardware/LEDs + * @{ + */ + /** + * Sync the LEDs with the underlying hardware. This should make sure that + * changes made before this call are reflected on the device. + */ + void syncLeds(void) {} + /** + * Set the color of a per-key LED at a given row and column. + * + * Setting the color does not need to take effect immediately, it can be + * delayed until @ref syncLeds is called. + * + * @param row is the logical row position of the key. + * @param col is the logical column position of the key. + * @param color is the color to set the LED to. + */ + void setCrgbAt(byte row, byte col, cRGB color) {} + /** + * Set the color of a per-key LED at a given LED index. + * + * Setting the color does not need to take effect immediately, it can be + * delayed until @ref syncLeds is called. + * + * @param i is the LED index to change the color of. + * @param color is the color to set it to. + */ + void setCrgbAt(uint8_t i, cRGB color) {} + /** + * Returns the color of the LED at a given index. + * + * @param i is the index of the LED to return the color of. + * + * @returns The color at the given position. + */ + cRGB getCrgbAt(uint8_t i) { + cRGB c = { + 0, 0, 0 + }; + return c; + } + /** + * Returns the index of the LED at a given row & column. + * + * @param row is the logical row position of the key. + * @param col is the logical column position of the key. + * + * @returns The index of the LED at the given position, or -1 if there are no + * LEDs there. + */ + int8_t getLedIndex(uint8_t row, byte col) { + return -1; + } + /** @} */ + + /** @defgroup kaleidoscope_hardware_matrix Kaleidoscope::Hardware/Matrix + * @{ + */ + /** + * Scan the keyboard matrix, and act on it. + */ + void scanMatrix(void) {} + /** + * Read the state of the keyboard matrix. + * + * Do whatever is necessary to read the current keyboard state - but without + * acting on it. + * + * This is primarily used by @ref scanMatrix, but may have other uses too. + */ + void readMatrix(void) {} + /** + * Act on the scanned keyboard matrix. + * + * Iterate through the scanned state (@see readMatrix), and act on any events. + */ + void actOnMatrixScan(void) {} + /** @} */ + + /** @defgroup kaleidoscope_hardware_masking Kaleidoscope::Hardware/Key masking + * + * Sometimes there are situations when one wants to ignore key events for a + * while, to mask them out. Masked keys will be ignored until they are + * released. + * + * This is implemented in the Hardware library because that knows best how + * to mask efficiently, as this requires a deeper knowledge of the hardware, + * which is all but hidden from the rest of the plugins. + * @{ + */ + /** + * Mask out a key. + * + * Masking a key out means that any other event than a release will be + * ignored until said release. + * + * @param row is the row the key is located at in the matrix. + * @param col is the column the key is located at in the matrix. + */ + void maskKey(byte row, byte col) {} + /** + * Unmask a key. + * + * Remove the mask - if any - for a given key. To be used when the mask + * needs to be removed without the key being released. + * + * @param row is the row the key is located at in the matrix. + * @param col is the column the key is located at in the matrix. + */ + void unMaskKey(byte row, byte col) {} + /** + * Check whether a key is masked or not. + * + * @param row is the row the key is located at in the matrix. + * @param col is the column the key is located at in the matrix. + * + * @returns true if the key is masked, false otherwise. + */ + bool isKeyMasked(byte row, byte col) { + return false; + } + /** @} */ + + /** @defgroup kaleidoscope_hardware_reattach Kaleidoscope::Hardware/Attach & Detach + * + * In situations where one wants to re-initialize the devices, perhaps to + * change settings inbetween, detaching from and then attaching back to the + * host is a desirable feature to have. Especially if this does not cut power, + * nor reboot the device. + * + * Because different hardware has different ways to accomplish this, the + * hardware plugin must provide these functions. Kaleidoscope will wrap them, + * so user code does not have to deal with KeyboardHardware. + * @{ + */ + /** + * Detach the device from the host. + * + * Must detach the device, without rebooting or cutting power. Only the end + * points should get detached, the device must remain powered on. + */ + void detachFromHost() { + UDCON |= _BV(DETACH); + } + /** + * Attack the device to the host. + * + * Must restore the link detachFromHost severed. + */ + void attachToHost() { + UDCON &= ~_BV(DETACH); + } + /** @} */ + + /** + * @defgroup kaleidoscope_hardware_keyswitch_state Kaleidoscope::Hardware/Key-switch state + * + * These methods offer a way to peek at the key switch states, for those cases + * where we need to deal with the state closest to the hardware. Some methods + * offer a way to check if a key is pressed, others return the number of + * pressed keys. + * + * @{ + */ + /** + * Check if a key is pressed at a given position. + * + * @param row is the row the key is located at in the matrix. + * @param col is the column the key is located at in the matrix. + * + * @returns true if the key is pressed, false otherwise. + */ + bool isKeyswitchPressed(byte row, byte col) { + return false; + } + /** + * Check if a key is pressed at a given position. + * + * @param keyIndex is the key index, as calculated by `keyIndex`. + * + * @note Key indexes start at 1, not 0! + * + * @returns true if the key is pressed, false otherwise. + */ + bool isKeyswitchPressed(uint8_t keyIndex) { + return false; + } + /** + * Check the number of key switches currently pressed. + * + * @returns the number of keys pressed. + */ + uint8_t pressedKeyswitchCount() { + return 0; + } + + /** @} */ + + /** + * @defgroup kaleidoscope_hardware_misc Kaleidoscope::Hardware/Miscellaneous methods + * @{ + */ + /** + * Method to do any hardware-specific initialization. + * + * Called once when the device boots, this should initialize the device, and + * bring it up into a useful state. + */ + void setup() {} + /** @} */ +}; +} diff --git a/src/kaleidoscope/hardware/ATMegaKeyboard.cpp b/src/kaleidoscope/hardware/ATMegaKeyboard.cpp index 230eb3de..59f17401 100644 --- a/src/kaleidoscope/hardware/ATMegaKeyboard.cpp +++ b/src/kaleidoscope/hardware/ATMegaKeyboard.cpp @@ -51,14 +51,6 @@ void ATMegaKeyboard::setup(void) { TIMSK1 = _BV(TOIE1); } -void ATMegaKeyboard::detachFromHost() { - UDCON |= _BV(DETACH); -} - -void ATMegaKeyboard::attachToHost() { - UDCON &= ~_BV(DETACH); -} - void __attribute__((optimize(3))) ATMegaKeyboard::readMatrix(void) { for (uint8_t current_row = 0; current_row < KeyboardHardware.matrix_rows; current_row++) { uint16_t mask, cols; diff --git a/src/kaleidoscope/hardware/ATMegaKeyboard.h b/src/kaleidoscope/hardware/ATMegaKeyboard.h index ca73a12f..88320fe4 100644 --- a/src/kaleidoscope/hardware/ATMegaKeyboard.h +++ b/src/kaleidoscope/hardware/ATMegaKeyboard.h @@ -39,6 +39,8 @@ struct cRGB { #endif +#include "kaleidoscope/Hardware.h" + #define ROW_PIN_LIST(...) __VA_ARGS__ #define COL_PIN_LIST(...) __VA_ARGS__ @@ -69,85 +71,21 @@ struct cRGB { namespace kaleidoscope { namespace hardware { -class ATMegaKeyboard { +class ATMegaKeyboard : public kaleidoscope::Hardware { public: ATMegaKeyboard(void) {} - // these will be overridden by the subclass static uint8_t debounce; - void syncLeds(void) {} - void setCrgbAt(uint8_t row, byte col, cRGB color) {} - void setCrgbAt(int8_t i, cRGB crgb) {} - cRGB getCrgbAt(int8_t i) { - return CRGB(0, 0, 0); - } - int8_t getLedIndex(uint8_t row, byte col) { - return -1; - } - void setup(void); - - /** Detaching from / attaching to the host. - * - * These two functions should detach the device from (or attach it to) the - * host, preferably without rebooting the device. Their purpose is to allow - * one to do some configuration inbetween, so the re-attach happens with - * different properties. The device remains powered between these operations, - * only the connection to the host gets severed. - */ - void detachFromHost(); - void attachToHost(); - void readMatrix(void); + void actOnMatrixScan(); + void scanMatrix(); - /** - * Check the number of key switches currently pressed. - * - * @returns the number of keys pressed. - */ uint8_t pressedKeyswitchCount(); - - /** Key switch states - * - * These methods offer a way to peek at the key switch states, for those cases - * where we need to deal with the state closest to the hardware. Some methods - * offer a way to check if a key is pressed, others return the number of - * pressed keys. - */ - /** - * Check if a key is pressed at a given position. - * - * @param row is the row the key is located at in the matrix. - * @param col is the column the key is located at in the matrix. - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(uint8_t row, byte col); - - /** - * Check if a key is pressed at a given position. - * - * @param keyIndex is the key index, as calculated by `keyIndex`. - * - * @note Key indexes start at 1, not 0! - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(uint8_t keyIndex); - void actOnMatrixScan(); - void scanMatrix(); - - /* Key masking - * ----------- - * - * There are situations when one wants to ignore key events for a while, and - * mask them out. These functions help do that. In isolation, they do nothing, - * plugins and the core firmware is expected to make use of these. - * - * See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case. - */ void maskKey(byte row, byte col); void unMaskKey(byte row, byte col); bool isKeyMasked(byte row, byte col); diff --git a/src/kaleidoscope/hardware/ez/ErgoDox.cpp b/src/kaleidoscope/hardware/ez/ErgoDox.cpp index 46f1fdd6..b5228780 100644 --- a/src/kaleidoscope/hardware/ez/ErgoDox.cpp +++ b/src/kaleidoscope/hardware/ez/ErgoDox.cpp @@ -223,14 +223,6 @@ void ErgoDox::debounceRow(uint8_t change, uint8_t row) { } } -void ErgoDox::detachFromHost() { - UDCON |= (1 << DETACH); -} - -void ErgoDox::attachToHost() { - UDCON &= ~(1 << DETACH); -} - bool ErgoDox::isKeyswitchPressed(byte row, byte col) { return (bitRead(keyState_[row], col) != 0); } diff --git a/src/kaleidoscope/hardware/ez/ErgoDox.h b/src/kaleidoscope/hardware/ez/ErgoDox.h index c7672ca7..87249560 100644 --- a/src/kaleidoscope/hardware/ez/ErgoDox.h +++ b/src/kaleidoscope/hardware/ez/ErgoDox.h @@ -42,11 +42,13 @@ struct cRGB { #define CRGB(r,g,b) (cRGB){b, g, r} +#include "kaleidoscope/Hardware.h" + namespace kaleidoscope { namespace hardware { namespace ez { -class ErgoDox { +class ErgoDox : public kaleidoscope::Hardware { public: ErgoDox(void) {} @@ -54,76 +56,17 @@ class ErgoDox { static constexpr byte matrix_rows = 14; static constexpr int8_t led_count = 0; - void syncLeds(void) {} - void setCrgbAt(byte row, byte col, cRGB color) {} - void setCrgbAt(int8_t i, cRGB crgb) {} - cRGB getCrgbAt(int8_t i) { - return CRGB(0, 0, 0); - } - int8_t getLedIndex(byte row, byte col) { - return -1; - } - void scanMatrix(void); void readMatrix(void); void actOnMatrixScan(void); void setup(); - /** Detaching from / attaching to the host. - * - * These two functions should detach the device from (or attach it to) the - * host, preferably without rebooting the device. Their purpose is to allow - * one to do some configuration inbetween, so the re-attach happens with - * different properties. The device remains powered between these operations, - * only the connection to the host gets severed. - */ - void detachFromHost(); - void attachToHost(); - - /* Key masking - * ----------- - * - * There are situations when one wants to ignore key events for a while, and - * mask them out. These functions help do that. In isolation, they do nothing, - * plugins and the core firmware is expected to make use of these. - * - * See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case. - */ void maskKey(byte row, byte col); void unMaskKey(byte row, byte col); bool isKeyMasked(byte row, byte col); - /** Key switch states - * - * These methods offer a way to peek at the key switch states, for those cases - * where we need to deal with the state closest to the hardware. Some methods - * offer a way to check if a key is pressed, others return the number of - * pressed keys. - */ - /** - * Check if a key is pressed at a given position. - * - * @param row is the row the key is located at in the matrix. - * @param col is the column the key is located at in the matrix. - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(byte row, byte col); - /** - * Check if a key is pressed at a given position. - * - * @param keyIndex is the key index, as calculated by `keyIndex`. - * - * @note Key indexes start at 1, not 0! - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(uint8_t keyIndex); - /** - * Check the number of key switches currently pressed. - * - * @returns the number of keys pressed. - */ uint8_t pressedKeyswitchCount(); // ErgoDox-specific stuff diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.cpp b/src/kaleidoscope/hardware/keyboardio/Model01.cpp index f0f67980..0db65458 100644 --- a/src/kaleidoscope/hardware/keyboardio/Model01.cpp +++ b/src/kaleidoscope/hardware/keyboardio/Model01.cpp @@ -292,14 +292,6 @@ void Model01::setKeyscanInterval(uint8_t interval) { rightHand.setKeyscanInterval(interval); } -void Model01::detachFromHost() { - UDCON |= (1 << DETACH); -} - -void Model01::attachToHost() { - UDCON &= ~(1 << DETACH); -} - bool Model01::isKeyswitchPressed(byte row, byte col) { if (col <= 7) { return (bitRead(leftHandState.rows[row], 7 - col) != 0); diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.h b/src/kaleidoscope/hardware/keyboardio/Model01.h index c0fc0a6e..5457f87b 100644 --- a/src/kaleidoscope/hardware/keyboardio/Model01.h +++ b/src/kaleidoscope/hardware/keyboardio/Model01.h @@ -29,11 +29,13 @@ #define CRGB(r,g,b) (cRGB){b, g, r} +#include "kaleidoscope/Hardware.h" + namespace kaleidoscope { namespace hardware { namespace keyboardio { -class Model01 { +class Model01 : public kaleidoscope::Hardware { public: Model01(void); @@ -53,17 +55,6 @@ class Model01 { void setup(); void rebootBootloader(); - /** Detaching from / attaching to the host. - * - * These two functions should detach the device from (or attach it to) the - * host, preferably without rebooting the device. Their purpose is to allow - * one to do some configuration inbetween, so the re-attach happens with - * different properties. The device remains powered between these operations, - * only the connection to the host gets severed. - */ - void detachFromHost(); - void attachToHost(); - /* These public functions are things supported by the Model 01, but * aren't necessarily part of the Kaleidoscope API */ @@ -72,51 +63,13 @@ class Model01 { void setKeyscanInterval(uint8_t interval); boolean ledPowerFault(void); - /* Key masking - * ----------- - * - * There are situations when one wants to ignore key events for a while, and - * mask them out. These functions help do that. In isolation, they do nothing, - * plugins and the core firmware is expected to make use of these. - * - * See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case. - */ void maskKey(byte row, byte col); void unMaskKey(byte row, byte col); bool isKeyMasked(byte row, byte col); void maskHeldKeys(void); - /** Key switch states - * - * These methods offer a way to peek at the key switch states, for those cases - * where we need to deal with the state closest to the hardware. Some methods - * offer a way to check if a key is pressed, others return the number of - * pressed keys. - */ - /** - * Check if a key is pressed at a given position. - * - * @param row is the row the key is located at in the matrix. - * @param col is the column the key is located at in the matrix. - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(byte row, byte col); - /** - * Check if a key is pressed at a given position. - * - * @param keyIndex is the key index, as calculated by `keyIndex`. - * - * @note Key indexes start at 1, not 0! - * - * @returns true if the key is pressed, false otherwise. - */ bool isKeyswitchPressed(uint8_t keyIndex); - /** - * Check the number of key switches currently pressed. - * - * @returns the number of keys pressed. - */ uint8_t pressedKeyswitchCount(); keydata_t leftHandState;