diff --git a/src/Kaleidoscope-Model01-TestMode.h b/src/Kaleidoscope-Model01-TestMode.h new file mode 100644 index 00000000..55ed92cb --- /dev/null +++ b/src/Kaleidoscope-Model01-TestMode.h @@ -0,0 +1,19 @@ +/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01. + * Copyright (C) 2017-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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/Model01-TestMode.h" diff --git a/src/kaleidoscope/plugin/Model01-TestMode.cpp b/src/kaleidoscope/plugin/Model01-TestMode.cpp new file mode 100644 index 00000000..b7bf3cce --- /dev/null +++ b/src/kaleidoscope/plugin/Model01-TestMode.cpp @@ -0,0 +1,166 @@ +/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01. + * Copyright (C) 2017-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 . + */ + +#include "Kaleidoscope.h" +#include "Kaleidoscope-Model01-TestMode.h" +#include "Kaleidoscope-LEDEffect-Rainbow.h" + +namespace kaleidoscope { +namespace plugin { + +constexpr uint8_t CHATTER_CYCLE_LIMIT = 30; +constexpr uint8_t TOGGLED_OFF = 2; +constexpr uint8_t TOGGLED_ON = 1; +constexpr uint8_t HELD = 3; +constexpr uint8_t RELEASED = 0; + +EventHandlerResult TestMode::beforeReportingState() { + if (KeyboardHardware.isKeyswitchPressed(R0C0) && + KeyboardHardware.isKeyswitchPressed(R0C6) && + KeyboardHardware.isKeyswitchPressed(R3C6) && + KeyboardHardware.pressedKeyswitchCount() == 3) { + run_tests(); + } + return EventHandlerResult::OK; +} + +void TestMode::waitForKeypress() { + for (uint8_t temp = 0; temp < 8; temp++) { + KeyboardHardware.readMatrix(); + } + while (1) { + KeyboardHardware.readMatrix(); + if (KeyboardHardware.isKeyswitchPressed(R3C6) + && KeyboardHardware.pressedKeyswitchCount() == 1 + && KeyboardHardware.previousLeftHandState.all == 0) { + break; + } + } +} + +void TestMode::set_leds(cRGB color) { + ::LEDControl.set_all_leds_to(color); + ::LEDControl.syncLeds(); + waitForKeypress(); +} + +void TestMode::test_leds(void) { + constexpr cRGB red = CRGB(201, 0, 0); + constexpr cRGB blue = CRGB(0, 0, 201); + constexpr cRGB green = CRGB(0, 201, 0); + constexpr cRGB brightWhite = CRGB(160, 160, 160); + + // make all the LEDs bright red + set_leds(red); + // make all the LEDs bright green + set_leds(green); + // make all the LEDs bright blue + set_leds(blue); + // make all the LEDs bright white (1.6A) + set_leds(brightWhite); + // rainbow for 10 seconds + for (auto i = 0; i < 1000; i++) { + ::LEDRainbowEffect.update(); + ::LEDControl.syncLeds(); + } + waitForKeypress(); +} + + + +void TestMode::handleKeyEvent(side_data_t *side, keydata_t *oldState, keydata_t *newState, uint8_t row, uint8_t col, uint8_t col_offset) { + + constexpr cRGB red = CRGB(201, 0, 0); + constexpr cRGB blue = CRGB(0, 0, 201); + constexpr cRGB green = CRGB(0, 201, 0); + + const uint8_t keynum = (row * 8) + (col); + + const uint8_t keyState = ((bitRead(oldState->all, keynum) << 1) | + (bitRead(newState->all, keynum) << 0)); + if (keyState == TOGGLED_ON) { + if (side->cyclesSinceStateChange[keynum] < CHATTER_CYCLE_LIMIT) { + bitSet(side->badKeys, keynum); + } + side->cyclesSinceStateChange[keynum] = 0; + } else if (side->cyclesSinceStateChange[keynum] <= CHATTER_CYCLE_LIMIT) { + side->cyclesSinceStateChange[keynum]++; + } + + + + // If the key is held down + if (keyState == HELD) { + KeyboardHardware.setCrgbAt(row, col_offset - col, green); + } + // If we triggered chatter detection ever on this key + else if (bitRead(side->badKeys, keynum) == 1) { + KeyboardHardware.setCrgbAt(row, col_offset - col, red); + } + + // If the key was just released + else if (keyState == TOGGLED_OFF) { + KeyboardHardware.setCrgbAt(row, col_offset - col, blue); + } +} + + +void TestMode::testMatrix() { + // Reset bad keys from previous tests. + side_data_t left = {{0}, 0}; + side_data_t right = {{0}, 0}; + + + ::LEDControl.set_all_leds_to(200, 0, 0); + // Clear out the key event buffer so we don't get messed up information from + // taps during LED test mode. + while (1) { + KeyboardHardware.readMatrix(); + if (KeyboardHardware.isKeyswitchPressed(R0C0) && + KeyboardHardware.isKeyswitchPressed(R0C6) && + KeyboardHardware.isKeyswitchPressed(R3C6) && + KeyboardHardware.pressedKeyswitchCount() == 3) { + break; + } + for (byte row = 0; row < 4; row++) { + for (byte col = 0; col < 8; col++) { + handleKeyEvent(&left, &(KeyboardHardware.previousLeftHandState), &(KeyboardHardware.leftHandState), row, col, 7); + handleKeyEvent(&right, &(KeyboardHardware.previousRightHandState), &(KeyboardHardware.rightHandState), row, col, 15); + } + } + ::LEDControl.syncLeds(); + } +} + +void TestMode::toggle_programming_leds_on() { + PORTD |= (1 << 5); + PORTB |= (1 << 0); +} + +void TestMode::run_tests() { + // Serial.println("Running tests"); + toggle_programming_leds_on(); + // Disable debouncing + KeyboardHardware.setKeyscanInterval(2); + test_leds(); + testMatrix(); + // Serial.println("Done running tests"); +} + +} +} + +kaleidoscope::plugin::TestMode TestMode; diff --git a/src/kaleidoscope/plugin/Model01-TestMode.h b/src/kaleidoscope/plugin/Model01-TestMode.h new file mode 100644 index 00000000..a3cbae0c --- /dev/null +++ b/src/kaleidoscope/plugin/Model01-TestMode.h @@ -0,0 +1,53 @@ +/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01. + * Copyright (C) 2017-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 . + */ + +#pragma once + +#ifndef ARDUINO_AVR_MODEL01 +#error The Kaleidoscope-Model01-TestMode plugin was designed for the Keyboardio Model01, and does not work with any other hardware. +#endif + +#include +#include "Kaleidoscope.h" + +namespace kaleidoscope { +namespace plugin { + +class TestMode : public kaleidoscope::Plugin { + public: + typedef struct { + uint8_t cyclesSinceStateChange[32]; + uint32_t badKeys; + + } side_data_t; + + TestMode(void) {}; + + EventHandlerResult beforeReportingState(); + + private: + static void run_tests(); + static void test_leds(); + static void testMatrix(); + static void toggle_programming_leds_on(); + static void handleKeyEvent(side_data_t *side, keydata_t *oldState, keydata_t *newState, uint8_t row, uint8_t col, uint8_t col_offset); + static void waitForKeypress(); + static void set_leds(cRGB color); +}; +} +} + +extern kaleidoscope::plugin::TestMode TestMode;