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