@ -165,11 +165,21 @@ namespace kaleidoscope {
namespace device {
namespace imaginary {
ATMEGA32U4_KEYBOARD(
Keypad, Caterina,
ROW_PIN_LIST({ PIN_D0, PIN_D1 }),
COL_PIN_LIST({ PIN_C0, PIN_C1 })
);
struct KeypadProps : kaleidoscope::device::ATmega32U4KeyboardProps {
struct KeyScannerProps : public kaleidoscope::driver::keyscanner::ATmegaProps {
static constexpr uint8_t matrix_rows = 2;
static constexpr uint8_t matrix_columns = 2;
typedef MatrixAddr< matrix_rows , matrix_columns > KeyAddr;
static constexpr uint8_t matrix_row_pins[matrix_rows] = {PIN_D0, PIN_D1};
static constexpr uint8_t matrix_col_pins[matrix_columns] = {PIN_C0, PIN_C1};
};
typedef kaleidoscope::driver::keyscanner::ATmega< KeyScannerProps > KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "imaginary-keypad";
};
class Keypad: public kaleidoscope::device::ATmega32U4Keyboard< KeypadProps > {};
#define PER_KEY_DATA(dflt, \
R0C0, R0C1, \
@ -180,7 +190,7 @@ ATMEGA32U4_KEYBOARD(
}
}
typedef kaleidoscope::device::imaginary::Keypad Device ;
EXPORT_DEVICE(kaleidoscope::device::imaginary::Keypad) ;
}
#endif
@ -193,11 +203,47 @@ typedef kaleidoscope::device::imaginary::Keypad Device;
#include < Kaleidoscope.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::imaginary::KeypadProps::KeyScannerProps;
using KeyScanner = typename kaleidoscope::device::imaginary::KeypadProps::KeyScanner;
namespace kaleidoscope {
namespace device {
namespace imaginary {
AVR_KEYSCANNER_BOILERPLATE
// `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];
// Resolving is a bit different in case of templates, however: the name of the
// array is resolved within the scope of the namespace and the class, but the
// array size is not - because it is a template. Therefore, we need a fully
// qualified name there - or an alias in the global scope, which we set up just
// above.
template< > uint16_t KeyScanner::previousKeyState_[KeyScannerProps::matrix_rows] = {};
template< > uint16_t KeyScanner::keyState_[KeyScannerProps::matrix_rows] = {};
template< > uint16_t KeyScanner::masks_[KeyScannerProps::matrix_rows] = {};
template< > uint8_t KeyScanner::debounce_matrix_[KeyScannerProps::matrix_rows][KeyScannerProps::matrix_columns] = {};
// 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;
}
}
}