From c3dcba47f3929e35a23ff875dec6869a53d1b32e Mon Sep 17 00:00:00 2001 From: Malcolm Vigren Date: Fri, 19 Jan 2024 20:40:54 +0100 Subject: [PATCH] Backlight and wave scheme works in simulator --- Makefile | 11 +++++-- core/backlight/backlight.h | 2 +- core/backlight/color.h | 40 ++++++++++++++++++++++++++ core/backlight/schemes/scheme.h | 3 +- core/backlight/schemes/wave.cpp | 40 ++++++++++++++++++++++++++ core/backlight/schemes/wave.h | 31 ++++++++++++++++++++ core/backlight/test/test_backlight.cpp | 8 ++++++ core/firmware.cpp | 17 +++++------ core/firmware.h | 13 +++++++++ core/testutil/testdevice.h | 1 + simulator/Makefile | 6 ++-- simulator/keyboard_state.cpp | 18 ++++++------ simulator/simulator_device.cpp | 9 +++--- simulator/simulator_device.h | 4 +++ simulator/simulator_window.cpp | 1 + 15 files changed, 176 insertions(+), 28 deletions(-) create mode 100644 core/backlight/schemes/wave.cpp create mode 100644 core/backlight/schemes/wave.h diff --git a/Makefile b/Makefile index b24105e..fb40131 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ TEST_CXX_FLAGS = -c -g -Wall -Wextra -std=gnu++23 CXX = $(TEENSY_COMPILE)/arm-none-eabi-g++ CC = $(TEENSY_COMPILE)/arm-none-eabi-gcc AR = $(TEENSY_COMPILE)/arm-none-eabi-gcc-ar +SIZE = $(TEENSY_COMPILE)/arm-none-eabi-size PRECOMPILE_HELPER = $(TEENSY_TOOLS)/teensy-tools/1.58.0/precompile_helper OBJCOPY = $(TEENSY_COMPILE)/arm-none-eabi-objcopy POST_COMPILE = $(TEENSY_TOOLS)/teensy-tools/1.58.0/teensy_post_compile @@ -65,8 +66,10 @@ OCTOWS2811_SOURCES = $(wildcard $(TEENSY_LIBS)/OctoWS2811/*.cpp) CORE_CPP_SOURCES = $(wildcard $(TEENSY4_CORE)/*.cpp) CORE_C_SOURCES = $(wildcard $(TEENSY4_CORE)/*.c) LIB_SOURCES = $(FASTLED_SOURCES) $(SPI_SOURCES) $(OCTOWS2811_SOURCES) -NON_HARDWARE_SOURCES = $(wildcard core/*.cpp) $(wildcard core/**/*.cpp) $(wildcard common/*.cpp) $(wildcard common/**/*.cpp) -TEST_SOURCES = $(NON_HARDWARE_SOURCES) $(wildcard core/test/*.cpp) $(wildcard core/**/test/*.cpp) $(CATCH2_PATH)/extras/catch_amalgamated.cpp +NON_HARDWARE_SOURCES_NON_FILTERED = $(wildcard core/*.cpp) $(wildcard core/**/**/*.cpp) $(wildcard core/**/*.cpp) $(wildcard common/*.cpp) $(wildcard common/**/*.cpp) $(wildcard common/**/**/*.cpp) +TEST_CPP = $(wildcard core/test/*.cpp) $(wildcard core/**/test/*.cpp) $(CATCH2_PATH)/extras/catch_amalgamated.cpp +TEST_SOURCES = $(NON_HARDWARE_SOURCES) $(TEST_CPP) +NON_HARDWARE_SOURCES = $(filter-out $(TEST_CPP), $(NON_HARDWARE_SOURCES_NON_FILTERED)) SOURCES = $(wildcard *.cpp) $(NON_HARDWARE_SOURCES) all: build/firmware.hex @@ -106,6 +109,10 @@ TEST_TARGETS = $(patsubst %.cpp,build/test/%.o,$(TEST_SOURCES)) build/firmware.elf: $(TARGETS) @$(CC) $(LINK_FLAGS) -o $@ $(TARGETS) build/core/core.a -Lbuild/ -larm_cortexM7lfsp_math -lm -lstdc++ + @echo + @echo "Firmware size:" + @$(SIZE) -B -d $@ + @echo build/firmware.hex: build/firmware.elf $(OBJCOPY) -O ihex -R .eeprom $< $@ diff --git a/core/backlight/backlight.h b/core/backlight/backlight.h index 4a59249..a78af58 100644 --- a/core/backlight/backlight.h +++ b/core/backlight/backlight.h @@ -14,7 +14,7 @@ namespace core::backlight class Backlight { public: - Backlight(Device& device, schemes::Scheme* schemes[], int num_schemes); + Backlight(Device& device, schemes::Scheme** schemes, int num_schemes); void update(const core::keyboard::KeyboardScanResult& scan_result); void increment_scheme(); diff --git a/core/backlight/color.h b/core/backlight/color.h index 82054ed..e8555dc 100644 --- a/core/backlight/color.h +++ b/core/backlight/color.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace core::backlight { @@ -41,6 +42,45 @@ struct Color static_cast(g + other.g), static_cast(b + other.b)}; } + + /** + * Creates a color from HSV values, where the hue, saturation and value + * is in the range [0, 1]. + */ + static Color from_hsv(float hue, float saturation, float value) + { + // This function was AI-generated + const float h = hue * 6.0f; + const float f = h - floor(h); + const float p = value * (1.0f - saturation); + const float q = value * (1.0f - saturation * f); + const float t = value * (1.0f - saturation * (1.0f - f)); + + if (h < 1.0f) + { + return Color{value, t, p}; + } + else if (h < 2.0f) + { + return Color{q, value, p}; + } + else if (h < 3.0f) + { + return Color{p, value, t}; + } + else if (h < 4.0f) + { + return Color{p, q, value}; + } + else if (h < 5.0f) + { + return Color{t, p, value}; + } + else + { + return Color{value, p, q}; + } + } }; } diff --git a/core/backlight/schemes/scheme.h b/core/backlight/schemes/scheme.h index 1343beb..27445ae 100644 --- a/core/backlight/schemes/scheme.h +++ b/core/backlight/schemes/scheme.h @@ -1,4 +1,5 @@ #pragma once + #include "../../../device.h" #include "../../keyboard/keyscan.h" #include "../ledstate.h" @@ -12,7 +13,7 @@ namespace core::backlight::schemes class Scheme { public: - Scheme(Device& device) : device(device) { } + Scheme(Device& device) : device{device} { } virtual void reset() = 0; diff --git a/core/backlight/schemes/wave.cpp b/core/backlight/schemes/wave.cpp new file mode 100644 index 0000000..04831c1 --- /dev/null +++ b/core/backlight/schemes/wave.cpp @@ -0,0 +1,40 @@ +#include "wave.h" +#include + + +namespace core::backlight::schemes +{ + +void Wave::reset() +{ + it = 0; +} + + +void Wave::update(const core::keyboard::KeyboardScanResult& scan_result, + core::backlight::LEDState led_states[common::constants::TOTAL_NUM_LEDS]) +{ + const float fade_x = sin(it * SPEED * X_SPEED); + const float fade_y = sin(it * SPEED * Y_SPEED); + for (int i = 0; i < common::constants::TOTAL_NUM_LEDS; ++i) + { + auto& state = led_states[i]; + const auto x = state.description->x; + const auto y = state.description->y; + + const float hue = (cos((it * SPEED + x * fade_x + y * fade_y) * MAX_PHASE_DIFFERENCE) + 1.0f) / 2.0f; + const Color color = Color::from_hsv(hue, 1.0f, 1.0f); + state.color = color; + } + + for (int i = 0; i < scan_result.num_pressed; ++i) + { + const common::LEDDescription pressed = scan_result.just_pressed[i]->get_associated_led(); + led_states[pressed.strip_index].start_fade( + device, Color{1.0f, 1.0f, 1.0f}, PRESS_FADE_TIME); + } + + it++; +} + +} diff --git a/core/backlight/schemes/wave.h b/core/backlight/schemes/wave.h new file mode 100644 index 0000000..31d1063 --- /dev/null +++ b/core/backlight/schemes/wave.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../../device.h" +#include "../../keyboard/keyscan.h" +#include "../ledstate.h" +#include "scheme.h" + +namespace core::backlight::schemes +{ + +const float SPEED = 0.00005f; +const float X_SPEED = 0.8f; +const float Y_SPEED = 1.1f; +const float MAX_PHASE_DIFFERENCE = 0.3f; +const uint32_t PRESS_FADE_TIME = 2000; + + +class Wave : public Scheme +{ +public: + Wave(Device& device) : Scheme{device} { } + + void reset() override; + + void update(const core::keyboard::KeyboardScanResult& scan_result, + core::backlight::LEDState led_states[common::constants::TOTAL_NUM_LEDS]) override; +private: + uint64_t it = 0; +}; + +} diff --git a/core/backlight/test/test_backlight.cpp b/core/backlight/test/test_backlight.cpp index 09239bc..9e8fa9a 100644 --- a/core/backlight/test/test_backlight.cpp +++ b/core/backlight/test/test_backlight.cpp @@ -56,6 +56,7 @@ TEST_CASE("Test backlight", "[Backlight]") backlight.update(core::keyboard::KeyboardScanResult{}); for (uint8_t i = 0; i < common::constants::TOTAL_NUM_LEDS; ++i) { + REQUIRE(device.leds_updated); auto c = static_cast(255.0f * static_cast(i) / static_cast(common::constants::TOTAL_NUM_LEDS)); auto not_c = static_cast(255.0f * (1.0f - static_cast(i) / static_cast(common::constants::TOTAL_NUM_LEDS))); REQUIRE(device.led_colors_r[i] == c); @@ -73,24 +74,28 @@ TEST_CASE("Test backlight", "[Backlight]") device.current_millis = 0; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 255); CHECK(device.led_colors_g[0] == 127); CHECK(device.led_colors_b[0] == 255); device.current_millis = 99; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 255); CHECK(device.led_colors_g[0] == 127); CHECK(device.led_colors_b[0] == 255); device.current_millis = 150; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 0); CHECK(device.led_colors_g[0] == 0); CHECK(device.led_colors_b[0] == 0); device.current_millis = 251; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 255); CHECK(device.led_colors_g[0] == 127); CHECK(device.led_colors_b[0] == 255); @@ -106,18 +111,21 @@ TEST_CASE("Test backlight", "[Backlight]") device.current_millis = 0; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 0); CHECK(device.led_colors_g[0] == 0); CHECK(device.led_colors_b[0] == 255); device.current_millis = 50; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 127); CHECK(device.led_colors_g[0] == 0); CHECK(device.led_colors_b[0] == 127); device.current_millis = 100; backlight.update(core::keyboard::KeyboardScanResult{}); + REQUIRE(device.leds_updated); CHECK(device.led_colors_r[0] == 255); CHECK(device.led_colors_g[0] == 0); CHECK(device.led_colors_b[0] == 0); diff --git a/core/firmware.cpp b/core/firmware.cpp index 10478bd..ced78e9 100644 --- a/core/firmware.cpp +++ b/core/firmware.cpp @@ -1,5 +1,6 @@ #include "firmware.h" #include "../common/constants.h" +#include "backlight/schemes/wave.h" #include "keyboard/communication.h" namespace core @@ -7,7 +8,13 @@ namespace core const int CYCLE_TIME_MICROS = 16000; -Firmware::Firmware(Device& device) : device{device}, key_scanner{device} +Firmware::Firmware(Device& device) : + device{device}, + key_scanner{device}, + + wave{device}, + + backlight{device, schemes, 1} { // TODO load from SD card when possible keymap.load_default(); @@ -20,13 +27,7 @@ void Firmware::update() key_scanner.scan(result); keymap.translate_keyboard_scan_result(result, key_queue); keyboard::communication::send_key_report(key_queue, device); - - // TODO remove this - for (int i = 0; i < common::constants::TOTAL_NUM_LEDS; ++i) - { - device.set_led(i, 255, 0, 0); - } - device.update_leds(); + backlight.update(result); const uint32_t elapsed = device.get_timer_micros(); if (elapsed < CYCLE_TIME_MICROS) diff --git a/core/firmware.h b/core/firmware.h index ad7b5e5..8977ab6 100644 --- a/core/firmware.h +++ b/core/firmware.h @@ -1,6 +1,8 @@ #pragma once #include "../device.h" +#include "backlight/backlight.h" +#include "backlight/schemes/wave.h" #include "keyboard/keymap.h" #include "keyboard/keyscan.h" @@ -22,6 +24,17 @@ class Firmware keyboard::KeyScanner key_scanner; keyboard::KeyQueue key_queue; keyboard::KeyMap keymap; + + // Backlight schemes + backlight::schemes::Wave wave; + + static constexpr int NUM_SCHEMES = 1; + backlight::schemes::Scheme* schemes[NUM_SCHEMES] = + { + &wave + }; + + backlight::Backlight backlight; }; } diff --git a/core/testutil/testdevice.h b/core/testutil/testdevice.h index cfd3ae9..442a8d2 100644 --- a/core/testutil/testdevice.h +++ b/core/testutil/testdevice.h @@ -99,6 +99,7 @@ class TestTimerLEDDevice : public TestDeviceBase led_colors_r[index] = r; led_colors_g[index] = g; led_colors_b[index] = b; + leds_updated = false; } }; diff --git a/simulator/Makefile b/simulator/Makefile index 2441b84..04d0a27 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -1,11 +1,13 @@ KEYBOARD_LAYOUT_JSON = ../submodules/scripts/resources/keyboard-layout.json -EXTRA_LEDS_JSON = submodules/scripts/resources/extra_leds.json +EXTRA_LEDS_JSON = ../submodules/scripts/resources/extra_leds.json PYTHON = python3 GENERATE_LAYOUT = ../submodules/scripts/generate_layout.py CXX = g++ CXX_FLAGS = -c -g -Wall -Wextra -std=gnu++23 -SOURCES = $(wildcard *.cpp) $(wildcard **/*.cpp) $(wildcard ../core/*.cpp) $(wildcard ../core/**/*.cpp) $(wildcard ../common/*.cpp) $(wildcard ../common/**/*.cpp) +TEST_CXX = $(wildcard ../core/test/*.cpp) $(wildcard ../core/**/test/*.cpp) +SOURCES_NON_FILTERED = $(wildcard *.cpp) $(wildcard **/*.cpp) $(wildcard ../core/*.cpp) $(wildcard ../core/**/*.cpp) $(wildcard ../core/**/**/*.cpp) $(wildcard ../common/*.cpp) $(wildcard ../common/**/*.cpp) +SOURCES = $(filter-out $(TEST_CXX), $(SOURCES_NON_FILTERED)) HEADERS = $(wildcard *.h) $(wildcard **/*.h) $(wildcard ../core/*.h) $(wildcard ../core/**/*.h) $(wildcard ../generated/*.h) $(wildcard ../common/*.h) $(wildcard ../common/**/*.h) TARGETS = $(patsubst %.cpp,obj/%.o,$(SOURCES)) diff --git a/simulator/keyboard_state.cpp b/simulator/keyboard_state.cpp index 4207b8d..db11a33 100644 --- a/simulator/keyboard_state.cpp +++ b/simulator/keyboard_state.cpp @@ -109,15 +109,6 @@ void KeyboardState::draw(sf::RenderWindow& window) rectangle.setFillColor(sf::Color{100, 100, 100, 255}); rectangle.setOutlineThickness(5); - const sf::Color colors[6] = { - sf::Color::Red, - sf::Color::Green, - sf::Color::Blue, - sf::Color::Yellow, - sf::Color::Magenta, - sf::Color::Cyan - }; - for (const auto& key : keys) { if (key.pressed) @@ -133,7 +124,13 @@ void KeyboardState::draw(sf::RenderWindow& window) rectangle.setFillColor(sf::Color{100, 100, 100, 255}); } - rectangle.setOutlineColor(colors[key.description->row]); + const auto led_description = key.description->get_associated_led(); + const auto led_index = led_description.strip_index; + const auto r = device.led_colors_r[led_index]; + const auto g = device.led_colors_g[led_index]; + const auto b = device.led_colors_b[led_index]; + + rectangle.setOutlineColor(sf::Color{r, g, b, 255}); const auto width = key.description->width * KEY_SIZE; const auto height = key.description->height * KEY_SIZE; rectangle.setSize(sf::Vector2f{width, height}); @@ -145,4 +142,5 @@ void KeyboardState::draw(sf::RenderWindow& window) } } + } diff --git a/simulator/simulator_device.cpp b/simulator/simulator_device.cpp index 7cf37e9..3a500ce 100644 --- a/simulator/simulator_device.cpp +++ b/simulator/simulator_device.cpp @@ -131,13 +131,14 @@ uint32_t SimulatorDevice::get_timer_micros() void SimulatorDevice::set_led(uint16_t index, uint8_t r, uint8_t g, uint8_t b) { - // TODO implement + std::lock_guard lock(mutex); + led_colors_r[index] = r; + led_colors_g[index] = g; + led_colors_b[index] = b; } void SimulatorDevice::update_leds() -{ - // TODO implement -} +{ } uint32_t SimulatorDevice::millis() const { diff --git a/simulator/simulator_device.h b/simulator/simulator_device.h index 721c115..de20033 100644 --- a/simulator/simulator_device.h +++ b/simulator/simulator_device.h @@ -70,6 +70,10 @@ class SimulatorDevice : public Device uint8_t current_modifier; uint8_t current_media; + uint8_t led_colors_r[common::constants::TOTAL_NUM_LEDS]; + uint8_t led_colors_g[common::constants::TOTAL_NUM_LEDS]; + uint8_t led_colors_b[common::constants::TOTAL_NUM_LEDS]; + private: uint32_t start_time; diff --git a/simulator/simulator_window.cpp b/simulator/simulator_window.cpp index 56219a1..61b67d4 100644 --- a/simulator/simulator_window.cpp +++ b/simulator/simulator_window.cpp @@ -88,6 +88,7 @@ void SimulatorWindow::draw() draw_sent_keys(); } + void SimulatorWindow::draw_sent_keys() { sf::Text text;