| @@ -0,0 +1,12 @@ | ||
| #ifndef _EDIT_MODE_H_ | ||
| #define _EDIT_MODE_H_ | ||
|
|
||
| #include "stdbool.h" | ||
| #include "stdint.h" | ||
|
|
||
| void set_edit_mode(void); | ||
| void set_edit_mode_script(uint8_t new_script); | ||
| void process_edit_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| bool screen_refresh_edit(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,56 @@ | ||
| #include "flash.h" | ||
|
|
||
| #include <string.h> | ||
|
|
||
| // asf | ||
| #include "flashc.h" | ||
|
|
||
| // this | ||
| #include "globals.h" | ||
|
|
||
| #define FIRSTRUN_KEY 0x22 | ||
|
|
||
| char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; | ||
|
|
||
| // NVRAM data structure located in the flash array. | ||
| __attribute__((__section__(".flash_nvram"))) nvram_data_t f; | ||
|
|
||
|
|
||
| uint8_t flash_is_fresh(void) { | ||
| return (f.fresh != FIRSTRUN_KEY); | ||
| } | ||
|
|
||
| // write fresh status | ||
| void flash_unfresh(void) { | ||
| for (uint8_t preset_select = 0; preset_select < SCENE_SLOTS; | ||
| preset_select++) { | ||
| flash_write(preset_select); | ||
| } | ||
| preset_select = 0; | ||
| flashc_memset8((void*)&(f.scene), preset_select, 1, true); | ||
| flashc_memset8((void*)&(f.mode), M_LIVE, 1, true); | ||
| flashc_memset8((void*)&(f.fresh), FIRSTRUN_KEY, 1, true); | ||
| } | ||
|
|
||
| void flash_write(uint8_t preset_no) { | ||
| flashc_memcpy((void*)&f.s[preset_no].script, ss_script_ptr(&scene_state), | ||
| ss_script_size(), true); | ||
| flashc_memcpy((void*)&f.s[preset_no].patterns, | ||
| ss_patterns_ptr(&scene_state), ss_patterns_size(), true); | ||
| flashc_memcpy((void*)&f.s[preset_no].text, &scene_text, sizeof(scene_text), | ||
| true); | ||
| flashc_memset8((void*)&(f.scene), preset_no, 1, true); | ||
| } | ||
|
|
||
| void flash_read(uint8_t preset_no) { | ||
| memcpy(ss_script_ptr(&scene_state), &f.s[preset_no].script, | ||
| ss_script_size()); | ||
| memcpy(ss_patterns_ptr(&scene_state), &f.s[preset_no].patterns, | ||
| ss_patterns_size()); | ||
| memcpy(&scene_text, &f.s[preset_no].text, sizeof(scene_text)); | ||
| flashc_memset8((void*)&(f.scene), preset_no, 1, true); | ||
| } | ||
|
|
||
| void flash_save_mode(tele_mode_t mode) { | ||
| flashc_memset8((void*)&(f.mode), mode, 1, true); | ||
| } |
| @@ -0,0 +1,38 @@ | ||
| #ifndef _FLASH_H_ | ||
| #define _FLASH_H_ | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "globals.h" | ||
| #include "line_editor.h" | ||
| #include "teletype.h" | ||
|
|
||
| #define SCENE_SLOTS 32 | ||
|
|
||
| #define SCENE_TEXT_LINES 32 | ||
| #define SCENE_TEXT_CHARS LINE_EDITOR_SIZE | ||
|
|
||
| extern char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; | ||
|
|
||
| typedef const struct { | ||
| scene_script_t script[10]; | ||
| scene_pattern_t patterns[4]; | ||
| char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; | ||
| } nvram_scene_t; | ||
|
|
||
| typedef const struct { | ||
| nvram_scene_t s[SCENE_SLOTS]; | ||
| uint8_t scene; | ||
| tele_mode_t mode; | ||
| uint8_t fresh; | ||
| } nvram_data_t; | ||
|
|
||
| extern nvram_data_t f; | ||
|
|
||
| uint8_t flash_is_fresh(void); | ||
| void flash_unfresh(void); | ||
| void flash_write(uint8_t preset_no); | ||
| void flash_read(uint8_t preset_no); | ||
| void flash_save_mode(tele_mode_t mode); | ||
|
|
||
| #endif |
| @@ -0,0 +1,33 @@ | ||
| #ifndef _GLOBALS_H_ | ||
| #define _GLOBALS_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include "region.h" | ||
| #include "teletype.h" | ||
|
|
||
| // global variables (defined in main.c) | ||
|
|
||
| // holds the current scene | ||
| extern scene_state_t scene_state; | ||
|
|
||
| // the current preset | ||
| extern uint8_t preset_select; | ||
|
|
||
| // holds screen data | ||
| extern region line[8]; | ||
|
|
||
| // mode handling | ||
| typedef enum { | ||
| M_LIVE, | ||
| M_EDIT, | ||
| M_PATTERN, | ||
| M_PRESET_W, | ||
| M_PRESET_R, | ||
| M_HELP | ||
| } tele_mode_t; | ||
|
|
||
| void set_mode(tele_mode_t mode); | ||
| void set_last_mode(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,11 @@ | ||
| #ifndef _HELP_MODE_H_ | ||
| #define _HELP_MODE_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| void set_help_mode(void); | ||
| void process_help_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| bool screen_refresh_help(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,83 @@ | ||
| #ifndef _KEYBOARD_HELPER_ | ||
| #define _KEYBOARD_HELPER_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| // small functions defined static inline, so that each compilation unit gets | ||
| // it's own copy and may inline (no LTO in gcc 4.4.7) | ||
|
|
||
| static inline bool no_mod(uint8_t mod) { | ||
| return mod == HID_MODIFIER_NONE; | ||
| } | ||
|
|
||
| static inline bool mod_only_shift(uint8_t mod) { | ||
| return mod == HID_MODIFIER_LEFT_SHIFT || mod == HID_MODIFIER_RIGHT_SHIFT || | ||
| mod == (HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT); | ||
| } | ||
|
|
||
| static inline bool mod_only_ctrl(uint8_t mod) { | ||
| return mod == HID_MODIFIER_LEFT_CTRL || mod == HID_MODIFIER_RIGHT_CTRL || | ||
| mod == (HID_MODIFIER_LEFT_CTRL | HID_MODIFIER_RIGHT_CTRL); | ||
| } | ||
|
|
||
| static inline bool mod_only_shift_ctrl(uint8_t mod) { | ||
| const uint8_t either_sh = | ||
| HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT; | ||
| const uint8_t either_ctrl = | ||
| HID_MODIFIER_LEFT_CTRL | HID_MODIFIER_RIGHT_CTRL; | ||
| // first check we only have shift and alt | ||
| if (mod & ~(either_sh | either_ctrl)) return false; | ||
| return (mod & either_sh) && (mod & either_ctrl); | ||
| } | ||
|
|
||
| static inline bool mod_only_alt(uint8_t mod) { | ||
| return mod == HID_MODIFIER_LEFT_ALT || mod == HID_MODIFIER_RIGHT_ALT || | ||
| mod == (HID_MODIFIER_LEFT_ALT | HID_MODIFIER_RIGHT_ALT); | ||
| } | ||
|
|
||
| static inline bool mod_only_shift_alt(uint8_t mod) { | ||
| const uint8_t either_sh = | ||
| HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT; | ||
| const uint8_t either_alt = HID_MODIFIER_LEFT_ALT | HID_MODIFIER_RIGHT_ALT; | ||
| // first check we only have shift and alt | ||
| if (mod & ~(either_sh | either_alt)) return false; | ||
| return (mod & either_sh) && (mod & either_alt); | ||
| } | ||
|
|
||
| static inline bool mod_only_win(uint8_t mod) { | ||
| return mod == HID_MODIFIER_LEFT_UI || mod == HID_MODIFIER_RIGHT_UI || | ||
| mod == (HID_MODIFIER_LEFT_UI | HID_MODIFIER_RIGHT_UI); | ||
| } | ||
|
|
||
| static inline bool match_no_mod(uint8_t mod, uint8_t key, | ||
| uint8_t required_key) { | ||
| return (mod == HID_MODIFIER_NONE) && (key == required_key); | ||
| } | ||
|
|
||
| static inline bool match_shift(uint8_t mod, uint8_t key, uint8_t required_key) { | ||
| return mod_only_shift(mod) && key == required_key; | ||
| } | ||
|
|
||
| static inline bool match_ctrl(uint8_t mod, uint8_t key, uint8_t required_key) { | ||
| return mod_only_ctrl(mod) && key == required_key; | ||
| } | ||
|
|
||
| static inline bool match_alt(uint8_t mod, uint8_t key, uint8_t required_key) { | ||
| return mod_only_alt(mod) && key == required_key; | ||
| } | ||
|
|
||
| static inline bool match_shift_alt(uint8_t mod, uint8_t key, | ||
| uint8_t required_key) { | ||
| return mod_only_shift_alt(mod) && key == required_key; | ||
| } | ||
|
|
||
| static inline bool match_win(uint8_t mod, uint8_t key, uint8_t required_key) { | ||
| return mod_only_win(mod) && key == required_key; | ||
| } | ||
|
|
||
| #endif |
| @@ -0,0 +1,170 @@ | ||
| #include "line_editor.h" | ||
|
|
||
| #include <string.h> | ||
|
|
||
| // this | ||
| #include "keyboard_helper.h" | ||
|
|
||
| // teletype | ||
| #include "teletype.h" | ||
|
|
||
| // libavr32 | ||
| #include "font.h" | ||
| #include "kbd.h" | ||
| #include "region.h" | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| // global copy buffer | ||
| static char copy_buffer[LINE_EDITOR_SIZE]; | ||
|
|
||
| void line_editor_set(line_editor_t *le, const char value[LINE_EDITOR_SIZE]) { | ||
| size_t length = strlen(value); | ||
| if (length < LINE_EDITOR_SIZE) { | ||
| strcpy(le->buffer, value); | ||
| le->cursor = length; | ||
| le->length = length; | ||
| } | ||
| else { | ||
| le->buffer[0] = 0; | ||
| le->cursor = 0; | ||
| le->length = 0; | ||
| } | ||
| } | ||
|
|
||
| void line_editor_set_command(line_editor_t *le, const tele_command_t *command) { | ||
| print_command(command, le->buffer); | ||
| le->length = strlen(le->buffer); | ||
| le->cursor = le->length; | ||
| } | ||
|
|
||
| char *line_editor_get(line_editor_t *le) { | ||
| return le->buffer; | ||
| } | ||
|
|
||
| bool line_editor_process_keys(line_editor_t *le, uint8_t k, uint8_t m, | ||
| bool is_key_held) { | ||
| // <left> or ctrl-b: move cursor left | ||
| if (match_no_mod(m, k, HID_LEFT) || match_ctrl(m, k, HID_B)) { | ||
| if (le->cursor) { le->cursor--; } | ||
| return true; | ||
| } | ||
| // <right> or ctrl-f: move cursor right | ||
| else if (match_no_mod(m, k, HID_RIGHT) || match_ctrl(m, k, HID_F)) { | ||
| if (le->cursor < le->length) { le->cursor++; } | ||
| return true; | ||
| } | ||
| // <home> or ctrl-a: move to beginning of line | ||
| else if (match_no_mod(m, k, HID_HOME) || match_ctrl(m, k, HID_A)) { | ||
| le->cursor = 0; | ||
| return true; | ||
| } | ||
| // <end> or ctrl-e: move to end of line | ||
| else if (match_no_mod(m, k, HID_END) || match_ctrl(m, k, HID_E)) { | ||
| le->cursor = le->length; | ||
| return true; | ||
| } | ||
| // <backspace> or ctrl-h: backwards delete one character | ||
| else if (match_no_mod(m, k, HID_BACKSPACE) || match_ctrl(m, k, HID_H)) { | ||
| if (le->cursor) { | ||
| le->cursor--; | ||
| for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) { | ||
| le->buffer[x] = le->buffer[x + 1]; | ||
| } | ||
| le->length--; | ||
| } | ||
| return true; | ||
| } | ||
| // <delete> or ctrl-d: forwards delete one character | ||
| else if (match_no_mod(m, k, HID_DELETE) || match_ctrl(m, k, HID_D)) { | ||
| if (le->cursor < le->length) { | ||
| for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) { | ||
| le->buffer[x] = le->buffer[x + 1]; | ||
| } | ||
| le->length--; | ||
| } | ||
| return true; | ||
| } | ||
| // shift-<backspace> or ctrl-u: delete from cursor to beginning | ||
| else if (match_shift(m, k, HID_BACKSPACE) || match_ctrl(m, k, HID_U)) { | ||
| // strings will overlap, so we need to use an intermediate buffer | ||
| char temp[LINE_EDITOR_SIZE]; | ||
| strcpy(temp, &le->buffer[le->cursor]); | ||
| line_editor_set(le, temp); | ||
| le->cursor = 0; | ||
| return true; | ||
| } | ||
| // shift-<delete> or ctrl-e: delete from cursor to end | ||
| else if (match_shift(m, k, HID_DELETE) || match_ctrl(m, k, HID_K)) { | ||
| le->buffer[le->cursor] = 0; | ||
| le->length = le->cursor; | ||
| return true; | ||
| } | ||
| // alt-<backspace> or ctrl-w: delete from cursor to beginning of word | ||
| else if (match_alt(m, k, HID_DELETE) || match_ctrl(m, k, HID_W)) { | ||
| while (le->cursor) { | ||
| // delete a character | ||
| le->cursor--; | ||
| for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) { | ||
| le->buffer[x] = le->buffer[x + 1]; | ||
| } | ||
| le->length--; | ||
|
|
||
| // place the check at the bottom so that we can chain invocations to | ||
| // delete multiple words | ||
| if (le->buffer[le->cursor - 1] == ' ') break; | ||
| } | ||
| return true; | ||
| } | ||
| // ctrl-x or alt-x: cut | ||
| else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) { | ||
| strcpy(copy_buffer, le->buffer); | ||
| line_editor_set(le, ""); | ||
| return true; | ||
| } | ||
| // ctrl-c or alt-c: copy | ||
| else if (match_ctrl(m, k, HID_C) || match_alt(m, k, HID_C)) { | ||
| strcpy(copy_buffer, le->buffer); | ||
| return true; | ||
| } | ||
| // ctrl-v or alt-v: paste | ||
| else if (match_ctrl(m, k, HID_V) || match_alt(m, k, HID_V)) { | ||
| line_editor_set(le, copy_buffer); | ||
| return true; | ||
| } | ||
| else if (no_mod(m) || mod_only_shift(m)) { | ||
| if (le->length < LINE_EDITOR_SIZE - 2) { // room for another char & 0 | ||
| uint8_t n = hid_to_ascii(k, m); | ||
| if (n) { | ||
| for (size_t x = LINE_EDITOR_SIZE - 1; x > le->cursor; x--) { | ||
| le->buffer[x] = le->buffer[x - 1]; // shuffle forwards | ||
| } | ||
|
|
||
| le->buffer[le->cursor] = n; | ||
| le->cursor++; | ||
| le->length++; | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // did't process a key | ||
| return false; | ||
| } | ||
|
|
||
| void line_editor_draw(line_editor_t *le, char prefix, region *reg) { | ||
| // LINE_EDITOR_SIZE includes space for null, need to also include space for | ||
| // the prefix, the space after the prefix and a space at the very end | ||
| char s[LINE_EDITOR_SIZE + 3] = { prefix, ' ', 0 }; | ||
| strcat(s, le->buffer); | ||
| strcat(s, " "); | ||
|
|
||
| region_fill(reg, 0); | ||
| font_string_region_clip_hi(reg, s, 0, 0, 0xf, 0, le->cursor + 2); | ||
| } | ||
|
|
||
| void line_editor_set_copy_buffer(const char *value) { | ||
| strcpy(copy_buffer, value); | ||
| } |
| @@ -0,0 +1,26 @@ | ||
| #ifndef _LINE_EDITOR_H_ | ||
| #define _LINE_EDITOR_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
| #include "region.h" | ||
| #include "teletype.h" | ||
|
|
||
| #define LINE_EDITOR_SIZE 32 // 31 characters + null termination | ||
|
|
||
| typedef struct { | ||
| char buffer[LINE_EDITOR_SIZE]; | ||
| size_t cursor; | ||
| size_t length; | ||
| } line_editor_t; | ||
|
|
||
| void line_editor_set(line_editor_t *le, const char value[LINE_EDITOR_SIZE]); | ||
| void line_editor_set_command(line_editor_t *le, const tele_command_t *command); | ||
| char *line_editor_get(line_editor_t *le); | ||
| bool line_editor_process_keys(line_editor_t *le, uint8_t key, uint8_t mod_key, | ||
| bool is_key_held); | ||
| void line_editor_draw(line_editor_t *le, char prefix, region *reg); | ||
| void line_editor_set_copy_buffer(const char *value); | ||
| #endif |
| @@ -0,0 +1,277 @@ | ||
| #include "live_mode.h" | ||
|
|
||
| #include <string.h> | ||
|
|
||
| // this | ||
| #include "flash.h" | ||
| #include "gitversion.h" | ||
| #include "globals.h" | ||
| #include "keyboard_helper.h" | ||
| #include "line_editor.h" | ||
|
|
||
| // teletype | ||
| #include "teletype_io.h" | ||
|
|
||
| // libavr32 | ||
| #include "font.h" | ||
| #include "region.h" | ||
| #include "util.h" | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| #define HISTORY_SIZE 16 | ||
| tele_command_t history[HISTORY_SIZE]; | ||
| uint8_t history_line; | ||
| line_editor_t le; | ||
| process_result_t output; | ||
| error_t status; | ||
| char error_msg[TELE_ERROR_MSG_LENGTH]; | ||
| bool show_welcome_message; | ||
|
|
||
| static const uint8_t D_INPUT = 1 << 0; | ||
| static const uint8_t D_LIST = 1 << 1; | ||
| static const uint8_t D_MESSAGE = 1 << 2; | ||
| static const uint8_t D_ALL = 0xFF; | ||
| uint8_t dirty; | ||
|
|
||
| static const uint8_t A_METRO = 1 << 0; | ||
| static const uint8_t A_SLEW = 1 << 1; | ||
| static const uint8_t A_DELAY = 1 << 2; | ||
| static const uint8_t A_STACK = 1 << 3; | ||
| static const uint8_t A_MUTES = 1 << 4; | ||
| uint8_t activity_prev; | ||
| uint8_t activity; | ||
|
|
||
| // teletype_io.h | ||
| void tele_has_delays(bool has_delays) { | ||
| if (has_delays) | ||
| activity |= A_DELAY; | ||
| else | ||
| activity &= ~A_DELAY; | ||
| } | ||
|
|
||
| void tele_has_stack(bool has_stack) { | ||
| if (has_stack) | ||
| activity |= A_STACK; | ||
| else | ||
| activity &= ~A_STACK; | ||
| } | ||
|
|
||
| void tele_mute() { | ||
| activity |= A_MUTES; | ||
| } | ||
|
|
||
| // set icons | ||
| void set_slew_icon(bool display) { | ||
| if (display) | ||
| activity |= A_SLEW; | ||
| else | ||
| activity &= ~A_SLEW; | ||
| } | ||
|
|
||
| void set_metro_icon(bool display) { | ||
| if (display) | ||
| activity |= A_METRO; | ||
| else | ||
| activity &= ~A_METRO; | ||
| } | ||
|
|
||
| // main mode functions | ||
| void init_live_mode() { | ||
| status = E_OK; | ||
| show_welcome_message = true; | ||
| activity_prev = 0xFF; | ||
| } | ||
|
|
||
| void set_live_mode() { | ||
| line_editor_set(&le, ""); | ||
| history_line = HISTORY_SIZE; | ||
| dirty = D_ALL; | ||
| } | ||
|
|
||
| void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { | ||
| // <down> or C-n: history next | ||
| if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { | ||
| if (history_line < (HISTORY_SIZE - 1)) { | ||
| history_line++; | ||
| line_editor_set_command(&le, &history[history_line]); | ||
| dirty |= D_INPUT; | ||
| } | ||
| else { | ||
| history_line = HISTORY_SIZE; | ||
| line_editor_set(&le, ""); | ||
| dirty |= D_INPUT; | ||
| } | ||
| } | ||
| // <up> or C-p: history previous | ||
| else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { | ||
| if (history_line) { | ||
| history_line--; | ||
| line_editor_set_command(&le, &history[history_line]); | ||
| dirty |= D_INPUT; | ||
| } | ||
| } | ||
| // <enter>: execute command | ||
| else if (match_no_mod(m, k, HID_ENTER)) { | ||
| dirty |= D_MESSAGE; // something will definitely happen | ||
| dirty |= D_INPUT; | ||
|
|
||
| tele_command_t command; | ||
|
|
||
| status = parse(line_editor_get(&le), &command, error_msg); | ||
| if (status != E_OK) | ||
| return; // quit, screen_refresh_live will display the error message | ||
|
|
||
| status = validate(&command, error_msg); | ||
| if (status != E_OK) | ||
| return; // quit, screen_refresh_live will display the error message | ||
|
|
||
| history_line = HISTORY_SIZE; | ||
| if (command.length) { | ||
| // shuffle the history up | ||
| // should really use some sort of ring buffer | ||
| for (size_t i = 0; i < HISTORY_SIZE - 1; i++) { | ||
| memcpy(&history[i], &history[i + 1], sizeof(command)); | ||
| } | ||
| memcpy(&history[HISTORY_SIZE - 1], &command, sizeof(command)); | ||
|
|
||
| output = run_command(&scene_state, &command); | ||
| } | ||
| line_editor_set(&le, ""); | ||
| } | ||
| // [ or ]: switch to edit mode | ||
| else if (match_no_mod(m, k, HID_OPEN_BRACKET) || | ||
| match_no_mod(m, k, HID_CLOSE_BRACKET)) { | ||
| set_mode(M_EDIT); | ||
| } | ||
| else { // pass the key though to the line editor | ||
| bool processed = line_editor_process_keys(&le, k, m, is_held_key); | ||
| if (processed) dirty |= D_INPUT; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| bool screen_refresh_live() { | ||
| bool screen_dirty = false; | ||
| if (dirty & D_INPUT) { | ||
| line_editor_draw(&le, '>', &line[7]); | ||
| screen_dirty = true; | ||
| dirty &= ~D_INPUT; | ||
| } | ||
|
|
||
| if (dirty & D_MESSAGE) { | ||
| char s[32]; | ||
| if (status != E_OK) { | ||
| strcpy(s, tele_error(status)); | ||
| if (error_msg[0]) { | ||
| strcat(s, ": "); | ||
| strcat(s, error_msg); | ||
| error_msg[0] = 0; | ||
| } | ||
| status = E_OK; | ||
| } | ||
| else if (output.has_value) { | ||
| itoa(output.value, s, 10); | ||
| output.has_value = false; | ||
| } | ||
| else if (show_welcome_message) { | ||
| strcpy(s, TELETYPE_VERSION ": "); | ||
| strcat(s, git_version); | ||
| show_welcome_message = false; | ||
| } | ||
| else { | ||
| s[0] = 0; | ||
| } | ||
|
|
||
| region_fill(&line[6], 0); | ||
| font_string_region_clip(&line[6], s, 0, 0, 0x4, 0); | ||
|
|
||
| screen_dirty = true; | ||
| dirty &= ~D_MESSAGE; | ||
| } | ||
|
|
||
| if (dirty & D_LIST) { | ||
| for (int i = 0; i < 6; i++) region_fill(&line[i], 0); | ||
|
|
||
| screen_dirty = true; | ||
| dirty &= ~D_LIST; | ||
| } | ||
|
|
||
| if ((activity != activity_prev)) { | ||
| region_fill(&line[0], 0); | ||
|
|
||
| // slew icon | ||
| uint8_t slew_fg = activity & A_SLEW ? 15 : 1; | ||
| line[0].data[98 + 0 + 512] = slew_fg; | ||
| line[0].data[98 + 1 + 384] = slew_fg; | ||
| line[0].data[98 + 2 + 256] = slew_fg; | ||
| line[0].data[98 + 3 + 128] = slew_fg; | ||
| line[0].data[98 + 4 + 0] = slew_fg; | ||
|
|
||
| // delay icon | ||
| uint8_t delay_fg = activity & A_DELAY ? 15 : 1; | ||
| line[0].data[106 + 0 + 0] = delay_fg; | ||
| line[0].data[106 + 1 + 0] = delay_fg; | ||
| line[0].data[106 + 2 + 0] = delay_fg; | ||
| line[0].data[106 + 3 + 0] = delay_fg; | ||
| line[0].data[106 + 4 + 0] = delay_fg; | ||
| line[0].data[106 + 0 + 128] = delay_fg; | ||
| line[0].data[106 + 0 + 256] = delay_fg; | ||
| line[0].data[106 + 0 + 384] = delay_fg; | ||
| line[0].data[106 + 0 + 512] = delay_fg; | ||
| line[0].data[106 + 4 + 128] = delay_fg; | ||
| line[0].data[106 + 4 + 256] = delay_fg; | ||
| line[0].data[106 + 4 + 384] = delay_fg; | ||
| line[0].data[106 + 4 + 512] = delay_fg; | ||
|
|
||
| // queue icon | ||
| uint8_t stack_fg = activity & A_STACK ? 15 : 1; | ||
| line[0].data[114 + 0 + 0] = stack_fg; | ||
| line[0].data[114 + 1 + 0] = stack_fg; | ||
| line[0].data[114 + 2 + 0] = stack_fg; | ||
| line[0].data[114 + 3 + 0] = stack_fg; | ||
| line[0].data[114 + 4 + 0] = stack_fg; | ||
| line[0].data[114 + 0 + 256] = stack_fg; | ||
| line[0].data[114 + 1 + 256] = stack_fg; | ||
| line[0].data[114 + 2 + 256] = stack_fg; | ||
| line[0].data[114 + 3 + 256] = stack_fg; | ||
| line[0].data[114 + 4 + 256] = stack_fg; | ||
| line[0].data[114 + 0 + 512] = stack_fg; | ||
| line[0].data[114 + 1 + 512] = stack_fg; | ||
| line[0].data[114 + 2 + 512] = stack_fg; | ||
| line[0].data[114 + 3 + 512] = stack_fg; | ||
| line[0].data[114 + 4 + 512] = stack_fg; | ||
|
|
||
| // metro icon | ||
| uint8_t metro_fg = activity & A_METRO ? 15 : 1; | ||
| line[0].data[122 + 0 + 0] = metro_fg; | ||
| line[0].data[122 + 0 + 128] = metro_fg; | ||
| line[0].data[122 + 0 + 256] = metro_fg; | ||
| line[0].data[122 + 0 + 384] = metro_fg; | ||
| line[0].data[122 + 0 + 512] = metro_fg; | ||
| line[0].data[122 + 1 + 128] = metro_fg; | ||
| line[0].data[122 + 2 + 256] = metro_fg; | ||
| line[0].data[122 + 3 + 128] = metro_fg; | ||
| line[0].data[122 + 4 + 0] = metro_fg; | ||
| line[0].data[122 + 4 + 128] = metro_fg; | ||
| line[0].data[122 + 4 + 256] = metro_fg; | ||
| line[0].data[122 + 4 + 384] = metro_fg; | ||
| line[0].data[122 + 4 + 512] = metro_fg; | ||
|
|
||
| // mutes | ||
| for (size_t i = 0; i < 8; i++) { | ||
| // make it staggered to match how the device looks | ||
| size_t stagger = i % 2 ? 384 : 128; | ||
| uint8_t mute_fg = ss_get_mute(&scene_state, i) ? 15 : 1; | ||
| line[0].data[87 + i + stagger] = mute_fg; | ||
| } | ||
|
|
||
| activity_prev = activity; | ||
| screen_dirty = true; | ||
| activity &= ~A_MUTES; | ||
| } | ||
|
|
||
| return screen_dirty; | ||
| } |
| @@ -0,0 +1,14 @@ | ||
| #ifndef _LIVE_MODE_H_ | ||
| #define _LIVE_MODE_H_ | ||
|
|
||
| #include "stdbool.h" | ||
| #include "stdint.h" | ||
|
|
||
| void set_slew_icon(bool display); | ||
| void set_metro_icon(bool display); | ||
| void init_live_mode(void); | ||
| void set_live_mode(void); | ||
| void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| bool screen_refresh_live(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,350 @@ | ||
| #include "pattern_mode.h" | ||
|
|
||
| // this | ||
| #include "globals.h" | ||
| #include "keyboard_helper.h" | ||
|
|
||
| // teletype | ||
| #include "teletype.h" | ||
| #include "teletype_io.h" | ||
|
|
||
| // libavr32 | ||
| #include "font.h" | ||
| #include "region.h" | ||
| #include "util.h" | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| int16_t copy_buffer; | ||
| uint8_t pattern; // which pattern are we editting | ||
| uint8_t base; // base + offset determine what we are editting | ||
| uint8_t offset; | ||
|
|
||
| bool dirty; | ||
|
|
||
| // teletype_io.h | ||
| void tele_pattern_updated() { | ||
| dirty = true; | ||
| } | ||
|
|
||
| void set_pattern_mode() { | ||
| dirty = true; | ||
| } | ||
|
|
||
| void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { | ||
| // <down>: move down | ||
| if (match_no_mod(m, k, HID_DOWN)) { | ||
| base++; | ||
| if (base == 8) { | ||
| base = 7; | ||
| if (offset < 56) { offset++; } | ||
| } | ||
| dirty = true; | ||
| } | ||
| // alt-<down>: move a page down | ||
| else if (match_alt(m, k, HID_DOWN)) { | ||
| if (offset < 48) | ||
| offset += 8; | ||
| else { | ||
| offset = 56; | ||
| base = 7; | ||
| } | ||
| dirty = true; | ||
| } | ||
| // <up>: move up | ||
| else if (match_no_mod(m, k, HID_UP)) { | ||
| if (base) | ||
| base--; | ||
| else if (offset) | ||
| offset--; | ||
| dirty = true; | ||
| } | ||
| // alt-<up>: move a page up | ||
| else if (match_alt(m, k, HID_UP)) { | ||
| if (offset > 8) { offset -= 8; } | ||
| else { | ||
| offset = 0; | ||
| base = 0; | ||
| } | ||
| dirty = true; | ||
| } | ||
| // <left>: move left | ||
| else if (match_no_mod(m, k, HID_LEFT)) { | ||
| if (pattern > 0) pattern--; | ||
| dirty = true; | ||
| } | ||
| // alt-<left>: move to the very left | ||
| else if (match_alt(m, k, HID_LEFT)) { | ||
| base = 0; | ||
| offset = 0; | ||
| dirty = true; | ||
| } | ||
| // <right>: move right | ||
| else if (match_no_mod(m, k, HID_RIGHT)) { | ||
| if (pattern < 3) pattern++; | ||
| dirty = true; | ||
| } | ||
| // alt-<right>: move to the very right | ||
| else if (match_alt(m, k, HID_RIGHT)) { | ||
| base = 7; | ||
| offset = 56; | ||
| } | ||
| // [: decrement by 1 | ||
| else if (match_no_mod(m, k, HID_OPEN_BRACKET)) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| if (v > INT16_MIN) { // -32767 | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, v - 1); | ||
| dirty = true; | ||
| } | ||
| } | ||
| // ]: increment by 1 | ||
| else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| if (v < INT16_MAX) { // 32766 | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, v + 1); | ||
| dirty = true; | ||
| } | ||
| } | ||
| // <backspace>: delete a digit | ||
| else if (match_no_mod(m, k, HID_BACKSPACE)) { | ||
| int16_t v = | ||
| ss_get_pattern_val(&scene_state, pattern, base + offset) / 10; | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, v); | ||
| dirty = true; | ||
| } | ||
| // shift-<backspace>: delete an entry, shift numbers up | ||
| else if (match_shift(m, k, HID_BACKSPACE)) { | ||
| for (size_t i = base + offset; i < 63; i++) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, i + 1); | ||
| ss_set_pattern_val(&scene_state, pattern, i, v); | ||
| } | ||
|
|
||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (l > base + offset) ss_set_pattern_len(&scene_state, pattern, l - 1); | ||
| dirty = true; | ||
| } | ||
| // <enter>: move down (increase length only if on the entry immediately | ||
| // after the current length) | ||
| else if (match_no_mod(m, k, HID_ENTER)) { | ||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (base + offset == l && l < 64) | ||
| ss_set_pattern_len(&scene_state, pattern, l + 1); | ||
| base++; | ||
| if (base == 8) { | ||
| base = 7; | ||
| if (offset < 56) { offset++; } | ||
| } | ||
| dirty = true; | ||
| } | ||
| // shift-<enter>: duplicate entry and shift downwards (increase length only | ||
| // if on the entry immediately after the current length) | ||
| else if (match_shift(m, k, HID_ENTER)) { | ||
| for (int i = 63; i > base + offset; i--) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, i - 1); | ||
| ss_set_pattern_val(&scene_state, pattern, i, v); | ||
| } | ||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (base + offset == l && l < 64) { | ||
| ss_set_pattern_len(&scene_state, pattern, l + 1); | ||
| } | ||
| dirty = true; | ||
| } | ||
| // alt-x: cut value (n.b. ctrl-x not supported) | ||
| else if (match_alt(m, k, HID_X)) { | ||
| copy_buffer = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| for (int i = base + offset; i < 63; i++) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, i + 1); | ||
| ss_set_pattern_val(&scene_state, pattern, i, v); | ||
| } | ||
|
|
||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (l > base + offset) { | ||
| ss_set_pattern_len(&scene_state, pattern, l - 1); | ||
| } | ||
| dirty = true; | ||
| } | ||
| // alt-c: copy value (n.b. ctrl-c not supported) | ||
| else if (match_alt(m, k, HID_C)) { | ||
| copy_buffer = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| } | ||
| // alt-v: paste value (n.b. ctrl-v not supported) | ||
| else if (match_alt(m, k, HID_V)) { | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, copy_buffer); | ||
| dirty = true; | ||
| } | ||
| // shift-alt-v: insert value | ||
| else if (match_shift_alt(m, k, HID_V)) { | ||
| for (int i = 63; i > base + offset; i--) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, i - 1); | ||
| ss_set_pattern_val(&scene_state, pattern, i, v); | ||
| } | ||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (l >= base + offset && l < 63) { | ||
| ss_set_pattern_len(&scene_state, pattern, l + 1); | ||
| } | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, copy_buffer); | ||
| dirty = true; | ||
| } | ||
| // shift-l: set length to current position | ||
| else if (match_shift(m, k, HID_L)) { | ||
| ss_set_pattern_len(&scene_state, pattern, base + offset + 1); | ||
| dirty = true; | ||
| } | ||
| // alt-l: go to current length entry | ||
| else if (match_alt(m, k, HID_L)) { | ||
| uint16_t l = ss_get_pattern_len(&scene_state, pattern); | ||
| if (l) { | ||
| offset = ((l - 1) >> 3) << 3; | ||
| base = (l - 1) & 0x7; | ||
| int8_t delta = base - 3; | ||
| if ((offset + delta > 0) && (offset + delta < 56)) { | ||
| offset += delta; | ||
| base = 3; | ||
| } | ||
| } | ||
| else { | ||
| offset = 0; | ||
| base = 0; | ||
| } | ||
| dirty = true; | ||
| } | ||
| // shift-s: set start to current position | ||
| else if (match_shift(m, k, HID_S)) { | ||
| ss_set_pattern_start(&scene_state, pattern, offset + base); | ||
| dirty = true; | ||
| } | ||
| // alt-s: go to start entry | ||
| else if (match_alt(m, k, HID_S)) { | ||
| int16_t start = ss_get_pattern_start(&scene_state, pattern); | ||
| if (start) { | ||
| offset = (start >> 3) << 3; | ||
| base = start & 0x7; | ||
| int8_t delta = base - 3; | ||
| if ((offset + delta > 0) && (offset + delta < 56)) { | ||
| offset += delta; | ||
| base = 3; | ||
| } | ||
| } | ||
| else { | ||
| offset = 0; | ||
| base = 0; | ||
| } | ||
| dirty = true; | ||
| } | ||
| // shift-e: set end to current position | ||
| else if (match_shift(m, k, HID_E)) { | ||
| ss_set_pattern_end(&scene_state, pattern, offset + base); | ||
| dirty = true; | ||
| } | ||
| // alt-e: go to end entry | ||
| else if (match_alt(m, k, HID_E)) { | ||
| int16_t end = ss_get_pattern_end(&scene_state, pattern); | ||
| if (end) { | ||
| offset = (end >> 3) << 3; | ||
| base = end & 0x7; | ||
| int8_t delta = base - 3; | ||
| if ((offset + delta > 0) && (offset + delta < 56)) { | ||
| offset += delta; | ||
| base = 3; | ||
| } | ||
| } | ||
| else { | ||
| offset = 0; | ||
| base = 0; | ||
| } | ||
| dirty = true; | ||
| } | ||
| // -: negate value | ||
| else if (match_no_mod(m, k, HID_UNDERSCORE)) { | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, -v); | ||
| dirty = true; | ||
| } | ||
| // <space>: toggle non-zero to zero, and zero to 1 | ||
| else if (match_no_mod(m, k, HID_SPACEBAR)) { | ||
| if (ss_get_pattern_val(&scene_state, pattern, base + offset)) | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, 0); | ||
| else | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, 1); | ||
| dirty = true; | ||
| } | ||
| // 0-9: numeric entry | ||
| else if (no_mod(m) && k >= HID_1 && k <= HID_0) { | ||
| uint8_t n = (k - HID_1 + 1) % 10; // convert HID numbers to decimal, | ||
| // taking care of HID_0 | ||
| int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset); | ||
| if (v && v < 3276 && v > -3276) { | ||
| v = v * 10; | ||
| if (v > 0) | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, v + n); | ||
| else | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, v - n); | ||
| } | ||
| else | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, n); | ||
| dirty = true; | ||
| } | ||
| } | ||
|
|
||
| void process_pattern_knob(uint16_t knob, uint8_t m) { | ||
| if (mod_only_ctrl(m)) { | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, knob >> 7); | ||
| dirty = true; | ||
| } | ||
| else if (mod_only_shift_ctrl(m)) { | ||
| ss_set_pattern_val(&scene_state, pattern, base + offset, knob >> 2); | ||
| dirty = true; | ||
| } | ||
| } | ||
|
|
||
| bool screen_refresh_pattern() { | ||
| if (!dirty) { return false; } | ||
|
|
||
| char s[32]; | ||
| for (uint8_t y = 0; y < 8; y++) { | ||
| region_fill(&line[y], 0); | ||
| itoa(y + offset, s, 10); | ||
| font_string_region_clip_right(&line[y], s, 4, 0, 0x1, 0); | ||
|
|
||
| for (uint8_t x = 0; x < 4; x++) { | ||
| uint8_t a = 1; | ||
| if (ss_get_pattern_len(&scene_state, x) > y + offset) a = 6; | ||
|
|
||
| itoa(ss_get_pattern_val(&scene_state, x, y + offset), s, 10); | ||
| font_string_region_clip_right(&line[y], s, (x + 1) * 30 + 4, 0, a, | ||
| 0); | ||
|
|
||
| if (y + offset >= ss_get_pattern_start(&scene_state, x)) { | ||
| if (y + offset <= ss_get_pattern_end(&scene_state, x)) { | ||
| for (uint8_t i = 0; i < 8; i += 2) { | ||
| line[y].data[i * 128 + (x + 1) * 30 + 6] = 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (y + offset == ss_get_pattern_idx(&scene_state, x)) { | ||
| line[y].data[2 * 128 + (x + 1) * 30 + 6] = 11; | ||
| line[y].data[3 * 128 + (x + 1) * 30 + 6] = 11; | ||
| line[y].data[4 * 128 + (x + 1) * 30 + 6] = 11; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| itoa(ss_get_pattern_val(&scene_state, pattern, base + offset), s, 10); | ||
| font_string_region_clip_right(&line[base], s, (pattern + 1) * 30 + 4, 0, | ||
| 0xf, 0); | ||
|
|
||
| for (uint8_t y = 0; y < 64; y += 2) { | ||
| line[y >> 3].data[(y & 0x7) * 128 + 8] = 1; | ||
| } | ||
|
|
||
| for (uint8_t y = 0; y < 8; y++) { | ||
| line[(offset + y) >> 3].data[((offset + y) & 0x7) * 128 + 8] = 6; | ||
| } | ||
|
|
||
| dirty = false; | ||
|
|
||
| return true; | ||
| } |
| @@ -0,0 +1,12 @@ | ||
| #ifndef _PATTERN_MODE_H_ | ||
| #define _PATTERN_MODE_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| void set_pattern_mode(void); | ||
| void process_pattern_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| void process_pattern_knob(uint16_t knob, uint8_t mod_key); | ||
| bool screen_refresh_pattern(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,92 @@ | ||
| #include "preset_r_mode.h" | ||
|
|
||
| // this | ||
| #include "flash.h" | ||
| #include "globals.h" | ||
| #include "keyboard_helper.h" | ||
|
|
||
| // libavr32 | ||
| #include "font.h" | ||
| #include "region.h" | ||
| #include "util.h" | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| uint8_t offset; | ||
| uint8_t knob_last; | ||
| bool dirty; | ||
|
|
||
| void set_preset_r_mode(uint16_t knob) { | ||
| knob_last = knob >> 7; | ||
| offset = 0; | ||
| dirty = true; | ||
| } | ||
|
|
||
| void process_preset_r_knob(uint16_t knob, uint8_t mod_key) { | ||
| uint8_t knob_now = knob >> 7; | ||
| if (knob_now != knob_last) { | ||
| preset_select = knob_now; | ||
| knob_last = knob_now; | ||
| dirty = true; | ||
| } | ||
| } | ||
|
|
||
| void process_preset_r_keys(uint8_t k, uint8_t m, bool is_held_key) { | ||
| // <down> or C-n: line down | ||
| if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { | ||
| if (offset < SCENE_TEXT_LINES - 8) { | ||
| offset++; | ||
| dirty = true; | ||
| } | ||
| } | ||
| // <up> or C-p: line up | ||
| else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { | ||
| if (offset) { | ||
| offset--; | ||
| dirty = true; | ||
| } | ||
| } | ||
| // <left> or [: preset down | ||
| else if (match_no_mod(m, k, HID_LEFT) || | ||
| match_no_mod(m, k, HID_OPEN_BRACKET)) { | ||
| if (preset_select) preset_select--; | ||
| dirty = true; | ||
| } | ||
| // <right> or ]: preset up | ||
| else if (match_no_mod(m, k, HID_RIGHT) || | ||
| match_no_mod(m, k, HID_CLOSE_BRACKET)) { | ||
| if (preset_select < SCENE_SLOTS - 1) preset_select++; | ||
| dirty = true; | ||
| } | ||
| // <enter>: load preset | ||
| else if (match_no_mod(m, k, HID_ENTER) && !is_held_key) { | ||
| flash_read(preset_select); | ||
| ss_set_scene(&scene_state, preset_select); | ||
|
|
||
| run_script(&scene_state, INIT_SCRIPT); | ||
|
|
||
| set_last_mode(); | ||
| } | ||
| } | ||
|
|
||
| bool screen_refresh_preset_r() { | ||
| if (!dirty) { return false; } | ||
|
|
||
| char s[32]; | ||
| itoa(preset_select, s, 10); | ||
| region_fill(&line[0], 1); | ||
| font_string_region_clip_right(&line[0], s, 126, 0, 0xf, 1); | ||
| font_string_region_clip(&line[0], f.s[preset_select].text[0], 2, 0, 0xf, 1); | ||
|
|
||
|
|
||
| for (uint8_t y = 1; y < 8; y++) { | ||
| region_fill(&line[y], 0); | ||
| font_string_region_clip(&line[y], f.s[preset_select].text[offset + y], | ||
| 2, 0, 0xa, 0); | ||
| } | ||
|
|
||
| dirty = false; | ||
| return true; | ||
| }; |
| @@ -0,0 +1,12 @@ | ||
| #ifndef _PRESET_R_MODE_H_ | ||
| #define _PRESET_R_MODE_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| void set_preset_r_mode(uint16_t knob); | ||
| void process_preset_r_knob(uint16_t knob, uint8_t mod_key); | ||
| void process_preset_r_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| bool screen_refresh_preset_r(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,125 @@ | ||
| #include "preset_w_mode.h" | ||
|
|
||
| #include <string.h> | ||
|
|
||
| // this | ||
| #include "flash.h" | ||
| #include "globals.h" | ||
| #include "keyboard_helper.h" | ||
| #include "line_editor.h" | ||
|
|
||
| // libavr32 | ||
| #include "font.h" | ||
| #include "kbd.h" | ||
| #include "region.h" | ||
| #include "util.h" | ||
|
|
||
| // asf | ||
| #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" | ||
| #include "usb_protocol_hid.h" | ||
|
|
||
| uint8_t edit_line; | ||
| uint8_t edit_offset; | ||
| line_editor_t le; | ||
|
|
||
| static const uint8_t D_INPUT = 1 << 0; | ||
| static const uint8_t D_LIST = 1 << 1; | ||
| static const uint8_t D_ALL = 0xFF; | ||
| uint8_t dirty; | ||
|
|
||
| void set_preset_w_mode() { | ||
| edit_line = 0; | ||
| edit_offset = 0; | ||
| line_editor_set(&le, scene_text[0]); | ||
| dirty = D_ALL; | ||
| } | ||
|
|
||
| void process_preset_w_keys(uint8_t k, uint8_t m, bool is_held_key) { | ||
| // <down> or C-n: line down | ||
| if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { | ||
| if ((edit_offset + edit_line) < 31) { | ||
| if (edit_line == 5) | ||
| edit_offset++; | ||
| else | ||
| edit_line++; | ||
| line_editor_set(&le, scene_text[edit_line + edit_offset]); | ||
| dirty |= D_LIST; | ||
| dirty |= D_INPUT; | ||
| } | ||
| } | ||
| // <up> or C-p: line up | ||
| else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { | ||
| if (edit_line + edit_offset) { | ||
| if (edit_line) | ||
| edit_line--; | ||
| else | ||
| edit_offset--; | ||
| line_editor_set(&le, scene_text[edit_line + edit_offset]); | ||
| dirty |= D_LIST; | ||
| dirty |= D_INPUT; | ||
| } | ||
| } | ||
| // [: preset down | ||
| else if (match_no_mod(m, k, HID_OPEN_BRACKET)) { | ||
| if (preset_select) preset_select--; | ||
| dirty |= D_LIST; | ||
| } | ||
| // ]: preset up | ||
| else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) { | ||
| if (preset_select < SCENE_SLOTS - 1) preset_select++; | ||
| dirty |= D_LIST; | ||
| } | ||
| // <enter>: enter text | ||
| else if (match_no_mod(m, k, HID_ENTER)) { | ||
| strcpy(scene_text[edit_line + edit_offset], line_editor_get(&le)); | ||
| if (edit_line + edit_offset < 31) { | ||
| if (edit_line == 5) | ||
| edit_offset++; | ||
| else | ||
| edit_line++; | ||
| } | ||
| line_editor_set(&le, scene_text[edit_line + edit_offset]); | ||
| dirty |= D_LIST; | ||
| dirty |= D_INPUT; | ||
| } | ||
| // alt-<enter>: save preset | ||
| else if (match_alt(m, k, HID_ENTER)) { | ||
| if (!is_held_key) { | ||
| strcpy(scene_text[edit_line + edit_offset], line_editor_get(&le)); | ||
| flash_write(preset_select); | ||
| set_last_mode(); | ||
| } | ||
| } | ||
| else { // pass to line editor | ||
| bool processed = line_editor_process_keys(&le, k, m, is_held_key); | ||
| if (processed) dirty |= D_INPUT; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| bool screen_refresh_preset_w() { | ||
| if (!(dirty & D_ALL)) { return false; } | ||
|
|
||
| if (dirty & D_LIST) { | ||
| char header[6] = ">>> "; | ||
| itoa(preset_select, header + 4, 10); | ||
| region_fill(&line[0], 1); | ||
| font_string_region_clip_right(&line[0], header, 126, 0, 0xf, 1); | ||
| font_string_region_clip(&line[0], "WRITE", 2, 0, 0xf, 1); | ||
|
|
||
| for (uint8_t y = 1; y < 7; y++) { | ||
| uint8_t a = edit_line == (y - 1); | ||
| region_fill(&line[y], a); | ||
| font_string_region_clip(&line[y], scene_text[edit_offset + y - 1], | ||
| 2, 0, 0xa + a * 5, a); | ||
| } | ||
| dirty &= ~D_LIST; | ||
| } | ||
|
|
||
| if (dirty & D_INPUT) { | ||
| line_editor_draw(&le, '+', &line[7]); | ||
| dirty &= ~D_INPUT; | ||
| } | ||
|
|
||
| return true; | ||
| } |
| @@ -0,0 +1,11 @@ | ||
| #ifndef _PRESET_W_MODE_H_ | ||
| #define _PRESET_W_MODE_H_ | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| void set_preset_w_mode(void); | ||
| void process_preset_w_keys(uint8_t key, uint8_t mod_key, bool is_held_key); | ||
| bool screen_refresh_preset_w(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,6 @@ | ||
| #ifndef _USB_DISK_MODE_H_ | ||
| #define _USB_DISK_MODE_H_ | ||
|
|
||
| void tele_usb_disk(void); | ||
|
|
||
| #endif |
| @@ -0,0 +1,13 @@ | ||
| #include "earthsea.h" | ||
|
|
||
| #include "ii.h" | ||
|
|
||
| const tele_op_t op_ES_PRESET = MAKE_SIMPLE_I2C_OP(ES.PRESET, ES_PRESET); | ||
| const tele_op_t op_ES_MODE = MAKE_SIMPLE_I2C_OP(ES.MODE, ES_MODE); | ||
| const tele_op_t op_ES_CLOCK = MAKE_SIMPLE_I2C_OP(ES.CLOCK, ES_CLOCK); | ||
| const tele_op_t op_ES_RESET = MAKE_SIMPLE_I2C_OP(ES.RESET, ES_RESET); | ||
| const tele_op_t op_ES_PATTERN = MAKE_SIMPLE_I2C_OP(ES.PATTERN, ES_PATTERN); | ||
| const tele_op_t op_ES_TRANS = MAKE_SIMPLE_I2C_OP(ES.TRANS, ES_TRANS); | ||
| const tele_op_t op_ES_STOP = MAKE_SIMPLE_I2C_OP(ES.STOP, ES_STOP); | ||
| const tele_op_t op_ES_TRIPLE = MAKE_SIMPLE_I2C_OP(ES.TRIPLE, ES_TRIPLE); | ||
| const tele_op_t op_ES_MAGIC = MAKE_SIMPLE_I2C_OP(ES.MAGIC, ES_MAGIC); |
| @@ -0,0 +1,16 @@ | ||
| #ifndef _OPS_EARTHSEA_H_ | ||
| #define _OPS_EARTHSEA_H_ | ||
|
|
||
| #include "ops/op.h" | ||
|
|
||
| extern const tele_op_t op_ES_PRESET; | ||
| extern const tele_op_t op_ES_MODE; | ||
| extern const tele_op_t op_ES_CLOCK; | ||
| extern const tele_op_t op_ES_RESET; | ||
| extern const tele_op_t op_ES_PATTERN; | ||
| extern const tele_op_t op_ES_TRANS; | ||
| extern const tele_op_t op_ES_STOP; | ||
| extern const tele_op_t op_ES_TRIPLE; | ||
| extern const tele_op_t op_ES_MAGIC; | ||
|
|
||
| #endif |
| @@ -0,0 +1,12 @@ | ||
| #include "meadowphysics.h" | ||
|
|
||
| #include "ii.h" | ||
|
|
||
| const tele_op_t op_MP_PRESET = MAKE_SIMPLE_I2C_OP(MP.PRESET, MP_PRESET); | ||
| const tele_op_t op_MP_RESET = MAKE_SIMPLE_I2C_OP(MP.RESET, MP_RESET); | ||
| const tele_op_t op_MP_SYNC = MAKE_SIMPLE_I2C_OP(MP.SYNC, MP_SYNC); | ||
| const tele_op_t op_MP_MUTE = MAKE_SIMPLE_I2C_OP(MP.MUTE, MP_MUTE); | ||
| const tele_op_t op_MP_UNMUTE = MAKE_SIMPLE_I2C_OP(MP.UNMUTE, MP_UNMUTE); | ||
| const tele_op_t op_MP_FREEZE = MAKE_SIMPLE_I2C_OP(MP.FREEZE, MP_FREEZE); | ||
| const tele_op_t op_MP_UNFREEZE = MAKE_SIMPLE_I2C_OP(MP.UNFREEZE, MP_UNFREEZE); | ||
| const tele_op_t op_MP_STOP = MAKE_SIMPLE_I2C_OP(MP.STOP, MP_STOP); |
| @@ -0,0 +1,15 @@ | ||
| #ifndef _OPS_MEADOWPHYSICS_H_ | ||
| #define _OPS_MEADOWPHYSICS_H_ | ||
|
|
||
| #include "ops/op.h" | ||
|
|
||
| extern const tele_op_t op_MP_PRESET; | ||
| extern const tele_op_t op_MP_RESET; | ||
| extern const tele_op_t op_MP_SYNC; | ||
| extern const tele_op_t op_MP_MUTE; | ||
| extern const tele_op_t op_MP_UNMUTE; | ||
| extern const tele_op_t op_MP_FREEZE; | ||
| extern const tele_op_t op_MP_UNFREEZE; | ||
| extern const tele_op_t op_MP_STOP; | ||
|
|
||
| #endif |
| @@ -0,0 +1,20 @@ | ||
| #include "orca.h" | ||
|
|
||
| #include "ii.h" | ||
|
|
||
| const tele_op_t op_OR_TRK = MAKE_SIMPLE_I2C_OP(OR.TRK, ORCA_TRACK); | ||
| const tele_op_t op_OR_CLK = MAKE_SIMPLE_I2C_OP(OR.CLK, ORCA_CLOCK); | ||
| const tele_op_t op_OR_DIV = MAKE_SIMPLE_I2C_OP(OR.DIV, ORCA_DIVISOR); | ||
| const tele_op_t op_OR_PHASE = MAKE_SIMPLE_I2C_OP(OR.PHASE, ORCA_PHASE); | ||
| const tele_op_t op_OR_RST = MAKE_SIMPLE_I2C_OP(OR.RST, ORCA_RESET); | ||
| const tele_op_t op_OR_WGT = MAKE_SIMPLE_I2C_OP(OR.WGT, ORCA_WEIGHT); | ||
| const tele_op_t op_OR_MUTE = MAKE_SIMPLE_I2C_OP(OR.MUTE, ORCA_MUTE); | ||
| const tele_op_t op_OR_SCALE = MAKE_SIMPLE_I2C_OP(OR.SCALE, ORCA_SCALE); | ||
| const tele_op_t op_OR_BANK = MAKE_SIMPLE_I2C_OP(OR.BANK, ORCA_BANK); | ||
| const tele_op_t op_OR_PRESET = MAKE_SIMPLE_I2C_OP(OR.PRESET, ORCA_PRESET); | ||
| const tele_op_t op_OR_RELOAD = MAKE_SIMPLE_I2C_OP(OR.RELOAD, ORCA_RELOAD); | ||
| const tele_op_t op_OR_ROTS = MAKE_SIMPLE_I2C_OP(OR.ROTS, ORCA_ROTATES); | ||
| const tele_op_t op_OR_ROTW = MAKE_SIMPLE_I2C_OP(OR.ROTW, ORCA_ROTATEW); | ||
| const tele_op_t op_OR_GRST = MAKE_SIMPLE_I2C_OP(OR.GRST, ORCA_GRESET); | ||
| const tele_op_t op_OR_CVA = MAKE_SIMPLE_I2C_OP(OR.CVA, ORCA_CVA); | ||
| const tele_op_t op_OR_CVB = MAKE_SIMPLE_I2C_OP(OR.CVB, ORCA_CVB); |
| @@ -0,0 +1,23 @@ | ||
| #ifndef _OPS_ORCA_H_ | ||
| #define _OPS_ORCA_H_ | ||
|
|
||
| #include "ops/op.h" | ||
|
|
||
| extern const tele_op_t op_OR_TRK; | ||
| extern const tele_op_t op_OR_CLK; | ||
| extern const tele_op_t op_OR_DIV; | ||
| extern const tele_op_t op_OR_PHASE; | ||
| extern const tele_op_t op_OR_RST; | ||
| extern const tele_op_t op_OR_WGT; | ||
| extern const tele_op_t op_OR_MUTE; | ||
| extern const tele_op_t op_OR_SCALE; | ||
| extern const tele_op_t op_OR_BANK; | ||
| extern const tele_op_t op_OR_PRESET; | ||
| extern const tele_op_t op_OR_RELOAD; | ||
| extern const tele_op_t op_OR_ROTS; | ||
| extern const tele_op_t op_OR_ROTW; | ||
| extern const tele_op_t op_OR_GRST; | ||
| extern const tele_op_t op_OR_CVA; | ||
| extern const tele_op_t op_OR_CVB; | ||
|
|
||
| #endif |