The new device APIs were built on top of composition (instead of inheritance, like the former one). At the highest level, we have `kaleidoscope::device::Base` and `kaleidoscope::device::BaseProps`. The latter is a set of overrideable properties, components that make up the device: the key scanner, LEDs, MCU, and so on. Many components - like the key scanner and LEDs - also come in a similar setup: the base class and properties, because this allows us to make them fairly efficient templates. All of the existing devices have been ported to the new APIs. While the old `Hardware` base class remains - for now, and deprecated - it is not guaranteed to work. Signed-off-by: Gergely Nagy <algernon@keyboard.io>pull/695/head
parent
cfeff8f2cf
commit
d39a8dc46c
@ -0,0 +1,58 @@
|
||||
# kaleidoscope::driver::bootloader
|
||||
|
||||
We rarely have to work with or care about the bootloader from the user firmware,
|
||||
but there's one scenario when we do: if we want to reset the device, and put it
|
||||
into bootloader (programmable) mode, we need to do that in a bootloader-specific
|
||||
manner.
|
||||
|
||||
This driver provides a number of helpers that implement the reset functionality
|
||||
for various bootloaders.
|
||||
|
||||
## Using the driver
|
||||
|
||||
To use the driver, we need to include the appropriate header, from the hardware plugin of
|
||||
our keyboard:
|
||||
|
||||
```c++
|
||||
#include <kaleidoscope/driver/bootloader/avr/Caterina.h>
|
||||
```
|
||||
|
||||
Next, we set up the device `Properties` so that it includes the override for our
|
||||
bootloader:
|
||||
|
||||
```c++
|
||||
struct OurBoardProps : kaleidoscope::device::BaseProps {
|
||||
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader;
|
||||
};
|
||||
```
|
||||
|
||||
The base classes will do all the rest.
|
||||
|
||||
## Methods provided by all bootloader drivers
|
||||
|
||||
### `.rebootBootloader()`
|
||||
|
||||
> Resets the device, and forces it into bootloader (programmable) mode.
|
||||
|
||||
## List of bootloaders
|
||||
|
||||
All of the drivers below live below the `kaleidoscope::driver::bootloader`
|
||||
namespace.
|
||||
|
||||
## `avr::Caterina`:
|
||||
|
||||
Used by many (most?) arduino MCUs. Provided by
|
||||
`kaleidoscope/driver/bootloader/avr/Caterina.h`.
|
||||
|
||||
### `avr::HalfKay`
|
||||
|
||||
Used by the Teensy2. Provided by `kaleidoscope/driver/bootloader/avr/HalfKay.h`.
|
||||
|
||||
### `avr::FLIP`
|
||||
|
||||
Used by the ATMega32U4 MCUs by default, unless another bootloader has been
|
||||
flashed on them. Provided by `kaleidoscope/driver/bootloader/avr/FLIP.h`.
|
||||
|
||||
For this driver to work, one also needs to define the
|
||||
`KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND` macro before including the driver
|
||||
header, for technical reasons.
|
@ -1,82 +0,0 @@
|
||||
# ATMegaKeyboard
|
||||
|
||||
A lot of custom keyboards are built upon the ATMega MCU (most often an
|
||||
`atmega32u4`), and the vast majority of them follow a similar architecture, so
|
||||
much so that the vast majority of code can be lifted out into a base class,
|
||||
making porting to these keyboards trivial. All we have to do is tell it our
|
||||
pinout, and we're all done.
|
||||
|
||||
## Porting hardware using the ATMegaKeyboard class
|
||||
|
||||
The plugin assumes a simple matrix layout, which we can tell it by using the
|
||||
`ATMEGA_KEYBOARD_CONFIG` macro, which takes two arguments: a list of row and
|
||||
column pins. In the `.cpp`, simply use `ATMEGA_KEYBOARD_DATA`, with the hardware
|
||||
object as its argument:
|
||||
|
||||
```c++
|
||||
// Kaleidoscope-Vendor-ExampleHardware.h
|
||||
#define KALEIDOSCOPE_WITH_ATMEGA_KEYBOARD 1
|
||||
#include "kaleidoscope/hardware/vendor/ExampleHardware.h"
|
||||
|
||||
// kaleidoscope/hardware/vendor/ExampleHardware.h
|
||||
namespace kaleidoscope {
|
||||
namespace hardware {
|
||||
namespace vendor {
|
||||
class ExampleKeyboard: public ATMegaKeyboard {
|
||||
public:
|
||||
ExampleKeyboard() {}
|
||||
|
||||
ATMEGA_KEYBOARD_CONFIG(
|
||||
ROW_PIN_LIST({PIN_D1, PIN_D2}),
|
||||
COL_PIN_LIST({PIN_F6, PIN_F7})
|
||||
);
|
||||
|
||||
static constexpr int8_t led_count = 0;
|
||||
};
|
||||
|
||||
#define KEYMAP( \
|
||||
r0c0 ,r0c1 \
|
||||
,r1c0 ,r1c1 \
|
||||
) \
|
||||
{ r0c0 ,r0c1 }, \
|
||||
{ r1c0 ,r1c1 }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kaleidoscope/hardware/vendor/ExampleHardware.cpp
|
||||
namespace kaleidoscope {
|
||||
namespace hardware {
|
||||
namespace vendor {
|
||||
|
||||
ATMEGA_KEYBOARD_DATA(ExampleHardware);
|
||||
constexpr int8_t ExampleHardware::led_count;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HARDWARE_IMPLEMENTATION KeyboardHardware;
|
||||
kaleidoscope::hardware::vendor::ExampleHardware &ExampleHardware = KeyboardHardware;
|
||||
```
|
||||
|
||||
## Overriding methods
|
||||
|
||||
For performance and space-saving reasons, the base class does not use virtual
|
||||
methods. Instead, whenever it calls a method of its own, it will call it through
|
||||
the `KeyboardHardware` singleton object, which is always an instance of the
|
||||
exact hardware plugin. Thus, implementing a function in the subclass will shadow
|
||||
the one in the base class.
|
||||
|
||||
This can be used to implement more efficient methods, would it be needed. The
|
||||
[Atreus][hardware:atreus] port does this, for example, by overriding the generic
|
||||
`readCols` with a more specialised, faster implementation.
|
||||
|
||||
## Further reading
|
||||
|
||||
See the [Planck][hardware:planck] and [Atreus][hardware:atreus] ports for an
|
||||
example of how this class can be used in practice.
|
||||
|
||||
[hardware:planck]: ../../src/kaleidoscope/hardware/olkb/Planck.h
|
||||
[hardware:atreus]: ../../src/kaleidoscope/hardware/technomancy/Atreus.h
|
@ -0,0 +1,59 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* 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
|
||||
* it under the terms of version 3 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __AVR__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "kaleidoscope/device/Base.h"
|
||||
|
||||
#include "kaleidoscope/driver/mcu/ATMega32U4.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_)); \
|
||||
}; \
|
||||
typedef kaleidoscope::driver::keyscanner::AVR<KeyScannerProps> KeyScanner; \
|
||||
typedef kaleidoscope::driver::bootloader::avr::BOOTLOADER_ BootLoader; \
|
||||
}; \
|
||||
class BOARD_: public kaleidoscope::device::ATMega32U4Keyboard<BOARD_##Props> {};
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace device {
|
||||
|
||||
struct ATMega32U4KeyboardProps : kaleidoscope::device::BaseProps {
|
||||
typedef kaleidoscope::driver::mcu::ATMega32U4 MCU;
|
||||
typedef kaleidoscope::driver::storage::ATMega32U4EEPROMProps StorageProps;
|
||||
typedef kaleidoscope::driver::storage::AVREEPROM<StorageProps> Storage;
|
||||
};
|
||||
|
||||
template <typename _DeviceProps>
|
||||
class ATMega32U4Keyboard : public kaleidoscope::device::Base<_DeviceProps> {
|
||||
public:
|
||||
auto serialPort() -> decltype(Serial) & {
|
||||
return Serial;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,150 +0,0 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* Kaleidoscope-Hardware-ATMegaKeyboard -- Base class for some ATMega-based boards
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Kaleidoscope.h"
|
||||
|
||||
#if KALEIDOSCOPE_WITH_ATMEGA_KEYBOARD
|
||||
|
||||
#include "kaleidoscope/device/ATMegaKeyboard.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace device {
|
||||
|
||||
uint8_t ATMegaKeyboard::debounce = 3;
|
||||
|
||||
void ATMegaKeyboard::setup(void) {
|
||||
wdt_disable();
|
||||
|
||||
for (uint8_t i = 0; i < Kaleidoscope.device().matrix_columns; i++) {
|
||||
DDR_INPUT(Kaleidoscope.device().matrix_col_pins[i]);
|
||||
ENABLE_PULLUP(Kaleidoscope.device().matrix_col_pins[i]);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < Kaleidoscope.device().matrix_rows; i++) {
|
||||
DDR_OUTPUT(Kaleidoscope.device().matrix_row_pins[i]);
|
||||
OUTPUT_HIGH(Kaleidoscope.device().matrix_row_pins[i]);
|
||||
}
|
||||
|
||||
/* Set up Timer1 for 1700usec */
|
||||
TCCR1B = _BV(WGM13);
|
||||
TCCR1A = 0;
|
||||
|
||||
const uint32_t cycles = (F_CPU / 2000000) * 1700;
|
||||
|
||||
ICR1 = cycles;
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
TIMSK1 = _BV(TOIE1);
|
||||
}
|
||||
|
||||
void __attribute__((optimize(3))) ATMegaKeyboard::readMatrix(void) {
|
||||
for (uint8_t current_row = 0; current_row < Kaleidoscope.device().matrix_rows; current_row++) {
|
||||
uint16_t mask, cols;
|
||||
|
||||
mask = Kaleidoscope.device().debounceMaskForRow(current_row);
|
||||
|
||||
OUTPUT_TOGGLE(Kaleidoscope.device().matrix_row_pins[current_row]);
|
||||
cols = (Kaleidoscope.device().readCols() & mask) | (Kaleidoscope.device().keyState_[current_row] & ~mask);
|
||||
OUTPUT_TOGGLE(Kaleidoscope.device().matrix_row_pins[current_row]);
|
||||
Kaleidoscope.device().debounceRow(cols ^ Kaleidoscope.device().keyState_[current_row], current_row);
|
||||
Kaleidoscope.device().keyState_[current_row] = cols;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ATMegaKeyboard::pressedKeyswitchCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
for (int8_t r = 0; r < Kaleidoscope.device().matrix_rows; r++) {
|
||||
count += __builtin_popcount(Kaleidoscope.device().keyState_[r]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t ATMegaKeyboard::previousPressedKeyswitchCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
for (int8_t r = 0; r < Kaleidoscope.device().matrix_rows; r++) {
|
||||
count += __builtin_popcount(Kaleidoscope.device().previousKeyState_[r]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void __attribute__((optimize(3))) ATMegaKeyboard::actOnMatrixScan() {
|
||||
for (byte row = 0; row < Kaleidoscope.device().matrix_rows; row++) {
|
||||
for (byte col = 0; col < Kaleidoscope.device().matrix_columns; col++) {
|
||||
uint8_t keyState = (bitRead(Kaleidoscope.device().previousKeyState_[row], col) << 0) |
|
||||
(bitRead(Kaleidoscope.device().keyState_[row], col) << 1);
|
||||
if (keyState) {
|
||||
handleKeyswitchEvent(Key_NoKey, ::KeyAddr(row, col), keyState);
|
||||
}
|
||||
}
|
||||
Kaleidoscope.device().previousKeyState_[row] = Kaleidoscope.device().keyState_[row];
|
||||
}
|
||||
}
|
||||
|
||||
void ATMegaKeyboard::scanMatrix() {
|
||||
// We ALWAYS want to tell Kaleidoscope about the state of the matrix
|
||||
Kaleidoscope.device().actOnMatrixScan();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function has loop unrolling disabled on purpose: we want to give the
|
||||
* hardware enough time to produce stable PIN reads for us. If we unroll the
|
||||
* loop, we will not have that, because even with the NOP, the codepath is too
|
||||
* fast. If we don't have stable reads, then entire rows or columns will behave
|
||||
* erratically.
|
||||
*
|
||||
* For this reason, we ask the compiler to not unroll our loop, which in turn,
|
||||
* gives hardware enough time to produce stable reads, at the cost of a little
|
||||
* bit of speed.
|
||||
*
|
||||
* Do not remove the attribute!
|
||||
*/
|
||||
__attribute__((optimize("no-unroll-loops")))
|
||||
uint16_t ATMegaKeyboard::readCols() {
|
||||
uint16_t results = 0x00 ;
|
||||
for (uint8_t i = 0; i < Kaleidoscope.device().matrix_columns; i++) {
|
||||
asm("NOP"); // We need to pause a beat before reading or we may read before the pin is hot
|
||||
results |= (!READ_PIN(Kaleidoscope.device().matrix_col_pins[i]) << i);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
uint16_t ATMegaKeyboard::debounceMaskForRow(uint8_t row) {
|
||||
uint16_t result = 0;
|
||||
|
||||
for (uint16_t c = 0; c < Kaleidoscope.device().matrix_columns; ++c) {
|
||||
if (Kaleidoscope.device().debounce_matrix_[row][c]) {
|
||||
--Kaleidoscope.device().debounce_matrix_[row][c];
|
||||
} else {
|
||||
result |= _BV(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ATMegaKeyboard::debounceRow(uint16_t change, uint8_t row) {
|
||||
for (uint16_t i = 0; i < Kaleidoscope.device().matrix_columns; ++i) {
|
||||
if (change & _BV(i)) {
|
||||
Kaleidoscope.device().debounce_matrix_[row][i] = debounce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,166 +0,0 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* Kaleidoscope-Hardware-ATMegaKeyboard -- Base class for some ATMega-based boards
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if KALEIDOSCOPE_WITH_ATMEGA_KEYBOARD
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <KeyboardioHID.h>
|
||||
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
|
||||
#include "kaleidoscope/MatrixAddr.h"
|
||||
|
||||
#include "kaleidoscope/macro_helpers.h"
|
||||
#include "kaleidoscope/device/avr/pins_and_ports.h"
|
||||
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#ifndef CRGB
|
||||
|
||||
struct cRGB {
|
||||
uint8_t r, g, b;
|
||||
};
|
||||
|
||||
#define CRGB(r,g,b) (cRGB){b, g, r}
|
||||
|
||||
#endif
|
||||
|
||||
#include "kaleidoscope/Hardware.h"
|
||||
#include "kaleidoscope/driver/MCU.h"
|
||||
|
||||
#define ROW_PIN_LIST(...) __VA_ARGS__
|
||||
#define COL_PIN_LIST(...) __VA_ARGS__
|
||||
|
||||
// By implementing all KeyAddr based access methods via macros in
|
||||
// the derived hardware classes, we deal with the problem that
|
||||
// keyboard matrix dimension (matrix_rows/matrix_columns)
|
||||
// and thus type KeyAddr is only known to the derived hardware classes
|
||||
// but not to ATMegaKeyboard.
|
||||
//
|
||||
#define ATMEGA_KEYBOARD_MATRIX_ACCESS_METHODS \
|
||||
bool isKeyswitchPressed(KeyAddr key_addr) { \
|
||||
return (bitRead(keyState_[key_addr.row()], \
|
||||
key_addr.col()) != 0); \
|
||||
} \
|
||||
DEPRECATED(ROW_COL_FUNC) bool isKeyswitchPressed(uint8_t row, byte col)\
|
||||
{ \
|
||||
return isKeyswitchPressed(KeyAddr(row, col)); \
|
||||
} \
|
||||
bool isKeyswitchPressed(uint8_t keyIndex) { \
|
||||
keyIndex--; \
|
||||
return isKeyswitchPressed(KeyAddr(keyIndex)); \
|
||||
} \
|
||||
bool wasKeyswitchPressed(KeyAddr key_addr) { \
|
||||
return (bitRead(previousKeyState_[key_addr.row()], \
|
||||
key_addr.col()) != 0); \
|
||||
} \
|
||||
DEPRECATED(ROW_COL_FUNC) bool wasKeyswitchPressed(uint8_t row, byte col)\
|
||||
{ \
|
||||
return wasKeyswitchPressed(KeyAddr(row, col)); \
|
||||
} \
|
||||
bool wasKeyswitchPressed(uint8_t keyIndex) { \
|
||||
keyIndex--; \
|
||||
return wasKeyswitchPressed(KeyAddr(keyIndex)); \
|
||||
} \
|
||||
void maskKey(KeyAddr key_addr) { \
|
||||
if (!key_addr.isValid()) \
|
||||
return; \
|
||||
\
|
||||
bitWrite(masks_[key_addr.row()], key_addr.col(), 1); \
|
||||
} \
|
||||
DEPRECATED(ROW_COL_FUNC) void maskKey(byte row, byte col) { \
|
||||
maskKey(KeyAddr(row, col)); \
|
||||
} \
|
||||
void unMaskKey(KeyAddr key_addr) { \
|
||||
if (!key_addr.isValid()) \
|
||||
return; \
|
||||
\
|
||||
bitWrite(masks_[key_addr.row()], key_addr.col(), 0); \
|
||||
} \
|
||||
DEPRECATED(ROW_COL_FUNC) void unMaskKey(byte row, byte col) { \
|
||||
unMaskKey(KeyAddr(row, col)); \
|
||||
} \
|
||||
bool isKeyMasked(KeyAddr key_addr) { \
|
||||
if (!key_addr.isValid()) \
|
||||
return false; \
|
||||
\
|
||||
return bitRead(masks_[key_addr.row()], \
|
||||
key_addr.col()); \
|
||||
} \
|
||||
DEPRECATED(ROW_COL_FUNC) bool isKeyMasked(byte row, byte col) { \
|
||||
return isKeyMasked(KeyAddr(row, col)); \
|
||||
}
|
||||
|
||||
#define ATMEGA_KEYBOARD_CONFIG(ROW_PINS_, COL_PINS_) \
|
||||
static const int8_t matrix_rows = NUM_ARGS(ROW_PINS_); \
|
||||
static const int8_t matrix_columns = 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_; \
|
||||
typedef MatrixAddr<NUM_ARGS(ROW_PINS_), NUM_ARGS(COL_PINS_)> KeyAddr; \
|
||||
\
|
||||
static uint16_t previousKeyState_[matrix_rows]; \
|
||||
static volatile uint16_t keyState_[matrix_rows]; \
|
||||
static uint16_t masks_[matrix_rows]; \
|
||||
static volatile uint8_t debounce_matrix_[matrix_rows][matrix_columns]; \
|
||||
\
|
||||
ATMEGA_KEYBOARD_MATRIX_ACCESS_METHODS
|
||||
|
||||
#define ATMEGA_KEYBOARD_DATA(BOARD) \
|
||||
const int8_t BOARD::matrix_rows; \
|
||||
const int8_t BOARD::matrix_columns; \
|
||||
constexpr uint8_t BOARD::matrix_row_pins[matrix_rows]; \
|
||||
constexpr uint8_t BOARD::matrix_col_pins[matrix_columns]; \
|
||||
uint16_t BOARD::previousKeyState_[matrix_rows]; \
|
||||
volatile uint16_t BOARD::keyState_[matrix_rows]; \
|
||||
uint16_t BOARD::masks_[matrix_rows]; \
|
||||
volatile uint8_t BOARD::debounce_matrix_[matrix_rows][matrix_columns]; \
|
||||
\
|
||||
ISR(TIMER1_OVF_vect) { \
|
||||
Kaleidoscope.device().readMatrix(); \
|
||||
}
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace device {
|
||||
class ATMegaKeyboard : public kaleidoscope::Hardware {
|
||||
public:
|
||||
ATMegaKeyboard(void) {}
|
||||
|
||||
static uint8_t debounce;
|
||||
|
||||
void setup(void);
|
||||
void readMatrix(void);
|
||||
void actOnMatrixScan();
|
||||
void scanMatrix();
|
||||
|
||||
uint8_t pressedKeyswitchCount();
|
||||
|
||||
uint8_t previousPressedKeyswitchCount();
|
||||
|
||||
|
||||
protected:
|
||||
kaleidoscope::driver::mcu::ATMega32U4 mcu_;
|
||||
|
||||
private:
|
||||
|
||||
uint16_t readCols();
|
||||
uint16_t debounceMaskForRow(uint8_t row);
|
||||
void debounceRow(uint16_t change, uint8_t row);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,504 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::device::Base -- Kaleidoscope device Base class
|
||||
* Copyright (C) 2017, 2018, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file kaleidoscope/device/Base.h
|
||||
* Base class for Kaleidoscope device libraries.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/MatrixAddr.h"
|
||||
#include "kaleidoscope_internal/deprecations.h"
|
||||
#include "kaleidoscope/macro_helpers.h"
|
||||
|
||||
#include "kaleidoscope/driver/keyscanner/None.h"
|
||||
#include "kaleidoscope/driver/led/None.h"
|
||||
#include "kaleidoscope/driver/mcu/None.h"
|
||||
#include "kaleidoscope/driver/bootloader/None.h"
|
||||
#include "kaleidoscope/driver/storage/None.h"
|
||||
|
||||
#ifndef CRGB
|
||||
#error cRGB and CRGB *must* be defined before including this header!
|
||||
#endif
|
||||
|
||||
/* All hardware libraries must define the following types and macros:
|
||||
* kaleidoscope::Device - a typedef to your device's class.
|
||||
* CRGB(r,g,b) - explained below
|
||||
* cRGB, a structure with 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.
|
||||
*/
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace device {
|
||||
|
||||
struct BaseProps {
|
||||
typedef kaleidoscope::driver::keyscanner::BaseProps KeyScannerProps;
|
||||
typedef kaleidoscope::driver::keyscanner::None KeyScanner;
|
||||
typedef kaleidoscope::driver::led::BaseProps LEDDriverProps;
|
||||
typedef kaleidoscope::driver::led::None LEDDriver;
|
||||
typedef kaleidoscope::driver::mcu::None MCU;
|
||||
typedef kaleidoscope::driver::bootloader::None Bootloader;
|
||||
typedef kaleidoscope::driver::storage::BaseProps StorageProps;
|
||||
typedef kaleidoscope::driver::storage::None Storage;
|
||||
};
|
||||
|
||||
template<typename _DeviceProps>
|
||||
class Base {
|
||||
private:
|
||||
class NoOpSerial {
|
||||
public:
|
||||
NoOpSerial() {}
|
||||
};
|
||||
|
||||
static NoOpSerial noop_serial_;
|
||||
|
||||
public:
|
||||
Base() {}
|
||||
|
||||
typedef _DeviceProps Props;
|
||||
|
||||
typedef typename _DeviceProps::KeyScanner KeyScanner;
|
||||
typedef typename _DeviceProps::KeyScannerProps KeyScannerProps;
|
||||
typedef typename _DeviceProps::KeyScannerProps::KeyAddr KeyAddr;
|
||||
typedef typename _DeviceProps::LEDDriverProps LEDDriverProps;
|
||||
typedef typename _DeviceProps::LEDDriver LEDDriver;
|
||||
typedef typename _DeviceProps::MCU MCU;
|
||||
typedef typename _DeviceProps::Bootloader Bootloader;
|
||||
typedef typename _DeviceProps::StorageProps StorageProps;
|
||||
typedef typename _DeviceProps::Storage Storage;
|
||||
|
||||
static constexpr uint8_t matrix_rows = KeyScannerProps::matrix_rows;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the number of keys on the keyboard.
|
||||
*/
|
||||
static constexpr int8_t numKeys() {
|
||||
return matrix_columns * matrix_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the storage driver used by the keyboard.
|
||||
*/
|
||||
Storage &storage() {
|
||||
return storage_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial port driver used by the keyboard.
|
||||
*/
|
||||
NoOpSerial &serialPort() {
|
||||
return noop_serial_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
led_driver_.syncLeds();
|
||||
}
|
||||
/**
|
||||
* 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 key_addr is the matrix address of the LED.
|
||||
* @param color is the color to set the LED to.
|
||||
*/
|
||||
void setCrgbAt(KeyAddr key_addr, cRGB color) {
|
||||
setCrgbAt(getLedIndex(key_addr), color);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) void setCrgbAt(byte row, byte col, cRGB color) {
|
||||
setCrgbAt(KeyAddr(row, col), 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) {
|
||||
led_driver_.setCrgbAt(i, 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) {
|
||||
return led_driver_.getCrgbAt(i);
|
||||
}
|
||||
/**
|
||||
* Returns the color of the LED at a given index.
|
||||
*
|
||||
* @param key_addr is the key address of the LED to return the color of.
|
||||
*
|
||||
* @returns The color at the given position.
|
||||
*/
|
||||
cRGB getCrgbAt(KeyAddr key_addr) {
|
||||
return getCrgbAt(getLedIndex(key_addr));
|
||||
}
|
||||
/**
|
||||
* Returns the index of the LED at a given row & column.
|
||||
*
|
||||
* @param key_addr is the matrix address of the LED.
|
||||
*
|
||||
* @returns The index of the LED at the given position, or -1 if there are no
|
||||
* LEDs there.
|
||||
*/
|
||||
int8_t getLedIndex(KeyAddr key_addr) {
|
||||
return led_driver_.getLedIndex(key_addr.toInt());
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) int8_t getLedIndex(uint8_t row, byte col) {
|
||||
return led_driver_.getLedIndex(KeyAddr(row, col));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** @defgroup kaleidoscope_hardware_matrix Kaleidoscope::Hardware/Matrix
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Scan the keyboard matrix, and act on it.
|
||||
*/
|
||||
void scanMatrix(void) {
|
||||
key_scanner_.scanMatrix();
|
||||
}
|
||||
/**
|
||||
* 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) {
|
||||
key_scanner_.readMatrix();
|
||||
}
|
||||
/**
|
||||
* Act on the scanned keyboard matrix.
|
||||
*
|
||||
* Iterate through the scanned state (@see readMatrix), and act on any events.
|
||||
*/
|
||||
void actOnMatrixScan(void) {
|
||||
key_scanner_.actOnMatrixScan();
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** @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 key_addr is the matrix address of the key.
|
||||
*/
|
||||
void maskKey(KeyAddr key_addr) {
|
||||
key_scanner_.maskKey(key_addr);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) void maskKey(byte row, byte col) {
|
||||
key_scanner_.maskKey(KeyAddr(row, 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 key_addr is the matrix address of the key.
|
||||
*/
|
||||
void unMaskKey(KeyAddr key_addr) {
|
||||
key_scanner_.unMaskKey(key_addr);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) void unMaskKey(byte row, byte col) {
|
||||
key_scanner_.unMaskKey(KeyAddr(row, col));
|
||||
}
|
||||
/**
|
||||
* Check whether a key is masked or not.
|
||||
*
|
||||
* @param key_addr is the matrix address of the key.
|
||||
*
|
||||
* @returns true if the key is masked, false otherwise.
|
||||
*/
|
||||
bool isKeyMasked(KeyAddr key_addr) {
|
||||
return key_scanner_.isKeyMasked(key_addr);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) bool isKeyMasked(byte row, byte col) {
|
||||
return key_scanner_.isKeyMasked(KeyAddr(row, col));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** @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 them directly.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* 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() {
|
||||
mcu_.detachFromHost();
|
||||
}
|
||||
/**
|
||||
* Attack the device to the host.
|
||||
*
|
||||
* Must restore the link detachFromHost severed.
|
||||
*/
|
||||
void attachToHost() {
|
||||
mcu_.attachToHost();
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @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 key_addr is the matrix address of the key.
|
||||
*
|
||||
* @returns true if the key is pressed, false otherwise.
|
||||
*/
|
||||
bool isKeyswitchPressed(KeyAddr key_addr) {
|
||||
return key_scanner_.isKeyswitchPressed(key_addr);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) bool isKeyswitchPressed(byte row, byte col) {
|
||||
return key_scanner_.isKeyswitchPressed(KeyAddr(row, 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) {
|
||||
return key_scanner_.isKeyswitchPressed(KeyAddr(--keyIndex));
|
||||
}
|
||||
/**
|
||||
* Check the number of key switches currently pressed.
|
||||
*
|
||||
* @returns the number of keys pressed.
|
||||
*/
|
||||
uint8_t pressedKeyswitchCount() {
|
||||
return key_scanner_.pressedKeyswitchCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a key was pressed at a given position on the previous scan
|
||||
*
|
||||
* @param key_addr is the matrix address of the key.
|
||||
*
|
||||
* @returns true if the key was pressed, false otherwise.
|
||||
*/
|
||||
bool wasKeyswitchPressed(KeyAddr key_addr) {
|
||||
return key_scanner_.wasKeyswitchPressed(key_addr);
|
||||
}
|
||||
/**
|
||||
* Check if a key was pressed at a given position on the previous scan
|
||||
*
|
||||
* @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 was pressed, false otherwise.
|
||||
*/
|
||||
DEPRECATED(ROW_COL_FUNC) bool wasKeyswitchPressed(byte row, byte col) {
|
||||
return key_scanner_.wasKeyswitchPressed(KeyAddr(row, col));
|
||||
}
|
||||
/**
|
||||
* Check if a key was pressed at a given position on the previous scan.
|
||||
*
|
||||
* @param keyIndex is the key index, as calculated by `keyIndex`.
|
||||
*
|
||||
* @note Key indexes start at 1, not 0!
|
||||
*
|
||||
* @returns true if the key was pressed, false otherwise.
|
||||
*/
|
||||
bool wasKeyswitchPressed(uint8_t keyIndex) {
|
||||
return key_scanner_.wasKeyswitchPressed(KeyAddr(--keyIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the number of key switches pressed in the previous scan.
|
||||
*
|
||||
* @returns the number of keys pressed.
|
||||
*/
|
||||
uint8_t previousPressedKeyswitchCount() {
|
||||
return key_scanner_.previousPressedKeyswitchCount();
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @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() {
|
||||
bootloader_.setup();
|
||||
mcu_.setup();
|
||||
storage_.setup();
|
||||
key_scanner_.setup();
|
||||
led_driver_.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to configure the device for a hardware test mode
|
||||
*
|
||||
* Called by the Kaleidoscope Hardware test plugin, this method should
|
||||
* do any device-specific initialization needed for factory hardware testing
|
||||
*
|
||||
*/
|
||||
void enableHardwareTestMode() {}
|
||||
|
||||
/**
|
||||
* Method to put the device into programmable/bootloader mode.
|
||||
*
|
||||
* This is the old, legacy name of the method.
|
||||
*/
|
||||
DEPRECATED(HARDWARE_RESETDEVICE) void resetDevice() {
|
||||
bootloader_.rebootBootloader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to put the device into programmable/bootloader mode.
|
||||
*/
|
||||
void rebootBootloader() {
|
||||
bootloader_.rebootBootloader();
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
protected:
|
||||
KeyScanner key_scanner_;
|
||||
LEDDriver led_driver_;
|
||||
MCU mcu_;
|
||||
Bootloader bootloader_;
|
||||
Storage storage_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::base -- Base Bootloader Driver
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
|
||||
class Base {
|
||||
public:
|
||||
Base() {}
|
||||
|
||||
void setup() {}
|
||||
static void rebootBootloader() {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::None -- Dummy Bootloader driver
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include "kaleidoscope/driver/bootloader/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
|
||||
/*
|
||||
* The purpose of this class is to serve as a default inside the base
|
||||
* `kaleidoscope::device::Base` class, with a name more descriptive than
|
||||
* `bootloader::Base`. In practice, one shouldn't use it, and should override
|
||||
* the bootloader in the device description.
|
||||
*/
|
||||
class None : public kaleidoscope::driver::bootloader::Base {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::avr::Caterina -- Driver for the Caterina bootloader
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include "kaleidoscope/driver/bootloader/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
namespace avr {
|
||||
|
||||
class Caterina : public kaleidoscope::driver::bootloader::Base {
|
||||
public:
|
||||
static void rebootBootloader() {
|
||||
// Set the magic bits to get a Caterina-based device
|
||||
// to reboot into the bootloader and stay there, rather
|
||||
// than run move onward
|
||||
//
|
||||
// These values are the same as those defined in
|
||||
// Caterina.c:
|
||||
// https://github.com/arduino/ArduinoCore-avr/blob/5755ddea49fa69d6c505c772ebee5af5078e2ebf/bootloaders/caterina/Caterina.c#L130-L133
|
||||
|
||||
uint16_t bootKey = 0x7777;
|
||||
uint16_t *const bootKeyPtr = reinterpret_cast<uint16_t *>(0x0800);
|
||||
|
||||
// Stash the magic key
|
||||
*bootKeyPtr = bootKey;
|
||||
|
||||
// Set a watchdog timer
|
||||
wdt_enable(WDTO_120MS);
|
||||
|
||||
while (true) {} // This infinite loop ensures nothing else
|
||||
// happens before the watchdog reboots us
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::avr::FLIP -- Driver for the Atmel FLIP bootloader
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Kaleidoscope.h>
|
||||
|
||||
#ifdef KALEIDOSCOPE_BOOTLOADER_FLIP_WORKAROUND
|
||||
#include "kaleidoscope/driver/bootloader/avr/FLIP.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
namespace avr {
|
||||
|
||||
// The FLIP bootloader does not provide a way to boot into bootloader mode from
|
||||
// within the firmware: it will always start the user firmware if available, and
|
||||
// if the reset wasn't triggered by the physical reset button. To enter the
|
||||
// bootloader mode, we need to jump there from the user firmware ourselves.
|
||||
//
|
||||
// Since we do not want to unconditionally jump into bootloader, we set a static
|
||||
// memory address to a magic value, to signal our intention, then reboot via the
|
||||
// watchdog timer. We need to reboot to clear registers and have a clean slate
|
||||
// for the bootloader.
|
||||
//
|
||||
// For this to work, we need to run our signal checking code before `main()`, so
|
||||
// we put the checker function into a special section that does that.
|
||||
//
|
||||
// Since this code cannot be optimized out on keyboards that use another
|
||||
// bootloader, we need to guard this implementation with an ifdef (see above).
|
||||
//
|
||||
// For more information, see:
|
||||
// http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
|
||||
|
||||
#define BOOTLOADER_RESET_KEY 0xB007B007
|
||||
static uint32_t reset_key __attribute__((section(".noinit")));
|
||||
|
||||
/*
|
||||
* This function runs before main(), and jumps to the bootloader after a reset
|
||||
* initiated by .resetDevice().
|
||||
*/
|
||||
static void _bootloader_jump_after_watchdog_reset()
|
||||
__attribute__((used, naked, section(".init3")));
|
||||
static void _bootloader_jump_after_watchdog_reset() {
|
||||
if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
|
||||
reset_key = 0;
|
||||
|
||||
((void (*)(void))(((FLASHEND + 1L) - 4096) >> 1))();
|
||||
}
|
||||
}
|
||||
|
||||
void FLIP::rebootBootloader() {
|
||||
reset_key = BOOTLOADER_RESET_KEY;
|
||||
wdt_enable(WDTO_250MS);
|
||||
while (true) {} // This infinite loop ensures nothing else
|
||||
// happens before the watchdog reboots us
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,41 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::avr::FLIP -- Driver for the Atmel FLIP bootloader
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#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
|
||||
|
||||
#include "kaleidoscope/driver/bootloader/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
namespace avr {
|
||||
|
||||
class FLIP : public kaleidoscope::driver::bootloader::Base {
|
||||
public:
|
||||
static void rebootBootloader();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::bootloader::avr::HalfKay -- Driver for the HalfKay bootloader
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include "kaleidoscope/driver/bootloader/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace bootloader {
|
||||
namespace avr {
|
||||
|
||||
class HalfKay : public kaleidoscope::driver::bootloader::Base {
|
||||
public:
|
||||
// To reset a Teensy with the HalfKay bootloader, we need to disable all
|
||||
// interrupts, all peripherals we have attached, USB, the watchdog timer, etc.
|
||||
// Once done, we can jump to the bootloader address.
|
||||
//
|
||||
// Documentation: https://www.pjrc.com/teensy/jump_to_bootloader.html
|
||||
static void rebootBootloader() {
|
||||
cli();
|
||||
UDCON = 1;
|
||||
USBCON = (1 << FRZCLK);
|
||||
UCSR1B = 0;
|
||||
_delay_ms(5);
|
||||
|
||||
EIMSK = 0;
|
||||
PCICR = 0;
|
||||
SPCR = 0;
|
||||
ACSR = 0;
|
||||
EECR = 0;
|
||||
ADCSRA = 0;
|
||||
TIMSK0 = 0;
|
||||
TIMSK1 = 0;
|
||||
TIMSK3 = 0;
|
||||
TIMSK4 = 0;
|
||||
UCSR1B = 0;
|
||||
TWCR = 0;
|
||||
DDRB = 0;
|
||||
DDRC = 0;
|
||||
DDRD = 0;
|
||||
DDRE = 0;
|
||||
DDRF = 0;
|
||||
TWCR = 0;
|
||||
PORTB = 0;
|
||||
PORTC = 0;
|
||||
PORTD = 0;
|
||||
PORTE = 0;
|
||||
PORTF = 0;
|
||||
asm volatile("jmp 0x7E00");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::keyscanner::AVR -- AVR-based keyscanner component
|
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
|
||||
|
||||
#include "kaleidoscope/macro_helpers.h"
|
||||
#include "kaleidoscope/driver/keyscanner/Base.h"
|
||||
#include "kaleidoscope/device/avr/pins_and_ports.h"
|
||||
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#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_)); \
|
||||
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 \
|
||||
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<> \
|
||||
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<> \
|
||||
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] = {}; \
|
||||
\
|
||||
ISR(TIMER1_OVF_vect) { \
|
||||
Kaleidoscope.device().readMatrix(); \
|
||||
}
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace keyscanner {
|
||||
|
||||
struct AVRProps: kaleidoscope::driver::keyscanner::BaseProps {
|
||||
static const uint8_t debounce = 3;
|
||||
|
||||
/*
|
||||
* The following two lines declare an empty array. Both of these must be
|
||||
* shadowed by the descendant keyscanner description class.
|
||||
*/
|
||||
static constexpr uint8_t matrix_row_pins[] = {};
|
||||
static constexpr uint8_t matrix_col_pins[] = {};
|
||||
};
|
||||
|
||||
template <typename _KeyScannerProps>
|
||||
class AVR : public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
|
||||
private:
|
||||
typedef AVR<_KeyScannerProps> ThisType;
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
static_assert(
|
||||
sizeof(_KeyScannerProps::matrix_row_pins) > 0,
|
||||
"The key scanner description has an empty array of matrix row pins."
|
||||
);
|
||||
static_assert(
|
||||
sizeof(_KeyScannerProps::matrix_col_pins) > 0,
|
||||
"The key scanner description has an empty array of matrix column pins."
|
||||
);
|
||||
|
||||
wdt_disable();
|
||||
|
||||
for (uint8_t i = 0; i < _KeyScannerProps::matrix_columns; i++) {
|
||||
DDR_INPUT(_KeyScannerProps::matrix_col_pins[i]);
|
||||
ENABLE_PULLUP(_KeyScannerProps::matrix_col_pins[i]);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < _KeyScannerProps::matrix_rows; i++) {
|
||||
DDR_OUTPUT(_KeyScannerProps::matrix_row_pins[i]);
|
||||
OUTPUT_HIGH(_KeyScannerProps::matrix_row_pins[i]);
|
||||
}
|
||||
|
||||
/* Set up Timer1 for 1700usec */
|
||||
TCCR1B = _BV(WGM13);
|
||||
TCCR1A = 0;
|
||||
|
||||
const uint32_t cycles = (F_CPU / 2000000) * 1700;
|
||||
|
||||
ICR1 = cycles;
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
TIMSK1 = _BV(TOIE1);
|
||||
}
|
||||
|
||||
void __attribute__((optimize(3))) readMatrix(void) {
|
||||
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
|
||||
uint16_t mask, cols;
|
||||
|
||||
mask = debounceMaskForRow(current_row);
|
||||
|
||||
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
|
||||
cols = (readCols() & mask) | (keyState_[current_row] & ~mask);
|
||||
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
|
||||
debounceRow(cols ^ keyState_[current_row], current_row);
|
||||
keyState_[current_row] = cols;
|
||||
}
|
||||
}
|
||||
|
||||
void scanMatrix() {
|
||||
actOnMatrixScan();
|
||||
}
|
||||
|
||||
void __attribute__((optimize(3))) actOnMatrixScan() {
|
||||
for (byte row = 0; row < _KeyScannerProps::matrix_rows; row++) {
|
||||
for (byte col = 0; col < _KeyScannerProps::matrix_columns; col++) {
|
||||
uint8_t keyState = (bitRead(previousKeyState_[row], col) << 0) |
|
||||
(bitRead(keyState_[row], col) << 1);
|
||||
if (keyState) {
|
||||
ThisType::handleKeyswitchEvent(Key_NoKey, typename _KeyScannerProps::KeyAddr(row, col), keyState);
|
||||
}
|
||||
}
|
||||
previousKeyState_[row] = keyState_[row];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pressedKeyswitchCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
|
||||
count += __builtin_popcount(keyState_[r]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
bool isKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||
return (bitRead(keyState_[key_addr.row()],
|
||||
key_addr.col()) != 0);
|
||||
}
|
||||
|
||||
uint8_t previousPressedKeyswitchCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
|
||||
count += __builtin_popcount(previousKeyState_[r]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
bool wasKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||
return (bitRead(previousKeyState_[key_addr.row()],
|
||||
key_addr.col()) != 0);
|
||||
}
|
||||
|
||||
void maskKey(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||
if (!key_addr.isValid())
|
||||
return;
|
||||
|
||||
bitWrite(masks_[key_addr.row()], key_addr.col(), 1);
|
||||
}
|
||||
void unMaskKey(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||
if (!key_addr.isValid())
|
||||
return;
|
||||
|
||||
bitWrite(masks_[key_addr.row()], key_addr.col(), 0);
|
||||
}
|
||||
bool isKeyMasked(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||
if (!key_addr.isValid())
|
||||
return false;
|
||||
|
||||
return bitRead(masks_[key_addr.row()],
|
||||
key_addr.col());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef _KeyScannerProps KeyScannerProps_;
|
||||
static volatile uint16_t previousKeyState_[_KeyScannerProps::matrix_rows];
|
||||
static volatile uint16_t keyState_[_KeyScannerProps::matrix_rows];
|
||||
static uint16_t masks_[_KeyScannerProps::matrix_rows];
|
||||
static uint8_t debounce_matrix_[_KeyScannerProps::matrix_rows][_KeyScannerProps::matrix_columns];
|
||||
|
||||
/*
|
||||
* This function has loop unrolling disabled on purpose: we want to give the
|
||||
* hardware enough time to produce stable PIN reads for us. If we unroll the
|
||||
* loop, we will not have that, because even with the NOP, the codepath is too
|
||||
* fast. If we don't have stable reads, then entire rows or columns will behave
|
||||
* erratically.
|
||||
*
|
||||
* For this reason, we ask the compiler to not unroll our loop, which in turn,
|
||||
* gives hardware enough time to produce stable reads, at the cost of a little
|
||||
* bit of speed.
|
||||
*
|
||||
* Do not remove the attribute!
|
||||
*/
|
||||
__attribute__((optimize("no-unroll-loops")))
|
||||
uint16_t readCols() {
|
||||
uint16_t results = 0x00 ;
|
||||
for (uint8_t i = 0; i < _KeyScannerProps::matrix_columns; i++) {
|
||||
asm("NOP"); // We need to pause a beat before reading or we may read before the pin is hot
|
||||
results |= (!READ_PIN(_KeyScannerProps::matrix_col_pins[i]) << i);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
uint16_t debounceMaskForRow(uint8_t row) {
|
||||
uint16_t result = 0;
|
||||
|
||||
for (uint16_t c = 0; c < _KeyScannerProps::matrix_columns; ++c) {
|
||||
if (debounce_matrix_[row][c]) {
|
||||
--debounce_matrix_[row][c];
|
||||
} else {
|
||||
result |= _BV(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void debounceRow(uint16_t change, uint8_t row) {
|
||||
for (uint16_t i = 0; i < _KeyScannerProps::matrix_columns; ++i) {
|
||||
if (change & _BV(i)) {
|
||||
debounce_matrix_[row][i] = _KeyScannerProps::debounce;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::keyscanner::base -- Keyscanner base class
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "kaleidoscope/key_defs.h"
|
||||
#include "kaleidoscope/MatrixAddr.h"
|
||||
|
||||
#define KEYSCANNER_PROPS(ROWS_, COLS_) \
|
||||
static constexpr uint8_t matrix_rows = ROWS_; \
|
||||
static constexpr uint8_t matrix_columns = COLS_; \
|
||||
typedef MatrixAddr<matrix_rows, matrix_columns> KeyAddr;
|
||||
|
||||
#define KEYSCANNER_PROPS_BOILERPLATE(BOARD) \
|
||||
const uint8_t BOARD::matrix_rows; \
|
||||
const uint8_t BOARD::matrix_columns;
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace keyscanner {
|
||||
|
||||
struct BaseProps {
|
||||
static constexpr uint8_t matrix_rows = 0;
|
||||
static constexpr uint8_t matrix_columns = 0;
|
||||
|
||||
typedef MatrixAddr<matrix_rows, matrix_columns> KeyAddr;
|
||||
};
|
||||
|
||||
template <typename _KeyScannerProps>
|
||||
class Base {
|
||||
public:
|
||||
Base() {}
|
||||
|
||||
typedef typename _KeyScannerProps::KeyAddr KeyAddr;
|
||||
|
||||
static void handleKeyswitchEvent(Key mappedKey, KeyAddr key_addr, uint8_t keyState);
|
||||
|
||||
void setup() {}
|
||||
void readMatrix() {}
|
||||
void scanMatrix() {}
|
||||
void actOnMatrixScan() {}
|
||||
|
||||
uint8_t pressedKeyswitchCount() {
|
||||
return 0;
|
||||
}
|
||||
bool isKeyswitchPressed(KeyAddr key_addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t previousPressedKeyswitchCount() {
|
||||
return 0;
|
||||
}
|
||||
bool wasKeyswitchPressed(KeyAddr key_addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void maskKey(KeyAddr key_addr) {}
|
||||
void unMaskKey(KeyAddr key_addr) {}
|
||||
bool isKeyMasked(KeyAddr key_addr) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::keyscanner::None -- Dummy keyscanner component
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "kaleidoscope/driver/keyscanner/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace keyscanner {
|
||||
|
||||
/*
|
||||
* The purpose of this class is to serve as a default inside the base
|
||||
* `kaleidoscope::device::Base` class, with a name more descriptive than
|
||||
* `keyscanner::Base`. In practice, one shouldn't use it, and should override
|
||||
* the bootloader in the device description.
|
||||
*/
|
||||
class None : public kaleidoscope::driver::keyscanner::Base<BaseProps> {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::led::Base -- LED hardware driver base class for Kaleidoscope
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CRGB
|
||||
#error cRGB and CRGB *must* be defined before including this header!
|
||||
#endif
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace led {
|
||||
|
||||
struct BaseProps {
|
||||
static constexpr uint8_t led_count = 0;
|
||||
};
|
||||
|
||||
template <typename _LEDDriverProps>
|
||||
class Base {
|
||||
public:
|
||||
Base() {}
|
||||
|
||||
void setup() {}
|
||||
void syncLeds(void) {}
|
||||
void setCrgbAt(uint8_t i, cRGB color) {}
|
||||
cRGB getCrgbAt(uint8_t i) {
|
||||
cRGB c = {
|
||||
0, 0, 0
|
||||
};
|
||||
return c;
|
||||
}
|
||||
uint8_t getLedIndex(uint8_t key_offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static class LEDs {
|
||||
private:
|
||||
uint8_t offset_;
|
||||
public:
|
||||
LEDs() : offset_(0) {}
|
||||
LEDs(uint8_t offset) : offset_(offset) {}
|
||||
|
||||
typedef LEDs ThisType;
|
||||
|
||||
constexpr uint8_t offset() {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
ThisType operator++() {
|
||||
++offset_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ThisType operator++(int) { // postfix ++
|
||||
ThisType copy(*this);
|
||||
++*this; // call the prefix increment
|
||||
return copy;
|
||||
}
|
||||
|
||||
ThisType operator--() {
|
||||
--offset_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ThisType operator--(int) { // postfix ++
|
||||
ThisType copy(*this);
|
||||
--*this; // call the prefix increment
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool operator==(const ThisType &other) const {
|
||||
return offset_ == other.offset_;
|
||||
}
|
||||
|
||||
bool operator!=(const ThisType &other) const {
|
||||
return offset_ != other.offset_;
|
||||
}
|
||||
|
||||
struct Range {
|
||||
typedef ThisType Iterator;
|
||||
static constexpr ThisType begin() {
|
||||
return ThisType(uint8_t(0));
|
||||
}
|
||||
static constexpr ThisType end() {
|
||||
return ThisType(_LEDDriverProps::led_count);
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr Range all() {
|
||||
return Range{};
|
||||
}
|
||||
constexpr const ThisType &operator*() const {
|
||||
return *this;
|
||||
}
|
||||
constexpr bool isValid(uint8_t index) {
|
||||
return (_LEDDriverProps::led_count > 0 && index < _LEDDriverProps::led_count);
|
||||
}
|
||||
} LEDs;
|
||||
|
||||
protected:
|
||||
typedef _LEDDriverProps Props_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::led::None -- Dummy LED hardware driver for Kaleidoscope
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CRGB
|
||||
|
||||
struct cRGB {
|
||||
uint8_t r, g, b;
|
||||
};
|
||||
|
||||
#define CRGB(r,g,b) (cRGB){b, g, r}
|
||||
|
||||
#endif
|
||||
|
||||
#include "kaleidoscope/driver/led/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace led {
|
||||
|
||||
/*
|
||||
* The purpose of this class is to serve as a default inside the base
|
||||
* `kaleidoscope::device::Base` class, with a name more descriptive than
|
||||
* `leddriver::Base`. In practice, one shouldn't use it, and should override the
|
||||
* bootloader in the device description.
|
||||
*/
|
||||
class None : public kaleidoscope::driver::led::Base<BaseProps> {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* driver::mcu::Base -- MCU driver base class for Kaleidoscope
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace mcu {
|
||||
|
||||
class Base {
|
||||
public:
|
||||
Base() {}
|
||||
|
||||
void setup() {}
|
||||
|
||||
/**
|
||||
* 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() {}
|
||||
/**
|
||||
* Attack the device to the host.
|
||||
*
|
||||
* Must restore the link detachFromHost severed.
|
||||
*/
|
||||
void attachToHost() {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* driver::MCU::None -- Dummy MCU driver for Kaleidoscope
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/driver/mcu/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace mcu {
|
||||
|
||||
/*
|
||||
* The purpose of this class is to serve as a default inside the base
|
||||
* `kaleidoscope::device::Base` class, with a name more descriptive than
|
||||
* `mcu::Base`. In practice, one shouldn't use it, and should override the
|
||||
* bootloader in the device description.
|
||||
*/
|
||||
class None : public kaleidoscope::driver::mcu::Base {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* 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
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/driver/storage/AVREEPROM.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace storage {
|
||||
|
||||
struct ATMega32U4EEPROMProps : kaleidoscope::driver::storage::AVREEPROMProps {
|
||||
static constexpr uint16_t length = 1024;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::storage::AVREEPROM -- Storage driver with AVR EEPROM backend
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/driver/storage/Base.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace storage {
|
||||
|
||||
struct AVREEPROMProps : kaleidoscope::driver::storage::BaseProps {
|
||||
static constexpr uint16_t length = 0;
|
||||
};
|
||||
|
||||
template <typename _StorageProps>
|
||||
class AVREEPROM : public kaleidoscope::driver::storage::Base<_StorageProps> {
|
||||
public:
|
||||
template<typename T>
|
||||
static T& get(uint16_t offset, T& t) {
|
||||
return EEPROM.get(offset, t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const T& put(uint16_t offset, T& t) {
|
||||
return 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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::storage::Base -- Base Storage driver class
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace storage {
|
||||
|
||||
struct BaseProps {
|
||||
static constexpr uint16_t length = 0;
|
||||
};
|
||||
|
||||
template <typename _StorageProps>
|
||||
class Base {
|
||||
public:
|
||||
template<typename T>
|
||||
static T& get(uint16_t offset, T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const T& put(uint16_t offset, T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
uint8_t read(int idx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write(int idx, uint8_t val) {}
|
||||
|
||||
void update(int idx, uint8_t val) {}
|
||||
|
||||
const uint16_t length() {
|
||||
return _StorageProps::length;
|
||||
}
|
||||
|
||||
void setup() {}
|
||||
void commit() {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* -*- mode: c++ -*-
|
||||
* kaleidoscope::driver::storage::None -- Dummy Storage hardware driver for Kaleidoscope
|
||||
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/driver/storage/Base.h"
|
||||
|
||||
namespace kaleidoscope {
|
||||
namespace driver {
|
||||
namespace storage {
|
||||
|
||||
/*
|
||||
* The purpose of this class is to serve as a default inside the base
|
||||
* `kaleidoscope::device::Base` class, with a name more descriptive than
|
||||
* `storage::Base`. In practice, one shouldn't use it, and should override the
|
||||
* bootloader in the device description.
|
||||
*/
|
||||
class None : public kaleidoscope::driver::storage::Base<BaseProps> {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue