From 2d42b221da129c201847b3b226d6ad4563016651 Mon Sep 17 00:00:00 2001 From: whowechina Date: Sat, 4 Nov 2023 20:30:53 +0800 Subject: [PATCH] LED and stuff working --- firmware/src/CMakeLists.txt | 2 +- firmware/src/board_defs.h | 2 +- firmware/src/commands.c | 27 +++++++ firmware/src/config.c | 4 +- firmware/src/config.h | 3 + firmware/src/main.c | 8 ++ firmware/src/rgb.c | 155 ++++++++++++++++++++++++++++++++++++ firmware/src/rgb.h | 24 ++++++ 8 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 firmware/src/rgb.c create mode 100644 firmware/src/rgb.h diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index 7213706..0db08c6 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -4,7 +4,7 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip) function(make_firmware board board_def) pico_sdk_init() add_executable(${board} - main.c save.c config.c commands.c + main.c save.c config.c commands.c rgb.c aime.c cli.c pn532.c usb_descriptors.c) target_compile_definitions(${board} PUBLIC ${board_def}) diff --git a/firmware/src/board_defs.h b/firmware/src/board_defs.h index a88251d..936db6b 100644 --- a/firmware/src/board_defs.h +++ b/firmware/src/board_defs.h @@ -10,7 +10,7 @@ #define I2C_SDA 20 #define I2C_FREQ 733*1000 -#define RGB_PIN 2 +#define RGB_PIN 22 #define RGB_ORDER GRB // or RGB #else diff --git a/firmware/src/commands.c b/firmware/src/commands.c index c248e2b..4bd1235 100644 --- a/firmware/src/commands.c +++ b/firmware/src/commands.c @@ -30,6 +30,12 @@ void fps_count(int core) counter[core] = 0; } +static void handle_display() +{ + printf("[Config]\n"); + printf(" LED level: %d\n", aic_cfg->led.level); +} + static void handle_save() { save_request(true); @@ -84,9 +90,30 @@ static void handle_nfc() printf("\n"); } +static void handle_level(int argc, char *argv[]) +{ + const char *usage = "Usage: level <0..255>\n"; + if (argc != 1) { + printf(usage); + return; + } + + int level = cli_extract_non_neg_int(argv[0], 0); + if ((level < 0) || (level > 255)) { + printf(usage); + return; + } + + aic_cfg->led.level = level; + config_changed(); + handle_display(); +} + void commands_init() { + cli_register("display", handle_display, "Display all settings."); cli_register("save", handle_save, "Save config to flash."); cli_register("factory", handle_factory_reset, "Reset everything to default."); cli_register("nfc", handle_nfc, "NFC debug."); + cli_register("level", handle_level, "Set LED level."); } diff --git a/firmware/src/config.c b/firmware/src/config.c index 519c385..6f2ab87 100644 --- a/firmware/src/config.c +++ b/firmware/src/config.c @@ -11,7 +11,9 @@ aic_cfg_t *aic_cfg; -static aic_cfg_t default_cfg = { 0 }; +static aic_cfg_t default_cfg = { + .led = { .level = 127, } +}; aic_runtime_t *aic_runtime; diff --git a/firmware/src/config.h b/firmware/src/config.h index 7d0d1ca..b61f1af 100644 --- a/firmware/src/config.h +++ b/firmware/src/config.h @@ -10,6 +10,9 @@ #include typedef struct __attribute__((packed)) { + struct { + uint8_t level; + } led; uint32_t reserved; } aic_cfg_t; diff --git a/firmware/src/main.c b/firmware/src/main.c index bb7bea8..a10196c 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -27,6 +27,7 @@ #include "config.h" #include "cli.h" #include "commands.h" +#include "rgb.h" #include "pn532.h" #include "aime.h" @@ -44,6 +45,11 @@ static void core1_loop() if (mutex_try_enter(&core1_io_lock, NULL)) { mutex_exit(&core1_io_lock); } + rgb_set_color(0, 0x800000); + rgb_set_color(1, 0x008000); + rgb_set_color(2, 0x000080); + rgb_set_color(3, 0x808080); + rgb_update(); cli_fps_count(1); sleep_ms(1); } @@ -61,6 +67,7 @@ static void core0_loop() cli_fps_count(0); report_usb_hid(); + sleep_ms(1); } } @@ -71,6 +78,7 @@ void init() board_init(); tusb_init(); stdio_init_all(); + rgb_init(); config_init(); mutex_init(&core1_io_lock); diff --git a/firmware/src/rgb.c b/firmware/src/rgb.c new file mode 100644 index 0000000..aa354ea --- /dev/null +++ b/firmware/src/rgb.c @@ -0,0 +1,155 @@ +/* + * RGB LED (WS2812) Strip control + * WHowe + * + */ + +#include "rgb.h" + +#include +#include +#include +#include + +#include "bsp/board.h" +#include "hardware/pio.h" +#include "hardware/timer.h" + +#include "ws2812.pio.h" + +#include "board_defs.h" +#include "config.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static uint32_t rgb_buf[16]; + +#define _MAP_LED(x) _MAKE_MAPPER(x) +#define _MAKE_MAPPER(x) MAP_LED_##x +#define MAP_LED_RGB { c1 = r; c2 = g; c3 = b; } +#define MAP_LED_GRB { c1 = g; c2 = r; c3 = b; } + +#define REMAP_BUTTON_RGB _MAP_LED(BUTTON_RGB_ORDER) +#define REMAP_TT_RGB _MAP_LED(TT_RGB_ORDER) + +static inline uint32_t _rgb32(uint32_t c1, uint32_t c2, uint32_t c3, bool gamma_fix) +{ + if (gamma_fix) { + c1 = ((c1 + 1) * (c1 + 1) - 1) >> 8; + c2 = ((c2 + 1) * (c2 + 1) - 1) >> 8; + c3 = ((c3 + 1) * (c3 + 1) - 1) >> 8; + } + + return (c1 << 16) | (c2 << 8) | (c3 << 0); +} + +uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix) +{ +#if BUTTON_RGB_ORDER == GRB + return _rgb32(g, r, b, gamma_fix); +#else + return _rgb32(r, g, b, gamma_fix); +#endif +} + +uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v) +{ + uint32_t region, remainder, p, q, t; + + if (s == 0) { + return v << 16 | v << 8 | v; + } + + region = h / 43; + remainder = (h % 43) * 6; + + p = (v * (255 - s)) >> 8; + q = (v * (255 - ((s * remainder) >> 8))) >> 8; + t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; + + switch (region) { + case 0: + return v << 16 | t << 8 | p; + case 1: + return q << 16 | v << 8 | p; + case 2: + return p << 16 | v << 8 | t; + case 3: + return p << 16 | q << 8 | v; + case 4: + return t << 16 | p << 8 | v; + default: + return v << 16 | p << 8 | q; + } +} + +static void drive_led() +{ + static uint64_t last = 0; + uint64_t now = time_us_64(); + if (now - last < 4000) { // no faster than 250Hz + return; + } + last = now; + + for (int i = 0; i < ARRAY_SIZE(rgb_buf); i++) { + pio_sm_put_blocking(pio0, 0, rgb_buf[i] << 8u); + } +} + +static inline uint32_t apply_level(uint32_t color) +{ + unsigned r = (color >> 16) & 0xff; + unsigned g = (color >> 8) & 0xff; + unsigned b = color & 0xff; + + r = r * aic_cfg->led.level / 255; + g = g * aic_cfg->led.level / 255; + b = b * aic_cfg->led.level / 255; + + return r << 16 | g << 8 | b; +} + +void rgb_set_color(unsigned index, uint32_t color) +{ + if (index >= ARRAY_SIZE(rgb_buf)) { + return; + } + rgb_buf[index] = apply_level(color); +} + +void rgb_set_color_all(uint32_t color) +{ + for (int i = 0; i < ARRAY_SIZE(rgb_buf); i++) { + rgb_buf[i] = apply_level(color); + } +} + +void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num) +{ + if (index >= ARRAY_SIZE(rgb_buf)) { + return; + } + if (index + num > ARRAY_SIZE(rgb_buf)) { + num = ARRAY_SIZE(rgb_buf) - index; + } + for (int i = 0; i < num; i++) { + uint8_t b = brg_array[i * 3 + 0]; + uint8_t r = brg_array[i * 3 + 1]; + uint8_t g = brg_array[i * 3 + 2]; + rgb_buf[index + i] = apply_level(rgb32(r, g, b, false)); + } +} + +void rgb_init() +{ + uint pio0_offset = pio_add_program(pio0, &ws2812_program); + + gpio_set_drive_strength(RGB_PIN, GPIO_DRIVE_STRENGTH_2MA); + ws2812_program_init(pio0, 0, pio0_offset, RGB_PIN, 800000, false); +} + +void rgb_update() +{ + drive_led(); +} diff --git a/firmware/src/rgb.h b/firmware/src/rgb.h new file mode 100644 index 0000000..5e9331e --- /dev/null +++ b/firmware/src/rgb.h @@ -0,0 +1,24 @@ +/* + * RGB LED (WS2812) Strip control + * WHowe + */ + +#ifndef RGB_H +#define RGB_H + +#include +#include +#include + +#include "config.h" + +void rgb_init(); +void rgb_update(); + +uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); +uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v); + +void rgb_set_color(unsigned index, uint32_t color); +void rgb_set_color_all(uint32_t color); + +#endif