#include #include "ui.h" #include #include "adc.h" #include "button.h" #include "system.h" #include "unicore-mx/stm32/gpio.h" #include "unicore-mx/stm32/rcc.h" #include "pot.h" #include "dac.h" #include "settings.h" #include "timer.h" #define CENTER_X ((int)(52)) #define CENTER_Y ((int)(50)) #define NEUTRAL 2 static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b); static void ui_master_action(struct display_menu_entry *e, uint8_t b); static void ui_bpm_action(struct display_menu_entry *e, uint8_t b); static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b); static void main_menu_prepare(struct display_menu *m); extern struct display_menu PatternMenu; static void ui_submenu_action(struct display_menu_entry *e, uint8_t b) { ui_display_menu(e->arg); } struct display_menu MainMenu = { .entry_n = 7, .render = main_menu_prepare, .entry = { { ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, .min = 0, .max = 0, .step = 0, NULL, .arg = NULL }, { ENTRY_TYPE_DEC, "Volume: ", ui_master_action, 0, 100, 2, NULL, NULL }, { ENTRY_TYPE_DEC, "BPM: ", ui_bpm_action, 30, 300, 1, NULL, NULL }, { ENTRY_TYPE_DEC, "Pattern :", NULL, 0, MAX_PATTERNS, 1, NULL, NULL }, { ENTRY_TYPE_DEC, "Pattern Len:", NULL, 8, MAX_PATTERN_LEN, 8, NULL, NULL }, { ENTRY_TYPE_TEXT, "Edit Pattern", ui_submenu_action, 0, 0, 0, NULL, &PatternMenu}, { ENTRY_TYPE_TEXT, "Save Pattern", ui_pattern_save_action, 0, 0, 0, NULL, NULL}, } }; struct display_menu *CurrentMenu = &MainMenu; extern volatile uint32_t jiffies; static uint32_t drone_xy_gain = 1; #if 0 static void ui_return(uint8_t press, int hold) { display_clear(NULL); clear_input_callback(); ui_display_menu(&MainMenu); } static void ui_action_interrupt(uint8_t press, int hold) { if (press == '+') { clear_keepalive(); display_clear(NULL); display_text(5, "Interrupted!"); set_input_callback(ui_return); } } static void display_drone(int line, uint16_t val) { char txt[] = "0000"; if (val >= 1000) txt[0] = '0' + val / 1000; val %= 1000; if (val != 0) txt[3] = '0' + val % 10; if (val > 9) txt[2] = '0' + ((val / 10) % 10); if (val > 99) txt[1] = '0' + (val / 100); display_text(line, txt); } static void display_thousand(uint32_t val) { char txt[4] = "000"; txt[0] = '0' + val / 100; txt[1] = '0' + (val % 100) / 10; txt[2] = '0' + (val % 10); display_text(6, txt); } static void display_volume(void) { display_thousand(pot_get_master()); } void ui_drone_xy_poll(void) { uint16_t x = 0, y = 0; char TXT[]="Bender!"; static uint32_t bend_update = 0; int X, Y; char bgain[4] = "000"; rcc_periph_clock_enable(RCC_GPIOA); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2); adc_pin_val(2, &x); adc_pin_val(1, &y); X = (100 * x) / 4096; Y = (100 * y) / 4096; if (((X > CENTER_X) && ((X - CENTER_X) > NEUTRAL)) || ((X < CENTER_X) && ((CENTER_X - X) > NEUTRAL))) { int off = X - CENTER_X; pot_offset(0, off/10); } if (((Y > CENTER_Y) && ((Y - CENTER_Y) > NEUTRAL)) || ((Y < CENTER_Y) && ((CENTER_Y - Y) > NEUTRAL))) { int off = Y - CENTER_Y; pot_offset(1, off/10); } led_beat(((jiffies / 100) % 8) + 1); display_text(4, TXT); display_drone(5, pot_get(0)); display_drone(6, pot_get(1)); bgain[0] = '0' + drone_xy_gain / 100; bgain[1] = '0' + (drone_xy_gain % 100) / 10; bgain[2] = '0' + (drone_xy_gain % 10); display_text(7, bgain); } void ui_bender_poll(void) { uint16_t x = 0, y = 0; char TXT[]="Bender!"; static uint32_t bend_update = 0; int X, Y; char bgain[4] = "000"; rcc_periph_clock_enable(RCC_GPIOA); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2); adc_pin_val(2, &x); adc_pin_val(1, &y); X = (100 * x) / 4096; Y = (100 * y) / 4096; pot_set(0, X); pot_set(1, Y); led_beat(((jiffies / 100) % 8) + 1); display_text(4, TXT); display_drone(5, pot_get(0)); display_drone(6, pot_get(1)); bgain[0] = '0' + drone_xy_gain / 100; bgain[1] = '0' + (drone_xy_gain % 100) / 10; bgain[2] = '0' + (drone_xy_gain % 10); display_text(7, bgain); } static void ui_gain_input(uint8_t press, int hold) { if (press == '+') { display_clear(NULL); display_text(5, "Interrupted!"); clear_keepalive(); set_input_callback(ui_return); return; } if (press == 'U') { if (drone_xy_gain < 10) drone_xy_gain++; } if (press == 'D') { if (drone_xy_gain > 0) drone_xy_gain--; } ui_drone_xy_poll(); } static void ui_drone_xy(const void *arg) { set_input_callback(ui_gain_input); set_keepalive(ui_drone_xy_poll); display_clear(NULL); ui_drone_xy_poll(); } static void ui_bender(const void *arg) { set_input_callback(ui_gain_input); set_keepalive(ui_bender_poll); display_clear(NULL); ui_bender_poll(); } static void ui_mastervol_input(uint8_t press, int hold) { int master_vol = pot_get_master(); if (press == 'U') if (master_vol < 100) pot_set_master(master_vol + 5); if (press == 'D') { if (master_vol > 4) pot_set_master(master_vol - 5); } if (press == '+') { display_clear(NULL); clear_input_callback(); ui_display_menu(&MainMenu); return; } display_text(5, "Master Volume"); display_volume(); } static void ui_mastervol(const void *arg) { set_input_callback(ui_mastervol_input); display_clear(NULL); display_text(5, "Master Volume"); display_volume(); } static void ui_bpm_input(uint8_t press, int hold) { uint32_t sys_bpm = timer_get_bpm(); if (press == 'U') { if (sys_bpm < 300) { timer_stop(); timer_set_bpm(); led_beat(1); settings_save(); timer_set_beat(1); timer_set_beat(1); timer_start(); } } if (press == 'D') { if (sys_bpm > 60) { timer_stop(); timer_set_bpm(sys_bpm - 1); led_beat(1); settings_save(); timer_set_beat(1); timer_start(); } } if (press == '*') { display_clear(NULL); clear_input_callback(); ui_display_menu(&MainMenu); return; } display_text(5, " BPM "); display_thousand(timer_get_bpm()); } static void ui_bpm(const void *arg) { set_input_callback(ui_bpm_input); display_clear(NULL); display_text(5, " BPM "); display_thousand(timer_get_bpm()); } static void ui_bytebeat_input(uint8_t press, int hold) { if (press == '+') { display_clear(NULL); clear_input_callback(); clear_keepalive(); ui_display_menu(&MainMenu); } } #define PLAY_SIZE 512 static uint8_t bb_buffer[PLAY_SIZE]; void ui_bytebeat_keepalive(void) { static uint32_t t = 0; int r = 0; for(r = 0;;t++) { while (dac_is_busy()) WFI(); bb_buffer[r++] = (t<<1)|(t>>4)*(((t>>12)|(t>>13)|(t>>6) | ((t>>2)|(t>>4))|(t<<1)|(t<<12)|((t<<5)&~(t>>22)))); if (r >= PLAY_SIZE) { dac_play_direct(bb_buffer, r); break; } } } static void ui_bytebeat(const void *arg) { set_input_callback(ui_bytebeat_input); display_clear(NULL); display_text(5, " Bytebeat! "); set_keepalive(ui_bytebeat_keepalive); } const struct display_menu DroneMenu = { .entry_n = 2, .entry = { { "Drone X, Y ", ui_drone_xy, NULL}, { "Bender ", ui_bender, NULL}, { "", NULL, NULL} } }; const struct display_menu SettingsMenu = { .entry_n = 1, .entry = { { "TODO", ui_submenu, &MainMenu }, { "", NULL, NULL} } }; #endif static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b) { if (Settings->sequencer_on) { timer_set_beat(1); timer_start(); } else { led_beat(0); drone_mute(); timer_stop(); } } static void ui_master_action(struct display_menu_entry *e, uint8_t b) { pot_sync(2); } static void ui_bpm_action(struct display_menu_entry *e, uint8_t b) { timer_stop(); timer_set_bpm(); led_beat(1); timer_set_beat(1); timer_start(); } static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b) { display_clear(); display_scroll(NULL, 0); display_text(5, "Saving to FLASH"); settings_save(); ui_display_menu(&MainMenu); } static void main_menu_prepare(struct display_menu *m) { if (m != &MainMenu) return; MainMenu.entry[0].var = &Settings->sequencer_on; MainMenu.entry[1].var = &Settings->levels[2]; MainMenu.entry[2].var = &Settings->bpm; MainMenu.entry[3].var = &Settings->current_pattern; MainMenu.entry[4].var = &(Settings->drums[Settings->current_pattern].len); } extern void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b);