1
0
mirror of https://github.com/whowechina/iidx_pico.git synced 2024-11-12 01:10:50 +01:00

Dynamic LED setup working

This commit is contained in:
whowe 2023-04-09 14:21:11 +08:00
parent 10e99e362a
commit ea01a60d6c
16 changed files with 442 additions and 333 deletions

BIN
Production/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
function(make_firmware board board_def) function(make_firmware board board_def)
add_executable(${board} add_executable(${board}
main.c buttons.c rgb.c config.c setup.c turntable.c main.c buttons.c rgb.c save.c config.c setup.c
tt_rainbow.c tt_blade.c turntable.c tt_rainbow.c tt_blade.c
usb_descriptors.c) usb_descriptors.c)
target_compile_definitions(${board} PUBLIC ${board_def}) target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1) pico_enable_stdio_usb(${board} 1)

View File

@ -1,145 +1,48 @@
/* /*
* Controller Config Save and Load * Controller Config Data
* WHowe <github.com/whowechina> * WHowe <github.com/whowechina>
* *
* Config is stored in last sector of flash * Config is a global data structure that stores all the configuration
*/ */
#include "config.h" #include "config.h"
#include "save.h"
#include <stdint.h> iidx_cfg_t *iidx_cfg;
#include <stdlib.h>
#include <stdbool.h>
#include <memory.h>
static iidx_cfg_t default_cfg = {
#include "bsp/board.h" .key_off = { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}},
#include "pico/bootrom.h" .key_on = { {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40},
#include "pico/stdio.h" {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40},
},
#include "hardware/flash.h" .tt_led = {
#include "hardware/sync.h" .start = 0,
.num = 24,
static struct { .effect = 0,
size_t size; .param = 0,
size_t offset; .brightness = 5,
void (*after_load)(); .reversed = false,
} modules[8] = {0}; },
static int module_num = 0; .tt_sensor_reversed = false,
.effects = {
#define CONFIG_PAGE_MAGIC 0x13424321 .play_vol = 255,
#define CONFIG_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) .filter = 128,
.eq_low = 128,
typedef struct __attribute ((packed)) { .eq_hi = 128,
uint32_t magic;
uint8_t data[FLASH_PAGE_SIZE - 4];
} page_t;
static page_t old_cfg = {0};
static page_t new_cfg = {0};
static page_t default_cfg = {0};
static int cfg_page = -1;
static bool requesting_save = false;
static uint64_t requesting_time = 0;
static io_locker_func io_lock;
static void config_save()
{
old_cfg = new_cfg;
cfg_page = (cfg_page + 1) % (FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE);
printf("Program Flash %d %8lx\n", cfg_page, old_cfg.magic);
io_lock(true);
uint32_t ints = save_and_disable_interrupts();
if (cfg_page == 0) {
flash_range_erase(CONFIG_SECTOR_OFFSET, FLASH_SECTOR_SIZE);
}
flash_range_program(CONFIG_SECTOR_OFFSET + cfg_page * FLASH_PAGE_SIZE,
(uint8_t *)&old_cfg, FLASH_PAGE_SIZE);
restore_interrupts(ints);
io_lock(false);
}
static void load_default()
{
printf("Load Default\n");
new_cfg = default_cfg;
new_cfg.magic = CONFIG_PAGE_MAGIC;
}
static const page_t *get_page(int id)
{
int addr = XIP_BASE + CONFIG_SECTOR_OFFSET;
return (page_t *)(addr + FLASH_PAGE_SIZE * id);
}
static void config_load()
{
for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) {
if (get_page(i)->magic != CONFIG_PAGE_MAGIC) {
break;
}
cfg_page = i;
}
if (cfg_page < 0) {
load_default();
config_request_save();
return;
}
old_cfg = *get_page(cfg_page);
new_cfg = old_cfg;
printf("Page Loaded %d %8lx\n", cfg_page, new_cfg.magic);
} }
};
static void config_loaded() static void config_loaded()
{ {
for (int i = 0; i < module_num; i++) { /* configuration validation */
modules[i].after_load();
}
} }
void config_init(io_locker_func locker) void config_changed()
{ {
io_lock = locker; save_request();
config_load();
config_loop();
config_loaded();
} }
void config_loop() void config_init()
{ {
if ((requesting_save) && (time_us_64() - requesting_time > 1000000)) { iidx_cfg = (iidx_cfg_t *)save_alloc(sizeof(iidx_cfg), &default_cfg, config_loaded);
requesting_save = false;
/* only when data is actually changed */
for (int i = 0; i < sizeof(old_cfg); i++) {
if (((uint8_t *)&old_cfg)[i] != ((uint8_t *)&new_cfg)[i]) {
config_save();
return;
}
}
}
}
void *config_alloc(size_t size, void *def, void (*after_load)())
{
modules[module_num].size = size;
size_t offset = module_num > 0 ? modules[module_num - 1].offset + size : 0;
modules[module_num].offset = offset;
modules[module_num].after_load = after_load;
module_num++;
memcpy(default_cfg.data + offset, def, size); // backup the default
return new_cfg.data + offset;
}
void config_request_save()
{
requesting_time = time_us_64();
if (!requesting_save) {
requesting_save = true;
new_cfg.magic = CONFIG_PAGE_MAGIC;
}
} }

View File

@ -1,21 +1,43 @@
/* /*
* Controller Config Save and Load * Controller Config
* WHowe <github.com/whowechina> * WHowe <github.com/whowechina>
*/ */
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include <stdlib.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/* It's safer to lock other I/O ops during saving, so we need a locker */ typedef struct __attribute ((packed)) {
typedef void (*io_locker_func)(bool pause); uint8_t h; // hue;
void config_init(io_locker_func locker); uint8_t s; // saturation;
uint8_t v; // value;
} hsv_t;
void config_loop(); typedef struct __attribute ((packed)) {
hsv_t key_off[11];
hsv_t key_on[11];
struct {
uint8_t start;
uint8_t num;
uint8_t effect;
uint8_t param;
uint8_t brightness;
bool reversed;
} tt_led;
bool tt_sensor_reversed;
struct {
uint8_t play_vol;
uint8_t filter;
uint8_t eq_low;
uint8_t eq_hi;
} effects;
} iidx_cfg_t;
void *config_alloc(size_t size, void *def, void (*after_load)()); extern iidx_cfg_t *iidx_cfg;
void config_request_save();
void config_init();
void config_changed(); // Notify the config has changed
#endif #endif

View File

@ -24,6 +24,7 @@
#include "tt_rainbow.h" #include "tt_rainbow.h"
#include "config.h" #include "config.h"
#include "save.h"
/* Measure the time of a function call */ /* Measure the time of a function call */
#define RUN_TIME(func) \ #define RUN_TIME(func) \
@ -38,10 +39,10 @@ struct {
void report_usb_hid() void report_usb_hid()
{ {
if (tud_hid_ready()) { if (tud_hid_ready()) {
hid_report.joy[2] = iidx_cfg.effects.play_vol; hid_report.joy[2] = iidx_cfg->effects.play_vol;
hid_report.joy[3] = iidx_cfg.effects.filter; hid_report.joy[3] = iidx_cfg->effects.filter;
hid_report.joy[4] = iidx_cfg.effects.eq_low; hid_report.joy[4] = iidx_cfg->effects.eq_low;
hid_report.joy[5] = iidx_cfg.effects.eq_hi; hid_report.joy[5] = iidx_cfg->effects.eq_hi;
tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_report, sizeof(hid_report)); tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_report, sizeof(hid_report));
} }
} }
@ -73,8 +74,10 @@ static void core1_loop()
while (true) { while (true) {
uint32_t angle = turntable_read(); uint32_t angle = turntable_read();
rgb_set_angle(angle); rgb_set_angle(angle);
hid_report.joy[0] = angle >> 4; // 12bit to 8bit hid_report.joy[0] = angle >> 4; // 12bit to 8bit
hid_report.joy[1] = 255 - hid_report.joy[0]; hid_report.joy[1] = 255 - hid_report.joy[0];
RUN_EVERY_N_MS(rgb_update(), 2); RUN_EVERY_N_MS(rgb_update(), 2);
turntable_update(); turntable_update();
frame++; frame++;
@ -92,18 +95,15 @@ static void core0_loop()
uint16_t buttons = button_read(); uint16_t buttons = button_read();
uint16_t angle = turntable_read() >> 4; uint16_t angle = turntable_read() >> 4;
if (setup_run(buttons, angle)) { if (setup_run(buttons, angle)) {
turntable_set_hardware(iidx_cfg.tt_sensor_reversed);
rgb_set_hardware(iidx_cfg.tt_led.start, iidx_cfg.tt_led.num, iidx_cfg.tt_led.reversed);
rgb_force_display(setup_led_button, setup_led_tt); rgb_force_display(setup_led_button, setup_led_tt);
report_usb_hid(); report_usb_hid();
sleep_ms(5);
continue; continue;
} }
hid_report.buttons = buttons; hid_report.buttons = buttons;
report_usb_hid(); report_usb_hid();
rgb_set_button_light(buttons); rgb_set_button_light(buttons);
config_loop(); save_loop();
} }
} }
@ -122,7 +122,8 @@ void init()
stdio_init_all(); stdio_init_all();
setup_init(); setup_init();
config_init(pause_core1); config_init();
save_init(pause_core1);
} }
int main(void) int main(void)

View File

@ -18,6 +18,7 @@
#include "ws2812.pio.h" #include "ws2812.pio.h"
#include "board_defs.h" #include "board_defs.h"
#include "config.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@ -86,13 +87,8 @@ void rgb_set_level(uint8_t level)
} }
uint8_t button_lights[BUTTON_RGB_NUM]; uint8_t button_lights[BUTTON_RGB_NUM];
uint32_t tt_led_buf[128] = {0};
static uint32_t tt_led_buf[128] = {0}; uint32_t tt_led_angle = 0;
uint32_t *tt_ring_buf = &tt_led_buf[0];
uint32_t tt_ring_start = 0;
uint32_t tt_ring_size = 24;
bool tt_ring_reversed = false;
uint32_t tt_ring_angle = 0;
static uint32_t button_led_buf[BUTTON_RGB_NUM] = {0}; static uint32_t button_led_buf[BUTTON_RGB_NUM] = {0};
@ -109,9 +105,46 @@ void drive_led()
for (int i = 0; i < ARRAY_SIZE(button_led_buf); i++) { for (int i = 0; i < ARRAY_SIZE(button_led_buf); i++) {
pio_sm_put_blocking(pio0, 0, button_led_buf[i] << 8u); pio_sm_put_blocking(pio0, 0, button_led_buf[i] << 8u);
} }
for (int i = 0; i < iidx_cfg->tt_led.start; i++) {
pio_sm_put_blocking(pio1, 0, 0);
}
for (int i = 0; i < TT_LED_NUM; i++) {
uint8_t id = iidx_cfg->tt_led.reversed ? TT_LED_NUM - i - 1 : i;
pio_sm_put_blocking(pio1, 0, tt_led_buf[id] << 8u);
}
for (int i = 0; i < 8; i++) { // a few more to wipe out the last led
pio_sm_put_blocking(pio1, 0, 0);
}
}
for (int i = 0; i < ARRAY_SIZE(tt_led_buf); i++) { uint32_t rgb32_from_hsv(hsv_t hsv)
pio_sm_put_blocking(pio1, 0, tt_led_buf[i] << 8u); {
uint8_t region, remainder, p, q, t;
if (hsv.s == 0) {
return hsv.v << 16 | hsv.v << 8 | hsv.v;
}
region = hsv.h / 43;
remainder = (hsv.h - (region * 43)) * 6;
p = (hsv.v * (255 - hsv.s)) >> 8;
q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
switch (region) {
case 0:
return hsv.v << 16 | t << 8 | p;
case 1:
return q << 16 | hsv.v << 8 | p;
case 2:
return p << 16 | hsv.v << 8 | t;
case 3:
return p << 16 | q << 8 | hsv.v;
case 4:
return t << 16 | p << 8 | hsv.v;
default:
return hsv.v << 16 | p << 8 | q;
} }
} }
@ -123,16 +156,16 @@ static void button_lights_update()
for (int i = 0; i < BUTTON_RGB_NUM; i++) { for (int i = 0; i < BUTTON_RGB_NUM; i++) {
int led = button_rgb_map[i]; int led = button_rgb_map[i];
if (button_lights[i] > 0) { if (button_lights[i] > 0) {
button_led_buf[led] = button_rgb32(0x80, 0x80, 0x80, true); button_led_buf[led] = rgb32_from_hsv(iidx_cfg->key_on[i]);
} else { } else {
button_led_buf[led] = 0; button_led_buf[led] = rgb32_from_hsv(iidx_cfg->key_off[i]);
} }
} }
} }
void rgb_set_angle(uint32_t angle) void rgb_set_angle(uint32_t angle)
{ {
tt_ring_angle = angle; tt_led_angle = angle;
effects[current_effect].set_angle(angle); effects[current_effect].set_angle(angle);
} }
@ -160,26 +193,34 @@ static void effect_update()
#define FORCE_EXPIRE_DURATION 100000ULL #define FORCE_EXPIRE_DURATION 100000ULL
static uint64_t force_expire_time = 0; static uint64_t force_expire_time = 0;
uint32_t *force_buttons = NULL;
uint32_t *force_tt = NULL;
void force_update()
{
for (int i = 0; i < BUTTON_RGB_NUM; i++) {
int led = button_rgb_map[i];
button_led_buf[led] = force_buttons[i];
}
memcpy(tt_led_buf, force_tt, TT_LED_NUM * sizeof(uint32_t));
}
void rgb_update() void rgb_update()
{ {
if (time_us_64() > force_expire_time) { if (time_us_64() > force_expire_time) {
effect_update(); effect_update();
button_lights_update(); button_lights_update();
} else {
force_update();
} }
drive_led(); drive_led();
} }
void rgb_force_display(uint32_t *keyboard, uint32_t *tt) void rgb_force_display(uint32_t *buttons, uint32_t *tt)
{ {
for (int i = 0; i < BUTTON_RGB_NUM; i++) { force_buttons = buttons;
int led = button_rgb_map[i]; force_tt = tt;
button_led_buf[led] = keyboard[i];
}
memset(tt_led_buf, 0, tt_ring_start * sizeof(uint32_t));
memcpy(tt_led_buf + tt_ring_start, tt, tt_ring_size * sizeof(uint32_t));
force_expire_time = time_us_64() + FORCE_EXPIRE_DURATION; force_expire_time = time_us_64() + FORCE_EXPIRE_DURATION;
} }
@ -199,11 +240,3 @@ void rgb_reg_tt_effect(tt_effect_t effect)
effects[effect_num] = effect; effects[effect_num] = effect;
effect_num++; effect_num++;
} }
void rgb_set_hardware(uint16_t tt_start, uint16_t tt_num, bool tt_reversed)
{
tt_ring_start = tt_start;
tt_ring_size = tt_num;
tt_ring_reversed = tt_reversed;
tt_ring_buf = &tt_led_buf[tt_start];
}

View File

@ -9,6 +9,8 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "config.h"
void rgb_init(); void rgb_init();
void rgb_set_hardware(uint16_t tt_start, uint16_t tt_num, bool tt_reversed); void rgb_set_hardware(uint16_t tt_start, uint16_t tt_num, bool tt_reversed);
@ -33,11 +35,12 @@ typedef struct {
void rgb_reg_tt_effect(tt_effect_t effect); void rgb_reg_tt_effect(tt_effect_t effect);
extern uint32_t tt_led_buf[];
#define TT_LED_NUM (iidx_cfg->tt_led.num)
/* These global variables meant to be accessed by effect codes */ /* These global variables meant to be accessed by effect codes */
extern uint32_t *tt_ring_buf; extern uint32_t tt_led_angle;
extern uint32_t tt_ring_size;
extern uint32_t tt_ring_angle;
extern bool tt_ring_reversed;
uint32_t button_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); uint32_t button_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix);
uint32_t tt_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); uint32_t tt_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix);

148
firmware/src/save.c Normal file
View File

@ -0,0 +1,148 @@
/*
* Controller Save Save and Load
* WHowe <github.com/whowechina>
*
* Save is stored in last sector of flash
*/
#include "save.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <memory.h>
#include "bsp/board.h"
#include "pico/bootrom.h"
#include "pico/stdio.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
static struct {
size_t size;
size_t offset;
void (*after_load)();
} modules[8] = {0};
static int module_num = 0;
#define SAVE_PAGE_MAGIC 0x13424321
#define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
typedef struct __attribute ((packed)) {
uint32_t magic;
uint8_t data[FLASH_PAGE_SIZE - 4];
} page_t;
static page_t old_data = {0};
static page_t new_data = {0};
static page_t default_data = {0};
static int data_page = -1;
static bool requesting_save = false;
static uint64_t requesting_time = 0;
static io_locker_func io_lock;
static void save_program()
{
old_data = new_data;
data_page = (data_page + 1) % (FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE);
printf("Program Flash %d %8lx\n", data_page, old_data.magic);
io_lock(true);
uint32_t ints = save_and_disable_interrupts();
if (data_page == 0) {
flash_range_erase(SAVE_SECTOR_OFFSET, FLASH_SECTOR_SIZE);
}
flash_range_program(SAVE_SECTOR_OFFSET + data_page * FLASH_PAGE_SIZE,
(uint8_t *)&old_data, FLASH_PAGE_SIZE);
restore_interrupts(ints);
io_lock(false);
}
static void load_default()
{
printf("Load Default\n");
new_data = default_data;
new_data.magic = SAVE_PAGE_MAGIC;
}
static const page_t *get_page(int id)
{
int addr = XIP_BASE + SAVE_SECTOR_OFFSET;
return (page_t *)(addr + FLASH_PAGE_SIZE * id);
}
static void save_load()
{
for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) {
if (get_page(i)->magic != SAVE_PAGE_MAGIC) {
break;
}
data_page = i;
}
if (data_page < 0) {
load_default();
save_request();
return;
}
old_data = *get_page(data_page);
new_data = old_data;
printf("Page Loaded %d %8lx\n", data_page, new_data.magic);
}
static void save_loaded()
{
for (int i = 0; i < module_num; i++) {
modules[i].after_load();
}
}
void save_init(io_locker_func locker)
{
io_lock = locker;
save_load();
save_loop();
save_loaded();
}
void save_loop()
{
if (requesting_save && (time_us_64() - requesting_time > 1000000)) {
requesting_save = false;
printf("Time to save.\n");
/* only when data is actually changed */
for (int i = 0; i < sizeof(old_data); i++) {
if (((uint8_t *)&old_data)[i] != ((uint8_t *)&new_data)[i]) {
save_program();
return;
}
}
printf("No change.\n");
}
}
void *save_alloc(size_t size, void *def, void (*after_load)())
{
modules[module_num].size = size;
size_t offset = module_num > 0 ? modules[module_num - 1].offset + size : 0;
modules[module_num].offset = offset;
modules[module_num].after_load = after_load;
module_num++;
memcpy(default_data.data + offset, def, size); // backup the default
return new_data.data + offset;
}
void save_request()
{
requesting_time = time_us_64();
if (!requesting_save) {
printf("Save marked.\n");
requesting_save = true;
new_data.magic = SAVE_PAGE_MAGIC;
}
}

21
firmware/src/save.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Controller Flash Save and Load
* WHowe <github.com/whowechina>
*/
#ifndef SAVE_H
#define SAVE_H
#include <stdlib.h>
#include <stdbool.h>
/* It's safer to lock other I/O ops during saving, so we need a locker */
typedef void (*io_locker_func)(bool pause);
void save_init(io_locker_func locker);
void save_loop();
void *save_alloc(size_t size, void *def, void (*after_load)());
void save_request();
#endif

View File

@ -12,26 +12,22 @@
#include <stdbool.h> #include <stdbool.h>
#include "bsp/board.h" #include "bsp/board.h"
#include "pico/bootrom.h"
#include "rgb.h" #include "rgb.h"
#include "config.h" #include "config.h"
iidx_cfg_t iidx_cfg;
static iidx_cfg_t cfg_save; static iidx_cfg_t cfg_save;
static uint64_t setup_tick_ms = 0;
#define CONCAT(a, b) a ## b
#define TVAR(line) CONCAT(a, line)
#define RUN_EVERY_N_MS(a, ms) { static uint64_t TVAR(__LINE__) = 0; \
if (setup_tick_ms - TVAR(__LINE__) >= ms) { a; TVAR(__LINE__) = setup_tick_ms; } }
uint32_t setup_led_tt[128]; uint32_t setup_led_tt[128];
uint32_t setup_led_button[BUTTON_RGB_NUM]; uint32_t setup_led_button[BUTTON_RGB_NUM];
static void cfg_loaded()
{
/* configuration validation */
}
void setup_init()
{
config_alloc(sizeof(iidx_cfg), &iidx_cfg, cfg_loaded);
}
typedef enum { typedef enum {
MODE_NONE, MODE_NONE,
MODE_TURNTABLE, MODE_TURNTABLE,
@ -43,11 +39,12 @@ static setup_mode_t current_mode = MODE_NONE;
static struct { static struct {
uint16_t last_keys; uint16_t last_keys;
uint16_t last_angle;
uint16_t keys; uint16_t keys;
int16_t angle;
uint16_t just_pressed; uint16_t just_pressed;
uint16_t just_released; uint16_t just_released;
int16_t last_angle;
int16_t angle;
int16_t rotate; int16_t rotate;
} input = { 0 }; } input = { 0 };
@ -58,10 +55,10 @@ static struct {
#define KEY_5 0x0010 #define KEY_5 0x0010
#define KEY_6 0x0020 #define KEY_6 0x0020
#define KEY_7 0x0040 #define KEY_7 0x0040
#define START 0x0080 #define E_START 0x0080
#define EFFECT 0x0100 #define E_EFFECT 0x0100
#define VEFX 0x0200 #define E_VEFX 0x0200
#define E4 0x0400 #define E_4 0x0400
#define AUX_NO 0x0800 #define AUX_NO 0x0800
#define AUX_YES 0x1000 #define AUX_YES 0x1000
@ -72,11 +69,10 @@ static struct {
#define LED_KEY_5 4 #define LED_KEY_5 4
#define LED_KEY_6 5 #define LED_KEY_6 5
#define LED_KEY_7 6 #define LED_KEY_7 6
#define LED_START 7 #define LED_E_START 7
#define LED_EFFECT 8 #define LED_E_EFFECT 8
#define LED_VEFX 9 #define LED_E_VEFX 9
#define LED_E4 10 #define LED_E_4 10
#define PRESSED_ALL(k) ((input.keys & (k)) == (k)) #define PRESSED_ALL(k) ((input.keys & (k)) == (k))
#define PRESSED_ANY(k) (input.keys & (k)) #define PRESSED_ANY(k) (input.keys & (k))
@ -105,6 +101,10 @@ static void mode_none_loop()
static bool escaped = false; static bool escaped = false;
static uint64_t escape_time = 0; static uint64_t escape_time = 0;
if (PRESSED_ALL(AUX_NO | AUX_YES | E_START)) {
reset_usb_boot(0, 2); // usb boot to flash
}
if (PRESSED_ALL(AUX_YES | AUX_NO)) { if (PRESSED_ALL(AUX_YES | AUX_NO)) {
if (!escaped) { if (!escaped) {
escaped = true; escaped = true;
@ -118,7 +118,7 @@ static void mode_none_loop()
return; return;
} }
uint16_t pressed = PRESSED_ANY(START | EFFECT | VEFX | E4); uint16_t pressed = PRESSED_ANY(E_START | E_EFFECT | E_VEFX | E_4);
if (pressed) { if (pressed) {
escaped = false; escaped = false;
join_mode(MODE_ANALOG); join_mode(MODE_ANALOG);
@ -133,7 +133,7 @@ static void mode_none_loop()
static struct { static struct {
bool adjust_led_start; bool adjust_led_start;
uint16_t start_angle; int16_t start_angle;
uint8_t counter; uint8_t counter;
} tt_ctx; } tt_ctx;
@ -142,95 +142,100 @@ void mode_tt_enter()
tt_ctx.start_angle = input.angle; tt_ctx.start_angle = input.angle;
} }
void mode_tt_op() static void mode_tt_key_change()
{ {
if (JUST_PRESSED(START)) { if (JUST_PRESSED(E_START)) {
tt_ctx.adjust_led_start = true; tt_ctx.adjust_led_start = true;
tt_ctx.start_angle = input.angle; tt_ctx.start_angle = input.angle;
} else if (JUST_PRESSED(EFFECT)) { } else if (JUST_PRESSED(E_EFFECT)) {
tt_ctx.adjust_led_start = false; tt_ctx.adjust_led_start = false;
tt_ctx.start_angle = input.angle; tt_ctx.start_angle = input.angle;
} else if (JUST_PRESSED(VEFX)) { } else if (JUST_PRESSED(E_VEFX)) {
iidx_cfg.tt_led.reversed = !iidx_cfg.tt_led.reversed; iidx_cfg->tt_led.reversed = !iidx_cfg->tt_led.reversed;
tt_ctx.counter = iidx_cfg.tt_led.num; } else if (JUST_PRESSED(E_4)) {
} else if (JUST_PRESSED(E4)) { iidx_cfg->tt_sensor_reversed = !iidx_cfg->tt_sensor_reversed;
iidx_cfg.tt_sensor_reversed = !iidx_cfg.tt_sensor_reversed;
tt_ctx.counter = iidx_cfg.tt_led.num;
} }
check_exit();
}
static void mode_tt_rotate()
{
int16_t delta = input.angle - tt_ctx.start_angle; int16_t delta = input.angle - tt_ctx.start_angle;
if (abs(delta) < 4) { if (abs(delta) > 8) {
return;
}
tt_ctx.start_angle = input.angle; tt_ctx.start_angle = input.angle;
#define LED_START iidx_cfg->tt_led.start
#define LED_NUM iidx_cfg->tt_led.num
if (tt_ctx.adjust_led_start) { if (tt_ctx.adjust_led_start) {
if ((delta > 0) && (iidx_cfg.tt_led.start < 8)) { if ((delta > 0) & (LED_START < 8)) {
iidx_cfg.tt_led.start++; LED_START++;
} else if ((delta < -8) && (iidx_cfg.tt_led.start > 0)) { if (LED_NUM > 1) {
iidx_cfg.tt_led.start--; LED_NUM--;
}
} else if ((delta < 0) & (LED_START > 0)) {
LED_START--;
LED_NUM++;
} }
} else { } else {
if ((delta < 0) && (iidx_cfg.tt_led.num < 128)) { if ((delta > 0) & (LED_NUM + LED_START < 128)) {
iidx_cfg.tt_led.num++; LED_NUM++;
} else if ((delta < -8) && (iidx_cfg.tt_led.num > 0)) { } else if ((delta < 0) & (LED_NUM > 1)) { // at least 1 led
iidx_cfg.tt_led.num--; LED_NUM--;
} }
} }
if (iidx_cfg.tt_led.start + iidx_cfg.tt_led.num > 128) {
iidx_cfg.tt_led.num = 128 - iidx_cfg.tt_led.start;
} }
check_exit();
} }
void mode_tt_loop() void mode_tt_loop()
{ {
for (int i = 0; i < iidx_cfg.tt_led.num; i++) { static uint32_t mask = 0xffffff;
int index = iidx_cfg.tt_led.start + i;
setup_led_tt[index] = tt_rgb32(10, 10, 10, false);
}
setup_led_tt[iidx_cfg.tt_led.start] = tt_rgb32(0xa0, 0, 0, false); RUN_EVERY_N_MS(mask = ~mask, 50);
setup_led_tt[iidx_cfg.tt_led.start + iidx_cfg.tt_led.num -1 ] = tt_rgb32(0, 0xa0, 0, false);
for (int i = 1; i < iidx_cfg->tt_led.num - 1; i++) {
setup_led_tt[i] = tt_rgb32(10, 10, 10, false);
}
int head = iidx_cfg->tt_led.reversed ? TT_LED_NUM - 1 : 0;
int tail = iidx_cfg->tt_led.reversed ? 0 : TT_LED_NUM - 1;
setup_led_tt[head] = tt_rgb32(0xa0, 0, 0, false);
setup_led_tt[tail] = tt_rgb32(0, 0xa0, 0, false);
if (tt_ctx.adjust_led_start) { if (tt_ctx.adjust_led_start) {
setup_led_button[LED_START] = tt_rgb32(0x80, 12, 12, false); setup_led_tt[head] &= mask;
setup_led_button[LED_EFFECT] = 0; setup_led_button[LED_E_START] = tt_rgb32(128, 0, 0, false) & mask;
setup_led_button[LED_E_EFFECT] = tt_rgb32(0, 10, 0, false);
} else { } else {
setup_led_button[LED_START] = 0; setup_led_tt[tail] &= mask;
setup_led_button[LED_EFFECT] = tt_rgb32(12, 0x80, 12, false); setup_led_button[LED_E_START] = tt_rgb32(10, 0, 0, false);
setup_led_button[LED_E_EFFECT] = tt_rgb32(0, 128, 0, false) & mask;
} }
if (iidx_cfg.tt_led.reversed) { uint32_t cyan = button_rgb32(0, 90, 90, false);
setup_led_button[LED_VEFX] = tt_rgb32(0x80, 12, 12, false); uint32_t yellow = button_rgb32(90, 90, 0, false);
} else {
setup_led_button[LED_VEFX] = tt_rgb32(12, 0x80, 12, false);
}
if (iidx_cfg.tt_sensor_reversed) { setup_led_button[LED_E_VEFX] = iidx_cfg->tt_led.reversed ? cyan : yellow;
setup_led_button[LED_E4] = tt_rgb32(0x80, 12, 12, false); setup_led_button[LED_E_4] = iidx_cfg->tt_sensor_reversed ? cyan : yellow;
} else {
setup_led_button[LED_E4] = tt_rgb32(12, 0x80, 12, false);
}
} }
static struct { static struct {
mode_func operate; mode_func key_change;
mode_func rotate;
mode_func loop; mode_func loop;
mode_func enter; mode_func enter;
} mode_defs[] = { } mode_defs[] = {
[MODE_NONE] = { nop, mode_none_loop, nop}, [MODE_NONE] = { nop, nop, mode_none_loop, nop},
[MODE_TURNTABLE] = { mode_tt_op, mode_tt_loop, mode_tt_enter}, [MODE_TURNTABLE] = { mode_tt_key_change, mode_tt_rotate, mode_tt_loop, mode_tt_enter},
[MODE_ANALOG] = { check_exit, nop, nop}, [MODE_ANALOG] = { nop, check_exit, nop, nop},
[MODE_TT_EFFECT] = { check_exit, nop, nop}, [MODE_TT_EFFECT] = { nop, check_exit, nop, nop},
[MODE_KEY_COLOR] = { check_exit, nop, nop}, [MODE_KEY_COLOR] = { nop, check_exit, nop, nop},
}; };
static void join_mode(uint8_t new_mode) static void join_mode(setup_mode_t new_mode)
{ {
cfg_save = iidx_cfg; cfg_save = *iidx_cfg;
memset(&setup_led_tt, 0, sizeof(setup_led_tt)); memset(&setup_led_tt, 0, sizeof(setup_led_tt));
memset(&setup_led_button, 0, sizeof(setup_led_button)); memset(&setup_led_button, 0, sizeof(setup_led_button));
current_mode = new_mode; current_mode = new_mode;
@ -241,27 +246,37 @@ static void join_mode(uint8_t new_mode)
static void quit_mode(bool apply) static void quit_mode(bool apply)
{ {
if (apply) { if (apply) {
iidx_cfg = iidx_cfg; config_changed();
config_request_save(); } else {
*iidx_cfg = cfg_save;
} }
current_mode = MODE_NONE; current_mode = MODE_NONE;
printf("Quit setup\n"); printf("Quit setup %s\n", apply ? "saved." : "discarded.");
} }
bool setup_run(uint16_t keys, uint16_t angle) bool setup_run(uint16_t keys, uint16_t angle)
{ {
setup_tick_ms = time_us_64() / 1000;
input.keys = keys; input.keys = keys;
input.angle = angle; input.angle = angle;
input.just_pressed = keys & ~input.last_keys; input.just_pressed = keys & ~input.last_keys;
input.just_released = ~keys & input.last_keys; input.just_released = ~keys & input.last_keys;
input.rotate = angle - input.last_angle; input.rotate = input.angle - input.last_angle;
if (input.just_pressed || input.just_released) { if (input.rotate != 0) {
printf("%4x %4x\n", input.just_pressed, input.just_released); printf("@ %d\n", input.rotate);
mode_defs[current_mode].rotate();
} }
if (input.just_pressed || input.just_released || input.rotate) { if (input.just_pressed) {
mode_defs[current_mode].operate(); printf("+ %04x\n", input.just_pressed);
}
if (input.just_released) {
printf("- %04x\n", input.just_released);
}
if (input.just_pressed || input.just_released) {
mode_defs[current_mode].key_change();
} }
mode_defs[current_mode].loop(); mode_defs[current_mode].loop();
@ -271,3 +286,7 @@ bool setup_run(uint16_t keys, uint16_t angle)
return current_mode != MODE_NONE; return current_mode != MODE_NONE;
} }
void setup_init()
{
}

View File

@ -10,34 +10,6 @@
#include <stdbool.h> #include <stdbool.h>
#include "board_defs.h" #include "board_defs.h"
typedef struct __attribute ((packed)) {
uint8_t hue;
uint8_t saturation;
uint8_t value;
} key_color_t;
typedef struct __attribute ((packed)) {
key_color_t key_off[11];
key_color_t key_on[11];
struct {
uint8_t start;
uint8_t num;
uint8_t effect;
uint8_t param;
uint8_t brightness;
bool reversed;
} tt_led;
bool tt_sensor_reversed;
struct {
uint8_t play_vol;
uint8_t filter;
uint8_t eq_low;
uint8_t eq_hi;
} effects;
} iidx_cfg_t;
extern iidx_cfg_t iidx_cfg;
void setup_init(); void setup_init();
bool setup_run(uint16_t key_flag, uint16_t tt_angle); bool setup_run(uint16_t key_flag, uint16_t tt_angle);

View File

@ -42,19 +42,14 @@ static inline void blade_color_mix(int index, uint32_t color, uint32_t distance,
/* pos: 0..4095 */ /* pos: 0..4095 */
static void blade_put_pixel(uint32_t pos, uint32_t color, uint32_t level) static void blade_put_pixel(uint32_t pos, uint32_t color, uint32_t level)
{ {
pos = (pos % 4096) * tt_ring_size / 16; // *256/4096, zoom in by 256x pos = (pos % 4096) * TT_LED_NUM / 16; // *256/4096, zoom in by 256x
// calc brightness share between left and right LEDs // calc brightness share between left and right LEDs
uint32_t index_left = pos >> 8; uint32_t index_left = pos >> 8;
uint32_t index_right = (index_left + 1) % tt_ring_size; uint32_t index_right = (index_left + 1) % TT_LED_NUM;
uint32_t dis_left = pos & 0xff; uint32_t dis_left = pos & 0xff;
uint32_t dis_right = 255 - dis_left; uint32_t dis_right = 255 - dis_left;
if (tt_ring_reversed) {
index_left = tt_ring_size - 1 - index_left;
index_right = tt_ring_size - 1 - index_right;
}
blade_color_mix(index_left, color, dis_left, level); blade_color_mix(index_left, color, dis_left, level);
blade_color_mix(index_right, color, dis_right, level); blade_color_mix(index_right, color, dis_right, level);
} }
@ -112,9 +107,9 @@ static uint32_t apply_level(uint32_t color)
static void update(uint32_t context) static void update(uint32_t context)
{ {
uint32_t delta = tt_ring_angle > snake[0] ? tt_ring_angle - snake[0] : snake[0] - tt_ring_angle; uint32_t delta = tt_led_angle > snake[0] ? tt_led_angle - snake[0] : snake[0] - tt_led_angle;
snake[0] = tt_ring_angle; snake[0] = tt_led_angle;
life[0] = 255; life[0] = 255;
life[1] = delta > 7 ? 255: delta * 8; life[1] = delta > 7 ? 255: delta * 8;
@ -136,8 +131,8 @@ static void update(uint32_t context)
life[i]--; life[i]--;
} }
} }
for (int i = 0; i < tt_ring_size; i++) { for (int i = 0; i < TT_LED_NUM; i++) {
tt_ring_buf[i] = apply_level(blade_buf[i]); tt_led_buf[i] = apply_level(blade_buf[i]);
} }
} }

View File

@ -64,11 +64,10 @@ static void set_angle(uint32_t angle)
static void update(uint32_t context) static void update(uint32_t context)
{ {
for (int i = 0; i < tt_ring_size; i++) { for (int i = 0; i < TT_LED_NUM; i++) {
uint32_t pitch = COLOR_WHEEL_SIZE * RGB_RING_CYCLE * i; uint32_t pitch = COLOR_WHEEL_SIZE * RGB_RING_CYCLE * i;
uint32_t index = (phase + pitch / tt_ring_size) % COLOR_WHEEL_SIZE; uint32_t index = (phase + pitch / TT_LED_NUM) % COLOR_WHEEL_SIZE;
int led = tt_ring_reversed ? tt_ring_size - 1 - i: i; tt_led_buf[i] = color_wheel[index];
tt_ring_buf[led] = color_wheel[index];
} }
} }

View File

@ -14,11 +14,10 @@
#include "hardware/i2c.h" #include "hardware/i2c.h"
#include "board_defs.h" #include "board_defs.h"
#include "rgb.h" #include "config.h"
static uint8_t as5600_addr = 0x36; static uint8_t as5600_addr = 0x36;
static uint16_t angle = 0; static uint16_t angle = 0;
static bool reversed = false;
void turntable_init() void turntable_init()
{ {
@ -33,19 +32,14 @@ void turntable_update()
{ {
uint8_t buf[2] = {0x0c, 0x00}; uint8_t buf[2] = {0x0c, 0x00};
i2c_write_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 1, true, i2c_write_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 1, true,
time_us_64() + 1000); make_timeout_time_ms(1));
i2c_read_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 2, false, i2c_read_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 2, false,
time_us_64() + 1000); make_timeout_time_ms(1));
angle = ((uint16_t)buf[0] & 0x0f) << 8 | buf[1]; angle = ((uint16_t)buf[0] & 0x0f) << 8 | buf[1];
} }
void turntable_set_hardware(bool sensor_reversed)
{
reversed = sensor_reversed;
}
uint16_t turntable_read() uint16_t turntable_read()
{ {
return reversed ? (4096 - angle) : angle; // 12bit return iidx_cfg->tt_sensor_reversed ? 4095 - angle : angle; // 12bit
} }

View File

@ -10,7 +10,6 @@
#include <stdbool.h> #include <stdbool.h>
void turntable_init(); void turntable_init();
void turntable_set_hardware(bool sensor_reversed);
uint16_t turntable_read(); uint16_t turntable_read();
void turntable_update(); void turntable_update();