Compare commits

...

5 Commits

@ -14,11 +14,11 @@ DEFAULT_GOAL: smoke-sketches
PLUGIN_TEST_SUPPORT_DIR ?= $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/build-tools/
PLUGIN_TEST_BIN_DIR ?= $(PLUGIN_TEST_SUPPORT_DIR)/../toolchain/$(shell gcc --print-multiarch)/bin
setup: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt $(ARDUINO_CLI_PATH) configure-arduino-cli install-arduino-core-avr
setup: $(ARDUINO_CLI_PATH) configure-arduino-cli install-arduino-core-avr install-adafruit-core-samd $(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt
@:
checkout-platform: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt
checkout-platform: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt $(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd/boards.txt
@:
prepare-virtual: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt
@ -27,6 +27,12 @@ prepare-virtual: $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.
$(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/virtual/boards.txt:
$(MAKE) -C $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio prepare-virtual
$(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd/boards.txt:
git clone -c core.symlinks=true \
https://github.com/keyboardio/ArduinoCore-samd \
$(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd
ln -s $(KALEIDOSCOPE_DIR) $(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd/libraries/Kaleidoscope
ln -s $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/KeyboardioHID $(ARDUINO_DIRECTORIES_USER)/hardware/kaleidoscope/samd/libraries/KeyboardioHID
$(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/boards.txt:
git clone -c core.symlinks=true --recurse-submodules=":(exclude)avr/libraries/Kaleidoscope" --recurse-submodules=build-tools --recurse-submodules=toolchain --recurse-submodules=avr/libraries/ git://github.com/keyboardio/Kaleidoscope-Bundle-Keyboardio $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio

@ -35,7 +35,7 @@ ARDUINO_CONTENT ?= $(KALEIDOSCOPE_DIR)/.arduino
export ARDUINO_DIRECTORIES_DATA ?= $(ARDUINO_CONTENT)/data
export ARDUINO_DIRECTORIES_DOWNLOADS ?= $(ARDUINO_CONTENT)/downloads
export ARDUINO_CLI_CONFIG ?= $(ARDUINO_DIRECTORIES_DATA)/arduino-cli.yaml
export ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS ?= https://raw.githubusercontent.com/keyboardio/boardsmanager/master/package_keyboardio_index.json
export ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS ?= https://raw.githubusercontent.com/keyboardio/boardsmanager/master/package_keyboardio_index.json https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
# If it looks like Kaleidoscope is inside a "traditional" Arduino hardware directory
# in the user's homedir, let's use that.
@ -145,10 +145,19 @@ configure-arduino-cli: $(ARDUINO_DIRECTORIES_DATA)/arduino-cli.yaml
$(ARDUINO_DIRECTORIES_DATA)/arduino-cli.yaml:
$(QUIET) $(ARDUINO_CLI) config init
$(QUIET) $(ARDUINO_CLI) core update-index
install-arduino-core-kaleidoscope:
$(QUIET) $(ARDUINO_CLI) core install "keyboardio:avr"
install-arduino-core-kaleidoscope-samd:
$(QUIET) $(ARDUINO_CLI) core install "kaleidoscope:samd"
install-arduino-core-avr:
$(QUIET) $(ARDUINO_CLI) core install "arduino:avr"
install-adafruit-core-samd:
$(QUIET) $(ARDUINO_CLI) core install "adafruit:samd"
arduino-cli-run:
$(ARDUINO_CLI) $(ARGS)

@ -0,0 +1,2 @@
DEFAULT_SKETCH="Atreus"
BOARD="keyboardio_atreus"

@ -0,0 +1,50 @@
# This makefile for a Kaleidoscope sketch pulls in all the targets
# required to build the example
$(info "mebbe Adding $(KALEIDOSCOPE_DIR)")
ifneq ($(KALEIDOSCOPE_DIR),)
search_path += $(KALEIDOSCOPE_DIR)
$(info "Adding $(KALEIDOSCOPE_DIR)")
endif
ifneq ($(ARDUINO_DIRECTORIES_USER),)
search_path += $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope
endif
ifeq ($(shell uname -s),Darwin)
search_path += $(HOME)/Documents/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
else
search_path += $(HOME)/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
endif
sketch_makefile := etc/makefiles/sketch.mk
$(foreach candidate, $(search_path), $(if $(wildcard $(candidate)/$(sketch_makefile)), $(eval ks_dir ?= $(candidate))))
ifneq ($(ks_dir),)
$(info Using Kaleidoscope from $(ks_dir))
export KALEIDOSCOPE_DIR := $(ks_dir)
include $(ks_dir)/$(sketch_makefile)
else
$(info I can't find your Kaleidoscope installation.)
$(info )
$(info I tried looking in:)
$(info )
$(foreach candidate, $(search_path), $(info $(candidate)))
$(info )
$(info The easiest way to fix this is to set the 'KALEIDOSCOPE_DIR' environment)
$(info variable to the location of your Kaleidoscope directory.)
endif
null-target:
$(info You should never see this message)
@:

@ -0,0 +1,146 @@
/* -*- mode: c++ -*-
* Atreus -- Chrysalis-enabled Sketch for the Keyboardio Atreus
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef BUILD_INFORMATION
#define BUILD_INFORMATION "locally built"
#endif
#include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h"
#include "Kaleidoscope-FocusSerial.h"
#include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Qukeys.h"
#include "Kaleidoscope-SpaceCadet.h"
#define MO(n) ShiftToLayer(n)
#define TG(n) LockLayer(n)
enum {
MACRO_QWERTY,
MACRO_VERSION_INFO
};
#define Key_Exclamation LSHIFT(Key_1)
#define Key_At LSHIFT(Key_2)
#define Key_Hash LSHIFT(Key_3)
#define Key_Dollar LSHIFT(Key_4)
#define Key_Percent LSHIFT(Key_5)
#define Key_Caret LSHIFT(Key_6)
#define Key_And LSHIFT(Key_7)
#define Key_Star LSHIFT(Key_8)
#define Key_Plus LSHIFT(Key_Equals)
enum {
QWERTY,
FUN,
UPPER
};
/* *INDENT-OFF* */
KEYMAPS(
[QWERTY] = KEYMAP_STACKED
(
Key_Q ,Key_W ,Key_E ,Key_R ,Key_T
,Key_A ,Key_S ,Key_D ,Key_F ,Key_G
,Key_Z ,Key_X ,Key_C ,Key_V ,Key_B, Key_Backtick
,Key_Esc ,Key_Tab ,Key_LeftGui ,Key_LeftShift ,Key_Backspace ,Key_LeftControl
,Key_Y ,Key_U ,Key_I ,Key_O ,Key_P
,Key_H ,Key_J ,Key_K ,Key_L ,Key_Semicolon
,Key_Backslash,Key_N ,Key_M ,Key_Comma ,Key_Period ,Key_Slash
,Key_LeftAlt ,Key_Space ,MO(FUN) ,Key_Minus ,Key_Quote ,Key_Enter
),
[FUN] = KEYMAP_STACKED
(
Key_Exclamation ,Key_At ,Key_UpArrow ,Key_Dollar ,Key_Percent
,Key_LeftParen ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_RightParen
,Key_LeftBracket ,Key_RightBracket ,Key_Hash ,Key_LeftCurlyBracket ,Key_RightCurlyBracket ,Key_Caret
,TG(UPPER) ,Key_Insert ,Key_LeftGui ,Key_LeftShift ,Key_Delete ,Key_LeftControl
,Key_PageUp ,Key_7 ,Key_8 ,Key_9 ,Key_Backspace
,Key_PageDown ,Key_4 ,Key_5 ,Key_6 ,___
,Key_And ,Key_Star ,Key_1 ,Key_2 ,Key_3 ,Key_Plus
,Key_LeftAlt ,Key_Space ,___ ,Key_Period ,Key_0 ,Key_Equals
),
[UPPER] = KEYMAP_STACKED
(
Key_Insert ,Key_Home ,Key_UpArrow ,Key_End ,Key_PageUp
,Key_Delete ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_PageDown
,M(MACRO_VERSION_INFO) ,Consumer_VolumeIncrement ,XXX ,XXX ,___ ,___
,MoveToLayer(QWERTY) ,Consumer_VolumeDecrement ,___ ,___ ,___ ,___
,Key_UpArrow ,Key_F7 ,Key_F8 ,Key_F9 ,Key_F10
,Key_DownArrow ,Key_F4 ,Key_F5 ,Key_F6 ,Key_F11
,___ ,XXX ,Key_F1 ,Key_F2 ,Key_F3 ,Key_F12
,___ ,___ ,MoveToLayer(QWERTY) ,Key_PrintScreen ,Key_ScrollLock ,Consumer_PlaySlashPause
)
)
/* *INDENT-ON* */
KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings,
EEPROMKeymap,
Focus,
FocusEEPROMCommand,
FocusSettingsCommand,
Qukeys,
SpaceCadet,
OneShot,
Macros,
MouseKeys
);
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
switch (macroIndex) {
case MACRO_QWERTY:
// This macro is currently unused, but is kept around for compatibility
// reasons. We used to use it in place of `MoveToLayer(QWERTY)`, but no
// longer do. We keep it so that if someone still has the old layout with
// the macro in EEPROM, it will keep working after a firmware update.
Layer.move(QWERTY);
break;
case MACRO_VERSION_INFO:
if (keyToggledOn(keyState)) {
Macros.type(PSTR("Keyboardio Atreus - Kaleidoscope "));
Macros.type(PSTR(BUILD_INFORMATION));
}
break;
default:
break;
}
return MACRO_NONE;
}
void setup() {
Kaleidoscope.setup();
SpaceCadet.disable();
EEPROMKeymap.setup(10);
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,6 @@
{
"cpu": {
"fqbn": "kaleidoscope:samd:kbio_metro_m4",
"port": ""
}
}

@ -0,0 +1,21 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Keyboardio-Atreus -- Keyboardio Atreus hardware support 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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/device/keyboardio/SAMDTestbed.h"

@ -0,0 +1,57 @@
/* -*- 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
#if defined(__SAMD51__) || defined(__SAMD21__) || defined(KALEIDOSCOPE_VIRTUAL_BUILD)
#include <Arduino.h>
#include "kaleidoscope/device/Base.h"
#include "kaleidoscope/driver/mcu/SAMD.h"
#include "kaleidoscope/driver/keyscanner/SAMD.h"
#include "kaleidoscope/driver/storage/Flash.h"
namespace kaleidoscope {
namespace device {
struct SAMDStorageProps : public kaleidoscope::driver::storage::FlashProps {
static constexpr uint16_t length = EEPROM_EMULATION_SIZE;
};
struct SAMDKeyboardProps : kaleidoscope::device::BaseProps {
typedef kaleidoscope::driver::mcu::SAMD MCU;
typedef SAMDStorageProps StorageProps;
typedef kaleidoscope::driver::storage::Flash<StorageProps> Storage;
};
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
template <typename _DeviceProps>
class SAMDKeyboard : public kaleidoscope::device::Base<_DeviceProps> {
public:
auto serialPort() -> decltype(Serial) & {
return Serial;
}
};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
template <typename _DeviceProps>
class SAMDKeyboard;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
}
}
#endif

@ -0,0 +1,65 @@
/* -*- mode: c++ -*-
* Keyboardio SAMD Testbed hardware support for Kaleidoscope
* Copyright (C) 2019, 2020 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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/>.
*/
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#ifdef KEYBOARDIO_SAMD_TESTBED
#include "kaleidoscope/Runtime.h"
#include "kaleidoscope/driver/keyscanner/Base_Impl.h"
// Here, we set up aliases to the device's KeyScanner and KeyScannerProps
// in the global namespace within the scope of this file. We'll use these
// aliases to simplify some template initialization code below.
using KeyScannerProps = typename kaleidoscope::device::keyboardio::SAMDTestbedProps::KeyScannerProps;
using KeyScanner = typename kaleidoscope::device::keyboardio::SAMDTestbedProps::KeyScanner;
namespace kaleidoscope {
namespace device {
namespace keyboardio {
// `KeyScannerProps` here refers to the alias set up above. We do not need to
// prefix the `matrix_rows` and `matrix_columns` names within the array
// declaration, because those are resolved within the context of the class, so
// the `matrix_rows` in `KeyScannerProps::matrix_row_pins[matrix_rows]` gets
// resolved as `KeyScannerProps::matrix_rows`.
const uint8_t KeyScannerProps::matrix_rows;
const uint8_t KeyScannerProps::matrix_columns;
constexpr uint8_t KeyScannerProps::matrix_row_pins[matrix_rows];
constexpr uint8_t KeyScannerProps::matrix_col_pins[matrix_columns];
// `KeyScanner` here refers to the alias set up above, just like in the
// `KeyScannerProps` case above.
template<> KeyScanner::row_state_t KeyScanner::matrix_state_[KeyScannerProps::matrix_rows] = {};
// We set up the TIMER1 interrupt vector here. Due to dependency reasons, this
// cannot be in a header-only driver, and must be placed here.
//
// Timer1 is responsible for setting a property on the KeyScanner, which will
// tell it to do a scan. We use this to make sure that scans happen at roughly
// the intervals we want. We do the scan outside of the interrupt scope for
// practical reasons: guarding every codepath against interrupts that can be
// reached from the scan is far too tedious, for very little gain.
//ISR(TIMER1_OVF_vect) { Runtime.device().keyScanner().do_scan_ = true; }
}
}
}
#endif
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD

@ -0,0 +1,96 @@
/* -*- mode: c++ -*-
* Keyboardio SAMD Testbed hardware support 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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 KEYBOARDIO_SAMD_TESTBED
#include <Arduino.h>
#include "kaleidoscope/device/SAMDKeyboard.h"
#include "kaleidoscope/driver/bootloader/samd/Bossac.h"
namespace kaleidoscope {
namespace device {
namespace keyboardio {
struct SAMDTestbedProps : kaleidoscope::device::SAMDKeyboardProps {
struct KeyScannerProps : public kaleidoscope::driver::keyscanner::SAMDProps {
static constexpr uint8_t matrix_rows = 4;
static constexpr uint8_t matrix_columns = 12;
typedef MatrixAddr<matrix_rows, matrix_columns> KeyAddr;
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
static constexpr uint8_t matrix_row_pins[matrix_rows] = {2,3,4,5};
static constexpr uint8_t matrix_col_pins[matrix_columns] = {7,8,9,10,11,12,13,14,15,16,17,18};
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
};
typedef kaleidoscope::driver::keyscanner::SAMD<KeyScannerProps> KeyScanner;
typedef kaleidoscope::driver::bootloader::samd::Bossac BootLoader;
static constexpr const char *short_name = "testbed";
};
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class SAMDTestbed: public kaleidoscope::device::SAMDKeyboard<SAMDTestbedProps> {};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
/* Device definition omitted for virtual device builds.
* We need to forward declare the device name, though, as there are
* some legacy extern references to boards whose definition
* depends on this.
*/
class SAMDTestbed;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#define PER_KEY_DATA(dflt, \
R0C0, R0C1, R0C2, R0C3, R0C4, R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C0, R1C1, R1C2, R1C3, R1C4, R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
R0C0, R0C1, R0C2, R0C3, R0C4, XXX, XXX, R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C0, R1C1, R1C2, R1C3, R1C4, XXX, XXX, R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11
#define PER_KEY_DATA_STACKED(dflt, \
R0C0, R0C1, R0C2, R0C3, R0C4, \
R1C0, R1C1, R1C2, R1C3, R1C4, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, \
\
R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
R0C0, R0C1, R0C2, R0C3, R0C4, XXX, XXX, R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C0, R1C1, R1C2, R1C3, R1C4, XXX, XXX, R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11
}
}
EXPORT_DEVICE(kaleidoscope::device::keyboardio::SAMDTestbed)
}
#endif

@ -0,0 +1,271 @@
/* -*- mode: c++ -*-
* kaleidoscope::driver::keyscanner::SAMD -- Microchip SAMD-based keyscanner component
* Copyright (C) 2018-2020 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/macro_helpers.h"
#include "kaleidoscope/driver/keyscanner/Base.h"
#include "kaleidoscope/driver/keyscanner/None.h"
//todo
#define DDR_INPUT
#define DDR_OUTPUT
#define ENABLE_PULLUP
#define OUTPUT_HIGH
#define OUTPUT_TOGGLE
#define READ_TOGGLE
#define READ_PIN
namespace kaleidoscope {
namespace driver {
namespace keyscanner {
struct SAMDProps: kaleidoscope::driver::keyscanner::BaseProps {
static const uint16_t keyscan_interval = 1500;
typedef uint16_t RowState;
/*
* 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[] = {};
};
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
template <typename _KeyScannerProps>
class SAMD: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
private:
typedef SAMD<_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."
);
//TODO XXX WDT_Disable(WDT);
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]);
}
setScanCycleTime(_KeyScannerProps::keyscan_interval);
}
/* setScanCycleTime takes a value of between 0 and 8192. This corresponds (roughly) to the number of microseconds to wait between scanning the key matrix. Our debouncing algorithm does four checks before deciding that a result is valid. Most normal mechanical switches specify a 5ms debounce period. On an ATMega32U4, 1700 gets you about 5ms of debouncing.
Because keycanning is triggered by an interrupt but not run in that interrupt, the actual amount of time between scans is prone to a little bit of jitter.
*/
void setScanCycleTime(uint16_t c) {
/* TODO
TCCR1B = _BV(WGM13);
TCCR1A = 0;
*/
const uint32_t cycles = (F_CPU / 2000000) * c;
/* TODO
ICR1 = cycles;
TCCR1B = _BV(WGM13) | _BV(CS10);
TIMSK1 = _BV(TOIE1);
*/
}
__attribute__((optimize(3)))
void readMatrix(void) {
typename _KeyScannerProps::RowState any_debounced_changes = 0;
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
typename _KeyScannerProps::RowState hot_pins = readCols();
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
any_debounced_changes |= debounce(hot_pins, &matrix_state_[current_row].debouncer);
if (any_debounced_changes) {
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
matrix_state_[current_row].current = matrix_state_[current_row].debouncer.debounced_state;
}
}
}
}
void scanMatrix() {
if (do_scan_) {
do_scan_ = false;
readMatrix();
}
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(matrix_state_[row].previous, col) << 0) | (bitRead(matrix_state_[row].current, col) << 1);
if (keyState) {
ThisType::handleKeyswitchEvent(Key_NoKey, typename _KeyScannerProps::KeyAddr(row, col), keyState);
}
}
matrix_state_[row].previous = matrix_state_[row].current;
}
}
uint8_t pressedKeyswitchCount() {
uint8_t count = 0;
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
count += __builtin_popcount(matrix_state_[r].current);
}
return count;
}
bool isKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
return (bitRead(matrix_state_[key_addr.row()].current, key_addr.col()) != 0);
}
uint8_t previousPressedKeyswitchCount() {
uint8_t count = 0;
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
count += __builtin_popcount(matrix_state_[r].previous);
}
return count;
}
bool wasKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
return (bitRead(matrix_state_[key_addr.row()].previous,
key_addr.col()) != 0);
}
void maskKey(typename _KeyScannerProps::KeyAddr key_addr) {
if (!key_addr.isValid())
return;
bitWrite(matrix_state_[key_addr.row()].masks, key_addr.col(), 1);
}
void unMaskKey(typename _KeyScannerProps::KeyAddr key_addr) {
if (!key_addr.isValid())
return;
bitWrite(matrix_state_[key_addr.row()].masks, key_addr.col(), 0);
}
bool isKeyMasked(typename _KeyScannerProps::KeyAddr key_addr) {
if (!key_addr.isValid())
return false;
return bitRead(matrix_state_[key_addr.row()].masks,
key_addr.col());
}
bool do_scan_;
protected:
/*
each of these variables are storing the state for a row of keys
so for key 0, the counter is represented by db0[0] and db1[0]
and the state in debounced_state[0].
*/
struct debounce_t {
typename _KeyScannerProps::RowState db0; // counter bit 0
typename _KeyScannerProps::RowState db1; // counter bit 1
typename _KeyScannerProps::RowState debounced_state; // debounced state
};
struct row_state_t {
typename _KeyScannerProps::RowState previous;
typename _KeyScannerProps::RowState current;
typename _KeyScannerProps::RowState masks;
debounce_t debouncer;
};
private:
typedef _KeyScannerProps KeyScannerProps_;
static row_state_t matrix_state_[_KeyScannerProps::matrix_rows];
/*
* 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")))
typename _KeyScannerProps::RowState readCols() {
typename _KeyScannerProps::RowState hot_pins = 0;
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
hot_pins |= (!READ_PIN(_KeyScannerProps::matrix_col_pins[i]) << i);
}
return hot_pins;
}
static inline typename _KeyScannerProps::RowState debounce(
typename _KeyScannerProps::RowState sample, debounce_t *debouncer
) {
typename _KeyScannerProps::RowState delta, changes;
// Use xor to detect changes from last stable state:
// if a key has changed, it's bit will be 1, otherwise 0
delta = sample ^ debouncer->debounced_state;
// Increment counters and reset any unchanged bits:
// increment bit 1 for all changed keys
debouncer->db1 = ((debouncer->db1) ^ (debouncer->db0)) & delta;
// increment bit 0 for all changed keys
debouncer->db0 = ~(debouncer->db0) & delta;
// Calculate returned change set: if delta is still true
// and the counter has wrapped back to 0, the key is changed.
changes = ~(~delta | (debouncer->db0) | (debouncer->db1));
// Update state: in this case use xor to flip any bit that is true in changes.
debouncer->debounced_state ^= changes;
return changes;
}
};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
template <typename _KeyScannerProps>
class SAMD : public keyscanner::None {};
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
}
}
}

@ -25,7 +25,7 @@
#pragma once
#ifdef __SAMD21G18A__
#if defined(__SAMD21__) || defined(__SAMD51__)
#include "kaleidoscope/driver/storage/Base.h"
#include <FlashStorage.h>

Loading…
Cancel
Save