Both the Atreus and the Planck ports use very similar architecture, lift out the common parts into a base class. Signed-off-by: Jesse Vincent <jesse@keyboard.io>pull/461/head
parent
a9ced18068
commit
94008c6b3d
@ -0,0 +1,174 @@
|
|||||||
|
/* -*- 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ARDUINO_AVR_PLANCK || ARDUINO_AVR_ATREUS
|
||||||
|
|
||||||
|
#include "Kaleidoscope.h"
|
||||||
|
#include "kaleidoscope/hardware/ATMegaKeyboard.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace hardware {
|
||||||
|
|
||||||
|
uint8_t ATMegaKeyboard::debounce = 3;
|
||||||
|
|
||||||
|
void ATMegaKeyboard::setup(void) {
|
||||||
|
wdt_disable();
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) {
|
||||||
|
DDR_INPUT(KeyboardHardware.matrix_col_pins[i]);
|
||||||
|
ENABLE_PULLUP(KeyboardHardware.matrix_col_pins[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < KeyboardHardware.matrix_rows; i++) {
|
||||||
|
DDR_OUTPUT(KeyboardHardware.matrix_row_pins[i]);
|
||||||
|
OUTPUT_HIGH(KeyboardHardware.matrix_row_pins[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up Timer1 for 500usec */
|
||||||
|
TCCR1B = _BV(WGM13);
|
||||||
|
TCCR1A = 0;
|
||||||
|
|
||||||
|
const uint32_t cycles = (F_CPU / 2000000) * 500;
|
||||||
|
|
||||||
|
ICR1 = cycles;
|
||||||
|
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||||
|
TIMSK1 = _BV(TOIE1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::detachFromHost() {
|
||||||
|
UDCON |= _BV(DETACH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::attachToHost() {
|
||||||
|
UDCON &= ~_BV(DETACH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::readMatrix(void) {
|
||||||
|
for (uint8_t current_row = 0; current_row < KeyboardHardware.matrix_rows; current_row++) {
|
||||||
|
uint16_t mask, cols;
|
||||||
|
|
||||||
|
KeyboardHardware.previousKeyState_[current_row] = KeyboardHardware.keyState_[current_row];
|
||||||
|
|
||||||
|
mask = debounceMaskForRow(current_row);
|
||||||
|
|
||||||
|
OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]);
|
||||||
|
cols = (readCols() & mask) | (KeyboardHardware.keyState_[current_row] & ~mask);
|
||||||
|
OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]);
|
||||||
|
debounceRow(cols ^ KeyboardHardware.keyState_[current_row], current_row);
|
||||||
|
KeyboardHardware.keyState_[current_row] = cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ATMegaKeyboard::pressedKeyswitchCount() {
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
for (int8_t r = 0; r < KeyboardHardware.matrix_rows; r++) {
|
||||||
|
count += __builtin_popcount(KeyboardHardware.keyState_[r]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATMegaKeyboard::isKeyswitchPressed(uint8_t row, byte col) {
|
||||||
|
return (bitRead(KeyboardHardware.keyState_[row], col) != 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATMegaKeyboard::isKeyswitchPressed(uint8_t keyIndex) {
|
||||||
|
keyIndex--;
|
||||||
|
return isKeyswitchPressed(keyIndex / KeyboardHardware.matrix_columns,
|
||||||
|
keyIndex % KeyboardHardware.matrix_columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::actOnMatrixScan() {
|
||||||
|
for (byte row = 0; row < KeyboardHardware.matrix_rows; row++) {
|
||||||
|
for (byte col = 0; col < KeyboardHardware.matrix_columns; col++) {
|
||||||
|
uint8_t keyState = (bitRead(KeyboardHardware.previousKeyState_[row], col) << 0) |
|
||||||
|
(bitRead(KeyboardHardware.keyState_[row], col) << 1);
|
||||||
|
if (keyState) {
|
||||||
|
handleKeyswitchEvent(Key_NoKey, row, col, keyState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyboardHardware.previousKeyState_[row] = KeyboardHardware.keyState_[row];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::scanMatrix() {
|
||||||
|
if (!do_scan_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_scan_ = false;
|
||||||
|
|
||||||
|
readMatrix();
|
||||||
|
actOnMatrixScan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::maskKey(byte row, byte col) {
|
||||||
|
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bitWrite(KeyboardHardware.masks_[row], col, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATMegaKeyboard::unMaskKey(byte row, byte col) {
|
||||||
|
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bitWrite(KeyboardHardware.masks_[row], col, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATMegaKeyboard::isKeyMasked(byte row, byte col) {
|
||||||
|
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(KeyboardHardware.masks_[row], col);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATMegaKeyboard::do_scan_;
|
||||||
|
|
||||||
|
uint16_t ATMegaKeyboard::readCols() {
|
||||||
|
uint16_t results = 0x00 ;
|
||||||
|
for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) {
|
||||||
|
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[i]) << i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ATMegaKeyboard::debounceMaskForRow(uint8_t row) {
|
||||||
|
uint16_t result = 0;
|
||||||
|
|
||||||
|
for (uint16_t c = 0; c < KeyboardHardware.matrix_columns; ++c) {
|
||||||
|
if (KeyboardHardware.debounce_matrix_[row][c]) {
|
||||||
|
--KeyboardHardware.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 < KeyboardHardware.matrix_columns; ++i) {
|
||||||
|
if (change & _BV(i)) {
|
||||||
|
KeyboardHardware.debounce_matrix_[row][i] = debounce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,148 @@
|
|||||||
|
/* -*- 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 ARDUINO_AVR_PLANCK || ARDUINO_AVR_ATREUS
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <KeyboardioHID.h>
|
||||||
|
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
|
||||||
|
|
||||||
|
#include "kaleidoscope/macro_helpers.h"
|
||||||
|
#include "kaleidoscope/key_events.h"
|
||||||
|
#include "kaleidoscope/hardware/avr/pins_and_ports.h"
|
||||||
|
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
|
struct cRGB {
|
||||||
|
uint8_t r, g, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CRGB(r,g,b) (cRGB){b, g, r}
|
||||||
|
|
||||||
|
#define ROW_PIN_LIST(...) __VA_ARGS__
|
||||||
|
#define COL_PIN_LIST(...) __VA_ARGS__
|
||||||
|
|
||||||
|
#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_ ;\
|
||||||
|
\
|
||||||
|
static uint16_t previousKeyState_[matrix_rows]; \
|
||||||
|
static uint16_t keyState_[matrix_rows]; \
|
||||||
|
static uint16_t masks_[matrix_rows]; \
|
||||||
|
static uint8_t debounce_matrix_[matrix_rows][matrix_columns];
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace hardware {
|
||||||
|
class ATMegaKeyboard {
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
static bool do_scan_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint16_t readCols();
|
||||||
|
uint16_t debounceMaskForRow(uint8_t row);
|
||||||
|
void debounceRow(uint16_t change, uint8_t row);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in new issue