diff --git a/.editorconfig b/.editorconfig index 8f9b90fa..e2ba9e79 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,8 +15,8 @@ indent_style = tab indent_size = 8 trim_trailing_whitespace = true -# C & Cpp -[*.{h,hpp,c,cpp}] +# C & Cpp & Ragel +[*.{h,hpp,c,cpp,rl}] indent_style = space indent_size = 4 trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index fd3dfb5c..35d6daaf 100644 --- a/.gitignore +++ b/.gitignore @@ -42,5 +42,8 @@ *.dSYM/ # Build outputs +/src/match_token.c +/src/scanner.c /simulator/tt +/module/gitversion.c /tests/tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 676db1fa..606ba6b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,23 @@ # Changelog ## vNext +- **BREAKING**: remove `II` op. Ops that required it will now work with out it. (e.g. `II MP.PRESET 1` will become just `MP.PRESET 1`) +- **BREAKING**: merge the `MUTE` and `UNMUTE` ops. Now `MUTE x` will return the mute status for trigger `x` (`0` is unmuted, `1` is muted), and `MUTE x y` will set the mute for trigger `x` (`y = 0` to unmute, `y = 1` to mute) +- **NEW**: sub commands, use a `;` separator to run multiple commands on a single line, e.g. `X 1; Y 2` +- **NEW**: key bindings rewritten, see [docs](./docs/modes.md) +- **NEW**: multiple commands on each line separated by ':' +- **NEW**: aliases: `+` for `ADD`, `-` for `SUB`, `*` for `MUL`, `/` for `DIV`, `%` for `MOD`, `<<` for `LSH`, `>>` for `RSH`, `==` for `EQ`, `!=` for `NE`, `<` for `LT`, `>` for `GT`, `<=` for `LTE`, `>=` for `GTE`, `!` for `EZ`, `&&` for `AND`, `||` for `OR`, `PRM` for `PARAM`, `TR.P` for `TR.PULSE` +- **NEW**: new ops: `LTE` (less than or equal), and `GTE` (greater than or equal) +- **NEW**: new pattern ops: `PN.L`, `PN.WRAP`, `PN.START`, `PN.END`, `PN.I`, `PN.HERE`, `PN.NEXT`, `PN.PREV`, `PN.INS`, `PN.RM`, `PN.PUSH` and `PN.POP` +- **NEW**: USB disk loading and saving works at any time +- **IMP**: new Ragel parser backend +- **IMP**: script recursion enhanced, maximum recursion depth is 8, and self recursion is allowed +- **IMP**: removed the need to prefix `:` and `;` with a space, e.g. `IF X : TR.PULSE 1` becomes `IF X: TR.PULSE` +- **FIX**: divide by zero errors now explicitly return a 0 (e.g. `DIV 5 0` now returns 0 instead of -1), previously the behaviour was undefined and would crash the simulator +- **FIX**: numerous crashing bugs with text entry +- **FIX**: `i2c` bus crashes under high `M` times with external triggers +- **NEW**: TELEX Aliases: `TO.TR.P` for `TO.TR.PULSE` (plus all sub-commands) and `TI.PRM` for `TI.PARAM` (plus all sub-commands) +- **NEW**: TELEX initialization commands: `TO.TR.INIT n`, `TO.CV.INIT n`, `TO.INIT x`, `TI.PARAM.INIT n`, `TI.IN.INIT n`, and `TI.INIT x` ## v1.41 - **NEW**: added Ansible remote commands `LV.CV` and `CY.CV` @@ -13,7 +30,7 @@ - **NEW**: [Full List of Methods Found and Maintained Here](https://github.com/bpcmusic/telex/blob/master/commands.md) ## v1.21 -- **NEW**: Just Friends ops: `JF.GOD`, `JF.MODE`, `JF.NOTE`, `JF.RMODE`, `JF.RUN`, `JF.SHIFT`, `JF.TICK`, `JF.TR`, `JF.VOX`, `JF.VTR` +- **NEW**: Just Friends ops: `JF.GOD`, `JF.MODE`, `JF.NOTE`, `JF.RMODE`, `JF.RUN`, `JF.SHIFT`, `JF.TICK`, `JF.TR`, `JF.TUNE`, `JF.VOX`, `JF.VTR` ## v1.2 - **NEW**: Ansible support added to ops: `CV`, `CV.OFF`, `CV.SET`, `CV.SLEW`, `STATE`, `TR`, `TR.POL`, `TR.PULSE`, `TR.TIME`, `TR.TOG` diff --git a/README.md b/README.md index 61b6ee71..a515e113 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ http://monome.org/docs/modular/teletype ## Building -See the [libavr32 repo](https://github.com/monome/libavr32) for more detailed instructions. +See the [libavr32 repo][libavr32] for more detailed instructions. You will also need `ragel` installed and on the path, see below. **Make sure that the `libavr32` submodule is correctly checked out** @@ -26,6 +26,43 @@ make ./flash.sh ``` +## Tests + +To run the tests: + +```bash +cd tests +make clean # only needed if you've built the module code +make test +``` + +## Ragel + +The [Ragel state machine compiler][ragel] is required to build the firmware. It needs to be installed and on the path: + +```bash +brew install ragel # Homebrew (OSX) +apt install ragel # Debian / Ubuntu / WSL (Windows 10) +pacman -Sy ragel # Arch Linux / MSYS2 (Windows) +``` + +Version 6.9 is known to work. + +See section 6.3 in the Ragel manual for information on the `=>` scanner constructor used. + +## Adding a new `OP` or `MOD` (a.k.a. `PRE`) + +If you want to add a new `OP` or `MOD`, please create the relevant `tele_op_t` or `tele_mod_t` in the `src/ops` directory. You will then need to reference it in the following places: + +- `src/ops/op.c`: add a reference to your struct to the relevant table, `tele_ops` or `tele_mods`. Ideally grouped with other ops from the same file. +- `src/ops/op_enum.h`: please run `utils/op_enums.py` to generate this file using Python3. +- `src/match_token.rl`: add an entry to the Ragel list to match the token to the struct. Again, please try to keep the order in the list sensible. + +There is a test that checks to see if the above have all been entered correctly. (See above to run tests.) + ## Code Formatting To format the code using `clang-format`, run `make format` in the project's root directory. This *shouldn't* format any code in the `libavr32` submodule. + +[libavr32]: https://github.com/monome/libavr32 +[ragel]: http://www.colm.net/open-source/ragel/ diff --git a/docs/modes.md b/docs/modes.md new file mode 100644 index 00000000..ac3e7e55 --- /dev/null +++ b/docs/modes.md @@ -0,0 +1,124 @@ + +## Global key bindings + +These bindings work everywhere. + +| Key | Action | +|------------------------------|------------------------------------------------| +| `` | change modes, live to edit to pattern and back | +| `` | preset read mode, or return to last mode | +| `alt-` | preset write mode | +| `win-` | clear delays, stack and slews | +| `` | help text, or return to last mode | +| `` to `` | run corresponding script | +| `` | run metro script | +| `` | run init script | +| `alt-` to `alt-` | edit corresponding script | +| `alt-` | edit metro script | +| `alt-` | edit init script | +| `` to `` | run corresponding script | + +## Text editing + +These bindings work when entering text or code. + +In most cases, the clipboard is shared between _live_, _edit_ and the 2 _preset_ modes. + +| Key | Action | +|--------------------------------|-----------------------------------------| +| `` / `ctrl-b` | move cursor left | +| `` / `ctrl-f` | move cursor right | +| `` / `ctrl-a` | move to beginning of line | +| `` / `ctrl-e` | move to end of line | +| `` / `ctrl-h` | backwards delete one character | +| `` / `ctrl-d` | forwards delete one character | +| `shift-` / `ctrl-u` | delete from cursor to beginning | +| `shift-` / `ctrl-e` | delete from cursor to end | +| `alt-` / `ctrl-w` | delete from cursor to beginning of word | +| `ctrl-x` / `alt-x` | cut to clipboard | +| `ctrl-c` / `alt-c` | copy to clipboard | +| `ctrl-v` / `alt-v` | paste to clipboard | + +## Live mode + +| Key | Action | +|------------------|---------------------| +| `` / `C-n` | history next | +| `` / `C-p` | history previous | +| `` | execute command | +| `[` / `]` | switch to edit mode | + +## Edit mode + +| Key | Action | +|--------------------|---------------------------| +| `` / `C-n` | line down | +| `` / `C-p` | line up | +| `[` | previous script | +| `]` | next script | +| `` | enter command | +| `shift-` | insert command | + +## Pattern mode + +The pattern mode clipboard is independent of text and code clipboard. + +| Key | Action | +|---------------------|---------------------------------------------------------------------------------------| +| `` | move down | +| `alt-` | move a page down | +| `` | move up | +| `alt-` | move a page up | +| `` | move left | +| `alt-` | move to the very left | +| `` | move right | +| `alt-` | move to the very right | +| `[` | decrement by 1 | +| `]` | increment by 1 | +| `` | delete a digit | +| `shift-` | delete an entry, shift numbers up | +| `` | move down (increase length only if on the entry immediately after the current length) | +| `shift-` | duplicate entry and shift downwards (increase length as ``) | +| `alt-x` | cut value (n.b. `ctrl-x` not supported) | +| `alt-c` | copy value (n.b. `ctrl-c` not supported) | +| `alt-v` | paste value (n.b. `ctrl-v` not supported) | +| `shift-alt-v` | insert value | +| `shift-l` | set length to current position | +| `alt-l` | go to current length entry | +| `shift-s` | set start to current position | +| `alt-s` | go to start entry | +| `shift-e` | set end to current position | +| `alt-e` | go to end entry | +| `-` | negate value | +| `` | toggle non-zero to zero, and zero to 1 | +| `0` to `9` | numeric entry | + +## Preset read mode + +| Key | Action | +|------------------|-------------| +| `` / `C-n` | line down | +| `` / `C-p` | line up | +| `` / `[` | preset down | +| `` / `]` | preset up | +| `` | load preset | + +## Preset write mode + +| Key | Action | +|------------------|-------------| +| `` / `C-n` | line down | +| `` / `C-p` | line up | +| `[` | preset down | +| `]` | preset up | +| `` | enter text | +| `alt-` | save preset | + +## Help mode + +| Key | Action | +|------------------|---------------| +| `` / `C-n` | line down | +| `` / `C-p` | line up | +| `` / `[` | previous page | +| `` / `]` | next page | diff --git a/libavr32 b/libavr32 index 4ee26221..85fdd92d 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit 4ee262216650bf2cf4914873df19cb21f5d12151 +Subproject commit 85fdd92df761dd95e34c89b2644267c927d180ab diff --git a/module/Makefile b/module/Makefile index 909ffc6e..5e8b18b3 100644 --- a/module/Makefile +++ b/module/Makefile @@ -60,7 +60,29 @@ # \asf_license_stop # +# Makefile.avr32.in defines an unused variable build, which is used in the clean +# target, it's probably there to list other build targets +build += ../src/scanner.c ../src/match_token.c ../module/gitversion.c + # Include the common Makefile, which will also include the project specific # config.mk file. MAKEFILE_PATH = ../libavr32/asf/avr32/utils/make/Makefile.avr32.in include $(MAKEFILE_PATH) + +# Add a rule to build match_token.c from match_token.rl +../src/match_token.c: ../src/match_token.rl + ragel -C -G2 ../src/match_token.rl -o ../src/match_token.c + +# Add a rule to build scanner.c from scanner.rl +../src/scanner.c: ../src/scanner.rl + ragel -C -G2 ../src/scanner.rl -o ../src/scanner.c + +# Add the git commit id to a file for use when printing out the version +../module/gitversion.c: ../.git/HEAD ../.git/index + echo "const char *git_version = \"$(shell git describe --always --dirty | tr '[a-z]' '[A-Z]')\";" > $@ + +# Make a zip release +.PHONY: release +release: teletype.hex + rm -f teletype.zip && \ + zip teletype.zip teletype.hex flash.sh update_firmware.command diff --git a/module/config.mk b/module/config.mk index d696612c..7cae0d93 100644 --- a/module/config.mk +++ b/module/config.mk @@ -61,28 +61,45 @@ TARGET = $(THIS).elf # List of C source files. CSRCS = \ - ../module/main.c \ + ../module/main.c \ + ../module/edit_mode.c \ + ../module/flash.c \ + ../module/gitversion.c \ + ../module/help_mode.c \ + ../module/line_editor.c \ + ../module/live_mode.c \ + ../module/pattern_mode.c \ + ../module/preset_r_mode.c \ + ../module/preset_w_mode.c \ + ../module/usb_disk_mode.c \ ../src/command.c \ ../src/helpers.c \ + ../src/match_token.c \ + ../src/scanner.c \ ../src/state.c \ ../src/table.c \ ../src/teletype.c \ ../src/ops/op.c \ - ../src/ops/constants.c \ + ../src/ops/ansible.c \ ../src/ops/controlflow.c \ ../src/ops/delay.c \ + ../src/ops/earthsea.c \ ../src/ops/hardware.c \ + ../src/ops/justfriends.c \ ../src/ops/maths.c \ + ../src/ops/meadowphysics.c \ ../src/ops/metronome.c \ + ../src/ops/orca.c \ ../src/ops/patterns.c \ ../src/ops/queue.c \ ../src/ops/stack.c \ ../src/ops/telex.c \ ../src/ops/variables.c \ + ../src/ops/whitewhale.c \ ../libavr32/src/adc.c \ ../libavr32/src/events.c \ - ../libavr32/src/euclidean/euclidean.c \ - ../libavr32/src/euclidean/data.c \ + ../libavr32/src/euclidean/euclidean.c \ + ../libavr32/src/euclidean/data.c \ ../libavr32/src/fix.c \ ../libavr32/src/font.c \ ../libavr32/src/i2c.c \ @@ -100,6 +117,7 @@ CSRCS = \ ../libavr32/src/usb/hid/uhi_hid.c \ ../libavr32/src/usb/midi/uhi_midi.c \ ../libavr32/src/usb/midi/midi.c \ + ../libavr32/src/usb/msc/msc.c \ avr32/drivers/adc/adc.c \ avr32/drivers/flashc/flashc.c \ avr32/drivers/gpio/gpio.c \ @@ -137,6 +155,7 @@ INC_PATH = \ ../src/usb/ftdi \ ../src/usb/hid \ ../src/usb/midi \ + ../src/usb/msc \ ../conf \ ../conf/teletype \ avr32/boards \ @@ -193,7 +212,7 @@ ARFLAGS = ASFLAGS = # Extra flags to use when compiling. -CFLAGS = -fshort-enums +CFLAGS = -fshort-enums -fno-common # Extra flags to use when preprocessing. # diff --git a/module/edit_mode.c b/module/edit_mode.c new file mode 100644 index 00000000..2fd2a5c2 --- /dev/null +++ b/module/edit_mode.c @@ -0,0 +1,226 @@ +#include "edit_mode.h" + +#include + +// 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" + +static line_editor_t le; +static uint8_t line_no; +static uint8_t script; +static error_t status; +static char error_msg[TELE_ERROR_MSG_LENGTH]; + +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; +static uint8_t dirty; + +void set_edit_mode() { + status = E_OK; + error_msg[0] = 0; + line_no = 0; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty = D_ALL; +} + +void set_edit_mode_script(uint8_t new_script) { + script = new_script; + if (script >= SCRIPT_COUNT) script = SCRIPT_COUNT - 1; +} + +void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { + // or C-n: line down + if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { + if (line_no < (SCRIPT_MAX_COMMANDS - 1) && + line_no < ss_get_script_len(&scene_state, script)) { + line_no++; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + } + // or C-p: line up + else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { + if (line_no) { + line_no--; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + } + // [: previous script + else if (match_no_mod(m, k, HID_OPEN_BRACKET)) { + status = E_OK; + error_msg[0] = 0; + if (script) + script--; + else + script = SCRIPT_COUNT - 1; + if (line_no > ss_get_script_len(&scene_state, script)) + line_no = ss_get_script_len(&scene_state, script); + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + // ]: next script + else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) { + status = E_OK; + error_msg[0] = 0; + script++; + if (script >= SCRIPT_COUNT) script = 0; + if (line_no > ss_get_script_len(&scene_state, script)) + line_no = ss_get_script_len(&scene_state, script); + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + // ctrl-x or alt-x: override line editors cut + else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) { + line_editor_set_copy_buffer(line_editor_get(&le)); + ss_delete_script_command(&scene_state, script, line_no); + if (line_no > ss_get_script_len(&scene_state, script)) { + line_no = ss_get_script_len(&scene_state, script); + } + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + + dirty |= D_LIST; + dirty |= D_INPUT; + } + // : enter command + else if (match_no_mod(m, k, HID_ENTER)) { + dirty |= D_MESSAGE; // something will happen + + tele_command_t command; + status = parse(line_editor_get(&le), &command, error_msg); + + if (status != E_OK) + return; // quit, screen_refresh_edit will display the error message + + status = validate(&command, error_msg); + if (status != E_OK) + return; // quit, screen_refresh_edit will display the error message + + if (command.length == 0) { // blank line, delete the command + ss_delete_script_command(&scene_state, script, line_no); + if (line_no > ss_get_script_len(&scene_state, script)) { + line_no = ss_get_script_len(&scene_state, script); + } + } + else { + ss_overwrite_script_command(&scene_state, script, line_no, + &command); + if (line_no < SCRIPT_MAX_COMMANDS - 1) { line_no++; } + } + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + // shift-: insert command + else if (match_shift(m, k, HID_ENTER)) { + dirty |= D_MESSAGE; // something will happen + + tele_command_t command; + status = parse(line_editor_get(&le), &command, error_msg); + + if (status != E_OK) + return; // quit, screen_refresh_edit will display the error message + + status = validate(&command, error_msg); + if (status != E_OK) + return; // quit, screen_refresh_edit will display the error message + + if (command.length > 0) { + ss_insert_script_command(&scene_state, script, line_no, &command); + if (line_no < (SCRIPT_MAX_COMMANDS - 1)) { line_no++; } + } + + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no)); + dirty |= D_LIST; + dirty |= D_INPUT; + } + 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_edit() { + bool screen_dirty = false; + + if (dirty & D_INPUT) { + char prefix = script + '1'; + if (script == METRO_SCRIPT) + prefix = 'M'; + else if (script == INIT_SCRIPT) + prefix = 'I'; + + line_editor_draw(&le, prefix, &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]) { + size_t len = strlen(s); + strcat(s, ": "); + strncat(s, error_msg, 32 - len - 3); + error_msg[0] = 0; + } + status = E_OK; + } + 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++) { + uint8_t a = line_no == i; + region_fill(&line[i], a); + if (ss_get_script_len(&scene_state, script) > i) { + char s[32]; + print_command(ss_get_script_command(&scene_state, script, i), + s); + region_string(&line[i], s, 2, 0, 0xf, a, 0); + } + } + + screen_dirty = true; + dirty &= ~D_LIST; + } + + return screen_dirty; +} diff --git a/module/edit_mode.h b/module/edit_mode.h new file mode 100644 index 00000000..f7c3fadd --- /dev/null +++ b/module/edit_mode.h @@ -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 diff --git a/module/flash.c b/module/flash.c new file mode 100644 index 00000000..80dece6d --- /dev/null +++ b/module/flash.c @@ -0,0 +1,78 @@ +#include "flash.h" + +#include + +// asf +#include "flashc.h" +#include "print_funcs.h" + +// this +#include "teletype.h" + +#define FIRSTRUN_KEY 0x22 + +// NVRAM data structure located in the flash array. +typedef const struct { + scene_script_t scripts[SCRIPT_COUNT]; + scene_pattern_t patterns[PATTERN_COUNT]; + char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; +} nvram_scene_t; + +typedef const struct { + nvram_scene_t scenes[SCENE_SLOTS]; + uint8_t last_scene; + uint8_t fresh; +} nvram_data_t; + +static __attribute__((__section__(".flash_nvram"))) nvram_data_t f; + +void flash_prepare() { + // if it's not empty return + if (f.fresh == FIRSTRUN_KEY) return; + + print_dbg("\r\n:::: first run, clearing flash"); + print_dbg("\r\nflash size: "); + print_dbg_ulong(sizeof(f)); + + // blank scene to write to flash + scene_state_t scene; + ss_init(&scene); + + char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; + memset(text, 0, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); + + for (uint8_t i = 0; i < SCENE_SLOTS; i++) { flash_write(i, &scene, &text); } + preset_select = 0; + flashc_memset8((void *)&f.last_scene, preset_select, 1, true); + flashc_memset8((void *)&f.fresh, FIRSTRUN_KEY, 1, true); +} + +void flash_write(uint8_t preset_no, scene_state_t *scene, + char (*text)[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]) { + flashc_memcpy((void *)&f.scenes[preset_no].scripts, ss_scripts_ptr(scene), + ss_scripts_size(), true); + flashc_memcpy((void *)&f.scenes[preset_no].patterns, ss_patterns_ptr(scene), + ss_patterns_size(), true); + flashc_memcpy((void *)&f.scenes[preset_no].text, text, + SCENE_TEXT_LINES * SCENE_TEXT_CHARS, true); + flashc_memset8((void *)&(f.last_scene), preset_no, 1, true); +} + +void flash_read(uint8_t preset_no, scene_state_t *scene, + char (*text)[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]) { + memcpy(ss_scripts_ptr(scene), &f.scenes[preset_no].scripts, + ss_scripts_size()); + memcpy(ss_patterns_ptr(scene), &f.scenes[preset_no].patterns, + ss_patterns_size()); + memcpy(text, &f.scenes[preset_no].text, + SCENE_TEXT_LINES * SCENE_TEXT_CHARS); + flashc_memset8((void *)&f.last_scene, preset_no, 1, true); +} + +uint8_t flash_last_saved_scene() { + return f.last_scene; +} + +const char *flash_scene_text(uint8_t preset_no, size_t line) { + return f.scenes[preset_no].text[line]; +} diff --git a/module/flash.h b/module/flash.h new file mode 100644 index 00000000..17d3e0fc --- /dev/null +++ b/module/flash.h @@ -0,0 +1,20 @@ +#ifndef _FLASH_H_ +#define _FLASH_H_ + +#include + +#include "globals.h" +#include "line_editor.h" +#include "teletype.h" + +#define SCENE_SLOTS 32 + +void flash_prepare(void); +void flash_read(uint8_t preset_no, scene_state_t *scene, + char (*text)[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]); +void flash_write(uint8_t preset_no, scene_state_t *scene, + char (*text)[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]); +uint8_t flash_last_saved_scene(void); +const char *flash_scene_text(uint8_t preset_no, size_t line); + +#endif diff --git a/module/gitversion.h b/module/gitversion.h new file mode 100644 index 00000000..91c3b145 --- /dev/null +++ b/module/gitversion.h @@ -0,0 +1,6 @@ +#ifndef _GITVERSION_H_ +#define _GITVERSION_H_ + +extern const char *git_version; + +#endif diff --git a/module/globals.h b/module/globals.h new file mode 100644 index 00000000..75ee8a7b --- /dev/null +++ b/module/globals.h @@ -0,0 +1,38 @@ +#ifndef _GLOBALS_H_ +#define _GLOBALS_H_ + +#include +#include +#include "line_editor.h" +#include "region.h" +#include "teletype.h" + +#define SCENE_TEXT_LINES 32 +#define SCENE_TEXT_CHARS LINE_EDITOR_SIZE + +// global variables (defined in main.c) + +// holds the current scene +extern scene_state_t scene_state; +extern char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; + +// 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 diff --git a/module/help.h b/module/help_mode.c similarity index 81% rename from module/help.h rename to module/help_mode.c index e2b635f3..4b5f1713 100644 --- a/module/help.h +++ b/module/help_mode.c @@ -1,4 +1,21 @@ -#include "teletype.h" +#include "help_mode.h" + +// this +#include "globals.h" +#include "keyboard_helper.h" + +// libavr32 +#include "font.h" +#include "region.h" + +// asf +#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" +#include "usb_protocol_hid.h" + +//////////////////////////////////////////////////////////////////////////////// +// Help text /////////////////////////////////////////////////////////////////// + +#define HELP_PAGES 8 #define HELP1_LENGTH 38 const char* help1[HELP1_LENGTH] = { "1/8 HELP", @@ -216,3 +233,78 @@ const char* help8[HELP8_LENGTH] = { "8/8 REMOTE", "ES.STOP|STOP PATTERN", "ES.TRIPLE|RECALL SHAPE 1-4", "ES.MAGIC|1=HALF, 2=DOUBLE" }; + + +//////////////////////////////////////////////////////////////////////////////// +// Help mode /////////////////////////////////////////////////////////////////// + +const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, + help5, help6, help7, help8 }; +const uint8_t help_length[HELP_PAGES] = { HELP1_LENGTH, HELP2_LENGTH, + HELP3_LENGTH, HELP4_LENGTH, + HELP5_LENGTH, HELP6_LENGTH, + HELP7_LENGTH, HELP8_LENGTH }; + +static uint8_t page_no; +static uint8_t offset; + +static bool dirty; + +void set_help_mode() { + dirty = true; +} + +void process_help_keys(uint8_t k, uint8_t m, bool is_held_key) { + // or C-n: line down + if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { + if (offset < help_length[page_no] - 8) { + offset++; + dirty = true; + } + } + // 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; + } + } + // or [: previous page + else if (match_no_mod(m, k, HID_LEFT) || + match_no_mod(m, k, HID_OPEN_BRACKET)) { + if (page_no) { + offset = 0; + page_no--; + dirty = true; + } + } + // or ]: next page + else if (match_no_mod(m, k, HID_RIGHT) || + match_no_mod(m, k, HID_CLOSE_BRACKET)) { + if (page_no < HELP_PAGES - 1) { + offset = 0; + page_no++; + dirty = true; + } + } +} + +bool screen_refresh_help() { + if (!dirty) { return false; } + + // clamp value of page_no + if (page_no >= HELP_PAGES) page_no = HELP_PAGES - 1; + + // clamp value of offset + if (offset >= help_length[page_no] - 8) offset = help_length[page_no] - 8; + + const char** text = help_pages[page_no]; + + for (uint8_t y = 0; y < 8; y++) { + region_fill(&line[y], 0); + font_string_region_clip_tab(&line[y], text[y + offset], 2, 0, 0xa, 0); + } + + dirty = false; + return true; +}; diff --git a/module/help_mode.h b/module/help_mode.h new file mode 100644 index 00000000..84d4ebb8 --- /dev/null +++ b/module/help_mode.h @@ -0,0 +1,11 @@ +#ifndef _HELP_MODE_H_ +#define _HELP_MODE_H_ + +#include +#include + +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 diff --git a/module/keyboard_helper.h b/module/keyboard_helper.h new file mode 100644 index 00000000..183f64c1 --- /dev/null +++ b/module/keyboard_helper.h @@ -0,0 +1,83 @@ +#ifndef _KEYBOARD_HELPER_ +#define _KEYBOARD_HELPER_ + +#include +#include + +// 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 diff --git a/module/line_editor.c b/module/line_editor.c new file mode 100644 index 00000000..2e4c654e --- /dev/null +++ b/module/line_editor.c @@ -0,0 +1,170 @@ +#include "line_editor.h" + +#include + +// 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) { + // 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; + } + // 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; + } + // 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; + } + // 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; + } + // 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; + } + // 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- 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- 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- 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); +} diff --git a/module/line_editor.h b/module/line_editor.h new file mode 100644 index 00000000..6b4f48a2 --- /dev/null +++ b/module/line_editor.h @@ -0,0 +1,26 @@ +#ifndef _LINE_EDITOR_H_ +#define _LINE_EDITOR_H_ + +#include +#include +#include + +#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 diff --git a/module/live_mode.c b/module/live_mode.c new file mode 100644 index 00000000..ecff4d56 --- /dev/null +++ b/module/live_mode.c @@ -0,0 +1,280 @@ +#include "live_mode.h" + +#include + +// 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 +static tele_command_t history[HISTORY_SIZE]; +static uint8_t history_line; +static line_editor_t le; +static process_result_t output; +static error_t status; +static char error_msg[TELE_ERROR_MSG_LENGTH]; +static 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; +static 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; +static uint8_t activity_prev; +static 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; + dirty = D_ALL; + activity_prev = 0xFF; +} + +void set_live_mode() { + line_editor_set(&le, ""); + history_line = HISTORY_SIZE; + dirty = D_ALL; + activity_prev = 0xFF; +} + +void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { + // 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; + } + } + // 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; + } + } + // : 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]) { + size_t len = strlen(s); + strcat(s, ": "); + strncat(s, error_msg, 32 - len - 3); + 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; +} diff --git a/module/live_mode.h b/module/live_mode.h new file mode 100644 index 00000000..25428ba8 --- /dev/null +++ b/module/live_mode.h @@ -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 diff --git a/module/main.c b/module/main.c index 825357ac..76665c47 100644 --- a/module/main.c +++ b/module/main.c @@ -1,238 +1,94 @@ -/* -teletype! - -todo: - -- remove op text strings? -- script tr execution clocked? on 1ms timer, where interrupts simply queue -execution? -- protect process() from ints? tele_tick?? - -serial framing: -http://eli.thegreenplace.net/2009/08/12/framing-in-serial-communications/ - -msgpack: -http://msgpack.org - -*/ - -#include // toupper -#include // sprintf -#include // memcpy +#include +#include +#include // asf #include "compiler.h" #include "delay.h" -#include "fat.h" -#include "file.h" -#include "flashc.h" -#include "fs_com.h" #include "gpio.h" #include "intc.h" -#include "navigation.h" #include "pm.h" #include "preprocessor.h" #include "print_funcs.h" #include "spi.h" #include "sysclk.h" -#include "uhi_msc.h" -#include "uhi_msc_mem.h" -#include "usb_protocol_msc.h" +#include "usb_protocol_hid.h" // system +#include "adc.h" #include "events.h" +#include "font.h" +#include "hid.h" #include "i2c.h" #include "init_common.h" #include "init_teletype.h" #include "kbd.h" -#include "types.h" -// #include "monome.h" -#include "adc.h" -#include "timers.h" -#include "util.h" -// #include "ftdi.h" -#include "font.h" -#include "hid.h" #include "region.h" #include "screen.h" - +#include "timers.h" +#include "util.h" // this #include "conf_board.h" -#include "help.h" +#include "edit_mode.h" +#include "flash.h" +#include "globals.h" +#include "help_mode.h" +#include "keyboard_helper.h" +#include "live_mode.h" +#include "pattern_mode.h" +#include "preset_r_mode.h" +#include "preset_w_mode.h" #include "teletype.h" #include "teletype_io.h" - -#define RATE_CLOCK 10 -#define RATE_CV 6 - -#define SCENE_SLOTS 32 -#define SCENE_SLOTS_ 31 - -#define SCENE_TEXT_LINES 32 -#define SCENE_TEXT_CHARS 32 +#include "usb_disk_mode.h" -uint8_t preset, preset_select, front_timer, preset_edit_line, - preset_edit_offset, offset_view, last_mode; - -u16 adc[4]; - -typedef struct { - u16 now; - u16 off; - u16 target; - u16 slew; - u16 step; - s32 delta; - u32 a; -} aout_t; - -aout_t aout[4]; - -u8 mutes[8]; +//////////////////////////////////////////////////////////////////////////////// +// constants -error_t status; -char error_msg[ERROR_MSG_LENGTH]; +#define RATE_CLOCK 10 +#define RATE_CV 6 -char input[32]; -char input_buffer[32]; -int num_buffer; -uint8_t pos; -uint8_t knob_now; -uint8_t knob_last; +//////////////////////////////////////////////////////////////////////////////// +// globals (defined in globals.h) -scene_script_t history; -uint8_t edit, edit_line, edit_index, edit_pattern, offset_index; +scene_state_t scene_state; char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; - -uint8_t metro_act; -unsigned int metro_time; - -uint8_t mod_key = 0, hold_key, hold_key_count = 0; - -uint8_t help_page; -uint8_t help_length[8] = { HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, - HELP4_LENGTH, HELP5_LENGTH, HELP6_LENGTH, - HELP7_LENGTH, HELP8_LENGTH }; - -int16_t output, output_new; - -#define I2C_DATA_LENGTH_MAX 8 -#define I2C_QUEUE_SIZE 16 - -struct { - bool waiting; - uint8_t addr; - uint8_t l; - uint8_t d[I2C_DATA_LENGTH_MAX]; -} i2c_queue[I2C_QUEUE_SIZE]; - -uint8_t i2c_waiting_count; - -#define FIRSTRUN_KEY 0x22 - -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; - uint8_t mode; - uint8_t fresh; -} nvram_data_t; - -// NVRAM data structure located in the flash array. -__attribute__((__section__(".flash_nvram"))) static nvram_data_t f; - - -#define M_LIVE 0 -#define M_EDIT 1 -#define M_TRACK 2 -#define M_PRESET_W 3 -#define M_PRESET_R 4 -#define M_HELP 5 - -uint8_t mode; - -#define R_PRESET (1 << 0) -#define R_INPUT (1 << 1) -#define R_MESSAGE (1 << 2) -#define R_LIST (1 << 3) -#define R_ALL 0xf -uint8_t r_edit_dirty; - -#define A_METRO 0x1 -#define A_TR 0x2 -#define A_SLEW 0x4 -#define A_DELAY 0x8 -#define A_Q 0x10 -#define A_X 0x20 -#define A_REFRESH 0x40 -#define A_MUTES 0x80 -uint8_t activity; -uint8_t activity_prev; - -static region line[8] = { +uint8_t preset_select; +region line[8] = { {.w = 128, .h = 8, .x = 0, .y = 0 }, {.w = 128, .h = 8, .x = 0, .y = 8 }, {.w = 128, .h = 8, .x = 0, .y = 16 }, {.w = 128, .h = 8, .x = 0, .y = 24 }, {.w = 128, .h = 8, .x = 0, .y = 32 }, {.w = 128, .h = 8, .x = 0, .y = 40 }, {.w = 128, .h = 8, .x = 0, .y = 48 }, {.w = 128, .h = 8, .x = 0, .y = 56 } }; -uint8_t sdirty; - //////////////////////////////////////////////////////////////////////////////// -// prototypes - -// check the event queue -static void check_events(void); - -// handler protos -// static void handler_None(s32 data) { ;; } -static void handler_KeyTimer(s32 data); -static void handler_Front(s32 data); -static void handler_HidConnect(s32 data); -static void handler_HidDisconnect(s32 data); -static void handler_HidPacket(s32 data); -static void handler_Trigger(s32 data); -static void handler_ScreenRefresh(s32 data); -static void handler_II(s32 data); - -static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key); - -static u8 flash_is_fresh(void); -static void flash_unfresh(void); -static void flash_write(void); -static void flash_read(void); - -static void render_init(void); +// locals -static void set_mode(uint8_t); +static tele_mode_t mode = M_LIVE; +static tele_mode_t last_mode = M_LIVE; -static void tele_usb_disk(void); -static void tele_mem_clear(void); +static uint16_t adc[4]; -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// application +typedef struct { + uint16_t now; + uint16_t off; + uint16_t target; + uint16_t slew; + uint16_t step; + int32_t delta; + uint32_t a; +} aout_t; +static aout_t aout[4]; +static bool metro_timer_enabled; +static uint8_t front_timer; +static uint8_t mod_key = 0, hold_key, hold_key_count = 0; -//////////////////////////////////////////////////////////////////////////////// // timers - static softTimer_t clockTimer = {.next = NULL, .prev = NULL }; static softTimer_t refreshTimer = {.next = NULL, .prev = NULL }; static softTimer_t keyTimer = {.next = NULL, .prev = NULL }; @@ -242,13 +98,54 @@ static softTimer_t hidTimer = {.next = NULL, .prev = NULL }; static softTimer_t metroTimer = {.next = NULL, .prev = NULL }; -static void cvTimer_callback(void* o) { - u8 i, r = 0; - u16 a; +//////////////////////////////////////////////////////////////////////////////// +// prototypes - activity &= ~A_SLEW; +// timer callback prototypes +static void cvTimer_callback(void* o); +static void clockTimer_callback(void* o); +static void refreshTimer_callback(void* o); +static void keyTimer_callback(void* o); +static void adcTimer_callback(void* o); +static void hidTimer_callback(void* o); +static void metroTimer_callback(void* o); + +// event handler prototypes +static void handler_None(int32_t data); +static void handler_Front(int32_t data); +static void handler_PollADC(int32_t data); +static void handler_KeyTimer(int32_t data); +static void handler_HidConnect(int32_t data); +static void handler_HidDisconnect(int32_t data); +static void handler_HidTimer(int32_t data); +static void handler_MscConnect(int32_t data); +static void handler_Trigger(int32_t data); +static void handler_ScreenRefresh(int32_t data); +static void handler_EventTimer(int32_t data); +static void handler_AppCustom(int32_t data); + +// event queue +static void empty_event_handlers(void); +static void assign_main_event_handlers(void); +static void assign_msc_event_handlers(void); +static void check_events(void); - for (i = 0; i < 4; i++) +// key handling +static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key); +static bool process_global_keys(uint8_t key, uint8_t mod_key, bool is_held_key); + +// other +static void render_init(void); + + +//////////////////////////////////////////////////////////////////////////////// +// timer callbacks + +void cvTimer_callback(void* o) { + bool updated = false; + bool slewing = false; + + for (size_t i = 0; i < 4; i++) { if (aout[i].step) { aout[i].step--; @@ -256,169 +153,118 @@ static void cvTimer_callback(void* o) { else { aout[i].a += aout[i].delta; aout[i].now = aout[i].a >> 16; - activity |= A_SLEW; + slewing = true; } - r++; + updated = true; } + } + + set_slew_icon(slewing); + + if (updated) { + uint16_t a0 = aout[0].now >> 2; + uint16_t a1 = aout[1].now >> 2; + uint16_t a2 = aout[2].now >> 2; + uint16_t a3 = aout[3].now >> 2; - if (r) { spi_selectChip(DAC_SPI, DAC_SPI_NPCS); spi_write(DAC_SPI, 0x31); - a = aout[2].now >> 2; - spi_write(DAC_SPI, a >> 4); - spi_write(DAC_SPI, a << 4); + spi_write(DAC_SPI, a2 >> 4); + spi_write(DAC_SPI, a2 << 4); spi_write(DAC_SPI, 0x31); - a = aout[0].now >> 2; - spi_write(DAC_SPI, a >> 4); - spi_write(DAC_SPI, a << 4); + spi_write(DAC_SPI, a0 >> 4); + spi_write(DAC_SPI, a0 << 4); spi_unselectChip(DAC_SPI, DAC_SPI_NPCS); spi_selectChip(DAC_SPI, DAC_SPI_NPCS); spi_write(DAC_SPI, 0x38); - a = aout[3].now >> 2; - spi_write(DAC_SPI, a >> 4); - spi_write(DAC_SPI, a << 4); + spi_write(DAC_SPI, a3 >> 4); + spi_write(DAC_SPI, a3 << 4); spi_write(DAC_SPI, 0x38); - a = aout[1].now >> 2; - spi_write(DAC_SPI, a >> 4); - spi_write(DAC_SPI, a << 4); + spi_write(DAC_SPI, a1 >> 4); + spi_write(DAC_SPI, a1 << 4); spi_unselectChip(DAC_SPI, DAC_SPI_NPCS); } } -static void clockTimer_callback(void* o) { - // static event_t e; - // e.type = kEventTimer; - // e.data = 0; - // event_post(&e); - // print_dbg("\r\ntimer."); - - // clock_phase++; - // if(clock_phase>1) clock_phase=0; - // (*clock_pulse)(clock_phase); - - // clock_time++; - - tele_tick(RATE_CLOCK); - - // i2c_master_tx(d); +void clockTimer_callback(void* o) { + event_t e = {.type = kEventTimer, .data = 0 }; + event_post(&e); } -static void refreshTimer_callback(void* o) { - static event_t e; - e.type = kEventScreenRefresh; - e.data = 0; +void refreshTimer_callback(void* o) { + event_t e = {.type = kEventScreenRefresh, .data = 0 }; event_post(&e); - - if (sdirty) { - for (int i = 0; i < 8; i++) region_draw(&line[i]); - - sdirty = 0; - } } -static void keyTimer_callback(void* o) { - static event_t e; - e.type = kEventKeyTimer; - e.data = 0; +void keyTimer_callback(void* o) { + event_t e = {.type = kEventKeyTimer, .data = 0 }; event_post(&e); } -static void adcTimer_callback(void* o) { - static event_t e; - e.type = kEventPollADC; - e.data = 0; +void adcTimer_callback(void* o) { + event_t e = {.type = kEventPollADC, .data = 0 }; event_post(&e); } -static void hidTimer_callback(void* o) { - static event_t e; - e.type = kEventHidTimer; - e.data = 0; +void hidTimer_callback(void* o) { + event_t e = {.type = kEventHidTimer, .data = 0 }; event_post(&e); } -static void metroTimer_callback(void* o) { - if (tele_get_script_l(METRO_SCRIPT)) { - activity |= A_METRO; - run_script(METRO_SCRIPT); - } - else - activity &= ~A_METRO; +void metroTimer_callback(void* o) { + event_t e = {.type = kEventAppCustom, .data = 0 }; + event_post(&e); } -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // event handlers -static void handler_Front(s32 data) { - // print_dbg("\r\n //// FRONT HOLD"); +void handler_None(int32_t data) {} +void handler_Front(int32_t data) { if (data == 0) { if (mode != M_PRESET_R) { front_timer = 0; - knob_last = adc[1] >> 7; - last_mode = mode; + set_preset_r_mode(adc[1]); set_mode(M_PRESET_R); } else front_timer = 15; } else { - if (front_timer) { set_mode(last_mode); } + if (front_timer) { set_last_mode(); } front_timer = 0; } } -static void handler_PollADC(s32 data) { +void handler_PollADC(int32_t data) { adc_convert(&adc); - tele_set_in(adc[0] << 2); + ss_set_in(&scene_state, adc[0] << 2); - if (mode == M_TRACK && (mod_key & CTRL)) { - if (mod_key & SHIFT) - tele_set_pattern_val(edit_pattern, edit_index + offset_index, - adc[1] >> 2); - else - tele_set_pattern_val(edit_pattern, edit_index + offset_index, - adc[1] >> 7); - r_edit_dirty |= R_ALL; + if (mode == M_PATTERN) { + process_pattern_knob(adc[1], mod_key); + ss_set_param(&scene_state, adc[1] << 2); } else if (mode == M_PRESET_R) { - knob_now = adc[1] >> 7; - if (knob_now != knob_last) { - preset_select = knob_now; - r_edit_dirty = R_ALL; - } - knob_last = knob_now; + process_preset_r_knob(adc[1], mod_key); + } + else { + ss_set_param(&scene_state, adc[1] << 2); } - else - tele_set_param(adc[1] << 2); - - // print_dbg("\r\nadc:\t"); print_dbg_ulong(adc[0]); - // print_dbg("\t"); print_dbg_ulong(adc[1]); - // print_dbg("\t"); print_dbg_ulong(adc[2]); - // print_dbg("\t"); print_dbg_ulong(adc[3]); -} - -static void handler_SaveFlash(s32 data) { - flash_write(); } -static void handler_KeyTimer(s32 data) { +void handler_KeyTimer(int32_t data) { if (front_timer) { if (front_timer == 1) { - flash_read(); + flash_read(preset_select, &scene_state, &scene_text); - run_script(INIT_SCRIPT); + run_script(&scene_state, INIT_SCRIPT); - set_mode(last_mode); + set_last_mode(); front_timer--; } @@ -434,28 +280,17 @@ static void handler_KeyTimer(s32 data) { } } -static void handler_HidConnect(s32 data) { - // print_dbg("\r\nhid connect\r\n"); +void handler_HidConnect(int32_t data) { timer_add(&hidTimer, 47, &hidTimer_callback, NULL); } -static void handler_HidDisconnect(s32 data) { +void handler_HidDisconnect(int32_t data) { timer_remove(&hidTimer); - // print_dbg("\r\nno more hid"); } - -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -// keys - -static void handler_HidTimer(s32 data) { +void handler_HidTimer(int32_t data) { if (hid_get_frame_dirty()) { - const s8* frame = (const s8*)hid_get_frame_data(); + const int8_t* frame = (const int8_t*)hid_get_frame_data(); for (size_t i = 2; i < 8; i++) { if (frame[i] == 0) { @@ -469,10 +304,6 @@ static void handler_HidTimer(s32 data) { } if (frame_compare(frame[i]) == false) { - // print_dbg("\r\nk: "); - // print_dbg_hex(frame[i]); - // print_dbg("\r\nmod: "); - // print_dbg_hex(frame[0]); hold_key = frame[i]; hold_key_count = 0; process_keypress(hold_key, mod_key, false); @@ -480,1224 +311,248 @@ static void handler_HidTimer(s32 data) { } set_old_frame(frame); - - // print_dbg("\r\nhid:\t"); - // for(i=0;i<8;i++) { - // print_dbg_ulong( (int) frame[i] ); - // print_dbg("\t"); - // } } hid_clear_frame_dirty(); } +void handler_MscConnect(int32_t data) { + // disable event handlers while doing USB write + assign_msc_event_handlers(); -static void handler_HidPacket(s32 data) { - // print_dbg("\r\nhid packet"); -} - - -static void handler_Trigger(s32 data) { - if (mutes[data]) { run_script(data); } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -// refresh - -static void handler_ScreenRefresh(s32 data) { - static uint8_t a; - static char s[32]; - - uint8_t y, x, i; - - if (mode == M_TRACK) { - if (r_edit_dirty & R_ALL) { - for (y = 0; y < 8; y++) { - region_fill(&line[y], 0); - itoa(y + offset_index, s, 10); - font_string_region_clip_right(&line[y], s, 4, 0, 0x1, 0); - - for (x = 0; x < 4; x++) { - if (tele_get_pattern_l(x) > y + offset_index) - a = 6; - else - a = 1; - itoa(tele_get_pattern_val(x, y + offset_index), s, 10); - font_string_region_clip_right(&line[y], s, (x + 1) * 30 + 4, - 0, a, 0); - - if (y + offset_index >= tele_get_pattern_start(x)) - if (y + offset_index <= tele_get_pattern_end(x)) - for (i = 0; i < 8; i += 2) - line[y].data[i * 128 + (x + 1) * 30 + 6] = 1; - - if (y + offset_index == tele_get_pattern_i(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(tele_get_pattern_val(edit_pattern, edit_index + offset_index), - s, 10); - font_string_region_clip_right( - &line[edit_index], s, (edit_pattern + 1) * 30 + 4, 0, 0xf, 0); + // disable timers + timers_pause(); - for (y = 0; y < 64; y += 2) { - line[y >> 3].data[(y & 0x7) * 128 + 8] = 1; - } - - for (y = 0; y < 8; y++) { - line[(offset_index + y) >> 3] - .data[((offset_index + y) & 0x7) * 128 + 8] = 6; - } - - r_edit_dirty &= ~R_ALL; - - sdirty++; - } + // clear screen + for (size_t i = 0; i < 8; i++) { + region_fill(&line[i], 0); + region_draw(&line[i]); } - else if (mode == M_PRESET_W) { - if (r_edit_dirty & R_ALL) { - strcpy(s, ">>> "); - itoa(preset_select, s + 4, 10); - region_fill(&line[0], 1); - font_string_region_clip_right(&line[0], s, 126, 0, 0xf, 1); - font_string_region_clip(&line[0], "WRITE", 2, 0, 0xf, 1); - - - for (y = 1; y < 7; y++) { - a = preset_edit_line == (y - 1); - region_fill(&line[y], a); - font_string_region_clip(&line[y], - scene_text[preset_edit_offset + y - 1], - 2, 0, 0xa + a * 5, a); - } + // do USB + tele_usb_disk(); - s[0] = '+'; - s[1] = ' '; - s[2] = 0; + // renable teletype + set_mode(M_LIVE); + assign_main_event_handlers(); + timers_resume(); +} - strcat(s, input); - strcat(s, " "); +void handler_Trigger(int32_t data) { + if (!ss_get_mute(&scene_state, data)) { run_script(&scene_state, data); } +} - region_fill(&line[7], 0); - // region_string(&line[7], s, 0, 0, 0xf, 0, 0); - // font_string_region_clip(&line[7], s, 0, 0, 0xf, 0); - font_string_region_clip_hi(&line[7], s, 0, 0, 0xf, 0, pos + 2); +void handler_ScreenRefresh(int32_t data) { + bool screen_dirty = false; - r_edit_dirty &= ~R_ALL; - sdirty++; - } + switch (mode) { + case M_PATTERN: screen_dirty = screen_refresh_pattern(); break; + case M_PRESET_W: screen_dirty = screen_refresh_preset_w(); break; + case M_PRESET_R: screen_dirty = screen_refresh_preset_r(); break; + case M_HELP: screen_dirty = screen_refresh_help(); break; + case M_LIVE: screen_dirty = screen_refresh_live(); break; + case M_EDIT: screen_dirty = screen_refresh_edit(); break; } - else if (mode == M_PRESET_R) { - if (r_edit_dirty & R_ALL) { - 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 (y = 1; y < 8; y++) { - region_fill(&line[y], 0); - font_string_region_clip( - &line[y], f.s[preset_select].text[preset_edit_offset + y], - 2, 0, 0xa, 0); - } - r_edit_dirty &= ~R_ALL; - sdirty++; - } + if (screen_dirty) { + for (size_t i = 0; i < 8; i++) { region_draw(&line[i]); } } - else if (mode == M_HELP) { - if (r_edit_dirty & R_ALL) { - for (y = 0; y < 8; y++) { - region_fill(&line[y], 0); - /// fixme: make a pointer array - if (help_page == 0) - font_string_region_clip_tab( - &line[y], help1[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 1) - font_string_region_clip_tab( - &line[y], help2[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 2) - font_string_region_clip_tab( - &line[y], help3[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 3) - font_string_region_clip_tab( - &line[y], help4[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 4) - font_string_region_clip_tab( - &line[y], help5[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 5) - font_string_region_clip_tab( - &line[y], help6[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 6) - font_string_region_clip_tab( - &line[y], help7[y + offset_view], 2, 0, 0xa, 0); - else if (help_page == 7) - font_string_region_clip_tab( - &line[y], help8[y + offset_view], 2, 0, 0xa, 0); - } - - r_edit_dirty &= ~R_ALL; - sdirty++; - } - } - else if (mode == M_LIVE || mode == M_EDIT) { - if (r_edit_dirty & R_INPUT) { - s[0] = '>'; - s[1] = ' '; - s[2] = 0; - - if (mode == M_EDIT) { - if (edit == 8) - s[0] = 'M'; - else if (edit == 9) - s[0] = 'I'; - else - s[0] = edit + 49; - } - - strcat(s, input); - strcat(s, " "); - - region_fill(&line[7], 0); - // region_string(&line[7], s, 0, 0, 0xf, 0, 0); - // font_string_region_clip(&line[7], s, 0, 0, 0xf, 0); - font_string_region_clip_hi(&line[7], s, 0, 0, 0xf, 0, pos + 2); - sdirty++; - r_edit_dirty &= ~R_INPUT; - } - if (r_edit_dirty & R_MESSAGE) { - if (status) { - 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_new) { - output_new = 0; - if (mode == M_LIVE) itoa(output, s, 10); - // strcat(s, " "); - // strcat(s, to_voltage(output)); - else - s[0] = 0; - } - else { - s[0] = 0; - } - region_fill(&line[6], 0); - font_string_region_clip(&line[6], s, 0, 0, 0x4, 0); - sdirty++; - r_edit_dirty &= ~R_MESSAGE; - } - if (r_edit_dirty & R_LIST) { - if (mode == M_LIVE) { - for (int i = 0; i < 6; i++) region_fill(&line[i], 0); - } - else { - for (int i = 0; i < 6; i++) { - a = edit_line == i; - region_fill(&line[i], a); - if (tele_get_script_l(edit) > i) { - print_command(tele_get_script_c(edit, i), s); - region_string(&line[i], s, 2, 0, 0xf, a, 0); - } - } - } - +} - sdirty++; - r_edit_dirty &= ~R_LIST; - } +void handler_EventTimer(int32_t data) { + tele_tick(&scene_state, RATE_CLOCK); +} - if ((activity != activity_prev) && (mode == M_LIVE)) { - region_fill(&line[0], 0); - - if (activity & A_SLEW) - a = 15; - else - a = 1; - - line[0].data[98 + 0 + 512] = a; - line[0].data[98 + 1 + 384] = a; - line[0].data[98 + 2 + 256] = a; - line[0].data[98 + 3 + 128] = a; - line[0].data[98 + 4 + 0] = a; - - if (activity & A_DELAY) - a = 15; - else - a = 1; - - line[0].data[106 + 0 + 0] = a; - line[0].data[106 + 1 + 0] = a; - line[0].data[106 + 2 + 0] = a; - line[0].data[106 + 3 + 0] = a; - line[0].data[106 + 4 + 0] = a; - line[0].data[106 + 0 + 128] = a; - line[0].data[106 + 0 + 256] = a; - line[0].data[106 + 0 + 384] = a; - line[0].data[106 + 0 + 512] = a; - line[0].data[106 + 4 + 128] = a; - line[0].data[106 + 4 + 256] = a; - line[0].data[106 + 4 + 384] = a; - line[0].data[106 + 4 + 512] = a; - - if (activity & A_Q) - a = 15; - else - a = 1; - - line[0].data[114 + 0 + 0] = a; - line[0].data[114 + 1 + 0] = a; - line[0].data[114 + 2 + 0] = a; - line[0].data[114 + 3 + 0] = a; - line[0].data[114 + 4 + 0] = a; - line[0].data[114 + 0 + 256] = a; - line[0].data[114 + 1 + 256] = a; - line[0].data[114 + 2 + 256] = a; - line[0].data[114 + 3 + 256] = a; - line[0].data[114 + 4 + 256] = a; - line[0].data[114 + 0 + 512] = a; - line[0].data[114 + 1 + 512] = a; - line[0].data[114 + 2 + 512] = a; - line[0].data[114 + 3 + 512] = a; - line[0].data[114 + 4 + 512] = a; - - if (activity & A_METRO) - a = 15; - else - a = 1; - - line[0].data[122 + 0 + 0] = a; - line[0].data[122 + 0 + 128] = a; - line[0].data[122 + 0 + 256] = a; - line[0].data[122 + 0 + 384] = a; - line[0].data[122 + 0 + 512] = a; - line[0].data[122 + 1 + 128] = a; - line[0].data[122 + 2 + 256] = a; - line[0].data[122 + 3 + 128] = a; - line[0].data[122 + 4 + 0] = a; - line[0].data[122 + 4 + 128] = a; - line[0].data[122 + 4 + 256] = a; - line[0].data[122 + 4 + 384] = a; - line[0].data[122 + 4 + 512] = a; - - // mutes - - line[0].data[87 + 0 + 128] = 15 - mutes[0] * 12; - line[0].data[87 + 1 + 384] = 15 - mutes[1] * 12; - line[0].data[87 + 2 + 128] = 15 - mutes[2] * 12; - line[0].data[87 + 3 + 384] = 15 - mutes[3] * 12; - line[0].data[87 + 4 + 128] = 15 - mutes[4] * 12; - line[0].data[87 + 5 + 384] = 15 - mutes[5] * 12; - line[0].data[87 + 6 + 128] = 15 - mutes[6] * 12; - line[0].data[87 + 7 + 384] = 15 - mutes[7] * 12; - - activity &= ~A_MUTES; - activity &= ~A_REFRESH; - - activity_prev = activity; - - // activity &= ~A_X; - - sdirty++; - } +void handler_AppCustom(int32_t data) { + // If we need multiple custom event handlers then we can use an enum in the + // data argument. For now, we're just using it for the metro + if (ss_get_script_len(&scene_state, METRO_SCRIPT)) { + set_metro_icon(true); + run_script(&scene_state, METRO_SCRIPT); } + else + set_metro_icon(false); } -static void handler_II(s32 data) { - uint8_t i = data & 0xff; - int16_t d = (int)(data >> 16); - uint8_t addr = i & 0xf0; - - uint8_t buffer[3]; - - buffer[0] = i; - buffer[1] = d >> 8; - buffer[2] = d & 0xff; - - i2c_master_tx(addr, buffer, 3); - // print_dbg("\r\ni2c: "); - // print_dbg_ulong(addr); - // print_dbg(" "); - // print_dbg_ulong(i); - // print_dbg(" "); - // if(d<0) - // print_dbg(" -"); - // print_dbg_ulong(d); -} -static void handler_IItx(s32 data) { - i2c_queue[data].waiting = false; - i2c_waiting_count--; - i2c_master_tx(i2c_queue[data].addr, i2c_queue[data].d, i2c_queue[data].l); +//////////////////////////////////////////////////////////////////////////////// +// event queue + +void empty_event_handlers() { + for (size_t i = 0; i < kNumEventTypes; i++) { + app_event_handlers[i] = &handler_None; + } } +void assign_main_event_handlers() { + empty_event_handlers(); -// assign event handlers -static inline void assign_main_event_handlers(void) { app_event_handlers[kEventFront] = &handler_Front; app_event_handlers[kEventPollADC] = &handler_PollADC; app_event_handlers[kEventKeyTimer] = &handler_KeyTimer; - app_event_handlers[kEventSaveFlash] = &handler_SaveFlash; app_event_handlers[kEventHidConnect] = &handler_HidConnect; app_event_handlers[kEventHidDisconnect] = &handler_HidDisconnect; - app_event_handlers[kEventHidPacket] = &handler_HidPacket; app_event_handlers[kEventHidTimer] = &handler_HidTimer; + app_event_handlers[kEventMscConnect] = &handler_MscConnect; app_event_handlers[kEventTrigger] = &handler_Trigger; app_event_handlers[kEventScreenRefresh] = &handler_ScreenRefresh; - app_event_handlers[kEventII] = &handler_II; - app_event_handlers[kEventIItx] = &handler_IItx; + app_event_handlers[kEventTimer] = &handler_EventTimer; + app_event_handlers[kEventAppCustom] = &handler_AppCustom; +} + +static void assign_msc_event_handlers(void) { + empty_event_handlers(); + + // one day this could be used to map the front button and pot to be used as + // a UI with a memory stick } // app event loop void check_events(void) { - static event_t e; + event_t e; if (event_next(&e)) { (app_event_handlers)[e.type](e.data); } } -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -// funcs +//////////////////////////////////////////////////////////////////////////////// +// mode handling -void set_mode(uint8_t m) { +// defined in globals.h +void set_mode(tele_mode_t m) { + last_mode = mode; switch (m) { case M_LIVE: - for (int n = 0; n < 32; n++) input[n] = 0; - pos = 0; + set_live_mode(); mode = M_LIVE; - flashc_memset8((void*)&(f.mode), mode, 1, true); - edit_line = SCRIPT_MAX_COMMANDS; - activity |= A_REFRESH; - r_edit_dirty |= R_ALL; break; case M_EDIT: + set_edit_mode(); mode = M_EDIT; - edit_line = 0; - print_command(tele_get_script_c(edit, edit_line), input); - pos = strlen(input); - for (int n = pos; n < 32; n++) input[n] = 0; - r_edit_dirty |= R_ALL; break; - case M_TRACK: - mode = M_TRACK; - flashc_memset8((void*)&(f.mode), mode, 1, true); - r_edit_dirty = R_ALL; + case M_PATTERN: + set_pattern_mode(); + mode = M_PATTERN; break; case M_PRESET_W: - preset_edit_line = 0; - preset_edit_offset = 0; - strcpy(input, scene_text[preset_edit_line + preset_edit_offset]); - pos = strlen(input); + set_preset_w_mode(); mode = M_PRESET_W; - r_edit_dirty = R_ALL; break; case M_PRESET_R: - preset_edit_offset = 0; - knob_last = adc[1] >> 7; + set_preset_r_mode(adc[1]); mode = M_PRESET_R; - r_edit_dirty = R_ALL; break; case M_HELP: + set_help_mode(); mode = M_HELP; - r_edit_dirty = R_ALL; break; } } -void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key) { - uint8_t mod_SH = mod_key & SHIFT; - uint8_t mod_ALT = mod_key & ALT; - uint8_t mod_META = mod_key & META; - - switch (key) { - case TAB: - if (mode == M_LIVE) - set_mode(M_EDIT); - else - set_mode(M_LIVE); - break; - case TILDE: - if (mode == M_TRACK) - set_mode(last_mode); - else { - last_mode = mode; - set_mode(M_TRACK); - } - break; - case ESCAPE: - if (mod_ALT) { - last_mode = mode; - set_mode(M_PRESET_W); - } - else if (mod_META) { - if (!is_held_key) { - clear_delays(); - for (int i = 0; i < 4; i++) { aout[i].step = 1; } - } - } - else if (mode == M_PRESET_R) - set_mode(last_mode); - else { - last_mode = mode; - set_mode(M_PRESET_R); - } - break; - case 0x3A: // F1 - if (mode == M_HELP) - set_mode(last_mode); - else { - last_mode = mode; - set_mode(M_HELP); - } - break; - case 0x51: // down - if (mode == M_TRACK) { - if (mod_ALT) { - if (offset_index < 48) - offset_index += 8; - else { - offset_index = 56; - edit_index = 7; - } - } - else { - edit_index++; - if (edit_index == 8) { - edit_index = 7; - if (offset_index < 56) { offset_index++; } - } - } - r_edit_dirty |= R_ALL; - } - else if (mode == M_PRESET_W) { - if ((preset_edit_offset + preset_edit_line) < 31) { - if (preset_edit_line == 5) - preset_edit_offset++; - else - preset_edit_line++; - strcpy(input, - scene_text[preset_edit_line + preset_edit_offset]); - pos = strlen(input); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_PRESET_R) { - if (preset_edit_offset < 24) { - preset_edit_offset++; - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_HELP) { - if (offset_view < help_length[help_page] - 8) { - offset_view++; - r_edit_dirty |= R_ALL; - } - } - else if (edit_line < (SCRIPT_MAX_COMMANDS - 1)) { - if (mode == M_LIVE) { - edit_line++; - print_command(&history.c[edit_line], input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) input[n] = 0; - } - else if (tele_get_script_l(edit) > edit_line) { - edit_line++; - print_command(tele_get_script_c(edit, edit_line), input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) input[n] = 0; - r_edit_dirty |= R_LIST; - } - } - else if (mode == M_LIVE) { - edit_line = SCRIPT_MAX_COMMANDS; - pos = 0; - for (size_t n = 0; n < 32; n++) input[n] = 0; - } - break; - case 0x52: // up - if (mode == M_TRACK) { - if (mod_ALT) { - if (offset_index > 8) { offset_index -= 8; } - else { - offset_index = 0; - edit_index = 0; - } - } - else { - if (edit_index) - edit_index--; - else if (offset_index) - offset_index--; - } - r_edit_dirty |= R_ALL; - } - else if (mode == M_PRESET_W) { - if (preset_edit_line + preset_edit_offset) { - if (preset_edit_line) - preset_edit_line--; - else - preset_edit_offset--; - strcpy(input, - scene_text[preset_edit_line + preset_edit_offset]); - pos = strlen(input); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_PRESET_R) { - if (preset_edit_offset) { - preset_edit_offset--; - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_HELP) { - if (offset_view) { - offset_view--; - r_edit_dirty |= R_ALL; - } - } - else if (edit_line) { - edit_line--; - if (mode == M_LIVE) - print_command(&history.c[edit_line], input); - else - print_command(tele_get_script_c(edit, edit_line), input); - - pos = strlen(input); - for (size_t n = pos; n < 32; n++) input[n] = 0; - if (mode != M_LIVE) r_edit_dirty |= R_LIST; - } - break; - case 0x50: // back - if (mode == M_TRACK) { - if (mod_ALT) { - edit_index = 0; - offset_index = 0; - } - else { - if (edit_pattern > 0) edit_pattern--; - } - r_edit_dirty |= R_ALL; - } - else if (pos) { - pos--; - } - break; - - case 0x4f: // forward - if (mode == M_TRACK) { - if (mod_ALT) { - edit_index = 7; - offset_index = 56; - } - else { - if (edit_pattern < 3) edit_pattern++; - } - r_edit_dirty |= R_ALL; - } - else if (pos < strlen(input)) { - pos++; - } - - break; - - case 0x30: // ] - if (mode == M_EDIT) { - edit++; - if (edit == 10) edit = 0; - if (edit_line > tele_get_script_l(edit)) - edit_line = tele_get_script_l(edit); - print_command(tele_get_script_c(edit, edit_line), input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) input[n] = 0; - - - r_edit_dirty |= R_LIST; - } - else if (mode == M_PRESET_W || mode == M_PRESET_R) { - if (preset_select < SCENE_SLOTS_) preset_select++; - r_edit_dirty |= R_ALL; - } - else if (mode == M_TRACK) { - int16_t v = tele_get_pattern_val(edit_pattern, - edit_index + offset_index); - if (v < 32766) { - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, v + 1); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_HELP) { - if (help_page < 7) { - offset_view = 0; - help_page++; - r_edit_dirty |= R_ALL; - } - } - break; - - case 0x2F: // [ - if (mode == M_EDIT) { - if (edit) - edit--; - else - edit = 9; - if (edit_line > tele_get_script_l(edit)) - edit_line = tele_get_script_l(edit); - print_command(tele_get_script_c(edit, edit_line), input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) input[n] = 0; - r_edit_dirty |= R_LIST; - } - else if (mode == M_PRESET_W || mode == M_PRESET_R) { - if (preset_select) preset_select--; - r_edit_dirty |= R_ALL; - } - else if (mode == M_TRACK) { - int16_t v = tele_get_pattern_val(edit_pattern, - edit_index + offset_index); - if (v > -32767) { - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, v - 1); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_HELP) { - if (help_page) { - offset_view = 0; - help_page--; - r_edit_dirty |= R_ALL; - } - } - break; - case BACKSPACE: - if (mode == M_LIVE || mode == M_EDIT || mode == M_PRESET_W) { - if (mod_SH) { - for (size_t n = 0; n < 32; n++) input[n] = 0; - pos = 0; - } - else if (pos) { - pos--; - // input[pos] = ' '; - for (int x = pos; x < 31; x++) input[x] = input[x + 1]; - } - } - else if (mode == M_TRACK) { - if (mod_SH) { - for (int i = edit_index + offset_index; i < 63; i++) { - int16_t v = tele_get_pattern_val(edit_pattern, i + 1); - tele_set_pattern_val(edit_pattern, i, v); - } - - uint16_t l = tele_get_pattern_l(edit_pattern); - if (l > edit_index + offset_index) - tele_set_pattern_l(edit_pattern, l - 1); - } - else { - int16_t new_v = - tele_get_pattern_val(edit_pattern, - edit_index + offset_index) / - 10; - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, new_v); - } - r_edit_dirty |= R_ALL; - } - break; +// defined in globals.h +void set_last_mode() { + if (mode == last_mode) return; - case RETURN: - if (mode == M_EDIT || mode == M_LIVE) { - tele_command_t temp; - status = parse(input, &temp, error_msg); - - if (status == E_OK) { - status = validate(&temp, error_msg); - - if (status == E_OK) { - if (mode == M_LIVE) { - edit_line = SCRIPT_MAX_COMMANDS; - - if (temp.l) { - memcpy(&history.c[0], &history.c[1], - sizeof(tele_command_t)); - memcpy(&history.c[1], &history.c[2], - sizeof(tele_command_t)); - memcpy(&history.c[2], &history.c[3], - sizeof(tele_command_t)); - memcpy(&history.c[3], &history.c[4], - sizeof(tele_command_t)); - memcpy(&history.c[4], &history.c[5], - sizeof(tele_command_t)); - memcpy(&history.c[5], &temp, - sizeof(tele_command_t)); - - process_result_t o = run_command(&temp); - if (o.has_value) { - output = o.value; - output_new++; - } - } - - for (size_t n = 0; n < 32; n++) input[n] = 0; - pos = 0; - } - else { - if (temp.l == 0) { // BLANK LINE - uint8_t script_len = tele_get_script_l(edit); - if (script_len && - tele_get_script_c(edit, edit_line)->l) { - script_len--; - tele_set_script_l(edit, script_len); - - for (size_t n = edit_line; n < script_len; - n++) { - const tele_command_t* cmd = - tele_get_script_c(edit, n + 1); - tele_set_script_c(edit, n, cmd); - } - - tele_command_t blank_command; - blank_command.l = 0; - tele_set_script_c(edit, script_len, - &blank_command); - - if (edit_line > script_len) - edit_line = script_len; - print_command( - tele_get_script_c(edit, edit_line), - input); - pos = strlen(input); - } - } - else if (mod_SH) { // SHIFT = INSERT - for (size_t n = tele_get_script_l(edit); - n > edit_line; n--) { - const tele_command_t* cmd = - tele_get_script_c(edit, n - 1); - tele_set_script_c(edit, n, cmd); - } - - if (tele_get_script_l(edit) < - SCRIPT_MAX_COMMANDS) { - tele_set_script_l( - edit, tele_get_script_l(edit) + 1); - } - - tele_set_script_c(edit, edit_line, &temp); - if ((edit_line == tele_get_script_l(edit)) && - (tele_get_script_l(edit) < 4)) { - tele_set_script_l( - edit, tele_get_script_l(edit) + 1); - } - if (edit_line < (SCRIPT_MAX_COMMANDS - 1)) { - edit_line++; - print_command( - tele_get_script_c(edit, edit_line), - input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) { - input[n] = 0; - } - } - } - else { - tele_set_script_c(edit, edit_line, &temp); - if ((edit_line == tele_get_script_l(edit)) && - (tele_get_script_l(edit) < - SCRIPT_MAX_COMMANDS)) { - tele_set_script_l( - edit, tele_get_script_l(edit) + 1); - } - if (edit_line < (SCRIPT_MAX_COMMANDS - 1)) { - edit_line++; - print_command( - tele_get_script_c(edit, edit_line), - input); - pos = strlen(input); - for (size_t n = pos; n < 32; n++) { - input[n] = 0; - } - } - } - - r_edit_dirty |= R_MESSAGE; - } - if (mode == M_EDIT) r_edit_dirty |= R_LIST; - } - else { - // print_dbg("\r\nvalidate: "); - // print_dbg(tele_error(status)); - } - } - else { - // print_dbg("\r\nERROR: "); - // print_dbg(tele_error(status)); - } + if (last_mode == M_LIVE || last_mode == M_EDIT || last_mode == M_PATTERN) + set_mode(last_mode); + else + set_mode(M_LIVE); +} - // print_dbg("\r\n\n> "); - r_edit_dirty |= R_MESSAGE; - } - else if (mode == M_PRESET_W) { - if (mod_ALT) { - if (!is_held_key) { - strcpy( - scene_text[preset_edit_line + preset_edit_offset], - input); - flash_write(); - for (size_t n = 0; n < 32; n++) input[n] = 0; - pos = 0; - set_mode(last_mode); - } - } - else { - strcpy(scene_text[preset_edit_line + preset_edit_offset], - input); - if (preset_edit_line + preset_edit_offset < 31) { - if (preset_edit_line == 5) - preset_edit_offset++; - else - preset_edit_line++; - } - strcpy(input, - scene_text[preset_edit_line + preset_edit_offset]); - pos = strlen(input); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_PRESET_R) { - if (!is_held_key) { - flash_read(); - tele_set_scene(preset_select); +//////////////////////////////////////////////////////////////////////////////// +// key handling - run_script(INIT_SCRIPT); +void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key) { + // first try global keys + if (process_global_keys(key, mod_key, is_held_key)) return; - for (size_t n = 0; n < 32; n++) input[n] = 0; - pos = 0; - set_mode(last_mode); - } - } - else if (mode == M_TRACK) { - if (mod_SH) { - for (int i = 63; i > edit_index + offset_index; i--) { - int16_t v = tele_get_pattern_val(edit_pattern, i - 1); - tele_set_pattern_val(edit_pattern, i, v); - } - uint16_t l = tele_get_pattern_l(edit_pattern); - if (l < 64) { tele_set_pattern_l(edit_pattern, l + 1); } - r_edit_dirty |= R_ALL; - } - else { - uint16_t l = tele_get_pattern_l(edit_pattern); - if (edit_index + offset_index == l && l < 64) - tele_set_pattern_l(edit_pattern, l + 1); - edit_index++; - if (edit_index == 8) { - edit_index = 7; - if (offset_index < 56) { offset_index++; } - } - r_edit_dirty |= R_ALL; - } - } + switch (mode) { + case M_EDIT: process_edit_keys(key, mod_key, is_held_key); break; + case M_LIVE: process_live_keys(key, mod_key, is_held_key); break; + case M_PATTERN: process_pattern_keys(key, mod_key, is_held_key); break; + case M_PRESET_W: + process_preset_w_keys(key, mod_key, is_held_key); break; - - default: - if (mod_ALT) { // ALT - if (key == 0x1b) { // x CUT - if (mode == M_EDIT || mode == M_LIVE) { - memcpy(&input_buffer, &input, sizeof(input)); - if (mode == M_LIVE) { - for (size_t n = 0; n < 32; n++) input[n] = 0; - pos = 0; - } - else { - if (tele_get_script_l(edit)) { - tele_set_script_l(edit, - tele_get_script_l(edit) - 1); - for (size_t n = edit_line; - n < tele_get_script_l(edit); n++) { - tele_set_script_c( - edit, n, - tele_get_script_c(edit, n + 1)); - } - - tele_command_t blank_command; - blank_command.l = 0; - tele_set_script_c(edit, tele_get_script_l(edit), - &blank_command); - if (edit_line > tele_get_script_l(edit)) { - edit_line = tele_get_script_l(edit); - } - print_command( - tele_get_script_c(edit, edit_line), input); - pos = strlen(input); - } - - r_edit_dirty |= R_LIST; - } - } - else if (mode == M_TRACK) { - num_buffer = tele_get_pattern_val( - edit_pattern, edit_index + offset_index); - for (int i = edit_index + offset_index; i < 63; i++) { - int16_t v = - tele_get_pattern_val(edit_pattern, i + 1); - tele_set_pattern_val(edit_pattern, i, v); - } - - uint16_t l = tele_get_pattern_l(edit_pattern); - if (l > edit_index + offset_index) { - tele_set_pattern_l(edit_pattern, l - 1); - } - r_edit_dirty |= R_ALL; - } - } - else if (key == 0x06) { // c COPY - if (mode == M_EDIT || mode == M_LIVE) { - memcpy(&input_buffer, &input, sizeof(input)); - } - else if (mode == M_TRACK) { - num_buffer = tele_get_pattern_val( - edit_pattern, edit_index + offset_index); - r_edit_dirty |= R_ALL; - } - } - else if (key == 0x19) { // v PASTE - if (mode == M_EDIT || mode == M_LIVE) { - memcpy(&input, &input_buffer, sizeof(input)); - pos = strlen(input); - } - else if (mode == M_TRACK) { - if (mod_SH) { - for (int i = 63; i > edit_index + offset_index; - i--) { - int16_t v = - tele_get_pattern_val(edit_pattern, i - 1); - tele_set_pattern_val(edit_pattern, i, v); - } - uint16_t l = tele_get_pattern_l(edit_pattern); - if (l >= edit_index + offset_index && l < 63) { - tele_set_pattern_l(edit_pattern, l + 1); - } - } - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, - num_buffer); - r_edit_dirty |= R_ALL; - } - } - else if (mode == M_TRACK) { - u8 n = hid_to_ascii_raw(key); - if (n == 'L') { - uint16_t l = tele_get_pattern_l(edit_pattern); - if (l) { - offset_index = ((l - 1) >> 3) << 3; - edit_index = (l - 1) & 0x7; - - int8_t delta = edit_index - 3; - - if ((offset_index + delta > 0) && - (offset_index + delta < 56)) { - offset_index += delta; - edit_index = 3; - } - } - else { - offset_index = 0; - edit_index = 0; - } - r_edit_dirty |= R_ALL; - } - else if (n == 'S') { - int16_t start = tele_get_pattern_start(edit_pattern); - if (start) { - offset_index = (start >> 3) << 3; - edit_index = start & 0x7; - - int8_t delta = edit_index - 3; - - if ((offset_index + delta > 0) && - (offset_index + delta < 56)) { - offset_index += delta; - edit_index = 3; - } - } - else { - offset_index = 0; - edit_index = 0; - } - r_edit_dirty |= R_ALL; - } - else if (n == 'E') { - int16_t end = tele_get_pattern_end(edit_pattern); - if (end) { - offset_index = (end >> 3) << 3; - edit_index = end & 0x7; - - int8_t delta = edit_index - 3; - - if ((offset_index + delta > 0) && - (offset_index + delta < 56)) { - offset_index += delta; - edit_index = 3; - } - } - else { - offset_index = 0; - edit_index = 0; - } - r_edit_dirty |= R_ALL; - } - } - } - else if (mod_SH && mode == M_TRACK) { - u8 n = hid_to_ascii_raw(key); - if (n == 'L') { - tele_set_pattern_l(edit_pattern, - edit_index + offset_index + 1); - r_edit_dirty |= R_ALL; - } - else if (n == 'S') { - tele_set_pattern_start(edit_pattern, - offset_index + edit_index); - } - else if (n == 'E') { - tele_set_pattern_end(edit_pattern, - offset_index + edit_index); - } - } - else if (mod_META) { - u8 n = hid_to_ascii_raw(key); - - if (n > 0x30 && n < 0x039) { - if (mod_SH) { - mutes[n - 0x31] ^= 1; - activity |= A_MUTES; - } - else - tele_script(n - 0x30); - } - else if (n == 'M') { - run_script(METRO_SCRIPT); - } - else if (n == 'I') { - run_script(INIT_SCRIPT); - } - } - else if (mode == M_TRACK) { - u8 n = hid_to_ascii(key, mod_key); - - if (n > 0x2F && n < 0x03A) { - int16_t v = tele_get_pattern_val(edit_pattern, - edit_index + offset_index); - if (v && v < 3276 && v > -3276) { - v = v * 10; - if (v > 0) - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, - v + n - 0x30); - else - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, - v - n - 0x30); - } - else - tele_set_pattern_val( - edit_pattern, edit_index + offset_index, n - 0x30); - r_edit_dirty |= R_ALL; - } - else if (n == 0x2D) { // - - int16_t v = tele_get_pattern_val(edit_pattern, - edit_index + offset_index); - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, -v); - r_edit_dirty |= R_ALL; - } - else if (n == 0x20) { // space - if (tele_get_pattern_val(edit_pattern, - edit_index + offset_index)) - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, 0); - else - tele_set_pattern_val(edit_pattern, - edit_index + offset_index, 1); - r_edit_dirty |= R_ALL; - } - } - else { /// NORMAL TEXT ENTRY - if (key > 0x58 && key < 0x61) { tele_script(key - 0x58); } - if (pos < 29) { - // print_dbg_char(hid_to_ascii(frame[i], - // frame[0])); - u8 n = hid_to_ascii(key, mod_key); - if (n) { - for (int x = 31; x > pos; x--) input[x] = input[x - 1]; - - input[pos] = n; - pos++; - } - // pos++; - // input[pos] = 0; - } - } - + case M_PRESET_R: + process_preset_r_keys(key, mod_key, is_held_key); break; + case M_HELP: process_help_keys(key, mod_key, is_held_key); break; } - - r_edit_dirty |= R_INPUT; } -u8 flash_is_fresh(void) { - return (f.fresh != FIRSTRUN_KEY); - // return 0; - // flashc_memcpy((void *)&flashy.fresh, &i, sizeof(flashy.fresh), true); - // flashc_memset32((void*)&(flashy.fresh), fresh_MAGIC, 4, true); - // flashc_memset((void *)nvram_data, 0x00, 8, sizeof(*nvram_data), true); -} - -// write fresh status -void flash_unfresh(void) { - flashc_memset8((void*)&(f.fresh), FIRSTRUN_KEY, 1, true); -} +bool process_global_keys(uint8_t k, uint8_t m, bool is_held_key) { + if (is_held_key) // none of these want to work with held keys + return false; -void flash_write(void) { - flashc_memcpy((void*)&f.s[preset_select].script, tele_script_ptr(), - tele_script_size(), true); - flashc_memcpy((void*)&f.s[preset_select].patterns, tele_patterns_ptr(), - tele_patterns_size(), true); - flashc_memcpy((void*)&f.s[preset_select].text, &scene_text, - sizeof(scene_text), true); - flashc_memset8((void*)&(f.scene), preset_select, 1, true); + // : change modes, live to edit to pattern and back + if (match_no_mod(m, k, HID_TAB)) { + if (mode == M_LIVE) + set_mode(M_EDIT); + else if (mode == M_EDIT) + set_mode(M_PATTERN); + else + set_mode(M_LIVE); + return true; + } + // : preset read mode, or return to last mode + else if (match_no_mod(m, k, HID_ESCAPE)) { + if (mode == M_PRESET_R) + set_last_mode(); + else { + set_mode(M_PRESET_R); + } + return true; + } + // alt-: preset write mode + else if (match_alt(m, k, HID_ESCAPE)) { + set_mode(M_PRESET_W); + return true; + } + // win-: clear delays, stack and slews + else if (match_win(m, k, HID_ESCAPE)) { + if (!is_held_key) { + clear_delays(&scene_state); + for (int i = 0; i < 4; i++) { aout[i].step = 1; } + } + return true; + } + // : help text, or return to last mode + else if (match_no_mod(m, k, HID_PRINTSCREEN)) { + if (mode == M_HELP) + set_last_mode(); + else { + set_mode(M_HELP); + } + return true; + } + // through : run corresponding script + // : run metro script + // : run init script + else if (no_mod(m) && k >= HID_F1 && k <= HID_F10) { + run_script(&scene_state, k - HID_F1); + return true; + } + // alt- through alt-: edit corresponding script + // alt-: edit metro script + // alt-: edit init script + else if (mod_only_alt(m) && k >= HID_F1 && k <= HID_F10) { + set_edit_mode_script(k - HID_F1); + set_mode(M_EDIT); + return true; + } + // through : run corresponding script + else if (no_mod(m) && k >= HID_KEYPAD_1 && k <= HID_KEYPAD_8) { + run_script(&scene_state, k - HID_KEYPAD_1); + return true; + } + else { + return false; + } } -void flash_read(void) { - memcpy(tele_script_ptr(), &f.s[preset_select].script, tele_script_size()); - memcpy(tele_patterns_ptr(), &f.s[preset_select].patterns, - tele_patterns_size()); - memcpy(&scene_text, &f.s[preset_select].text, sizeof(scene_text)); - flashc_memset8((void*)&(f.scene), preset_select, 1, true); -} +//////////////////////////////////////////////////////////////////////////////// +// other void render_init(void) { region_alloc(&line[0]); @@ -1711,30 +566,35 @@ void render_init(void) { } -void tele_metro(int16_t m, int16_t m_act, uint8_t m_reset) { - metro_time = m; +//////////////////////////////////////////////////////////////////////////////// +// teletype_io.h + +void tele_metro_updated() { + uint32_t metro_time = scene_state.variables.m; - if (m_act && !metro_act) { - // print_dbg("\r\nTURN ON METRO"); - metro_act = 1; - if (tele_get_script_l(METRO_SCRIPT)) activity |= A_METRO; + bool m_act = scene_state.variables.m_act > 0; + if (metro_time < 10) metro_time = 10; + + if (m_act && !metro_timer_enabled) { // enable the timer timer_add(&metroTimer, metro_time, &metroTimer_callback, NULL); + metro_timer_enabled = true; } - else if (!m_act && metro_act) { - // print_dbg("\r\nTURN OFF METRO"); - metro_act = 0; + else if (!m_act && metro_timer_enabled) { // disable the timer timer_remove(&metroTimer); + metro_timer_enabled = false; } - else if (!m_reset) { - // print_dbg("\r\nSET METRO"); + else if (metro_timer_enabled) { // just update the time timer_set(&metroTimer, metro_time); } - else { - // print_dbg("\r\nRESET METRO"); - timer_reset(&metroTimer); - } - if (!metro_act) activity &= ~A_METRO; + if (metro_timer_enabled && ss_get_script_len(&scene_state, METRO_SCRIPT)) + set_metro_icon(true); + else + set_metro_icon(false); +} + +void tele_metro_reset() { + if (metro_timer_enabled) { timer_reset(&metroTimer); } } void tele_tr(uint8_t i, int16_t v) { @@ -1770,58 +630,12 @@ void tele_cv_slew(uint8_t i, int16_t v) { if (aout[i].slew == 0) aout[i].slew = 1; } -void tele_delay(uint8_t i) { - if (i) { activity |= A_DELAY; } - else - activity &= ~A_DELAY; -} - -void tele_s(uint8_t i) { - if (i) { activity |= A_Q; } - else - activity &= ~A_Q; -} - void tele_cv_off(uint8_t i, int16_t v) { aout[i].off = v; } -void tele_ii(uint8_t i, int16_t d) { - static event_t e; - e.type = kEventII; - e.data = (d << 16) + i; - event_post(&e); -} - void tele_ii_tx(uint8_t addr, uint8_t* data, uint8_t l) { i2c_master_tx(addr, data, l); - /* - int i = 0, n; - - if (i2c_waiting_count < I2C_QUEUE_SIZE) { - while (i2c_queue[i].waiting == true) i++; - - i2c_queue[i].waiting = true; - i2c_queue[i].addr = addr; - i2c_queue[i].l = l; - - for (n = 0; n < l; n++) i2c_queue[i].d[n] = data[n]; - - i2c_waiting_count++; - - static event_t e; - e.type = kEventIItx; - e.data = i; - event_post(&e); - } - else { - print_dbg("\r\ni2c queue full"); - } - */ -} - -void tele_ii_tx_now(uint8_t addr, uint8_t* data, uint8_t l) { - i2c_master_tx(addr, data, l); } void tele_ii_rx(uint8_t addr, uint8_t* data, uint8_t l) { @@ -1830,459 +644,20 @@ void tele_ii_rx(uint8_t addr, uint8_t* data, uint8_t l) { void tele_scene(uint8_t i) { preset_select = i; - flash_read(); -} - -void tele_pi() { - if (mode == M_TRACK) r_edit_dirty |= R_ALL; -} - -int8_t script_caller; -void tele_script(uint8_t a) { - if (!script_caller) { - script_caller = a; - run_script(a - 1); - } - else if (a != script_caller) { - run_script(a - 1); - } - - script_caller = 0; + flash_read(i, &scene_state, &scene_text); } void tele_kill() { for (int i = 0; i < 4; i++) aout[i].step = 1; } -void tele_mute(uint8_t i, uint8_t s) { - mutes[i] = s; - activity |= A_MUTES; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -// usb disk - -static void tele_usb_disk() { - uint8_t usb_retry = 15; - print_dbg("\r\nusb"); - while (usb_retry--) { - print_dbg("."); - - if (!uhi_msc_is_available()) { - uint8_t lun, lun_state = 0; - - for (lun = 0; (lun < uhi_msc_mem_get_lun()) && (lun < 8); lun++) { - // print_dbg("\r\nlun: "); - // print_dbg_ulong(lun); - - // Mount drive - nav_drive_set(lun); - if (!nav_partition_mount()) { - if (fs_g_status == FS_ERR_HW_NO_PRESENT) { - // The test can not be done, if LUN is not present - lun_state &= ~(1 << lun); // LUN test reseted - continue; - } - lun_state |= (1 << lun); // LUN test is done. - print_dbg("\r\nfail"); - // ui_test_finish(false); // Test fail - continue; - } - // Check if LUN has been already tested - if (lun_state & (1 << lun)) { continue; } - - // WRITE SCENES - char filename[13]; - strcpy(filename, "tt00s.txt"); - - print_dbg("\r\nwriting scenes"); - strcpy(input_buffer, "WRITE"); - region_fill(&line[0], 0); - font_string_region_clip_tab(&line[0], input_buffer, 2, 0, 0xa, - 0); - region_draw(&line[0]); - - for (int i = 0; i < SCENE_SLOTS; i++) { - strcat(input_buffer, "."); - region_fill(&line[0], 0); - font_string_region_clip_tab(&line[0], input_buffer, 2, 0, - 0xa, 0); - region_draw(&line[0]); - - memcpy(tele_script_ptr(), &f.s[i].script, - tele_script_size()); - memcpy(tele_patterns_ptr(), &f.s[i].patterns, - tele_patterns_size()); - memcpy(&scene_text, &f.s[i].text, sizeof(scene_text)); - - if (!nav_file_create((FS_STRING)filename)) { - if (fs_g_status != FS_ERR_FILE_EXIST) { - if (fs_g_status == FS_LUN_WP) { - // Test can be done only on no write protected - // device - continue; - } - lun_state |= (1 << lun); // LUN test is done. - print_dbg("\r\nfail"); - continue; - } - } - if (!file_open(FOPEN_MODE_W)) { - if (fs_g_status == FS_LUN_WP) { - // Test can be done only on no write protected - // device - continue; - } - lun_state |= (1 << lun); // LUN test is done. - print_dbg("\r\nfail"); - continue; - } - - char blank = 0; - for (int l = 0; l < SCENE_TEXT_LINES; l++) { - if (strlen(scene_text[l])) { - file_write_buf((uint8_t*)scene_text[l], - strlen(scene_text[l])); - file_putc('\n'); - blank = 0; - } - else if (!blank) { - file_putc('\n'); - blank = 1; - } - } - - char input[36]; - for (int s = 0; s < 10; s++) { - file_putc('\n'); - file_putc('\n'); - file_putc('#'); - if (s == 8) - file_putc('M'); - else if (s == 9) - file_putc('I'); - else - file_putc(s + 49); - - for (int l = 0; l < tele_get_script_l(s); l++) { - file_putc('\n'); - print_command(tele_get_script_c(s, l), input); - file_write_buf((uint8_t*)input, strlen(input)); - } - } - - file_putc('\n'); - file_putc('\n'); - file_putc('#'); - file_putc('P'); - file_putc('\n'); - - for (int b = 0; b < 4; b++) { - itoa(tele_get_pattern_l(b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); - if (b == 3) - file_putc('\n'); - else - file_putc('\t'); - } - - for (int b = 0; b < 4; b++) { - itoa(tele_get_pattern_wrap(b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); - if (b == 3) - file_putc('\n'); - else - file_putc('\t'); - } - - for (int b = 0; b < 4; b++) { - itoa(tele_get_pattern_start(b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); - if (b == 3) - file_putc('\n'); - else - file_putc('\t'); - } - - for (int b = 0; b < 4; b++) { - itoa(tele_get_pattern_end(b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); - if (b == 3) - file_putc('\n'); - else - file_putc('\t'); - } - - file_putc('\n'); - - for (int l = 0; l < 64; l++) { - for (int b = 0; b < 4; b++) { - itoa(tele_get_pattern_val(b, l), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); - if (b == 3) - file_putc('\n'); - else - file_putc('\t'); - } - } - - file_close(); - lun_state |= (1 << lun); // LUN test is done. - - if (filename[3] == '9') { - filename[3] = '0'; - filename[2]++; - } - else - filename[3]++; - - print_dbg("."); - } - - nav_filelist_reset(); - - - // READ SCENES - strcpy(filename, "tt00.txt"); - print_dbg("\r\nreading scenes..."); - - strcpy(input_buffer, "READ"); - region_fill(&line[1], 0); - font_string_region_clip_tab(&line[1], input_buffer, 2, 0, 0xa, - 0); - region_draw(&line[1]); - - for (int i = 0; i < SCENE_SLOTS; i++) { - strcat(input_buffer, "."); - region_fill(&line[1], 0); - font_string_region_clip_tab(&line[1], input_buffer, 2, 0, - 0xa, 0); - region_draw(&line[1]); - delay_ms(50); - if (nav_filelist_findname(filename, 0)) { - print_dbg("\r\nfound: "); - print_dbg(filename); - if (!file_open(FOPEN_MODE_R)) - print_dbg("\r\ncan't open"); - else { - tele_mem_clear(); - - char c; - uint8_t l = 0; - uint8_t p = 0; - int8_t s = 99; - uint8_t b = 0; - uint16_t num = 0; - int8_t neg = 1; - - while (!file_eof() && s != -1) { - c = toupper(file_getc()); - // print_dbg_char(c); - - if (c == '#') { - if (!file_eof()) { - c = toupper(file_getc()); - // print_dbg_char(c); - - if (c == 'M') - s = 8; - else if (c == 'I') - s = 9; - else if (c == 'P') - s = 10; - else { - s = c - 49; - if (s < 0 || s > 7) s = -1; - } - - l = 0; - p = 0; - - if (!file_eof()) - c = toupper(file_getc()); - } - else - s = -1; - - // print_dbg("\r\nsection: "); - // print_dbg_ulong(s); - } - // SCENE TEXT - else if (s == 99) { - if (c == '\n') { - l++; - p = 0; - } - else { - if (l < SCENE_TEXT_LINES && - p < SCENE_TEXT_CHARS) { - scene_text[l][p] = c; - p++; - } - } - } - // SCRIPTS - else if (s >= 0 && s <= 9) { - if (c == '\n') { - if (p && l < SCRIPT_MAX_COMMANDS) { - tele_command_t temp; - status = - parse(input, &temp, error_msg); - - if (status == E_OK) { - status = - validate(&temp, error_msg); - - if (status == E_OK) { - tele_set_script_c(s, l, - &temp); - memset(input, 0, - sizeof(input)); - tele_set_script_l( - s, - tele_get_script_l(s) + - 1); - } - else { - print_dbg("\r\nvalidate: "); - print_dbg( - tele_error(status)); - } - } - else { - print_dbg("\r\nERROR: "); - print_dbg(tele_error(status)); - print_dbg(" >> "); - char pcmd[32]; - print_command( - tele_get_script_c(s, l), - pcmd); - print_dbg(pcmd); - } - - l++; - p = 0; - } - } - else { - if (p < 32) input[p] = c; - p++; - } - } - // PATTERNS - // tele_patterns[]. l wrap start end v[64] - else if (s == 10) { - if (c == '\n' || c == '\t') { - if (b < 4) { - if (l > 3) { - tele_set_pattern_val(b, l - 4, - neg * num); - // print_dbg("\r\nset: "); - // print_dbg_ulong(b); - // print_dbg(" "); - // print_dbg_ulong(l-4); - // print_dbg(" "); - // print_dbg_ulong(num); - } - else if (l == 0) { - tele_set_pattern_l(b, num); - } - else if (l == 1) { - tele_set_pattern_wrap(b, num); - } - else if (l == 2) { - tele_set_pattern_start(b, num); - } - else if (l == 3) { - tele_set_pattern_end(b, num); - } - } - - b++; - num = 0; - neg = 1; - - if (c == '\n') { - if (p) l++; - if (l > 68) s = -1; - b = 0; - p = 0; - } - } - else { - if (c == '-') - neg = -1; - else if (c >= '0' && c <= '9') { - num = num * 10 + (c - 48); - // print_dbg("\r\nnum: "); - // print_dbg_ulong(num); - } - p++; - } - } - } - - - file_close(); - - preset_select = i; - flash_write(); - } - } - else - nav_filelist_reset(); - - if (filename[3] == '9') { - filename[3] = '0'; - filename[2]++; - } - else - filename[3]++; - - preset_select = 0; - } - } - - usb_retry = 0; - - nav_exit(); - region_fill(&line[0], 0); - region_fill(&line[1], 0); - tele_mem_clear(); - } - delay_ms(100); - } -} - -void tele_mem_clear(void) { - memset(tele_script_ptr(), 0, tele_script_size()); - memset(tele_patterns_ptr(), 0, tele_patterns_size()); - memset(&scene_text, 0, sizeof(scene_text)); -} bool tele_get_input_state(uint8_t n) { return gpio_get_pin_value(A00 + n) > 0; } -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // main int main(void) { @@ -2302,53 +677,24 @@ int main(void) { cpu_irq_enable(); init_usb_host(); - // init_monome(); - init_oled(); - init_i2c_master(); print_dbg("\r\n\n// teletype! //////////////////////////////// "); - print_dbg("\r\nflash size: "); - print_dbg_ulong(sizeof(f)); - tele_init(); + ss_init(&scene_state); - if (flash_is_fresh()) { - print_dbg("\r\n:::: first run, clearing flash"); + // prepare flash (if needed) + flash_prepare(); - for (preset_select = 0; preset_select < SCENE_SLOTS; preset_select++) { - flash_write(); - print_dbg("."); - } - preset_select = 0; - flashc_memset8((void*)&(f.scene), preset_select, 1, true); - flashc_memset8((void*)&(f.mode), M_LIVE, 1, true); - flash_unfresh(); - - // clear out some reasonable defaults - - // save all presets, clear glyphs - // for(i1=0;i1<8;i1++) { - // flashc_memcpy((void *)&flashy.es[i1], &es, sizeof(es), true); - // glyph[i1] = (1<: move down + if (match_no_mod(m, k, HID_DOWN)) { + base++; + if (base == 8) { + base = 7; + if (offset < 56) { offset++; } + } + dirty = true; + } + // alt-: move a page down + else if (match_alt(m, k, HID_DOWN)) { + if (offset < 48) + offset += 8; + else { + offset = 56; + base = 7; + } + dirty = true; + } + // : move up + else if (match_no_mod(m, k, HID_UP)) { + if (base) + base--; + else if (offset) + offset--; + dirty = true; + } + // alt-: move a page up + else if (match_alt(m, k, HID_UP)) { + if (offset > 8) { offset -= 8; } + else { + offset = 0; + base = 0; + } + dirty = true; + } + // : move left + else if (match_no_mod(m, k, HID_LEFT)) { + if (pattern > 0) pattern--; + dirty = true; + } + // alt-: move to the very left + else if (match_alt(m, k, HID_LEFT)) { + base = 0; + offset = 0; + dirty = true; + } + // : move right + else if (match_no_mod(m, k, HID_RIGHT)) { + if (pattern < 3) pattern++; + dirty = true; + } + // alt-: 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; + } + } + // : 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-: 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; + } + // : 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-: 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; + } + // : 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; +} diff --git a/module/pattern_mode.h b/module/pattern_mode.h new file mode 100644 index 00000000..a9b9c0a8 --- /dev/null +++ b/module/pattern_mode.h @@ -0,0 +1,12 @@ +#ifndef _PATTERN_MODE_H_ +#define _PATTERN_MODE_H_ + +#include +#include + +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 diff --git a/module/preset_r_mode.c b/module/preset_r_mode.c new file mode 100644 index 00000000..2775cdb2 --- /dev/null +++ b/module/preset_r_mode.c @@ -0,0 +1,94 @@ +#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" + +static uint8_t offset; +static uint8_t knob_last; +static 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) { + // 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; + } + } + // 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; + } + } + // 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; + } + // 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; + } + // : load preset + else if (match_no_mod(m, k, HID_ENTER) && !is_held_key) { + flash_read(preset_select, &scene_state, &scene_text); + 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], flash_scene_text(preset_select, 0), 2, 0, + 0xf, 1); + + + for (uint8_t y = 1; y < 8; y++) { + region_fill(&line[y], 0); + font_string_region_clip(&line[y], + flash_scene_text(preset_select, offset + y), 2, + 0, 0xa, 0); + } + + dirty = false; + return true; +}; diff --git a/module/preset_r_mode.h b/module/preset_r_mode.h new file mode 100644 index 00000000..e9f28c35 --- /dev/null +++ b/module/preset_r_mode.h @@ -0,0 +1,12 @@ +#ifndef _PRESET_R_MODE_H_ +#define _PRESET_R_MODE_H_ + +#include +#include + +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 diff --git a/module/preset_w_mode.c b/module/preset_w_mode.c new file mode 100644 index 00000000..3db48423 --- /dev/null +++ b/module/preset_w_mode.c @@ -0,0 +1,125 @@ +#include "preset_w_mode.h" + +#include + +// 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" + +static uint8_t edit_line; +static uint8_t edit_offset; +static 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; +static 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) { + // 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; + } + } + // 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 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-: 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, &scene_state, &scene_text); + 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; +} diff --git a/module/preset_w_mode.h b/module/preset_w_mode.h new file mode 100644 index 00000000..ece4aa73 --- /dev/null +++ b/module/preset_w_mode.h @@ -0,0 +1,11 @@ +#ifndef _PRESET_W_MODE_H_ +#define _PRESET_W_MODE_H_ + +#include +#include + +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 diff --git a/module/usb_disk_mode.c b/module/usb_disk_mode.c new file mode 100644 index 00000000..a7127f1a --- /dev/null +++ b/module/usb_disk_mode.c @@ -0,0 +1,400 @@ +#include "usb_disk_mode.h" + +#include +#include +#include + +// this +#include "flash.h" +#include "globals.h" +#include "teletype.h" + +// libavr32 +#include "font.h" +#include "region.h" +#include "util.h" + +// asf +#include "delay.h" +#include "fat.h" +#include "file.h" +#include "fs_com.h" +#include "navigation.h" +#include "print_funcs.h" +#include "uhi_msc.h" +#include "uhi_msc_mem.h" +#include "usb_protocol_msc.h" + + +void tele_usb_disk() { + char input_buffer[32]; + print_dbg("\r\nusb"); + + uint8_t lun_state = 0; + + for (uint8_t lun = 0; (lun < uhi_msc_mem_get_lun()) && (lun < 8); lun++) { + // print_dbg("\r\nlun: "); + // print_dbg_ulong(lun); + + // Mount drive + nav_drive_set(lun); + if (!nav_partition_mount()) { + if (fs_g_status == FS_ERR_HW_NO_PRESENT) { + // The test can not be done, if LUN is not present + lun_state &= ~(1 << lun); // LUN test reseted + continue; + } + lun_state |= (1 << lun); // LUN test is done. + print_dbg("\r\nfail"); + // ui_test_finish(false); // Test fail + continue; + } + // Check if LUN has been already tested + if (lun_state & (1 << lun)) { continue; } + + // WRITE SCENES + char filename[13]; + strcpy(filename, "tt00s.txt"); + + print_dbg("\r\nwriting scenes"); + strcpy(input_buffer, "WRITE"); + region_fill(&line[0], 0); + font_string_region_clip_tab(&line[0], input_buffer, 2, 0, 0xa, 0); + region_draw(&line[0]); + + for (int i = 0; i < SCENE_SLOTS; i++) { + scene_state_t scene; + ss_init(&scene); + + char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; + memset(text, 0, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); + + strcat(input_buffer, "."); + region_fill(&line[0], 0); + font_string_region_clip_tab(&line[0], input_buffer, 2, 0, 0xa, 0); + region_draw(&line[0]); + + flash_read(i, &scene, &text); + + if (!nav_file_create((FS_STRING)filename)) { + if (fs_g_status != FS_ERR_FILE_EXIST) { + if (fs_g_status == FS_LUN_WP) { + // Test can be done only on no write protected + // device + continue; + } + lun_state |= (1 << lun); // LUN test is done. + print_dbg("\r\nfail"); + continue; + } + } + if (!file_open(FOPEN_MODE_W)) { + if (fs_g_status == FS_LUN_WP) { + // Test can be done only on no write protected + // device + continue; + } + lun_state |= (1 << lun); // LUN test is done. + print_dbg("\r\nfail"); + continue; + } + + char blank = 0; + for (int l = 0; l < SCENE_TEXT_LINES; l++) { + if (strlen(text[l])) { + file_write_buf((uint8_t*)text[l], strlen(text[l])); + file_putc('\n'); + blank = 0; + } + else if (!blank) { + file_putc('\n'); + blank = 1; + } + } + + char input[36]; + for (int s = 0; s < 10; s++) { + file_putc('\n'); + file_putc('\n'); + file_putc('#'); + if (s == 8) + file_putc('M'); + else if (s == 9) + file_putc('I'); + else + file_putc(s + 49); + + for (int l = 0; l < ss_get_script_len(&scene, s); l++) { + file_putc('\n'); + print_command(ss_get_script_command(&scene, s, l), input); + file_write_buf((uint8_t*)input, strlen(input)); + } + } + + file_putc('\n'); + file_putc('\n'); + file_putc('#'); + file_putc('P'); + file_putc('\n'); + + for (int b = 0; b < 4; b++) { + itoa(ss_get_pattern_len(&scene, b), input, 10); + file_write_buf((uint8_t*)input, strlen(input)); + if (b == 3) + file_putc('\n'); + else + file_putc('\t'); + } + + for (int b = 0; b < 4; b++) { + itoa(ss_get_pattern_wrap(&scene, b), input, 10); + file_write_buf((uint8_t*)input, strlen(input)); + if (b == 3) + file_putc('\n'); + else + file_putc('\t'); + } + + for (int b = 0; b < 4; b++) { + itoa(ss_get_pattern_start(&scene, b), input, 10); + file_write_buf((uint8_t*)input, strlen(input)); + if (b == 3) + file_putc('\n'); + else + file_putc('\t'); + } + + for (int b = 0; b < 4; b++) { + itoa(ss_get_pattern_end(&scene, b), input, 10); + file_write_buf((uint8_t*)input, strlen(input)); + if (b == 3) + file_putc('\n'); + else + file_putc('\t'); + } + + file_putc('\n'); + + for (int l = 0; l < 64; l++) { + for (int b = 0; b < 4; b++) { + itoa(ss_get_pattern_val(&scene, b, l), input, 10); + file_write_buf((uint8_t*)input, strlen(input)); + if (b == 3) + file_putc('\n'); + else + file_putc('\t'); + } + } + + file_close(); + lun_state |= (1 << lun); // LUN test is done. + + if (filename[3] == '9') { + filename[3] = '0'; + filename[2]++; + } + else + filename[3]++; + + print_dbg("."); + } + + nav_filelist_reset(); + + + // READ SCENES + strcpy(filename, "tt00.txt"); + print_dbg("\r\nreading scenes..."); + + strcpy(input_buffer, "READ"); + region_fill(&line[1], 0); + font_string_region_clip_tab(&line[1], input_buffer, 2, 0, 0xa, 0); + region_draw(&line[1]); + + for (int i = 0; i < SCENE_SLOTS; i++) { + scene_state_t scene; + ss_init(&scene); + char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; + memset(text, 0, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); + + strcat(input_buffer, "."); + region_fill(&line[1], 0); + font_string_region_clip_tab(&line[1], input_buffer, 2, 0, 0xa, 0); + region_draw(&line[1]); + if (nav_filelist_findname(filename, 0)) { + print_dbg("\r\nfound: "); + print_dbg(filename); + if (!file_open(FOPEN_MODE_R)) + print_dbg("\r\ncan't open"); + else { + char c; + uint8_t l = 0; + uint8_t p = 0; + int8_t s = 99; + uint8_t b = 0; + uint16_t num = 0; + int8_t neg = 1; + + char input[32]; + memset(input, 0, sizeof(input)); + + while (!file_eof() && s != -1) { + c = toupper(file_getc()); + // print_dbg_char(c); + + if (c == '#') { + if (!file_eof()) { + c = toupper(file_getc()); + // print_dbg_char(c); + + if (c == 'M') + s = 8; + else if (c == 'I') + s = 9; + else if (c == 'P') + s = 10; + else { + s = c - 49; + if (s < 0 || s > 7) s = -1; + } + + l = 0; + p = 0; + + if (!file_eof()) c = toupper(file_getc()); + } + else + s = -1; + + // print_dbg("\r\nsection: "); + // print_dbg_ulong(s); + } + // SCENE TEXT + else if (s == 99) { + if (c == '\n') { + l++; + p = 0; + } + else { + if (l < SCENE_TEXT_LINES && + p < SCENE_TEXT_CHARS) { + text[l][p] = c; + p++; + } + } + } + // SCRIPTS + else if (s >= 0 && s <= 9) { + if (c == '\n') { + if (p && l < SCRIPT_MAX_COMMANDS) { + tele_command_t temp; + error_t status; + char error_msg[TELE_ERROR_MSG_LENGTH]; + status = parse(input, &temp, error_msg); + + if (status == E_OK) { + status = validate(&temp, error_msg); + + if (status == E_OK) { + ss_overwrite_script_command( + &scene, s, l, &temp); + l++; + } + else { + print_dbg("\r\nvalidate: "); + print_dbg(tele_error(status)); + print_dbg(" >> "); + print_dbg("\r\nINPUT: "); + print_dbg(input); + } + } + else { + print_dbg("\r\nERROR: "); + print_dbg(tele_error(status)); + print_dbg(" >> "); + print_dbg("\r\nINPUT: "); + print_dbg(input); + } + + memset(input, 0, sizeof(input)); + p = 0; + } + } + else { + if (p < 32) input[p] = c; + p++; + } + } + // PATTERNS + // tele_patterns[]. l wrap start end v[64] + else if (s == 10) { + if (c == '\n' || c == '\t') { + if (b < 4) { + if (l > 3) { + ss_set_pattern_val(&scene, b, l - 4, + neg * num); + // print_dbg("\r\nset: "); + // print_dbg_ulong(b); + // print_dbg(" "); + // print_dbg_ulong(l-4); + // print_dbg(" "); + // print_dbg_ulong(num); + } + else if (l == 0) { + ss_set_pattern_len(&scene, b, num); + } + else if (l == 1) { + ss_set_pattern_wrap(&scene, b, num); + } + else if (l == 2) { + ss_set_pattern_start(&scene, b, num); + } + else if (l == 3) { + ss_set_pattern_end(&scene, b, num); + } + } + + b++; + num = 0; + neg = 1; + + if (c == '\n') { + if (p) l++; + if (l > 68) s = -1; + b = 0; + p = 0; + } + } + else { + if (c == '-') + neg = -1; + else if (c >= '0' && c <= '9') { + num = num * 10 + (c - 48); + // print_dbg("\r\nnum: "); + // print_dbg_ulong(num); + } + p++; + } + } + } + + + file_close(); + + flash_write(i, &scene, &text); + } + } + + nav_filelist_reset(); + + if (filename[3] == '9') { + filename[3] = '0'; + filename[2]++; + } + else + filename[3]++; + } + } + + nav_exit(); +} diff --git a/module/usb_disk_mode.h b/module/usb_disk_mode.h new file mode 100644 index 00000000..f7b85851 --- /dev/null +++ b/module/usb_disk_mode.h @@ -0,0 +1,6 @@ +#ifndef _USB_DISK_MODE_H_ +#define _USB_DISK_MODE_H_ + +void tele_usb_disk(void); + +#endif diff --git a/simulator/Makefile b/simulator/Makefile index 982a8a2d..936febd8 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -1,12 +1,15 @@ .PHONY: clean -CFLAGS=-std=c99 -g -Wall -DSIM -I. -I../src -I../libavr32/src +CFLAGS=-std=c99 -g -Wall -fno-common -DSIM -I. -I../src -I../libavr32/src DEPS = OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o \ + ../src/match_token.o ../src/scanner.o \ ../src/state.o ../src/table.o \ - ../src/ops/op.o ../src/ops/constants.o ../src/ops/controlflow.o \ - ../src/ops/delay.o ../src/ops/hardware.o ../src/ops/metronome.o \ - ../src/ops/maths.o ../src/ops/patterns.o ../src/ops/queue.o \ - ../src/ops/stack.o ../src/ops/telex.o ../src/ops/variables.o \ + ../src/ops/op.o ../src/ops/ansible.c ../src/ops/controlflow.o \ + ../src/ops/delay.o ../src/ops/earthsea.o ../src/ops/hardware.o \ + ../src/ops/justfriends.o ../src/ops/meadowphysics.o \ + ../src/ops/metronome.o ../src/ops/maths.o ../src/ops/orca.o \ + ../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \ + ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.c \ ../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \ ../libavr32/src/util.o @@ -16,6 +19,12 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o \ tt: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) +../src/match_token.c: ../src/match_token.rl + ragel -C -G2 ../src/match_token.rl -o ../src/match_token.c + +../src/scanner.c: ../src/scanner.rl + ragel -C -G2 ../src/scanner.rl -o ../src/scanner.c + clean: rm -f tt rm -rf tt.dSYM @@ -24,3 +33,5 @@ clean: rm -f ../src/ops/*.o rm -f ../libavr32/src/euclidean/*.o rm -f ../libavr32/src/*.o + rm -f ../src/match_token.c + rm -f ../src/scanner.c diff --git a/simulator/tt.c b/simulator/tt.c index e1dc4eb0..ea82fb98 100644 --- a/simulator/tt.c +++ b/simulator/tt.c @@ -11,9 +11,13 @@ #include "util.h" -void tele_metro(int16_t m, int16_t m_act, uint8_t m_reset) { - printf("METRO m:%" PRIi16 " m_act:%" PRIi16 "m_reset:%" PRIu8, m, m_act, - m_reset); +void tele_metro_updated() { + printf("METRO UPDATED"); + printf("\n"); +} + +void tele_metro_reset() { + printf("METRO RESET"); printf("\n"); } @@ -32,13 +36,13 @@ void tele_cv_slew(uint8_t i, int16_t v) { printf("\n"); } -void tele_delay(uint8_t i) { - printf("DELAY i:%" PRIu8, i); +void tele_has_delays(bool i) { + printf("DELAY i:%s", i ? "true" : "false"); printf("\n"); } -void tele_s(uint8_t i) { - printf("S i:%" PRIu8, i); +void tele_has_stack(bool i) { + printf("STACK i:%s", i ? "true" : "false"); printf("\n"); } @@ -47,23 +51,16 @@ void tele_cv_off(uint8_t i, int16_t v) { printf("\n"); } -void tele_ii(uint8_t i, int16_t d) { - printf("II i:%" PRIu8 " d:%" PRId16, i, d); - printf("\n"); -} - void tele_ii_tx(uint8_t addr, uint8_t *data, uint8_t l) { - printf("II_tx addr:%" PRIu8 " l:%" PRId16, addr, l); - printf("\n"); -} - -void tele_ii_tx_now(uint8_t addr, uint8_t *data, uint8_t l) { - printf("II_tx addr:%" PRIu8 " l:%" PRId16, addr, l); + printf("II_tx addr:%" PRIu8 " l:%" PRIu8, addr, l); printf("\n"); + for (size_t i = 0; i < l; i++) { + printf("[%" PRIuPTR "] = %" PRIu8 "\n", i, data[i]); + } } void tele_ii_rx(uint8_t addr, uint8_t *data, uint8_t l) { - printf("II_rx addr:%" PRIu8 " l:%" PRId16, addr, l); + printf("II_rx addr:%" PRIu8 " l:%" PRIu8, addr, l); printf("\n"); } @@ -72,12 +69,8 @@ void tele_scene(uint8_t i) { printf("\n"); } -void tele_pi() { - printf("PI"); - printf("\n"); -} -void tele_script(uint8_t a) { - printf("SCRIPT a:%" PRIu8, a); +void tele_pattern_updated() { + printf("PATTERN UPDATED"); printf("\n"); } @@ -86,8 +79,8 @@ void tele_kill() { printf("\n"); } -void tele_mute(uint8_t i, uint8_t s) { - printf("MUTE i:%" PRIu8 " s:%" PRIu8, i, s); +void tele_mute() { + printf("MUTE"); printf("\n"); } @@ -119,10 +112,11 @@ int main() { in = malloc(256); - tele_init(); - printf("teletype. (blank line quits)\n\n"); + scene_state_t ss; + ss_init(&ss); + do { printf("> "); fgets(in, 256, stdin); @@ -136,7 +130,7 @@ int main() { tele_command_t temp; exec_state_t es; es_init(&es); - char error_msg[ERROR_MSG_LENGTH]; + char error_msg[TELE_ERROR_MSG_LENGTH]; status = parse(in, &temp, error_msg); if (status == E_OK) { status = validate(&temp, error_msg); @@ -144,7 +138,7 @@ int main() { if (error_msg[0]) printf(": %s", error_msg); printf("\n"); if (status == E_OK) { - process_result_t output = process(&es, &temp); + process_result_t output = process_command(&ss, &es, &temp); if (output.has_value) { printf(">>> %i\n", output.value); } } } diff --git a/src/command.c b/src/command.c index a628cba5..9320afa4 100644 --- a/src/command.c +++ b/src/command.c @@ -10,30 +10,40 @@ void copy_command(tele_command_t *dst, const tele_command_t *src) { memcpy(dst, src, sizeof(tele_command_t)); } -void copy_sub_command(tele_command_t *dst, const tele_command_t *src) { - dst->l = src->l - src->separator - 1; +void copy_post_command(tele_command_t *dst, const tele_command_t *src) { + dst->length = src->length - src->separator - 1; dst->separator = -1; memcpy(dst->data, &src->data[src->separator + 1], - dst->l * sizeof(tele_data_t)); + dst->length * sizeof(tele_data_t)); } -void print_command(const tele_command_t *c, char *out) { - *out = 0; - for (int n = 0; n < c->l; n++) { - switch (c->data[n].t) { - case OP: strcat(out, tele_ops[c->data[n].v]->name); break; +void print_command(const tele_command_t *cmd, char *out) { + out[0] = 0; + for (size_t i = 0; i < cmd->length; i++) { + tele_word_t tag = cmd->data[i].tag; + int16_t value = cmd->data[i].value; + + switch (tag) { + case OP: strcat(out, tele_ops[value]->name); break; case NUMBER: { char number[8]; - itoa(c->data[n].v, number, 10); + itoa(value, number, 10); strcat(out, number); break; } - case MOD: strcat(out, tele_mods[c->data[n].v]->name); break; - case SEP: strcat(out, ":"); break; - default: break; + case MOD: strcat(out, tele_mods[value]->name); break; + case PRE_SEP: strcat(out, ":"); break; + case SUB_SEP: strcat(out, ";"); break; + } + + // do we need to add a space? + // first check if we're not at the end + if (i < cmd->length - 1) { + // otherwise, only add a space if the next tag is a not a seperator + tele_word_t next_tag = cmd->data[i + 1].tag; + if (next_tag != PRE_SEP && next_tag != SUB_SEP) { + strcat(out, " "); + } } - strcat(out, " "); } - size_t out_len = strlen(out); - if (out_len > 0) out[out_len - 1] = 0; } diff --git a/src/command.h b/src/command.h index 73556ef7..e16c6e9d 100644 --- a/src/command.h +++ b/src/command.h @@ -5,21 +5,21 @@ #define COMMAND_MAX_LENGTH 12 -typedef enum { NUMBER, MOD, SEP, OP } tele_word_t; +typedef enum { NUMBER, OP, MOD, PRE_SEP, SUB_SEP } tele_word_t; typedef struct { - tele_word_t t; - int16_t v; + tele_word_t tag; + int16_t value; } tele_data_t; typedef struct { - uint8_t l; + uint8_t length; int8_t separator; tele_data_t data[COMMAND_MAX_LENGTH]; } tele_command_t; void copy_command(tele_command_t *dst, const tele_command_t *src); -void copy_sub_command(tele_command_t *dst, const tele_command_t *src); +void copy_post_command(tele_command_t *dst, const tele_command_t *src); void print_command(const tele_command_t *c, char *out); #endif diff --git a/src/match_token.h b/src/match_token.h new file mode 100644 index 00000000..953044e7 --- /dev/null +++ b/src/match_token.h @@ -0,0 +1,11 @@ +#ifndef _MATCH_TOKEN_H_ +#define _MATCH_TOKEN_H_ + +#include +#include + +#include "command.h" + +bool match_token(const char *token, const size_t len, tele_data_t *out); + +#endif diff --git a/src/match_token.rl b/src/match_token.rl new file mode 100644 index 00000000..809db9d8 --- /dev/null +++ b/src/match_token.rl @@ -0,0 +1,435 @@ +#include "match_token.h" + +#include // isdigit +#include // rand, strtol + +#include + +#include "ops/op.h" +#include "ops/op_enum.h" + +%%{ + machine match_token; # declare our ragel machine + + number = '-'? digit+; + + main := |* + # NUMBERS + number => { MATCH_NUMBER() }; + + # OPS + # variables + "A" => { MATCH_OP(E_OP_A); }; + "B" => { MATCH_OP(E_OP_B); }; + "C" => { MATCH_OP(E_OP_C); }; + "D" => { MATCH_OP(E_OP_D); }; + "DRUNK" => { MATCH_OP(E_OP_DRUNK); }; + "DRUNK.MAX" => { MATCH_OP(E_OP_DRUNK_MAX); }; + "DRUNK.MIN" => { MATCH_OP(E_OP_DRUNK_MIN); }; + "DRUNK.WRAP" => { MATCH_OP(E_OP_DRUNK_WRAP); }; + "FLIP" => { MATCH_OP(E_OP_FLIP); }; + "I" => { MATCH_OP(E_OP_I); }; + "O" => { MATCH_OP(E_OP_O); }; + "O.INC" => { MATCH_OP(E_OP_O_INC); }; + "O.MAX" => { MATCH_OP(E_OP_O_MAX); }; + "O.MIN" => { MATCH_OP(E_OP_O_MIN); }; + "O.WRAP" => { MATCH_OP(E_OP_O_WRAP); }; + "T" => { MATCH_OP(E_OP_T); }; + "TIME" => { MATCH_OP(E_OP_TIME); }; + "TIME.ACT" => { MATCH_OP(E_OP_TIME_ACT); }; + "X" => { MATCH_OP(E_OP_X); }; + "Y" => { MATCH_OP(E_OP_Y); }; + "Z" => { MATCH_OP(E_OP_Z); }; + + # metronome + "M" => { MATCH_OP(E_OP_M); }; + "M.ACT" => { MATCH_OP(E_OP_M_ACT); }; + "M.RESET" => { MATCH_OP(E_OP_M_RESET); }; + + # patterns + "P.N" => { MATCH_OP(E_OP_P_N); }; + "P" => { MATCH_OP(E_OP_P); }; + "PN" => { MATCH_OP(E_OP_PN); }; + "P.L" => { MATCH_OP(E_OP_P_L); }; + "PN.L" => { MATCH_OP(E_OP_PN_L); }; + "P.WRAP" => { MATCH_OP(E_OP_P_WRAP); }; + "PN.WRAP" => { MATCH_OP(E_OP_PN_WRAP); }; + "P.START" => { MATCH_OP(E_OP_P_START); }; + "PN.START" => { MATCH_OP(E_OP_PN_START); }; + "P.END" => { MATCH_OP(E_OP_P_END); }; + "PN.END" => { MATCH_OP(E_OP_PN_END); }; + "P.I" => { MATCH_OP(E_OP_P_I); }; + "PN.I" => { MATCH_OP(E_OP_PN_I); }; + "P.HERE" => { MATCH_OP(E_OP_P_HERE); }; + "PN.HERE" => { MATCH_OP(E_OP_PN_HERE); }; + "P.NEXT" => { MATCH_OP(E_OP_P_NEXT); }; + "PN.NEXT" => { MATCH_OP(E_OP_PN_NEXT); }; + "P.PREV" => { MATCH_OP(E_OP_P_PREV); }; + "PN.PREV" => { MATCH_OP(E_OP_PN_PREV); }; + "P.INS" => { MATCH_OP(E_OP_P_INS); }; + "PN.INS" => { MATCH_OP(E_OP_PN_INS); }; + "P.RM" => { MATCH_OP(E_OP_P_RM); }; + "PN.RM" => { MATCH_OP(E_OP_PN_RM); }; + "P.PUSH" => { MATCH_OP(E_OP_P_PUSH); }; + "PN.PUSH" => { MATCH_OP(E_OP_PN_PUSH); }; + "P.POP" => { MATCH_OP(E_OP_P_POP); }; + "PN.POP" => { MATCH_OP(E_OP_PN_POP); }; + + # queue + "Q" => { MATCH_OP(E_OP_Q); }; + "Q.AVG" => { MATCH_OP(E_OP_Q_AVG); }; + "Q.N" => { MATCH_OP(E_OP_Q_N); }; + + # hardware + "CV" => { MATCH_OP(E_OP_CV); }; + "CV.OFF" => { MATCH_OP(E_OP_CV_OFF); }; + "CV.SLEW" => { MATCH_OP(E_OP_CV_SLEW); }; + "IN" => { MATCH_OP(E_OP_IN); }; + "PARAM" => { MATCH_OP(E_OP_PARAM); }; + "PRM" => { MATCH_OP(E_OP_PRM); }; + "TR" => { MATCH_OP(E_OP_TR); }; + "TR.POL" => { MATCH_OP(E_OP_TR_POL); }; + "TR.TIME" => { MATCH_OP(E_OP_TR_TIME); }; + "TR.TOG" => { MATCH_OP(E_OP_TR_TOG); }; + "TR.PULSE" => { MATCH_OP(E_OP_TR_PULSE); }; + "TR.P" => { MATCH_OP(E_OP_TR_P); }; + "CV.SET" => { MATCH_OP(E_OP_CV_SET); }; + "MUTE" => { MATCH_OP(E_OP_MUTE); }; + "STATE" => { MATCH_OP(E_OP_STATE); }; + + # maths + "ADD" => { MATCH_OP(E_OP_ADD); }; + "SUB" => { MATCH_OP(E_OP_SUB); }; + "MUL" => { MATCH_OP(E_OP_MUL); }; + "DIV" => { MATCH_OP(E_OP_DIV); }; + "MOD" => { MATCH_OP(E_OP_MOD); }; + "RAND" => { MATCH_OP(E_OP_RAND); }; + "RRAND" => { MATCH_OP(E_OP_RRAND); }; + "TOSS" => { MATCH_OP(E_OP_TOSS); }; + "MIN" => { MATCH_OP(E_OP_MIN); }; + "MAX" => { MATCH_OP(E_OP_MAX); }; + "LIM" => { MATCH_OP(E_OP_LIM); }; + "WRAP" => { MATCH_OP(E_OP_WRAP); }; + "QT" => { MATCH_OP(E_OP_QT); }; + "AVG" => { MATCH_OP(E_OP_AVG); }; + "EQ" => { MATCH_OP(E_OP_EQ); }; + "NE" => { MATCH_OP(E_OP_NE); }; + "LT" => { MATCH_OP(E_OP_LT); }; + "GT" => { MATCH_OP(E_OP_GT); }; + "NZ" => { MATCH_OP(E_OP_NZ); }; + "EZ" => { MATCH_OP(E_OP_EZ); }; + "RSH" => { MATCH_OP(E_OP_RSH); }; + "LSH" => { MATCH_OP(E_OP_LSH); }; + "EXP" => { MATCH_OP(E_OP_EXP); }; + "ABS" => { MATCH_OP(E_OP_ABS); }; + "AND" => { MATCH_OP(E_OP_AND); }; + "OR" => { MATCH_OP(E_OP_OR); }; + "XOR" => { MATCH_OP(E_OP_XOR); }; + "JI" => { MATCH_OP(E_OP_JI); }; + "SCALE" => { MATCH_OP(E_OP_SCALE); }; + "N" => { MATCH_OP(E_OP_N); }; + "V" => { MATCH_OP(E_OP_V); }; + "VV" => { MATCH_OP(E_OP_VV); }; + "ER" => { MATCH_OP(E_OP_ER); }; + "+" => { MATCH_OP(E_OP_SYM_PLUS); }; + "-" => { MATCH_OP(E_OP_SYM_DASH); }; + "*" => { MATCH_OP(E_OP_SYM_STAR); }; + "/" => { MATCH_OP(E_OP_SYM_FORWARD_SLASH); }; + "%" => { MATCH_OP(E_OP_SYM_PERCENTAGE); }; + "==" => { MATCH_OP(E_OP_SYM_EQUAL_x2); }; + "!=" => { MATCH_OP(E_OP_SYM_EXCLAMATION_EQUAL); }; + "<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED); }; + ">" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED); }; + "<=" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_EQUAL); }; + ">=" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_EQUAL); }; + "!" => { MATCH_OP(E_OP_SYM_EXCLAMATION); }; + "<<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_x2); }; + ">>" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_x2); }; + "&&" => { MATCH_OP(E_OP_AMPERSAND_x2); }; + "||" => { MATCH_OP(E_OP_PIPE_x2); }; + + # stack + "S.ALL" => { MATCH_OP(E_OP_S_ALL); }; + "S.POP" => { MATCH_OP(E_OP_S_POP); }; + "S.CLR" => { MATCH_OP(E_OP_S_CLR); }; + "S.L" => { MATCH_OP(E_OP_S_L); }; + + # controlflow + "SCRIPT" => { MATCH_OP(E_OP_SCRIPT); }; + "KILL" => { MATCH_OP(E_OP_KILL); }; + "SCENE" => { MATCH_OP(E_OP_SCENE); }; + + # delay + "DEL.CLR" => { MATCH_OP(E_OP_DEL_CLR); }; + + # whitewhale + "WW.PRESET" => { MATCH_OP(E_OP_WW_PRESET); }; + "WW.POS" => { MATCH_OP(E_OP_WW_POS); }; + "WW.SYNC" => { MATCH_OP(E_OP_WW_SYNC); }; + "WW.START" => { MATCH_OP(E_OP_WW_START); }; + "WW.END" => { MATCH_OP(E_OP_WW_END); }; + "WW.PMODE" => { MATCH_OP(E_OP_WW_PMODE); }; + "WW.PATTERN" => { MATCH_OP(E_OP_WW_PATTERN); }; + "WW.QPATTERN" => { MATCH_OP(E_OP_WW_QPATTERN); }; + "WW.MUTE1" => { MATCH_OP(E_OP_WW_MUTE1); }; + "WW.MUTE2" => { MATCH_OP(E_OP_WW_MUTE2); }; + "WW.MUTE3" => { MATCH_OP(E_OP_WW_MUTE3); }; + "WW.MUTE4" => { MATCH_OP(E_OP_WW_MUTE4); }; + "WW.MUTEA" => { MATCH_OP(E_OP_WW_MUTEA); }; + "WW.MUTEB" => { MATCH_OP(E_OP_WW_MUTEB); }; + + # earthsea + "MP.PRESET" => { MATCH_OP(E_OP_MP_PRESET); }; + "MP.RESET" => { MATCH_OP(E_OP_MP_RESET); }; + "MP.SYNC" => { MATCH_OP(E_OP_MP_SYNC); }; + "MP.MUTE" => { MATCH_OP(E_OP_MP_MUTE); }; + "MP.UNMUTE" => { MATCH_OP(E_OP_MP_UNMUTE); }; + "MP.FREEZE" => { MATCH_OP(E_OP_MP_FREEZE); }; + "MP.UNFREEZE" => { MATCH_OP(E_OP_MP_UNFREEZE); }; + "MP.STOP" => { MATCH_OP(E_OP_MP_STOP); }; + + # earthsea + "ES.PRESET" => { MATCH_OP(E_OP_ES_PRESET); }; + "ES.MODE" => { MATCH_OP(E_OP_ES_MODE); }; + "ES.CLOCK" => { MATCH_OP(E_OP_ES_CLOCK); }; + "ES.RESET" => { MATCH_OP(E_OP_ES_RESET); }; + "ES.PATTERN" => { MATCH_OP(E_OP_ES_PATTERN); }; + "ES.TRANS" => { MATCH_OP(E_OP_ES_TRANS); }; + "ES.STOP" => { MATCH_OP(E_OP_ES_STOP); }; + "ES.TRIPLE" => { MATCH_OP(E_OP_ES_TRIPLE); }; + "ES.MAGIC" => { MATCH_OP(E_OP_ES_MAGIC); }; + + # orca + "OR.TRK" => { MATCH_OP(E_OP_OR_TRK); }; + "OR.CLK" => { MATCH_OP(E_OP_OR_CLK); }; + "OR.DIV" => { MATCH_OP(E_OP_OR_DIV); }; + "OR.PHASE" => { MATCH_OP(E_OP_OR_PHASE); }; + "OR.RST" => { MATCH_OP(E_OP_OR_RST); }; + "OR.WGT" => { MATCH_OP(E_OP_OR_WGT); }; + "OR.MUTE" => { MATCH_OP(E_OP_OR_MUTE); }; + "OR.SCALE" => { MATCH_OP(E_OP_OR_SCALE); }; + "OR.BANK" => { MATCH_OP(E_OP_OR_BANK); }; + "OR.PRESET" => { MATCH_OP(E_OP_OR_PRESET); }; + "OR.RELOAD" => { MATCH_OP(E_OP_OR_RELOAD); }; + "OR.ROTS" => { MATCH_OP(E_OP_OR_ROTS); }; + "OR.ROTW" => { MATCH_OP(E_OP_OR_ROTW); }; + "OR.GRST" => { MATCH_OP(E_OP_OR_GRST); }; + "OR.CVA" => { MATCH_OP(E_OP_OR_CVA); }; + "OR.CVB" => { MATCH_OP(E_OP_OR_CVB); }; + + # ansible + "KR.PRE" => { MATCH_OP(E_OP_KR_PRESET); }; + "KR.PAT" => { MATCH_OP(E_OP_KR_PATTERN); }; + "KR.SCALE" => { MATCH_OP(E_OP_KR_SCALE); }; + "KR.PERIOD" => { MATCH_OP(E_OP_KR_PERIOD); }; + "KR.POS" => { MATCH_OP(E_OP_KR_POS); }; + "KR.L.ST" => { MATCH_OP(E_OP_KR_LOOP_ST); }; + "KR.L.LEN" => { MATCH_OP(E_OP_KR_LOOP_LEN); }; + "KR.RES" => { MATCH_OP(E_OP_KR_RESET); }; + "MP.PRE" => { MATCH_OP(E_OP_MP_PRESET1); }; + "MP.RES" => { MATCH_OP(E_OP_MP_RESET1); }; + "MP.OFF" => { MATCH_OP(E_OP_MP_STOP1); }; + "MP.SCALE" => { MATCH_OP(E_OP_MP_SCALE); }; + "MP.PERIOD" => { MATCH_OP(E_OP_MP_PERIOD); }; + "LV.PRE" => { MATCH_OP(E_OP_LV_PRESET); }; + "LV.RES" => { MATCH_OP(E_OP_LV_RESET); }; + "LV.POS" => { MATCH_OP(E_OP_LV_POS); }; + "LV.L.ST" => { MATCH_OP(E_OP_LV_L_ST); }; + "LV.L.LEN" => { MATCH_OP(E_OP_LV_L_LEN); }; + "LV.L.DIR" => { MATCH_OP(E_OP_LV_L_DIR); }; + "LV.CV" => { MATCH_OP(E_OP_LV_CV); }; + "CY.PRE" => { MATCH_OP(E_OP_CY_PRESET); }; + "CY.RES" => { MATCH_OP(E_OP_CY_RESET); }; + "CY.POS" => { MATCH_OP(E_OP_CY_POS); }; + "CY.REV" => { MATCH_OP(E_OP_CY_REV); }; + "CY.CV" => { MATCH_OP(E_OP_CY_CV); }; + "MID.SHIFT" => { MATCH_OP(E_OP_MID_SHIFT); }; + "MID.SLEW" => { MATCH_OP(E_OP_MID_SLEW); }; + "ARP.STY" => { MATCH_OP(E_OP_ARP_STYLE); }; + "ARP.HLD" => { MATCH_OP(E_OP_ARP_HOLD); }; + "ARP.RPT" => { MATCH_OP(E_OP_ARP_RPT); }; + "ARP.GT" => { MATCH_OP(E_OP_ARP_GATE); }; + "ARP.DIV" => { MATCH_OP(E_OP_ARP_DIV); }; + "ARP.RES" => { MATCH_OP(E_OP_ARP_RESET); }; + "ARP.SHIFT" => { MATCH_OP(E_OP_ARP_SHIFT); }; + "ARP.SLEW" => { MATCH_OP(E_OP_ARP_SLEW); }; + "ARP.FIL" => { MATCH_OP(E_OP_ARP_FILL); }; + "ARP.ROT" => { MATCH_OP(E_OP_ARP_ROT); }; + "ARP.ER" => { MATCH_OP(E_OP_ARP_ER); }; + + # justfriends + "JF.TR" => { MATCH_OP(E_OP_JF_TR); }; + "JF.RMODE" => { MATCH_OP(E_OP_JF_RMODE); }; + "JF.RUN" => { MATCH_OP(E_OP_JF_RUN); }; + "JF.SHIFT" => { MATCH_OP(E_OP_JF_SHIFT); }; + "JF.VTR" => { MATCH_OP(E_OP_JF_VTR); }; + "JF.MODE" => { MATCH_OP(E_OP_JF_MODE); }; + "JF.TICK" => { MATCH_OP(E_OP_JF_TICK); }; + "JF.VOX" => { MATCH_OP(E_OP_JF_VOX); }; + "JF.NOTE" => { MATCH_OP(E_OP_JF_NOTE); }; + "JF.GOD" => { MATCH_OP(E_OP_JF_GOD); }; + "JF.TUNE" => { MATCH_OP(E_OP_JF_TUNE); }; + "JF.QT" => { MATCH_OP(E_OP_JF_QT); }; + + # telex + "TO.TR" => { MATCH_OP(E_OP_TO_TR); }; + "TO.TR.TOG" => { MATCH_OP(E_OP_TO_TR_TOG); }; + "TO.TR.PULSE" => { MATCH_OP(E_OP_TO_TR_PULSE); }; + "TO.TR.TIME" => { MATCH_OP(E_OP_TO_TR_TIME); }; + "TO.TR.TIME.S" => { MATCH_OP(E_OP_TO_TR_TIME_S); }; + "TO.TR.TIME.M" => { MATCH_OP(E_OP_TO_TR_TIME_M); }; + "TO.TR.POL" => { MATCH_OP(E_OP_TO_TR_POL); }; + "TO.KILL" => { MATCH_OP(E_OP_TO_KILL); }; + + "TO.TR.PULSE.DIV" => { MATCH_OP(E_OP_TO_TR_PULSE_DIV); }; + "TO.TR.M" => { MATCH_OP(E_OP_TO_TR_M); }; + "TO.TR.M.S" => { MATCH_OP(E_OP_TO_TR_M_S); }; + "TO.TR.M.M" => { MATCH_OP(E_OP_TO_TR_M_M); }; + "TO.TR.M.BPM" => { MATCH_OP(E_OP_TO_TR_M_BPM); }; + "TO.TR.M.ACT" => { MATCH_OP(E_OP_TO_TR_M_ACT); }; + "TO.TR.M.SYNC" => { MATCH_OP(E_OP_TO_TR_M_SYNC); }; + "TO.TR.WIDTH" => { MATCH_OP(E_OP_TO_TR_WIDTH); }; + "TO.TR.M.COUNT" => { MATCH_OP(E_OP_TO_TR_M_COUNT); }; + + "TO.CV" => { MATCH_OP(E_OP_TO_CV); }; + "TO.CV.SLEW" => { MATCH_OP(E_OP_TO_CV_SLEW); }; + "TO.CV.SLEW.S" => { MATCH_OP(E_OP_TO_CV_SLEW_S); }; + "TO.CV.SLEW.M" => { MATCH_OP(E_OP_TO_CV_SLEW_M); }; + "TO.CV.SET" => { MATCH_OP(E_OP_TO_CV_SET); }; + "TO.CV.OFF" => { MATCH_OP(E_OP_TO_CV_OFF); }; + "TO.CV.QT" => { MATCH_OP(E_OP_TO_CV_QT); }; + "TO.CV.QT.SET" => { MATCH_OP(E_OP_TO_CV_QT_SET); }; + "TO.CV.N" => { MATCH_OP(E_OP_TO_CV_N); }; + "TO.CV.N.SET" => { MATCH_OP(E_OP_TO_CV_N_SET); }; + "TO.CV.SCALE" => { MATCH_OP(E_OP_TO_CV_SCALE); }; + + "TO.CV.INIT" => { MATCH_OP(E_OP_TO_CV_INIT); }; + "TO.TR.INIT" => { MATCH_OP(E_OP_TO_TR_INIT); }; + "TO.INIT" => { MATCH_OP(E_OP_TO_INIT); }; + + "TO.TR.P" => { MATCH_OP(E_OP_TO_TR_P); }; + "TO.TR.P.DIV" => { MATCH_OP(E_OP_TO_TR_P_DIV); }; + + "TO.OSC" => { MATCH_OP(E_OP_TO_OSC); }; + "TO.OSC.SET" => { MATCH_OP(E_OP_TO_OSC_SET); }; + "TO.OSC.QT" => { MATCH_OP(E_OP_TO_OSC_QT); }; + "TO.OSC.QT.SET" => { MATCH_OP(E_OP_TO_OSC_QT_SET); }; + "TO.OSC.FQ" => { MATCH_OP(E_OP_TO_OSC_FQ); }; + "TO.OSC.FQ.SET" => { MATCH_OP(E_OP_TO_OSC_FQ_SET); }; + "TO.OSC.N" => { MATCH_OP(E_OP_TO_OSC_N); }; + "TO.OSC.N.SET" => { MATCH_OP(E_OP_TO_OSC_N_SET); }; + "TO.OSC.LFO" => { MATCH_OP(E_OP_TO_OSC_LFO); }; + "TO.OSC.LFO.SET" => { MATCH_OP(E_OP_TO_OSC_LFO_SET); }; + "TO.OSC.WAVE" => { MATCH_OP(E_OP_TO_OSC_WAVE); }; + "TO.OSC.SYNC" => { MATCH_OP(E_OP_TO_OSC_SYNC); }; + "TO.OSC.PHASE" => { MATCH_OP(E_OP_TO_OSC_PHASE); }; + "TO.OSC.WIDTH" => { MATCH_OP(E_OP_TO_OSC_WIDTH); }; + "TO.OSC.RECT" => { MATCH_OP(E_OP_TO_OSC_RECT); }; + "TO.OSC.SLEW" => { MATCH_OP(E_OP_TO_OSC_SLEW); }; + "TO.OSC.SLEW.S" => { MATCH_OP(E_OP_TO_OSC_SLEW_S); }; + "TO.OSC.SLEW.M" => { MATCH_OP(E_OP_TO_OSC_SLEW_M); }; + "TO.OSC.SCALE" => { MATCH_OP(E_OP_TO_OSC_SCALE); }; + "TO.OSC.CYC" => { MATCH_OP(E_OP_TO_OSC_CYC); }; + "TO.OSC.CYC.S" => { MATCH_OP(E_OP_TO_OSC_CYC_S); }; + "TO.OSC.CYC.M" => { MATCH_OP(E_OP_TO_OSC_CYC_M); }; + "TO.OSC.CYC.SET" => { MATCH_OP(E_OP_TO_OSC_CYC_SET); }; + "TO.OSC.CYC.S.SET" => { MATCH_OP(E_OP_TO_OSC_CYC_S_SET); }; + "TO.OSC.CYC.M.SET" => { MATCH_OP(E_OP_TO_OSC_CYC_M_SET); }; + + "TO.ENV.ACT" => { MATCH_OP(E_OP_TO_ENV_ACT); }; + "TO.ENV.ATT" => { MATCH_OP(E_OP_TO_ENV_ATT); }; + "TO.ENV.ATT.S" => { MATCH_OP(E_OP_TO_ENV_ATT_S); }; + "TO.ENV.ATT.M" => { MATCH_OP(E_OP_TO_ENV_ATT_M); }; + "TO.ENV.DEC" => { MATCH_OP(E_OP_TO_ENV_DEC); }; + "TO.ENV.DEC.S" => { MATCH_OP(E_OP_TO_ENV_DEC_S); }; + "TO.ENV.DEC.M" => { MATCH_OP(E_OP_TO_ENV_DEC_M); }; + "TO.ENV.TRIG" => { MATCH_OP(E_OP_TO_ENV_TRIG); }; + + "TI.PARAM" => { MATCH_OP(E_OP_TI_PARAM); }; + "TI.PARAM.QT" => { MATCH_OP(E_OP_TI_PARAM_QT); }; + "TI.PARAM.N" => { MATCH_OP(E_OP_TI_PARAM_N); }; + "TI.PARAM.SCALE" => { MATCH_OP(E_OP_TI_PARAM_SCALE); }; + "TI.PARAM.MAP" => { MATCH_OP(E_OP_TI_PARAM_MAP); }; + "TI.IN" => { MATCH_OP(E_OP_TI_IN); }; + "TI.IN.QT" => { MATCH_OP(E_OP_TI_IN_QT); }; + "TI.IN.N" => { MATCH_OP(E_OP_TI_IN_N); }; + "TI.IN.SCALE" => { MATCH_OP(E_OP_TI_IN_SCALE); }; + "TI.IN.MAP" => { MATCH_OP(E_OP_TI_IN_MAP); }; + "TI.PARAM.CALIB" => { MATCH_OP(E_OP_TI_PARAM_CALIB); }; + "TI.IN.CALIB" => { MATCH_OP(E_OP_TI_IN_CALIB); }; + "TI.STORE" => { MATCH_OP(E_OP_TI_STORE); }; + "TI.RESET" => { MATCH_OP(E_OP_TI_RESET); }; + + "TI.PARAM.INIT" => { MATCH_OP(E_OP_TI_PARAM_INIT); }; + "TI.IN.INIT" => { MATCH_OP(E_OP_TI_IN_INIT); }; + "TI.INIT" => { MATCH_OP(E_OP_TI_INIT); }; + + "TI.PRM" => { MATCH_OP(E_OP_TI_PRM); }; + "TI.PRM.QT" => { MATCH_OP(E_OP_TI_PRM_QT); }; + "TI.PRM.N" => { MATCH_OP(E_OP_TI_PRM_N); }; + "TI.PRM.SCALE" => { MATCH_OP(E_OP_TI_PRM_SCALE); }; + "TI.PRM.MAP" => { MATCH_OP(E_OP_TI_PRM_MAP); }; + "TI.PRM.INIT" => { MATCH_OP(E_OP_TI_PRM_INIT); }; + + # MODS + # controlflow + "IF" => { MATCH_MOD(E_MOD_IF); }; + "ELIF" => { MATCH_MOD(E_MOD_ELIF); }; + "ELSE" => { MATCH_MOD(E_MOD_ELSE); }; + "L" => { MATCH_MOD(E_MOD_L); }; + + # delay + "PROB" => { MATCH_MOD(E_MOD_PROB); }; + "DEL" => { MATCH_MOD(E_MOD_DEL); }; + + # stack + "S" => { MATCH_MOD(E_MOD_S); }; + *|; + + write data; # write any ragel data here +}%% + +// these are our macros that are inserted into the code when Ragel finds a match +#define MATCH_OP(op) { out->tag = OP; out->value = op; no_of_tokens++; } +#define MATCH_MOD(mod) { out->tag = MOD; out->value = mod; no_of_tokens++; } +#define MATCH_NUMBER() \ + { \ + out->tag = NUMBER; \ + out->value = strtol(token, NULL, 0); \ + no_of_tokens++; \ + } + +// matches a single token, out contains the token, return value indicates +// success or failure +bool match_token(const char *token, const size_t len, tele_data_t *out) { + // required ragel declarations + int cs; // machine state + int act; // used with '=>' + const char* ts; // token start + const char* te; // token end + + const char* p = token; // pointer to data + const char* pe = token + len; // pointer to end of data + const char* eof = pe; // pointer to eof + (void)match_token_en_main; // fix unused variable warning + + int no_of_tokens = 0; + + %%{ + write init; # write initialisation + write exec; # run the machine + }%% + + // Ragel errors + if (cs == match_token_error || cs < match_token_first_final) { + return false; + } + // only 1 token! + else if (no_of_tokens != 1) { + return false; + } + else { + return true; + } + +} diff --git a/src/ops/ansible.c b/src/ops/ansible.c new file mode 100644 index 00000000..6b14a1e9 --- /dev/null +++ b/src/ops/ansible.c @@ -0,0 +1,684 @@ +#include "ops/ansible.h" + +#include "helpers.h" +#include "ii.h" +#include "teletype_io.h" + + +static void op_KR_PRESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_PRESET_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_PATTERN_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_PATTERN_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_SCALE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_SCALE_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_PERIOD_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_PERIOD_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_KR_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_KR_LOOP_ST_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_LOOP_ST_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_LOOP_LEN_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_LOOP_LEN_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_MP_PRESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_PRESET_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_STOP_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_SCALE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_SCALE_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_PERIOD_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MP_PERIOD_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_LV_PRESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_PRESET_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_LV_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_LV_L_ST_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_L_ST_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_L_LEN_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_L_LEN_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_L_DIR_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_L_DIR_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_LV_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + +static void op_CY_PRESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_CY_PRESET_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_CY_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_CY_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_CY_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_CY_REV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_CY_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + +static void op_MID_SHIFT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MID_SLEW_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_ARP_STYLE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_HOLD_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_RPT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_GATE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_DIV_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_SHIFT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_SLEW_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_FILL_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_ROT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_ARP_ER_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + + +// clang-format off +const tele_op_t op_KR_PRESET = MAKE_GET_SET_OP(KR.PRE , op_KR_PRESET_get , op_KR_PRESET_set , 0, true); +const tele_op_t op_KR_PATTERN = MAKE_GET_SET_OP(KR.PAT , op_KR_PATTERN_get , op_KR_PATTERN_set , 0, true); +const tele_op_t op_KR_SCALE = MAKE_GET_SET_OP(KR.SCALE , op_KR_SCALE_get , op_KR_SCALE_set , 0, true); +const tele_op_t op_KR_PERIOD = MAKE_GET_SET_OP(KR.PERIOD , op_KR_PERIOD_get , op_KR_PERIOD_set , 0, true); +const tele_op_t op_KR_POS = MAKE_GET_SET_OP(KR.POS , op_KR_POS_get , op_KR_POS_set , 2, true); +const tele_op_t op_KR_LOOP_ST = MAKE_GET_SET_OP(KR.L.ST , op_KR_LOOP_ST_get , op_KR_LOOP_ST_set , 2, true); +const tele_op_t op_KR_LOOP_LEN = MAKE_GET_SET_OP(KR.L.LEN , op_KR_LOOP_LEN_get , op_KR_LOOP_LEN_set , 2, true); +const tele_op_t op_KR_RESET = MAKE_GET_OP (KR.RES , op_KR_RESET_get , 2, false); + +const tele_op_t op_MP_PRESET1 = MAKE_GET_SET_OP(MP.PRE , op_MP_PRESET_get , op_MP_PRESET_set , 0, true); +const tele_op_t op_MP_RESET1 = MAKE_GET_OP (MP.RES , op_MP_RESET_get , 1, false); +const tele_op_t op_MP_STOP1 = MAKE_GET_OP (MP.OFF , op_MP_STOP_get , 1, false); +const tele_op_t op_MP_SCALE = MAKE_GET_SET_OP(MP.SCALE , op_MP_SCALE_get , op_MP_SCALE_set , 0, true); +const tele_op_t op_MP_PERIOD = MAKE_GET_SET_OP(MP.PERIOD , op_MP_PERIOD_get , op_MP_PERIOD_set , 0, true); + +const tele_op_t op_LV_PRESET = MAKE_GET_SET_OP(LV.PRE , op_LV_PRESET_get , op_LV_PRESET_set , 0, true); +const tele_op_t op_LV_RESET = MAKE_GET_OP(LV.RES , op_LV_RESET_get , 1, false); +const tele_op_t op_LV_POS = MAKE_GET_SET_OP(LV.POS , op_LV_POS_get , op_LV_POS_set , 0, true); +const tele_op_t op_LV_L_ST = MAKE_GET_SET_OP(LV.L.ST , op_LV_L_ST_get , op_LV_L_ST_set , 0, true); +const tele_op_t op_LV_L_LEN = MAKE_GET_SET_OP(LV.L.LEN , op_LV_L_LEN_get , op_LV_L_LEN_set , 0, true); +const tele_op_t op_LV_L_DIR = MAKE_GET_SET_OP(LV.L.DIR , op_LV_L_DIR_get , op_LV_L_DIR_set , 0, true); +const tele_op_t op_LV_CV = MAKE_GET_OP(LV.CV , op_LV_CV_get , 1, true); + +const tele_op_t op_CY_PRESET = MAKE_GET_SET_OP(CY.PRE , op_CY_PRESET_get , op_CY_PRESET_set , 0, true); +const tele_op_t op_CY_RESET = MAKE_GET_OP (CY.RES , op_CY_RESET_get , 1, false); +const tele_op_t op_CY_POS = MAKE_GET_SET_OP(CY.POS , op_CY_POS_get , op_CY_POS_set , 1, true); +const tele_op_t op_CY_REV = MAKE_GET_OP(CY.REV , op_CY_REV_get , 1, false); +const tele_op_t op_CY_CV = MAKE_GET_OP(CY.CV , op_CY_CV_get , 1, true); + +const tele_op_t op_MID_SHIFT = MAKE_GET_OP(MID.SHIFT , op_MID_SHIFT_get , 1, false); +const tele_op_t op_MID_SLEW = MAKE_GET_OP(MID.SLEW , op_MID_SLEW_get , 1, false); + +const tele_op_t op_ARP_STYLE = MAKE_GET_OP(ARP.STY , op_ARP_STYLE_get , 1, false); +const tele_op_t op_ARP_HOLD = MAKE_GET_OP(ARP.HLD , op_ARP_HOLD_get , 1, false); +const tele_op_t op_ARP_RPT = MAKE_GET_OP(ARP.RPT , op_ARP_RPT_get , 3, false); +const tele_op_t op_ARP_GATE = MAKE_GET_OP(ARP.GT , op_ARP_GATE_get , 2, false); +const tele_op_t op_ARP_DIV = MAKE_GET_OP(ARP.DIV , op_ARP_DIV_get , 2, false); +const tele_op_t op_ARP_RESET = MAKE_GET_OP(ARP.RES , op_ARP_RESET_get , 1, false); +const tele_op_t op_ARP_SHIFT = MAKE_GET_OP(ARP.SHIFT , op_ARP_SHIFT_get , 2, false); +const tele_op_t op_ARP_SLEW = MAKE_GET_OP(ARP.SLEW , op_ARP_SLEW_get , 2, false); +const tele_op_t op_ARP_FILL = MAKE_GET_OP(ARP.FIL , op_ARP_FILL_get , 2, false); +const tele_op_t op_ARP_ROT = MAKE_GET_OP(ARP.ROT , op_ARP_ROT_get , 2, false); +const tele_op_t op_ARP_ER = MAKE_GET_OP(ARP.ER , op_ARP_ER_get , 4, false); +// clang-format on + + +static void op_KR_PRESET_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_KR_PRESET, a }; + tele_ii_tx(II_KR_ADDR, d, 2); +} + +static void op_KR_PRESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_KR_PRESET | II_GET }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_PATTERN_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_KR_PATTERN, a }; + tele_ii_tx(II_KR_ADDR, d, 2); +} + +static void op_KR_PATTERN_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_KR_PATTERN | II_GET }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_SCALE_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_KR_SCALE, a }; + tele_ii_tx(II_KR_ADDR, d, 2); +} + +static void op_KR_SCALE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_KR_SCALE | II_GET }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_PERIOD_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_KR_PERIOD, a >> 8, a & 0xff }; + tele_ii_tx(II_KR_ADDR, d, 3); +} + +static void op_KR_PERIOD_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_KR_PERIOD | II_GET, 0 }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + d[1] = 0; + tele_ii_rx(addr, d, 2); + cs_push(cs, (d[0] << 8) + d[1]); +} + +static void op_KR_POS_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { II_KR_POS, a, b, c }; + tele_ii_tx(II_KR_ADDR, d, 4); +} + +static void op_KR_POS_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_KR_POS | II_GET, a, b }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 3); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_LOOP_ST_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { II_KR_LOOP_ST, a, b, c }; + tele_ii_tx(II_KR_ADDR, d, 4); +} + +static void op_KR_LOOP_ST_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_KR_LOOP_ST | II_GET, a, b }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 3); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_LOOP_LEN_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { II_KR_LOOP_LEN, a, b, c }; + tele_ii_tx(II_KR_ADDR, d, 4); +} + +static void op_KR_LOOP_LEN_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_KR_LOOP_LEN | II_GET, a, b }; + uint8_t addr = II_KR_ADDR; + tele_ii_tx(addr, d, 3); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_KR_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_KR_RESET, a, b }; + tele_ii_tx(II_KR_ADDR, d, 3); +} + +static void op_MP_PRESET_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MP_PRESET, a }; + tele_ii_tx(II_MP_ADDR, d, 2); +} + +static void op_MP_PRESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_MP_PRESET | II_GET }; + uint8_t addr = II_MP_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_MP_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MP_RESET, a }; + tele_ii_tx(II_MP_ADDR, d, 2); +} + +static void op_MP_STOP_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MP_STOP, a }; + tele_ii_tx(II_MP_ADDR, d, 2); +} + +static void op_MP_SCALE_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MP_SCALE, a }; + tele_ii_tx(II_MP_ADDR, d, 2); +} + +static void op_MP_SCALE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_MP_SCALE | II_GET }; + uint8_t addr = II_MP_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_MP_PERIOD_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MP_PERIOD, a >> 8, a & 0xff }; + tele_ii_tx(II_MP_ADDR, d, 3); +} + +static void op_MP_PERIOD_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_MP_PERIOD | II_GET, 0 }; + uint8_t addr = II_MP_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + d[1] = 0; + tele_ii_rx(addr, d, 2); + cs_push(cs, (d[0] << 8) + d[1]); +} + +static void op_LV_PRESET_set(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_PRESET, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_PRESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_LV_PRESET | II_GET }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_LV_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_RESET, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_POS, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs) { + uint8_t d[] = { II_LV_POS | II_GET }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_LV_L_ST_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_L_ST, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_L_ST_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + uint8_t d[] = { II_LV_L_ST | II_GET }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_LV_L_LEN_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_L_LEN, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_L_LEN_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + uint8_t d[] = { II_LV_L_LEN | II_GET }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_LV_L_DIR_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_LV_L_DIR, a }; + tele_ii_tx(II_LV_ADDR, d, 2); +} + +static void op_LV_L_DIR_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + uint8_t d[] = { II_LV_L_DIR | II_GET }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_LV_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs) { + int16_t a = cs_pop(cs); + a--; + uint8_t d[] = { II_LV_CV | II_GET, a & 0x3 }; + uint8_t addr = II_LV_ADDR; + tele_ii_tx(addr, d, 2); + d[0] = 0; + d[1] = 0; + tele_ii_rx(addr, d, 2); + cs_push(cs, (d[0] << 8) + d[1]); +} + +static void op_CY_PRESET_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_CY_PRESET, a }; + tele_ii_tx(II_CY_ADDR, d, 2); +} + +static void op_CY_PRESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { II_CY_PRESET | II_GET }; + uint8_t addr = II_CY_ADDR; + tele_ii_tx(addr, d, 1); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_CY_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_CY_RESET, a }; + tele_ii_tx(II_CY_ADDR, d, 2); +} + +static void op_CY_POS_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_CY_POS, a, b }; + tele_ii_tx(II_CY_ADDR, d, 3); +} + +static void op_CY_POS_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_CY_POS | II_GET, a }; + uint8_t addr = II_CY_ADDR; + tele_ii_tx(addr, d, 2); + d[0] = 0; + tele_ii_rx(addr, d, 1); + cs_push(cs, d[0]); +} + +static void op_CY_REV_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_CY_REV, a }; + tele_ii_tx(II_CY_ADDR, d, 2); +} + +static void op_CY_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs) { + int16_t a = cs_pop(cs); + a--; + uint8_t d[] = { II_CY_CV | II_GET, a & 0x3 }; + uint8_t addr = II_CY_ADDR; + tele_ii_tx(addr, d, 2); + d[0] = 0; + d[1] = 0; + tele_ii_rx(addr, d, 2); + cs_push(cs, (d[0] << 8) + d[1]); +} + +static void op_MID_SHIFT_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MID_SHIFT, a >> 8, a & 0xff }; + tele_ii_tx(II_MID_ADDR, d, 3); +} + +static void op_MID_SLEW_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_MID_SLEW, a >> 8, a & 0xff }; + tele_ii_tx(II_MID_ADDR, d, 3); +} + +static void op_ARP_STYLE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_ARP_STYLE, a }; + tele_ii_tx(II_ARP_ADDR, d, 2); +} + +static void op_ARP_HOLD_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_ARP_HOLD, a & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 2); +} + +static void op_ARP_RPT_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { II_ARP_RPT, a, b, c >> 8, c & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 5); +} + +static void op_ARP_GATE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_GATE, a & 0xff, b & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 3); +} + +static void op_ARP_DIV_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_DIV, a & 0xff, b & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 3); +} + +static void op_ARP_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { II_ARP_RESET, a }; + tele_ii_tx(II_ARP_ADDR, d, 2); +} + +static void op_ARP_SHIFT_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_SHIFT, a, b >> 8, b & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 4); +} + +static void op_ARP_SLEW_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_SLEW, a, b >> 8, b & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 4); +} + +static void op_ARP_FILL_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_FILL, a, b }; + tele_ii_tx(II_ARP_ADDR, d, 3); +} + +static void op_ARP_ROT_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { II_ARP_ROT, a, b >> 8, b & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 4); +} + +static void op_ARP_ER_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + int16_t e = cs_pop(cs); + uint8_t d[] = { II_ARP_ER, a, b, c, e >> 8, e & 0xff }; + tele_ii_tx(II_ARP_ADDR, d, 6); +} diff --git a/src/ops/ansible.h b/src/ops/ansible.h new file mode 100644 index 00000000..fe424681 --- /dev/null +++ b/src/ops/ansible.h @@ -0,0 +1,50 @@ +#ifndef _OPS_ANSIBLE_H_ +#define _OPS_ANSIBLE_H_ + +#include "ops/op.h" + +extern const tele_op_t op_KR_PRESET; +extern const tele_op_t op_KR_PATTERN; +extern const tele_op_t op_KR_SCALE; +extern const tele_op_t op_KR_PERIOD; +extern const tele_op_t op_KR_POS; +extern const tele_op_t op_KR_LOOP_ST; +extern const tele_op_t op_KR_LOOP_LEN; +extern const tele_op_t op_KR_RESET; + +extern const tele_op_t op_MP_PRESET1; +extern const tele_op_t op_MP_RESET1; +extern const tele_op_t op_MP_STOP1; +extern const tele_op_t op_MP_SCALE; +extern const tele_op_t op_MP_PERIOD; + +extern const tele_op_t op_LV_PRESET; +extern const tele_op_t op_LV_RESET; +extern const tele_op_t op_LV_POS; +extern const tele_op_t op_LV_L_ST; +extern const tele_op_t op_LV_L_LEN; +extern const tele_op_t op_LV_L_DIR; +extern const tele_op_t op_LV_CV; + +extern const tele_op_t op_CY_PRESET; +extern const tele_op_t op_CY_RESET; +extern const tele_op_t op_CY_POS; +extern const tele_op_t op_CY_REV; +extern const tele_op_t op_CY_CV; + +extern const tele_op_t op_MID_SHIFT; +extern const tele_op_t op_MID_SLEW; + +extern const tele_op_t op_ARP_STYLE; +extern const tele_op_t op_ARP_HOLD; +extern const tele_op_t op_ARP_RPT; +extern const tele_op_t op_ARP_GATE; +extern const tele_op_t op_ARP_DIV; +extern const tele_op_t op_ARP_RESET; +extern const tele_op_t op_ARP_SHIFT; +extern const tele_op_t op_ARP_SLEW; +extern const tele_op_t op_ARP_FILL; +extern const tele_op_t op_ARP_ROT; +extern const tele_op_t op_ARP_ER; + +#endif diff --git a/src/ops/constants.c b/src/ops/constants.c deleted file mode 100644 index c14ce373..00000000 --- a/src/ops/constants.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "ops/constants.h" -#include "ops/op.h" - -#include "ii.h" - -const tele_op_t op_WW_PRESET = MAKE_CONSTANT_OP(WW.PRESET, WW_PRESET); -const tele_op_t op_WW_POS = MAKE_CONSTANT_OP(WW.POS, WW_POS); -const tele_op_t op_WW_SYNC = MAKE_CONSTANT_OP(WW.SYNC, WW_SYNC); -const tele_op_t op_WW_START = MAKE_CONSTANT_OP(WW.START, WW_START); -const tele_op_t op_WW_END = MAKE_CONSTANT_OP(WW.END, WW_END); -const tele_op_t op_WW_PMODE = MAKE_CONSTANT_OP(WW.PMODE, WW_PMODE); -const tele_op_t op_WW_PATTERN = MAKE_CONSTANT_OP(WW.PATTERN, WW_PATTERN); -const tele_op_t op_WW_QPATTERN = MAKE_CONSTANT_OP(WW.QPATTERN, WW_QPATTERN); -const tele_op_t op_WW_MUTE1 = MAKE_CONSTANT_OP(WW.MUTE1, WW_MUTE1); -const tele_op_t op_WW_MUTE2 = MAKE_CONSTANT_OP(WW.MUTE2, WW_MUTE2); -const tele_op_t op_WW_MUTE3 = MAKE_CONSTANT_OP(WW.MUTE3, WW_MUTE3); -const tele_op_t op_WW_MUTE4 = MAKE_CONSTANT_OP(WW.MUTE4, WW_MUTE4); -const tele_op_t op_WW_MUTEA = MAKE_CONSTANT_OP(WW.MUTEA, WW_MUTEA); -const tele_op_t op_WW_MUTEB = MAKE_CONSTANT_OP(WW.MUTEB, WW_MUTEB); - -const tele_op_t op_MP_PRESET = MAKE_CONSTANT_OP(MP.PRESET, MP_PRESET); -const tele_op_t op_MP_RESET = MAKE_CONSTANT_OP(MP.RESET, MP_RESET); -const tele_op_t op_MP_SYNC = MAKE_CONSTANT_OP(MP.SYNC, MP_SYNC); -const tele_op_t op_MP_MUTE = MAKE_CONSTANT_OP(MP.MUTE, MP_MUTE); -const tele_op_t op_MP_UNMUTE = MAKE_CONSTANT_OP(MP.UNMUTE, MP_UNMUTE); -const tele_op_t op_MP_FREEZE = MAKE_CONSTANT_OP(MP.FREEZE, MP_FREEZE); -const tele_op_t op_MP_UNFREEZE = MAKE_CONSTANT_OP(MP.UNFREEZE, MP_UNFREEZE); -const tele_op_t op_MP_STOP = MAKE_CONSTANT_OP(MP.STOP, MP_STOP); - -const tele_op_t op_ES_PRESET = MAKE_CONSTANT_OP(ES.PRESET, ES_PRESET); -const tele_op_t op_ES_MODE = MAKE_CONSTANT_OP(ES.MODE, ES_MODE); -const tele_op_t op_ES_CLOCK = MAKE_CONSTANT_OP(ES.CLOCK, ES_CLOCK); -const tele_op_t op_ES_RESET = MAKE_CONSTANT_OP(ES.RESET, ES_RESET); -const tele_op_t op_ES_PATTERN = MAKE_CONSTANT_OP(ES.PATTERN, ES_PATTERN); -const tele_op_t op_ES_TRANS = MAKE_CONSTANT_OP(ES.TRANS, ES_TRANS); -const tele_op_t op_ES_STOP = MAKE_CONSTANT_OP(ES.STOP, ES_STOP); -const tele_op_t op_ES_TRIPLE = MAKE_CONSTANT_OP(ES.TRIPLE, ES_TRIPLE); -const tele_op_t op_ES_MAGIC = MAKE_CONSTANT_OP(ES.MAGIC, ES_MAGIC); - -const tele_op_t op_ORCA_TRK = MAKE_CONSTANT_OP(OR.TRK, ORCA_TRACK); -const tele_op_t op_ORCA_CLK = MAKE_CONSTANT_OP(OR.CLK, ORCA_CLOCK); -const tele_op_t op_ORCA_DIV = MAKE_CONSTANT_OP(OR.DIV, ORCA_DIVISOR); -const tele_op_t op_ORCA_PHASE = MAKE_CONSTANT_OP(OR.PHASE, ORCA_PHASE); -const tele_op_t op_ORCA_RST = MAKE_CONSTANT_OP(OR.RST, ORCA_RESET); -const tele_op_t op_ORCA_WGT = MAKE_CONSTANT_OP(OR.WGT, ORCA_WEIGHT); -const tele_op_t op_ORCA_MUTE = MAKE_CONSTANT_OP(OR.MUTE, ORCA_MUTE); -const tele_op_t op_ORCA_SCALE = MAKE_CONSTANT_OP(OR.SCALE, ORCA_SCALE); -const tele_op_t op_ORCA_BANK = MAKE_CONSTANT_OP(OR.BANK, ORCA_BANK); -const tele_op_t op_ORCA_PRESET = MAKE_CONSTANT_OP(OR.PRESET, ORCA_PRESET); -const tele_op_t op_ORCA_RELOAD = MAKE_CONSTANT_OP(OR.RELOAD, ORCA_RELOAD); -const tele_op_t op_ORCA_ROTS = MAKE_CONSTANT_OP(OR.ROTS, ORCA_ROTATES); -const tele_op_t op_ORCA_ROTW = MAKE_CONSTANT_OP(OR.ROTW, ORCA_ROTATEW); -const tele_op_t op_ORCA_GRST = MAKE_CONSTANT_OP(OR.GRST, ORCA_GRESET); -const tele_op_t op_ORCA_CVA = MAKE_CONSTANT_OP(OR.CVA, ORCA_CVA); -const tele_op_t op_ORCA_CVB = MAKE_CONSTANT_OP(OR.CVB, ORCA_CVB); diff --git a/src/ops/constants.h b/src/ops/constants.h deleted file mode 100644 index 424d75f9..00000000 --- a/src/ops/constants.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _OPS_CONSTANTS_H_ -#define _OPS_CONSTANTS_H_ - -#include "ops/op.h" - -extern const tele_op_t op_WW_PRESET; -extern const tele_op_t op_WW_POS; -extern const tele_op_t op_WW_SYNC; -extern const tele_op_t op_WW_START; -extern const tele_op_t op_WW_END; -extern const tele_op_t op_WW_PMODE; -extern const tele_op_t op_WW_PATTERN; -extern const tele_op_t op_WW_QPATTERN; -extern const tele_op_t op_WW_MUTE1; -extern const tele_op_t op_WW_MUTE2; -extern const tele_op_t op_WW_MUTE3; -extern const tele_op_t op_WW_MUTE4; -extern const tele_op_t op_WW_MUTEA; -extern const tele_op_t op_WW_MUTEB; -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; -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; -extern const tele_op_t op_ORCA_TRK; -extern const tele_op_t op_ORCA_CLK; -extern const tele_op_t op_ORCA_DIV; -extern const tele_op_t op_ORCA_PHASE; -extern const tele_op_t op_ORCA_RST; -extern const tele_op_t op_ORCA_WGT; -extern const tele_op_t op_ORCA_MUTE; -extern const tele_op_t op_ORCA_SCALE; -extern const tele_op_t op_ORCA_BANK; -extern const tele_op_t op_ORCA_PRESET; -extern const tele_op_t op_ORCA_RELOAD; -extern const tele_op_t op_ORCA_ROTS; -extern const tele_op_t op_ORCA_ROTW; -extern const tele_op_t op_ORCA_GRST; -extern const tele_op_t op_ORCA_CVA; -extern const tele_op_t op_ORCA_CVB; - -#endif diff --git a/src/ops/controlflow.c b/src/ops/controlflow.c index 25e842ad..bf4e6c3d 100644 --- a/src/ops/controlflow.c +++ b/src/ops/controlflow.c @@ -7,15 +7,19 @@ #include "teletype_io.h" static void mod_PROB_func(scene_state_t *ss, exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command); + command_state_t *cs, + const tele_command_t *post_command); static void mod_IF_func(scene_state_t *ss, exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command); + command_state_t *cs, + const tele_command_t *post_command); static void mod_ELIF_func(scene_state_t *ss, exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command); + command_state_t *cs, + const tele_command_t *post_command); static void mod_ELSE_func(scene_state_t *ss, exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command); + command_state_t *cs, + const tele_command_t *post_command); static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, - tele_command_t *sub_command); + const tele_command_t *post_command); static void op_SCENE_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -39,50 +43,57 @@ const tele_op_t op_SCENE = MAKE_GET_SET_OP(SCENE, op_SCENE_get, op_SCENE_set, 0, true); -static void mod_PROB_func(scene_state_t *NOTUSED(ss), exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command) { +static void mod_PROB_func(scene_state_t *ss, exec_state_t *es, + command_state_t *cs, + const tele_command_t *post_command) { int16_t a = cs_pop(cs); - if (rand() % 101 < a) { process(es, sub_command); } + if (rand() % 101 < a) { process_command(ss, es, post_command); } } -static void mod_IF_func(scene_state_t *NOTUSED(ss), exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command) { +static void mod_IF_func(scene_state_t *ss, exec_state_t *es, + command_state_t *cs, + const tele_command_t *post_command) { + int16_t a = cs_pop(cs); + es->if_else_condition = false; - if (cs_pop(cs)) { + if (a) { es->if_else_condition = true; - process(es, sub_command); + process_command(ss, es, post_command); } } -static void mod_ELIF_func(scene_state_t *NOTUSED(ss), exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command) { +static void mod_ELIF_func(scene_state_t *ss, exec_state_t *es, + command_state_t *cs, + const tele_command_t *post_command) { + int16_t a = cs_pop(cs); + if (!es->if_else_condition) { - if (cs_pop(cs)) { + if (a) { es->if_else_condition = true; - process(es, sub_command); + process_command(ss, es, post_command); } } } -static void mod_ELSE_func(scene_state_t *NOTUSED(ss), exec_state_t *es, +static void mod_ELSE_func(scene_state_t *ss, exec_state_t *es, command_state_t *NOTUSED(cs), - tele_command_t *sub_command) { + const tele_command_t *post_command) { if (!es->if_else_condition) { es->if_else_condition = true; - process(es, sub_command); + process_command(ss, es, post_command); } } static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, - tele_command_t *sub_command) { + const tele_command_t *post_command) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); int16_t loop_size = a < b ? b - a : a - b; for (int16_t i = 0; i <= loop_size; i++) { ss->variables.i = a < b ? a + i : a - i; - process(es, sub_command); + process_command(ss, es, post_command); } } @@ -98,14 +109,17 @@ static void op_SCENE_set(const void *NOTUSED(data), scene_state_t *ss, tele_scene(scene); } -static void op_SCRIPT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - uint16_t a = cs_pop(cs); - if (a > 0 && a < 9) tele_script(a); +static void op_SCRIPT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { + uint16_t a = cs_pop(cs) - 1; + if (a >= SCRIPT_COUNT || a == INIT_SCRIPT || a == METRO_SCRIPT) return; + + run_script_with_exec_state(ss, es, a); } -static void op_KILL_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + +static void op_KILL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { - clear_delays(); + clear_delays(ss); tele_kill(); } diff --git a/src/ops/delay.c b/src/ops/delay.c index 9486a7d9..0d851fed 100644 --- a/src/ops/delay.c +++ b/src/ops/delay.c @@ -5,7 +5,8 @@ #include "teletype_io.h" static void mod_DEL_func(scene_state_t *ss, exec_state_t *es, - command_state_t *cs, tele_command_t *sub_command); + command_state_t *cs, + const tele_command_t *post_command); static void op_DEL_CLR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -15,7 +16,8 @@ const tele_mod_t mod_DEL = MAKE_MOD(DEL, mod_DEL_func, 1); const tele_op_t op_DEL_CLR = MAKE_GET_OP(DEL.CLR, op_DEL_CLR_get, 0, false); static void mod_DEL_func(scene_state_t *ss, exec_state_t *NOTUSED(es), - command_state_t *cs, tele_command_t *sub_command) { + command_state_t *cs, + const tele_command_t *post_command) { int16_t i = 0; int16_t a = cs_pop(cs); @@ -25,16 +27,15 @@ static void mod_DEL_func(scene_state_t *ss, exec_state_t *NOTUSED(es), if (i < DELAY_SIZE) { ss->delay.count++; - if (ss->delay.count == 1) tele_delay(1); + tele_has_delays(ss->delay.count > 0); ss->delay.time[i] = a; - copy_command(&ss->delay.commands[i], sub_command); + copy_command(&ss->delay.commands[i], post_command); } } -static void op_DEL_CLR_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), +static void op_DEL_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { - clear_delays(); + clear_delays(ss); } diff --git a/src/ops/earthsea.c b/src/ops/earthsea.c new file mode 100644 index 00000000..5b2d2fff --- /dev/null +++ b/src/ops/earthsea.c @@ -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); diff --git a/src/ops/earthsea.h b/src/ops/earthsea.h new file mode 100644 index 00000000..f21fd183 --- /dev/null +++ b/src/ops/earthsea.h @@ -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 diff --git a/src/ops/hardware.c b/src/ops/hardware.c index 0f268c1f..53ccc44d 100644 --- a/src/ops/hardware.c +++ b/src/ops/hardware.c @@ -2,7 +2,6 @@ #include "helpers.h" #include "ii.h" -#include "teletype.h" #include "teletype_io.h" static void op_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -17,6 +16,10 @@ static void op_CV_OFF_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_CV_OFF_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_IN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs); +static void op_PARAM_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs); static void op_TR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_TR_set(const void *data, scene_state_t *ss, exec_state_t *es, @@ -33,240 +36,37 @@ static void op_TR_TOG_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_TR_PULSE_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_II_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); static void op_CV_SET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_MUTE_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_UNMUTE_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); +static void op_MUTE_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); static void op_STATE_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_JF_TR_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_JF_RMODE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_RUN_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_JF_SHIFT_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_VTR_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_JF_MODE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_TICK_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_VOX_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_JF_NOTE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_GOD_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_JF_TUNE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_JF_QT_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - -static void op_KR_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_PATTERN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_PATTERN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_SCALE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_SCALE_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_PERIOD_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_PERIOD_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_KR_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_KR_LOOP_ST_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_LOOP_ST_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_LOOP_LEN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_LOOP_LEN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_KR_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); - -static void op_MP_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_STOP_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_SCALE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_SCALE_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_PERIOD_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MP_PERIOD_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); - -static void op_LV_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_LV_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_LV_L_ST_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_L_ST_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_L_LEN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_L_LEN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_L_DIR_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_L_DIR_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_LV_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - -static void op_CY_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_CY_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_CY_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_CY_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_CY_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_CY_REV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_CY_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - -static void op_MID_SHIFT_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_MID_SLEW_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); - -static void op_ARP_STYLE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_HOLD_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_RPT_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_GATE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_DIV_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_SHIFT_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_SLEW_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_FILL_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_ROT_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_ARP_ER_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - // clang-format off -const tele_op_t op_CV = MAKE_GET_SET_OP(CV , op_CV_get , op_CV_set , 1, true); -const tele_op_t op_CV_OFF = MAKE_GET_SET_OP(CV.OFF , op_CV_OFF_get , op_CV_OFF_set , 1, true); -const tele_op_t op_CV_SLEW = MAKE_GET_SET_OP(CV.SLEW, op_CV_SLEW_get, op_CV_SLEW_set, 1, true); -const tele_op_t op_TR = MAKE_GET_SET_OP(TR , op_TR_get , op_TR_set , 1, true); -const tele_op_t op_TR_POL = MAKE_GET_SET_OP(TR.POL , op_TR_POL_get , op_TR_POL_set , 1, true); -const tele_op_t op_TR_TIME = MAKE_GET_SET_OP(TR.TIME, op_TR_TIME_get, op_TR_TIME_set, 1, true); -const tele_op_t op_TR_TOG = MAKE_GET_OP(TR.TOG , op_TR_TOG_get , 1, false); -const tele_op_t op_TR_PULSE = MAKE_GET_OP(TR.PULSE, op_TR_PULSE_get, 1, false); -const tele_op_t op_II = MAKE_GET_OP(II , op_II_get , 2, false); -const tele_op_t op_CV_SET = MAKE_GET_OP(CV.SET , op_CV_SET_get , 2, false); -const tele_op_t op_MUTE = MAKE_GET_OP(MUTE , op_MUTE_get , 1, false); -const tele_op_t op_UNMUTE = MAKE_GET_OP(UNMUTE , op_UNMUTE_get , 1, false); -const tele_op_t op_STATE = MAKE_GET_OP(STATE , op_STATE_get , 1, true ); - -const tele_op_t op_JF_TR = MAKE_GET_OP(JF.TR , op_JF_TR_get , 2, false); -const tele_op_t op_JF_RMODE = MAKE_GET_OP(JF.RMODE , op_JF_RMODE_get , 1, false); -const tele_op_t op_JF_RUN = MAKE_GET_OP(JF.RUN , op_JF_RUN_get , 1, false); -const tele_op_t op_JF_SHIFT = MAKE_GET_OP(JF.SHIFT , op_JF_SHIFT_get , 1, false); -const tele_op_t op_JF_VTR = MAKE_GET_OP(JF.VTR , op_JF_VTR_get , 2, false); -const tele_op_t op_JF_MODE = MAKE_GET_OP(JF.MODE , op_JF_MODE_get , 1, false); -const tele_op_t op_JF_TICK = MAKE_GET_OP(JF.TICK , op_JF_TICK_get , 1, false); -const tele_op_t op_JF_VOX = MAKE_GET_OP(JF.VOX , op_JF_VOX_get , 3, false); -const tele_op_t op_JF_NOTE = MAKE_GET_OP(JF.NOTE , op_JF_NOTE_get , 2, false); -const tele_op_t op_JF_GOD = MAKE_GET_OP(JF.GOD , op_JF_GOD_get , 1, false); -const tele_op_t op_JF_TUNE = MAKE_GET_OP(JF.TUNE , op_JF_TUNE_get , 3, false); -const tele_op_t op_JF_QT = MAKE_GET_OP(JF.QT , op_JF_QT_get , 1, false); - -const tele_op_t op_KR_PRESET = MAKE_GET_SET_OP(KR.PRE , op_KR_PRESET_get , op_KR_PRESET_set , 0, true); -const tele_op_t op_KR_PATTERN = MAKE_GET_SET_OP(KR.PAT , op_KR_PATTERN_get , op_KR_PATTERN_set , 0, true); -const tele_op_t op_KR_SCALE = MAKE_GET_SET_OP(KR.SCALE , op_KR_SCALE_get , op_KR_SCALE_set , 0, true); -const tele_op_t op_KR_PERIOD = MAKE_GET_SET_OP(KR.PERIOD , op_KR_PERIOD_get , op_KR_PERIOD_set , 0, true); -const tele_op_t op_KR_POS = MAKE_GET_SET_OP(KR.POS , op_KR_POS_get , op_KR_POS_set , 2, true); -const tele_op_t op_KR_LOOP_ST = MAKE_GET_SET_OP(KR.L.ST , op_KR_LOOP_ST_get , op_KR_LOOP_ST_set , 2, true); -const tele_op_t op_KR_LOOP_LEN = MAKE_GET_SET_OP(KR.L.LEN , op_KR_LOOP_LEN_get , op_KR_LOOP_LEN_set , 2, true); -const tele_op_t op_KR_RESET = MAKE_GET_OP(KR.RES , op_KR_RESET_get , 2, false); - -const tele_op_t op_MP_PRESET1 = MAKE_GET_SET_OP(MP.PRE , op_MP_PRESET_get , op_MP_PRESET_set , 0, true); -const tele_op_t op_MP_RESET1 = MAKE_GET_OP(MP.RES , op_MP_RESET_get , 1, false); -const tele_op_t op_MP_STOP1 = MAKE_GET_OP(MP.OFF , op_MP_STOP_get , 1, false); -const tele_op_t op_MP_SCALE = MAKE_GET_SET_OP(MP.SCALE , op_MP_SCALE_get , op_MP_SCALE_set , 0, true); -const tele_op_t op_MP_PERIOD = MAKE_GET_SET_OP(MP.PERIOD , op_MP_PERIOD_get , op_MP_PERIOD_set , 0, true); - -const tele_op_t op_LV_PRESET = MAKE_GET_SET_OP(LV.PRE , op_LV_PRESET_get , op_LV_PRESET_set , 0, true); -const tele_op_t op_LV_RESET = MAKE_GET_OP(LV.RES , op_LV_RESET_get , 1, false); -const tele_op_t op_LV_POS = MAKE_GET_SET_OP(LV.POS , op_LV_POS_get , op_LV_POS_set , 0, true); -const tele_op_t op_LV_L_ST = MAKE_GET_SET_OP(LV.L.ST , op_LV_L_ST_get , op_LV_L_ST_set , 0, true); -const tele_op_t op_LV_L_LEN = MAKE_GET_SET_OP(LV.L.LEN , op_LV_L_LEN_get , op_LV_L_LEN_set , 0, true); -const tele_op_t op_LV_L_DIR = MAKE_GET_SET_OP(LV.L.DIR , op_LV_L_DIR_get , op_LV_L_DIR_set , 0, true); -const tele_op_t op_LV_CV = MAKE_GET_OP(LV.CV , op_LV_CV_get , 1, true); - -const tele_op_t op_CY_PRESET = MAKE_GET_SET_OP(CY.PRE , op_CY_PRESET_get , op_CY_PRESET_set , 0, true); -const tele_op_t op_CY_RESET = MAKE_GET_OP(CY.RES , op_CY_RESET_get , 1, false); -const tele_op_t op_CY_POS = MAKE_GET_SET_OP(CY.POS , op_CY_POS_get , op_CY_POS_set , 1, true); -const tele_op_t op_CY_REV = MAKE_GET_OP(CY.REV , op_CY_REV_get , 1, false); -const tele_op_t op_CY_CV = MAKE_GET_OP(CY.CV , op_CY_CV_get , 1, true); - -const tele_op_t op_MID_SHIFT = MAKE_GET_OP(MID.SHIFT , op_MID_SHIFT_get , 1, false); -const tele_op_t op_MID_SLEW = MAKE_GET_OP(MID.SLEW , op_MID_SLEW_get , 1, false); - -const tele_op_t op_ARP_STYLE = MAKE_GET_OP(ARP.STY , op_ARP_STYLE_get , 1, false); -const tele_op_t op_ARP_HOLD = MAKE_GET_OP(ARP.HLD , op_ARP_HOLD_get , 1, false); -const tele_op_t op_ARP_RPT = MAKE_GET_OP(ARP.RPT , op_ARP_RPT_get , 3, false); -const tele_op_t op_ARP_GATE = MAKE_GET_OP(ARP.GT , op_ARP_GATE_get , 2, false); -const tele_op_t op_ARP_DIV = MAKE_GET_OP(ARP.DIV , op_ARP_DIV_get , 2, false); -const tele_op_t op_ARP_RESET = MAKE_GET_OP(ARP.RES , op_ARP_RESET_get , 1, false); -const tele_op_t op_ARP_SHIFT = MAKE_GET_OP(ARP.SHIFT , op_ARP_SHIFT_get , 2, false); -const tele_op_t op_ARP_SLEW = MAKE_GET_OP(ARP.SLEW , op_ARP_SLEW_get , 2, false); -const tele_op_t op_ARP_FILL = MAKE_GET_OP(ARP.FIL , op_ARP_FILL_get , 2, false); -const tele_op_t op_ARP_ROT = MAKE_GET_OP(ARP.ROT , op_ARP_ROT_get , 2, false); -const tele_op_t op_ARP_ER = MAKE_GET_OP(ARP.ER , op_ARP_ER_get , 4, false); - - +const tele_op_t op_CV = MAKE_GET_SET_OP(CV , op_CV_get , op_CV_set , 1, true); +const tele_op_t op_CV_OFF = MAKE_GET_SET_OP(CV.OFF , op_CV_OFF_get , op_CV_OFF_set , 1, true); +const tele_op_t op_CV_SLEW = MAKE_GET_SET_OP(CV.SLEW , op_CV_SLEW_get , op_CV_SLEW_set, 1, true); +const tele_op_t op_IN = MAKE_GET_OP (IN , op_IN_get , 0, true); +const tele_op_t op_PARAM = MAKE_GET_OP (PARAM , op_PARAM_get , 0, true); +const tele_op_t op_PRM = MAKE_ALIAS_OP (PRM , op_PARAM_get , NULL, 0, true); +const tele_op_t op_TR = MAKE_GET_SET_OP(TR , op_TR_get , op_TR_set , 1, true); +const tele_op_t op_TR_POL = MAKE_GET_SET_OP(TR.POL , op_TR_POL_get , op_TR_POL_set , 1, true); +const tele_op_t op_TR_TIME = MAKE_GET_SET_OP(TR.TIME , op_TR_TIME_get , op_TR_TIME_set, 1, true); +const tele_op_t op_TR_TOG = MAKE_GET_OP (TR.TOG , op_TR_TOG_get , 1, false); +const tele_op_t op_TR_PULSE = MAKE_GET_OP (TR.PULSE, op_TR_PULSE_get, 1, false); +const tele_op_t op_TR_P = MAKE_ALIAS_OP (TR.P , op_TR_PULSE_get, NULL, 1, false); +const tele_op_t op_CV_SET = MAKE_GET_OP (CV.SET , op_CV_SET_get , 2, false); +const tele_op_t op_MUTE = MAKE_GET_SET_OP(MUTE , op_MUTE_get , op_MUTE_set , 1, true); +const tele_op_t op_STATE = MAKE_GET_OP (STATE , op_STATE_get , 1, true ); // clang-format on static void op_CV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); - // cs_push(cs, ss->variables.cv[a]); - a--; if (a < 0) cs_push(cs, 0); @@ -275,7 +75,7 @@ static void op_CV_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_CV | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; d[1] = 0; tele_ii_rx(addr, d, 2); @@ -289,11 +89,7 @@ static void op_CV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); b = normalise_value(0, 16383, 0, b); - // ss->variables.cv[a] = b; - // tele_cv(a, b, 1); - a--; if (a < 0) return; @@ -312,9 +108,6 @@ static void op_CV_set(const void *NOTUSED(data), scene_state_t *ss, static void op_CV_SLEW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); - // cs_push(cs, ss->variables.cv_slew[a]); - a--; if (a < 0) cs_push(cs, 0); @@ -323,7 +116,7 @@ static void op_CV_SLEW_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_CV_SLEW | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; d[1] = 0; tele_ii_rx(addr, d, 2); @@ -337,11 +130,7 @@ static void op_CV_SLEW_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); b = normalise_value(1, 32767, 0, b); // min slew = 1 - // ss->variables.cv_slew[a] = b; - // tele_cv_slew(a, b); - a--; if (a < 0) return; @@ -359,9 +148,6 @@ static void op_CV_SLEW_set(const void *NOTUSED(data), scene_state_t *ss, static void op_CV_OFF_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); - // cs_push(cs, ss->variables.cv_off[a]); - a--; if (a < 0) cs_push(cs, 0); @@ -370,7 +156,7 @@ static void op_CV_OFF_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_CV_OFF | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; d[1] = 0; tele_ii_rx(addr, d, 2); @@ -384,11 +170,7 @@ static void op_CV_OFF_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, CV_COUNT - 1, 0, a - 1); ss->variables.cv_off[a] = b; - // tele_cv_off(a, b); - // tele_cv(a, ss->variables.cv[a], 1); - a--; if (a < 0) return; @@ -404,10 +186,19 @@ static void op_CV_OFF_set(const void *NOTUSED(data), scene_state_t *ss, } } +static void op_IN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, ss->variables.in); +} + +static void op_PARAM_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, ss->variables.param); +} + static void op_TR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); a--; if (a < 0) cs_push(cs, 0); @@ -416,7 +207,7 @@ static void op_TR_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_TR | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; tele_ii_rx(addr, d, 1); cs_push(cs, d[0]); @@ -429,7 +220,6 @@ static void op_TR_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); a--; if (a < 0) return; @@ -447,8 +237,6 @@ static void op_TR_set(const void *NOTUSED(data), scene_state_t *ss, static void op_TR_POL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); - // cs_push(cs, ss->variables.tr_pol[a]); a--; if (a < 0) cs_push(cs, 0); @@ -457,7 +245,7 @@ static void op_TR_POL_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_TR_POL | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; tele_ii_rx(addr, d, 1); cs_push(cs, d[0]); @@ -470,8 +258,6 @@ static void op_TR_POL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); - // ss->variables.tr_pol[a] = b > 0; a--; if (a < 0) return; @@ -488,8 +274,6 @@ static void op_TR_POL_set(const void *NOTUSED(data), scene_state_t *ss, static void op_TR_TIME_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); - // cs_push(cs, ss->variables.tr_time[a]); a--; if (a < 0) cs_push(cs, 0); @@ -498,7 +282,7 @@ static void op_TR_TIME_get(const void *NOTUSED(data), scene_state_t *ss, else if (a < 20) { uint8_t d[] = { II_ANSIBLE_TR_TIME | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 4) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; d[1] = 0; tele_ii_rx(addr, d, 2); @@ -512,9 +296,7 @@ static void op_TR_TIME_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // a = normalise_value(0, TR_COUNT - 1, 0, a - 1); if (b < 0) b = 0; - // ss->variables.tr_time[a] = b; a--; if (a < 0) return; @@ -531,14 +313,6 @@ static void op_TR_TIME_set(const void *NOTUSED(data), scene_state_t *ss, static void op_TR_TOG_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // saturate and shift - // a--; - // if (ss->variables.tr[a]) - // ss->variables.tr[a] = 0; - // else - // ss->variables.tr[a] = 1; - // tele_tr(a, ss->variables.tr[a]); - a--; if (a < 0) return; @@ -559,19 +333,6 @@ static void op_TR_TOG_get(const void *NOTUSED(data), scene_state_t *ss, static void op_TR_PULSE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // saturate and shift - // if (a < 1) - // a = 1; - // else if (a > 4) - // a = 4; - // a--; - // int16_t time = ss->variables.tr_time[a]; // pulse time - // if (time <= 0) return; // if time <= 0 don't do - // anything - // ss->variables.tr[a] = ss->variables.tr_pol[a]; - // ss->tr_pulse_timer[a] = time; // set time - // tele_tr(a, ss->variables.tr[a]); - a--; if (a < 0) return; @@ -589,29 +350,15 @@ static void op_TR_PULSE_get(const void *NOTUSED(data), scene_state_t *ss, } } -static void op_II_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - tele_ii(a, b); -} - static void op_CV_SET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - // saturate and shift - // if (a < 1) - // a = 1; - // else if (a > 4) - // a = 4; - // a--; + if (b < 0) b = 0; else if (b > 16383) b = 16383; - // ss->variables.cv[a] = b; - // tele_cv(a, b, 0); a--; if (a < 0) @@ -627,31 +374,25 @@ static void op_CV_SET_get(const void *NOTUSED(data), scene_state_t *ss, } } -static void op_MUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), +static void op_MUTE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a; - a = cs_pop(cs); - if (a > 0 && a < 9) { tele_mute(a - 1, 0); } + int16_t a = cs_pop(cs) - 1; + if (a >= 0 && a < TRIGGER_INPUTS) { cs_push(cs, ss_get_mute(ss, a)); } + else { + cs_push(cs, 0); + } } -static void op_UNMUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a; - a = cs_pop(cs); - if (a > 0 && a < 9) { tele_mute(a - 1, 1); } +static void op_MUTE_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs) - 1; + bool b = cs_pop(cs) > 0; + if (a >= 0 && a < TRIGGER_INPUTS) { ss_set_mute(ss, a, b); } } static void op_STATE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - // a--; - // if (a < 0) - // a = 0; - // else if (a > 7) - // a = 7; - - // cs_push(cs, tele_get_input_state(a)); - a--; if (a < 0) cs_push(cs, 0); @@ -660,7 +401,7 @@ static void op_STATE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), else if (a < 24) { uint8_t d[] = { II_ANSIBLE_INPUT | II_GET, a & 0x3 }; uint8_t addr = II_ANSIBLE_ADDR + (((a - 8) >> 2) << 1); - tele_ii_tx_now(addr, d, 2); + tele_ii_tx(addr, d, 2); d[0] = 0; tele_ii_rx(addr, d, 1); cs_push(cs, d[0]); @@ -668,589 +409,3 @@ static void op_STATE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), else cs_push(cs, 0); } - - -static void op_JF_TR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { JF_TR, a, b }; - tele_ii_tx(JF_ADDR, d, 3); -} - -static void op_JF_RMODE_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_RMODE, a }; - tele_ii_tx(JF_ADDR, d, 2); -} - -static void op_JF_RUN_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_RUN, a >> 8, a & 0xff }; - tele_ii_tx(JF_ADDR, d, 3); -} - -static void op_JF_SHIFT_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_SHIFT, a >> 8, a & 0xff }; - tele_ii_tx(JF_ADDR, d, 3); -} - -static void op_JF_VTR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { JF_VTR, a, b >> 8, b & 0xff }; - tele_ii_tx(JF_ADDR, d, 4); -} - -static void op_JF_MODE_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_MODE, a }; - tele_ii_tx(JF_ADDR, d, 2); -} - -static void op_JF_TICK_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_TICK, a }; - tele_ii_tx(JF_ADDR, d, 2); -} - -static void op_JF_VOX_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { JF_VOX, a, b >> 8, b & 0xff, c >> 8, c & 0xff }; - tele_ii_tx(JF_ADDR, d, 6); -} - -static void op_JF_NOTE_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { JF_NOTE, a >> 8, a & 0xff, b >> 8, b & 0xff }; - tele_ii_tx(JF_ADDR, d, 5); -} - -static void op_JF_GOD_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_GOD, a }; - tele_ii_tx(JF_ADDR, d, 2); -} - -static void op_JF_TUNE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { JF_TUNE, a, b, c }; - tele_ii_tx(JF_ADDR, d, 4); -} - -static void op_JF_QT_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { JF_QT, a }; - tele_ii_tx(JF_ADDR, d, 2); -} - - -static void op_KR_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_KR_PRESET, a }; - tele_ii_tx(II_KR_ADDR, d, 2); -} - -static void op_KR_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_KR_PRESET | II_GET }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_PATTERN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_KR_PATTERN, a }; - tele_ii_tx(II_KR_ADDR, d, 2); -} - -static void op_KR_PATTERN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_KR_PATTERN | II_GET }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_SCALE_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_KR_SCALE, a }; - tele_ii_tx(II_KR_ADDR, d, 2); -} - -static void op_KR_SCALE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_KR_SCALE | II_GET }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_PERIOD_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_KR_PERIOD, a >> 8, a & 0xff }; - tele_ii_tx(II_KR_ADDR, d, 3); -} - -static void op_KR_PERIOD_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_KR_PERIOD | II_GET, 0 }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - d[1] = 0; - tele_ii_rx(addr, d, 2); - cs_push(cs, (d[0] << 8) + d[1]); -} - -static void op_KR_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { II_KR_POS, a, b, c }; - tele_ii_tx(II_KR_ADDR, d, 4); -} - -static void op_KR_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_KR_POS | II_GET, a, b }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 3); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_LOOP_ST_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { II_KR_LOOP_ST, a, b, c }; - tele_ii_tx(II_KR_ADDR, d, 4); -} - -static void op_KR_LOOP_ST_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_KR_LOOP_ST | II_GET, a, b }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 3); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_LOOP_LEN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { II_KR_LOOP_LEN, a, b, c }; - tele_ii_tx(II_KR_ADDR, d, 4); -} - -static void op_KR_LOOP_LEN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_KR_LOOP_LEN | II_GET, a, b }; - uint8_t addr = II_KR_ADDR; - tele_ii_tx_now(addr, d, 3); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_KR_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_KR_RESET, a, b }; - tele_ii_tx(II_KR_ADDR, d, 3); -} - -static void op_MP_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MP_PRESET, a }; - tele_ii_tx(II_MP_ADDR, d, 2); -} - -static void op_MP_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_MP_PRESET | II_GET }; - uint8_t addr = II_MP_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_MP_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MP_RESET, a }; - tele_ii_tx(II_MP_ADDR, d, 2); -} - -static void op_MP_STOP_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MP_STOP, a }; - tele_ii_tx(II_MP_ADDR, d, 2); -} - -static void op_MP_SCALE_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MP_SCALE, a }; - tele_ii_tx(II_MP_ADDR, d, 2); -} - -static void op_MP_SCALE_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_MP_SCALE | II_GET }; - uint8_t addr = II_MP_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_MP_PERIOD_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MP_PERIOD, a >> 8, a & 0xff }; - tele_ii_tx(II_MP_ADDR, d, 3); -} - -static void op_MP_PERIOD_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_MP_PERIOD | II_GET, 0 }; - uint8_t addr = II_MP_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - d[1] = 0; - tele_ii_rx(addr, d, 2); - cs_push(cs, (d[0] << 8) + d[1]); -} - -static void op_LV_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_PRESET, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_LV_PRESET | II_GET }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_LV_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_RESET, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_POS, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - uint8_t d[] = { II_LV_POS | II_GET }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_LV_L_ST_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_L_ST, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_L_ST_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_LV_L_ST | II_GET }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_LV_L_LEN_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_L_LEN, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_L_LEN_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_LV_L_LEN | II_GET }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_LV_L_DIR_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_LV_L_DIR, a }; - tele_ii_tx(II_LV_ADDR, d, 2); -} - -static void op_LV_L_DIR_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_LV_L_DIR | II_GET }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_LV_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - a--; - uint8_t d[] = { II_LV_CV | II_GET, a & 0x3 }; - uint8_t addr = II_LV_ADDR; - tele_ii_tx_now(addr, d, 2); - d[0] = 0; - d[1] = 0; - tele_ii_rx(addr, d, 2); - cs_push(cs, (d[0] << 8) + d[1]); -} - -static void op_CY_PRESET_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_CY_PRESET, a }; - tele_ii_tx(II_CY_ADDR, d, 2); -} - -static void op_CY_PRESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - uint8_t d[] = { II_CY_PRESET | II_GET }; - uint8_t addr = II_CY_ADDR; - tele_ii_tx_now(addr, d, 1); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_CY_RESET_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_CY_RESET, a }; - tele_ii_tx(II_CY_ADDR, d, 2); -} - -static void op_CY_POS_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_CY_POS, a, b }; - tele_ii_tx(II_CY_ADDR, d, 3); -} - -static void op_CY_POS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_CY_POS | II_GET, a }; - uint8_t addr = II_CY_ADDR; - tele_ii_tx_now(addr, d, 2); - d[0] = 0; - tele_ii_rx(addr, d, 1); - cs_push(cs, d[0]); -} - -static void op_CY_REV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_CY_REV, a }; - tele_ii_tx(II_CY_ADDR, d, 2); -} - -static void op_CY_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs) { - int16_t a = cs_pop(cs); - a--; - uint8_t d[] = { II_CY_CV | II_GET, a & 0x3 }; - uint8_t addr = II_CY_ADDR; - tele_ii_tx_now(addr, d, 2); - d[0] = 0; - d[1] = 0; - tele_ii_rx(addr, d, 2); - cs_push(cs, (d[0] << 8) + d[1]); -} - -static void op_MID_SHIFT_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MID_SHIFT, a >> 8, a & 0xff }; - tele_ii_tx(II_MID_ADDR, d, 3); -} - -static void op_MID_SLEW_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_MID_SLEW, a >> 8, a & 0xff }; - tele_ii_tx(II_MID_ADDR, d, 3); -} - -static void op_ARP_STYLE_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_ARP_STYLE, a }; - tele_ii_tx(II_ARP_ADDR, d, 2); -} - -static void op_ARP_HOLD_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_ARP_HOLD, a & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 2); -} - -static void op_ARP_RPT_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - uint8_t d[] = { II_ARP_RPT, a, b, c >> 8, c & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 5); -} - -static void op_ARP_GATE_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_GATE, a & 0xff, b & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 3); -} - -static void op_ARP_DIV_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_DIV, a & 0xff, b & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 3); -} - -static void op_ARP_RESET_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - uint8_t d[] = { II_ARP_RESET, a }; - tele_ii_tx(II_ARP_ADDR, d, 2); -} - -static void op_ARP_SHIFT_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_SHIFT, a, b >> 8, b & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 4); -} - -static void op_ARP_SLEW_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_SLEW, a, b >> 8, b & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 4); -} - -static void op_ARP_FILL_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_FILL, a, b }; - tele_ii_tx(II_ARP_ADDR, d, 3); -} - -static void op_ARP_ROT_get(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - uint8_t d[] = { II_ARP_ROT, a, b >> 8, b & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 4); -} - -static void op_ARP_ER_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - int16_t e = cs_pop(cs); - uint8_t d[] = { II_ARP_ER, a, b, c, e >> 8, e & 0xff }; - tele_ii_tx(II_ARP_ADDR, d, 6); -} diff --git a/src/ops/hardware.h b/src/ops/hardware.h index eb67ca19..895b36bc 100644 --- a/src/ops/hardware.h +++ b/src/ops/hardware.h @@ -6,73 +6,17 @@ extern const tele_op_t op_CV; extern const tele_op_t op_CV_OFF; extern const tele_op_t op_CV_SLEW; +extern const tele_op_t op_IN; +extern const tele_op_t op_PARAM; +extern const tele_op_t op_PRM; extern const tele_op_t op_TR; extern const tele_op_t op_TR_POL; extern const tele_op_t op_TR_TIME; extern const tele_op_t op_TR_TOG; extern const tele_op_t op_TR_PULSE; -extern const tele_op_t op_II; +extern const tele_op_t op_TR_P; extern const tele_op_t op_CV_SET; extern const tele_op_t op_MUTE; -extern const tele_op_t op_UNMUTE; extern const tele_op_t op_STATE; -extern const tele_op_t op_JF_TR; -extern const tele_op_t op_JF_RMODE; -extern const tele_op_t op_JF_RUN; -extern const tele_op_t op_JF_SHIFT; -extern const tele_op_t op_JF_VTR; -extern const tele_op_t op_JF_MODE; -extern const tele_op_t op_JF_TICK; -extern const tele_op_t op_JF_VOX; -extern const tele_op_t op_JF_NOTE; -extern const tele_op_t op_JF_GOD; -extern const tele_op_t op_JF_TUNE; -extern const tele_op_t op_JF_QT; - -extern const tele_op_t op_KR_PRESET; -extern const tele_op_t op_KR_PATTERN; -extern const tele_op_t op_KR_SCALE; -extern const tele_op_t op_KR_PERIOD; -extern const tele_op_t op_KR_POS; -extern const tele_op_t op_KR_LOOP_ST; -extern const tele_op_t op_KR_LOOP_LEN; -extern const tele_op_t op_KR_RESET; - -extern const tele_op_t op_MP_PRESET1; -extern const tele_op_t op_MP_RESET1; -extern const tele_op_t op_MP_STOP1; -extern const tele_op_t op_MP_SCALE; -extern const tele_op_t op_MP_PERIOD; - -extern const tele_op_t op_LV_PRESET; -extern const tele_op_t op_LV_RESET; -extern const tele_op_t op_LV_POS; -extern const tele_op_t op_LV_L_ST; -extern const tele_op_t op_LV_L_LEN; -extern const tele_op_t op_LV_L_DIR; -extern const tele_op_t op_LV_CV; - -extern const tele_op_t op_CY_PRESET; -extern const tele_op_t op_CY_RESET; -extern const tele_op_t op_CY_POS; -extern const tele_op_t op_CY_REV; -extern const tele_op_t op_CY_CV; - -extern const tele_op_t op_MID_SHIFT; -extern const tele_op_t op_MID_SLEW; - -extern const tele_op_t op_ARP_STYLE; -extern const tele_op_t op_ARP_HOLD; -extern const tele_op_t op_ARP_RPT; -extern const tele_op_t op_ARP_GATE; -extern const tele_op_t op_ARP_DIV; -extern const tele_op_t op_ARP_RESET; -extern const tele_op_t op_ARP_SHIFT; -extern const tele_op_t op_ARP_SLEW; -extern const tele_op_t op_ARP_FILL; -extern const tele_op_t op_ARP_ROT; -extern const tele_op_t op_ARP_ER; - - #endif diff --git a/src/ops/justfriends.c b/src/ops/justfriends.c new file mode 100644 index 00000000..49563ddc --- /dev/null +++ b/src/ops/justfriends.c @@ -0,0 +1,143 @@ +#include "ops/justfriends.h" + +#include "helpers.h" +#include "ii.h" +#include "teletype_io.h" + +static void op_JF_TR_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_JF_RMODE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_RUN_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_JF_SHIFT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_VTR_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_JF_MODE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_TICK_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_VOX_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_JF_NOTE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_GOD_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_JF_TUNE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_JF_QT_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + +// clang-format off +const tele_op_t op_JF_TR = MAKE_GET_OP(JF.TR , op_JF_TR_get , 2, false); +const tele_op_t op_JF_RMODE = MAKE_GET_OP(JF.RMODE , op_JF_RMODE_get , 1, false); +const tele_op_t op_JF_RUN = MAKE_GET_OP(JF.RUN , op_JF_RUN_get , 1, false); +const tele_op_t op_JF_SHIFT = MAKE_GET_OP(JF.SHIFT , op_JF_SHIFT_get , 1, false); +const tele_op_t op_JF_VTR = MAKE_GET_OP(JF.VTR , op_JF_VTR_get , 2, false); +const tele_op_t op_JF_MODE = MAKE_GET_OP(JF.MODE , op_JF_MODE_get , 1, false); +const tele_op_t op_JF_TICK = MAKE_GET_OP(JF.TICK , op_JF_TICK_get , 1, false); +const tele_op_t op_JF_VOX = MAKE_GET_OP(JF.VOX , op_JF_VOX_get , 3, false); +const tele_op_t op_JF_NOTE = MAKE_GET_OP(JF.NOTE , op_JF_NOTE_get , 2, false); +const tele_op_t op_JF_GOD = MAKE_GET_OP(JF.GOD , op_JF_GOD_get , 1, false); +const tele_op_t op_JF_TUNE = MAKE_GET_OP(JF.TUNE , op_JF_TUNE_get , 3, false); +const tele_op_t op_JF_QT = MAKE_GET_OP(JF.QT , op_JF_QT_get , 1, false); +// clang-format on + + +static void op_JF_TR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { JF_TR, a, b }; + tele_ii_tx(JF_ADDR, d, 3); +} + +static void op_JF_RMODE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_RMODE, a }; + tele_ii_tx(JF_ADDR, d, 2); +} + +static void op_JF_RUN_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_RUN, a >> 8, a & 0xff }; + tele_ii_tx(JF_ADDR, d, 3); +} + +static void op_JF_SHIFT_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_SHIFT, a >> 8, a & 0xff }; + tele_ii_tx(JF_ADDR, d, 3); +} + +static void op_JF_VTR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { JF_VTR, a, b >> 8, b & 0xff }; + tele_ii_tx(JF_ADDR, d, 4); +} + +static void op_JF_MODE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_MODE, a }; + tele_ii_tx(JF_ADDR, d, 2); +} + +static void op_JF_TICK_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_TICK, a }; + tele_ii_tx(JF_ADDR, d, 2); +} + +static void op_JF_VOX_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { JF_VOX, a, b >> 8, b & 0xff, c >> 8, c & 0xff }; + tele_ii_tx(JF_ADDR, d, 6); +} + +static void op_JF_NOTE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + uint8_t d[] = { JF_NOTE, a >> 8, a & 0xff, b >> 8, b & 0xff }; + tele_ii_tx(JF_ADDR, d, 5); +} + +static void op_JF_GOD_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_GOD, a }; + tele_ii_tx(JF_ADDR, d, 2); +} + +static void op_JF_TUNE_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t c = cs_pop(cs); + uint8_t d[] = { JF_TUNE, a, b, c }; + tele_ii_tx(JF_ADDR, d, 4); +} + +static void op_JF_QT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + uint8_t d[] = { JF_QT, a }; + tele_ii_tx(JF_ADDR, d, 2); +} diff --git a/src/ops/justfriends.h b/src/ops/justfriends.h new file mode 100644 index 00000000..dc4ca1b4 --- /dev/null +++ b/src/ops/justfriends.h @@ -0,0 +1,19 @@ +#ifndef _OPS_JUSTFRIENDS_H_ +#define _OPS_JUSTFRIENDS_H_ + +#include "ops/op.h" + +extern const tele_op_t op_JF_TR; +extern const tele_op_t op_JF_RMODE; +extern const tele_op_t op_JF_RUN; +extern const tele_op_t op_JF_SHIFT; +extern const tele_op_t op_JF_VTR; +extern const tele_op_t op_JF_MODE; +extern const tele_op_t op_JF_TICK; +extern const tele_op_t op_JF_VOX; +extern const tele_op_t op_JF_NOTE; +extern const tele_op_t op_JF_GOD; +extern const tele_op_t op_JF_TUNE; +extern const tele_op_t op_JF_QT; + +#endif diff --git a/src/ops/maths.c b/src/ops/maths.c index d6eb6dca..c67381c8 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -42,6 +42,10 @@ static void op_LT_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_GT_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_LTE_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_GTE_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); static void op_NZ_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_EZ_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -93,6 +97,8 @@ const tele_op_t op_EQ = MAKE_GET_OP(EQ , op_EQ_get , 2, true); const tele_op_t op_NE = MAKE_GET_OP(NE , op_NE_get , 2, true); const tele_op_t op_LT = MAKE_GET_OP(LT , op_LT_get , 2, true); const tele_op_t op_GT = MAKE_GET_OP(GT , op_GT_get , 2, true); +const tele_op_t op_LTE = MAKE_GET_OP(LTE , op_LTE_get , 2, true); +const tele_op_t op_GTE = MAKE_GET_OP(GTE , op_GTE_get , 2, true); const tele_op_t op_NZ = MAKE_GET_OP(NZ , op_NZ_get , 1, true); const tele_op_t op_EZ = MAKE_GET_OP(EZ , op_EZ_get , 1, true); const tele_op_t op_RSH = MAKE_GET_OP(RSH , op_RSH_get , 2, true); @@ -108,6 +114,23 @@ const tele_op_t op_N = MAKE_GET_OP(N , op_N_get , 1, true); const tele_op_t op_V = MAKE_GET_OP(V , op_V_get , 1, true); const tele_op_t op_VV = MAKE_GET_OP(VV , op_VV_get , 1, true); const tele_op_t op_ER = MAKE_GET_OP(ER , op_ER_get , 3, true); + +const tele_op_t op_SYM_PLUS = MAKE_ALIAS_OP(+ , op_ADD_get, NULL, 2, true); +const tele_op_t op_SYM_DASH = MAKE_ALIAS_OP(- , op_SUB_get, NULL, 2, true); +const tele_op_t op_SYM_STAR = MAKE_ALIAS_OP(* , op_MUL_get, NULL, 2, true); +const tele_op_t op_SYM_FORWARD_SLASH = MAKE_ALIAS_OP(/ , op_DIV_get, NULL, 2, true); +const tele_op_t op_SYM_PERCENTAGE = MAKE_ALIAS_OP(% , op_MOD_get, NULL, 2, true); +const tele_op_t op_SYM_EQUAL_x2 = MAKE_ALIAS_OP(==, op_EQ_get , NULL, 2, true); +const tele_op_t op_SYM_EXCLAMATION_EQUAL = MAKE_ALIAS_OP(!=, op_NE_get , NULL, 2, true); +const tele_op_t op_SYM_LEFT_ANGLED = MAKE_ALIAS_OP(< , op_LT_get , NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED = MAKE_ALIAS_OP(> , op_GT_get , NULL, 2, true); +const tele_op_t op_SYM_LEFT_ANGLED_EQUAL = MAKE_ALIAS_OP(<=, op_LTE_get, NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL = MAKE_ALIAS_OP(>=, op_GTE_get, NULL, 2, true); +const tele_op_t op_SYM_EXCLAMATION = MAKE_ALIAS_OP(! , op_EZ_get , NULL, 1, true); +const tele_op_t op_SYM_LEFT_ANGLED_x2 = MAKE_ALIAS_OP(<<, op_LSH_get, NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED_x2 = MAKE_ALIAS_OP(>>, op_RSH_get, NULL, 2, true); +const tele_op_t op_AMPERSAND_x2 = MAKE_ALIAS_OP(&&, op_AND_get, NULL, 2, true); +const tele_op_t op_PIPE_x2 = MAKE_ALIAS_OP(||, op_OR_get , NULL, 2, true); // clang-format on @@ -128,12 +151,18 @@ static void op_MUL_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_DIV_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, cs_pop(cs) / cs_pop(cs)); + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t out = b != 0 ? a / b : 0; + cs_push(cs, out); } static void op_MOD_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, cs_pop(cs) % cs_pop(cs)); + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + int16_t out = b != 0 ? a % b : 0; + cs_push(cs, out); } static void op_RAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), @@ -232,6 +261,11 @@ static void op_QT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), b = cs_pop(cs); a = cs_pop(cs); + if (a == 0) { + cs_push(cs, 0); + return; + } + c = b / a; d = c * a; e = (c + 1) * a; @@ -267,6 +301,16 @@ static void op_GT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), cs_push(cs, cs_pop(cs) > cs_pop(cs)); } +static void op_LTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, cs_pop(cs) <= cs_pop(cs)); +} + +static void op_GTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, cs_pop(cs) >= cs_pop(cs)); +} + static void op_NZ_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, cs_pop(cs) != 0); @@ -332,7 +376,15 @@ static void op_XOR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_JI_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - uint32_t ji = (((cs_pop(cs) << 8) / cs_pop(cs)) * 1684) >> 8; + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + + if (a == 0) { + cs_push(cs, 0); + return; + } + + uint32_t ji = (((a << 8) / b) * 1684) >> 8; while (ji > 1683) ji >>= 1; cs_push(cs, ji); } @@ -346,6 +398,11 @@ static void op_SCALE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), y = cs_pop(cs); i = cs_pop(cs); + if ((b - a) == 0) { + cs_push(cs, 0); + return; + } + cs_push(cs, (i - a) * (y - x) / (b - a) + x); } diff --git a/src/ops/maths.h b/src/ops/maths.h index d340a8fc..5e51ef12 100644 --- a/src/ops/maths.h +++ b/src/ops/maths.h @@ -21,6 +21,8 @@ extern const tele_op_t op_EQ; extern const tele_op_t op_NE; extern const tele_op_t op_LT; extern const tele_op_t op_GT; +extern const tele_op_t op_LTE; +extern const tele_op_t op_GTE; extern const tele_op_t op_NZ; extern const tele_op_t op_EZ; extern const tele_op_t op_RSH; @@ -37,5 +39,21 @@ extern const tele_op_t op_V; extern const tele_op_t op_VV; extern const tele_op_t op_ER; +extern const tele_op_t op_SYM_PLUS; // + alias ADD +extern const tele_op_t op_SYM_DASH; // - alias SUB +extern const tele_op_t op_SYM_STAR; // * alias MUL +extern const tele_op_t op_SYM_FORWARD_SLASH; // / alias DIV +extern const tele_op_t op_SYM_PERCENTAGE; // % alias MOD +extern const tele_op_t op_SYM_EQUAL_x2; // == alias EQ +extern const tele_op_t op_SYM_EXCLAMATION_EQUAL; // != alias NE +extern const tele_op_t op_SYM_LEFT_ANGLED; // < alias LT +extern const tele_op_t op_SYM_RIGHT_ANGLED; // > alias GT +extern const tele_op_t op_SYM_LEFT_ANGLED_EQUAL; // <= alias LTE +extern const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL; // >= alias GT +extern const tele_op_t op_SYM_EXCLAMATION; // ! alias NZ +extern const tele_op_t op_SYM_LEFT_ANGLED_x2; // << alias LSH +extern const tele_op_t op_SYM_RIGHT_ANGLED_x2; // >> alias RSH +extern const tele_op_t op_AMPERSAND_x2; // && alias AND +extern const tele_op_t op_PIPE_x2; // || alias OR #endif diff --git a/src/ops/meadowphysics.c b/src/ops/meadowphysics.c new file mode 100644 index 00000000..2b771661 --- /dev/null +++ b/src/ops/meadowphysics.c @@ -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); diff --git a/src/ops/meadowphysics.h b/src/ops/meadowphysics.h new file mode 100644 index 00000000..838183d1 --- /dev/null +++ b/src/ops/meadowphysics.h @@ -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 diff --git a/src/ops/metronome.c b/src/ops/metronome.c index 225c364c..9ad563b8 100644 --- a/src/ops/metronome.c +++ b/src/ops/metronome.c @@ -26,7 +26,7 @@ static void op_M_set(const void *NOTUSED(data), scene_state_t *ss, int16_t m = cs_pop(cs); if (m < 10) m = 10; ss->variables.m = m; - tele_metro(m, ss->variables.m_act, 0); + tele_metro_updated(); } const tele_op_t op_M_ACT = @@ -40,16 +40,16 @@ static void op_M_ACT_get(const void *NOTUSED(data), scene_state_t *ss, static void op_M_ACT_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t m_act = cs_pop(cs); - if (m_act != 0) m_act = 1; + bool m_act = cs_pop(cs) > 0; ss->variables.m_act = m_act; - tele_metro(ss->variables.m, m_act, 0); + tele_metro_updated(); } const tele_op_t op_M_RESET = MAKE_GET_OP(M.RESET, op_M_RESET_get, 0, false); -static void op_M_RESET_get(const void *NOTUSED(data), scene_state_t *ss, +static void op_M_RESET_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { - tele_metro(ss->variables.m, ss->variables.m_act, 1); + tele_metro_reset(); } diff --git a/src/ops/op.c b/src/ops/op.c index 83df5517..71612620 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -3,60 +3,65 @@ #include // offsetof #include "helpers.h" +#include "teletype_io.h" -#include "ops/constants.h" +#include "ops/ansible.h" #include "ops/controlflow.h" #include "ops/delay.h" +#include "ops/earthsea.h" #include "ops/hardware.h" +#include "ops/justfriends.h" #include "ops/maths.h" +#include "ops/meadowphysics.h" #include "ops/metronome.h" +#include "ops/orca.h" #include "ops/patterns.h" #include "ops/queue.h" #include "ops/stack.h" #include "ops/telex.h" #include "ops/variables.h" +#include "ops/whitewhale.h" ///////////////////////////////////////////////////////////////// // OPS ////////////////////////////////////////////////////////// -const tele_op_t *tele_ops[OPS] = { +// If you edit this array, you need to run 'utils/op_enums.py' to update the +// values in 'op_enum.h' so that the order matches. +const tele_op_t *tele_ops[E_OP__LENGTH] = { // variables &op_A, &op_B, &op_C, &op_D, &op_DRUNK, &op_DRUNK_MAX, &op_DRUNK_MIN, - &op_DRUNK_WRAP, &op_FLIP, &op_I, &op_IN, &op_O, &op_O_INC, &op_O_MAX, - &op_O_MIN, &op_O_WRAP, &op_PARAM, &op_T, &op_TIME, &op_TIME_ACT, &op_X, - &op_Y, &op_Z, + &op_DRUNK_WRAP, &op_FLIP, &op_I, &op_O, &op_O_INC, &op_O_MAX, &op_O_MIN, + &op_O_WRAP, &op_T, &op_TIME, &op_TIME_ACT, &op_X, &op_Y, &op_Z, // metronome &op_M, &op_M_ACT, &op_M_RESET, // patterns - &op_P, &op_P_HERE, &op_P_END, &op_P_I, &op_P_L, &op_P_N, &op_P_NEXT, - &op_P_PREV, &op_P_START, &op_P_WRAP, &op_P_INS, &op_P_RM, &op_P_PUSH, - &op_P_POP, &op_PN, + &op_P_N, &op_P, &op_PN, &op_P_L, &op_PN_L, &op_P_WRAP, &op_PN_WRAP, + &op_P_START, &op_PN_START, &op_P_END, &op_PN_END, &op_P_I, &op_PN_I, + &op_P_HERE, &op_PN_HERE, &op_P_NEXT, &op_PN_NEXT, &op_P_PREV, &op_PN_PREV, + &op_P_INS, &op_PN_INS, &op_P_RM, &op_PN_RM, &op_P_PUSH, &op_PN_PUSH, + &op_P_POP, &op_PN_POP, // queue &op_Q, &op_Q_AVG, &op_Q_N, // hardware - &op_CV, &op_CV_OFF, &op_CV_SLEW, &op_TR, &op_TR_POL, &op_TR_TIME, - &op_TR_TOG, &op_TR_PULSE, &op_II, &op_CV_SET, &op_MUTE, &op_UNMUTE, - &op_STATE, &op_JF_TR, &op_JF_RMODE, &op_JF_RUN, &op_JF_SHIFT, &op_JF_VTR, - &op_JF_MODE, &op_JF_TICK, &op_JF_VOX, &op_JF_NOTE, &op_JF_GOD, &op_JF_TUNE, - &op_JF_QT, &op_KR_PRESET, &op_KR_PATTERN, &op_KR_SCALE, &op_KR_PERIOD, - &op_KR_POS, &op_KR_LOOP_ST, &op_KR_LOOP_LEN, &op_KR_RESET, &op_MP_PRESET1, - &op_MP_RESET1, &op_MP_STOP1, &op_MP_SCALE, &op_MP_PERIOD, &op_LV_PRESET, - &op_LV_RESET, &op_LV_POS, &op_LV_L_ST, &op_LV_L_LEN, &op_LV_L_DIR, - &op_LV_CV, &op_CY_PRESET, &op_CY_RESET, &op_CY_POS, &op_CY_REV, &op_CY_CV, - &op_MID_SLEW, &op_MID_SHIFT, &op_ARP_STYLE, &op_ARP_HOLD, &op_ARP_RPT, - &op_ARP_GATE, &op_ARP_DIV, &op_ARP_RESET, &op_ARP_SHIFT, &op_ARP_SLEW, - &op_ARP_FILL, &op_ARP_ROT, &op_ARP_ER, + &op_CV, &op_CV_OFF, &op_CV_SLEW, &op_IN, &op_PARAM, &op_PRM, &op_TR, + &op_TR_POL, &op_TR_TIME, &op_TR_TOG, &op_TR_PULSE, &op_TR_P, &op_CV_SET, + &op_MUTE, &op_STATE, // maths &op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RRAND, &op_TOSS, &op_MIN, &op_MAX, &op_LIM, &op_WRAP, &op_QT, &op_AVG, &op_EQ, &op_NE, &op_LT, &op_GT, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, &op_ABS, &op_AND, &op_OR, &op_XOR, &op_JI, &op_SCALE, &op_N, &op_V, &op_VV, &op_ER, + &op_SYM_PLUS, &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, + &op_SYM_PERCENTAGE, &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, + &op_SYM_LEFT_ANGLED, &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, + &op_SYM_RIGHT_ANGLED_EQUAL, &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, + &op_SYM_RIGHT_ANGLED_x2, &op_AMPERSAND_x2, &op_PIPE_x2, // stack &op_S_ALL, &op_S_POP, &op_S_CLR, &op_S_L, @@ -67,17 +72,37 @@ const tele_op_t *tele_ops[OPS] = { // delay &op_DEL_CLR, - // constants + // whitewhale &op_WW_PRESET, &op_WW_POS, &op_WW_SYNC, &op_WW_START, &op_WW_END, &op_WW_PMODE, &op_WW_PATTERN, &op_WW_QPATTERN, &op_WW_MUTE1, &op_WW_MUTE2, - &op_WW_MUTE3, &op_WW_MUTE4, &op_WW_MUTEA, &op_WW_MUTEB, &op_MP_PRESET, - &op_MP_RESET, &op_MP_SYNC, &op_MP_MUTE, &op_MP_UNMUTE, &op_MP_FREEZE, - &op_MP_UNFREEZE, &op_MP_STOP, &op_ES_PRESET, &op_ES_MODE, &op_ES_CLOCK, - &op_ES_RESET, &op_ES_PATTERN, &op_ES_TRANS, &op_ES_STOP, &op_ES_TRIPLE, - &op_ES_MAGIC, &op_ORCA_TRK, &op_ORCA_CLK, &op_ORCA_DIV, &op_ORCA_PHASE, - &op_ORCA_RST, &op_ORCA_WGT, &op_ORCA_MUTE, &op_ORCA_SCALE, &op_ORCA_BANK, - &op_ORCA_PRESET, &op_ORCA_RELOAD, &op_ORCA_ROTS, &op_ORCA_ROTW, - &op_ORCA_GRST, &op_ORCA_CVA, &op_ORCA_CVB, + &op_WW_MUTE3, &op_WW_MUTE4, &op_WW_MUTEA, &op_WW_MUTEB, + + // meadowphysics + &op_MP_PRESET, &op_MP_RESET, &op_MP_SYNC, &op_MP_MUTE, &op_MP_UNMUTE, + &op_MP_FREEZE, &op_MP_UNFREEZE, &op_MP_STOP, + + // earthsea + &op_ES_PRESET, &op_ES_MODE, &op_ES_CLOCK, &op_ES_RESET, &op_ES_PATTERN, + &op_ES_TRANS, &op_ES_STOP, &op_ES_TRIPLE, &op_ES_MAGIC, + + // orca + &op_OR_TRK, &op_OR_CLK, &op_OR_DIV, &op_OR_PHASE, &op_OR_RST, &op_OR_WGT, + &op_OR_MUTE, &op_OR_SCALE, &op_OR_BANK, &op_OR_PRESET, &op_OR_RELOAD, + &op_OR_ROTS, &op_OR_ROTW, &op_OR_GRST, &op_OR_CVA, &op_OR_CVB, + + // ansible + &op_KR_PRESET, &op_KR_PATTERN, &op_KR_SCALE, &op_KR_PERIOD, &op_KR_POS, + &op_KR_LOOP_ST, &op_KR_LOOP_LEN, &op_KR_RESET, &op_MP_PRESET1, + &op_MP_RESET1, &op_MP_STOP1, &op_MP_SCALE, &op_MP_PERIOD, &op_LV_PRESET, + &op_LV_RESET, &op_LV_POS, &op_LV_L_ST, &op_LV_L_LEN, &op_LV_L_DIR, + &op_LV_CV, &op_CY_PRESET, &op_CY_RESET, &op_CY_POS, &op_CY_REV, &op_CY_CV, + &op_MID_SHIFT, &op_MID_SLEW, &op_ARP_STYLE, &op_ARP_HOLD, &op_ARP_RPT, + &op_ARP_GATE, &op_ARP_DIV, &op_ARP_RESET, &op_ARP_SHIFT, &op_ARP_SLEW, + &op_ARP_FILL, &op_ARP_ROT, &op_ARP_ER, + + // justfriends + &op_JF_TR, &op_JF_RMODE, &op_JF_RUN, &op_JF_SHIFT, &op_JF_VTR, &op_JF_MODE, + &op_JF_TICK, &op_JF_VOX, &op_JF_NOTE, &op_JF_GOD, &op_JF_TUNE, &op_JF_QT, // telex &op_TO_TR, &op_TO_TR_TOG, &op_TO_TR_PULSE, &op_TO_TR_TIME, &op_TO_TR_TIME_S, @@ -91,6 +116,10 @@ const tele_op_t *tele_ops[OPS] = { &op_TO_CV_SET, &op_TO_CV_OFF, &op_TO_CV_QT, &op_TO_CV_QT_SET, &op_TO_CV_N, &op_TO_CV_N_SET, &op_TO_CV_SCALE, + &op_TO_CV_INIT, &op_TO_TR_INIT, &op_TO_INIT, + + &op_TO_TR_P, &op_TO_TR_P_DIV, + &op_TO_OSC, &op_TO_OSC_SET, &op_TO_OSC_QT, &op_TO_OSC_QT_SET, &op_TO_OSC_FQ, &op_TO_OSC_FQ_SET, &op_TO_OSC_N, &op_TO_OSC_N_SET, &op_TO_OSC_LFO, &op_TO_OSC_LFO_SET, &op_TO_OSC_WAVE, &op_TO_OSC_SYNC, &op_TO_OSC_PHASE, @@ -105,13 +134,18 @@ const tele_op_t *tele_ops[OPS] = { &op_TI_PARAM, &op_TI_PARAM_QT, &op_TI_PARAM_N, &op_TI_PARAM_SCALE, &op_TI_PARAM_MAP, &op_TI_IN, &op_TI_IN_QT, &op_TI_IN_N, &op_TI_IN_SCALE, &op_TI_IN_MAP, &op_TI_PARAM_CALIB, &op_TI_IN_CALIB, &op_TI_STORE, - &op_TI_RESET + &op_TI_RESET, + + &op_TI_PARAM_INIT, &op_TI_IN_INIT, &op_TI_INIT, + + &op_TI_PRM, &op_TI_PRM_QT, &op_TI_PRM_N, &op_TI_PRM_SCALE, &op_TI_PRM_MAP, + &op_TI_PRM_INIT }; ///////////////////////////////////////////////////////////////// // MODS ///////////////////////////////////////////////////////// -const tele_mod_t *tele_mods[MODS] = { +const tele_mod_t *tele_mods[E_MOD__LENGTH] = { // controlflow &mod_IF, &mod_ELIF, &mod_ELSE, &mod_L, &mod_PROB, @@ -126,11 +160,6 @@ const tele_mod_t *tele_mods[MODS] = { ///////////////////////////////////////////////////////////////// // HELPERS ////////////////////////////////////////////////////// -void op_constant(const void *data, scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, (intptr_t)data); -} - void op_peek_i16(const void *data, scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { char *base = (char *)ss; @@ -146,3 +175,16 @@ void op_poke_i16(const void *data, scene_state_t *ss, exec_state_t *NOTUSED(es), int16_t *ptr = (int16_t *)(base + offset); *ptr = cs_pop(cs); } + +void op_simple_i2c(const void *data, scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t message = (intptr_t)data; + int16_t value = cs_pop(cs); + + uint8_t address = message & 0xF0; + uint8_t message_type = message & 0xFF; + + uint8_t buffer[3] = { message_type, value >> 8, value & 0xFF }; + + tele_ii_tx(address, buffer, 3); +} diff --git a/src/ops/op.h b/src/ops/op.h index 668ca133..0484aa41 100644 --- a/src/ops/op.h +++ b/src/ops/op.h @@ -5,6 +5,7 @@ #include #include "command.h" +#include "op_enum.h" #include "state.h" typedef struct { @@ -21,15 +22,12 @@ typedef struct { typedef struct { const char *name; void (*const func)(scene_state_t *ss, exec_state_t *es, command_state_t *cs, - tele_command_t *sub_command); + const tele_command_t *post_command); const uint8_t params; } tele_mod_t; -#define OPS 270 -extern const tele_op_t *tele_ops[OPS]; - -#define MODS 7 -extern const tele_mod_t *tele_mods[MODS]; +extern const tele_op_t *tele_ops[E_OP__LENGTH]; +extern const tele_mod_t *tele_mods[E_MOD__LENGTH]; // Get only ops #define MAKE_GET_OP(n, g, p, r) \ @@ -44,17 +42,6 @@ extern const tele_mod_t *tele_mods[MODS]; { .name = #n, .get = g, .set = s, .params = p, .returns = r, .data = NULL } -// Constant Ops -#define MAKE_CONSTANT_OP(n, v) \ - { \ - .name = #n, .get = op_constant, .set = NULL, .params = 0, \ - .returns = 1, .data = (void *)v \ - } - -void op_constant(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - - // Variables, peek & poke #define MAKE_SIMPLE_VARIABLE_OP(n, v) \ { \ @@ -67,6 +54,23 @@ void op_peek_i16(const void *data, scene_state_t *ss, exec_state_t *es, void op_poke_i16(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +// Alias one OP to another +#define MAKE_ALIAS_OP(n, g, s, p, r) \ + { .name = #n, .get = g, .set = s, .params = p, .returns = r, .data = NULL } + + +// Simple I2C op (to support the original Trilogy modules) +#define MAKE_SIMPLE_I2C_OP(n, v) \ + { \ + .name = #n, .get = op_simple_i2c, .set = NULL, .params = 1, \ + .returns = 0, .data = (void *)v \ + } + +void op_simple_i2c(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + + // Mods #define MAKE_MOD(n, f, p) \ { .name = #n, .func = f, .params = p } diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h new file mode 100644 index 00000000..df42d3a4 --- /dev/null +++ b/src/ops/op_enum.h @@ -0,0 +1,335 @@ +// clang-format off + +#ifndef _OP_ENUM_H_ +#define _OP_ENUM_H_ + +// This file has been autogenerated by 'utils/op_enums.py' + +typedef enum { + E_OP_A, + E_OP_B, + E_OP_C, + E_OP_D, + E_OP_DRUNK, + E_OP_DRUNK_MAX, + E_OP_DRUNK_MIN, + E_OP_DRUNK_WRAP, + E_OP_FLIP, + E_OP_I, + E_OP_O, + E_OP_O_INC, + E_OP_O_MAX, + E_OP_O_MIN, + E_OP_O_WRAP, + E_OP_T, + E_OP_TIME, + E_OP_TIME_ACT, + E_OP_X, + E_OP_Y, + E_OP_Z, + E_OP_M, + E_OP_M_ACT, + E_OP_M_RESET, + E_OP_P_N, + E_OP_P, + E_OP_PN, + E_OP_P_L, + E_OP_PN_L, + E_OP_P_WRAP, + E_OP_PN_WRAP, + E_OP_P_START, + E_OP_PN_START, + E_OP_P_END, + E_OP_PN_END, + E_OP_P_I, + E_OP_PN_I, + E_OP_P_HERE, + E_OP_PN_HERE, + E_OP_P_NEXT, + E_OP_PN_NEXT, + E_OP_P_PREV, + E_OP_PN_PREV, + E_OP_P_INS, + E_OP_PN_INS, + E_OP_P_RM, + E_OP_PN_RM, + E_OP_P_PUSH, + E_OP_PN_PUSH, + E_OP_P_POP, + E_OP_PN_POP, + E_OP_Q, + E_OP_Q_AVG, + E_OP_Q_N, + E_OP_CV, + E_OP_CV_OFF, + E_OP_CV_SLEW, + E_OP_IN, + E_OP_PARAM, + E_OP_PRM, + E_OP_TR, + E_OP_TR_POL, + E_OP_TR_TIME, + E_OP_TR_TOG, + E_OP_TR_PULSE, + E_OP_TR_P, + E_OP_CV_SET, + E_OP_MUTE, + E_OP_STATE, + E_OP_ADD, + E_OP_SUB, + E_OP_MUL, + E_OP_DIV, + E_OP_MOD, + E_OP_RAND, + E_OP_RRAND, + E_OP_TOSS, + E_OP_MIN, + E_OP_MAX, + E_OP_LIM, + E_OP_WRAP, + E_OP_QT, + E_OP_AVG, + E_OP_EQ, + E_OP_NE, + E_OP_LT, + E_OP_GT, + E_OP_NZ, + E_OP_EZ, + E_OP_RSH, + E_OP_LSH, + E_OP_EXP, + E_OP_ABS, + E_OP_AND, + E_OP_OR, + E_OP_XOR, + E_OP_JI, + E_OP_SCALE, + E_OP_N, + E_OP_V, + E_OP_VV, + E_OP_ER, + E_OP_SYM_PLUS, + E_OP_SYM_DASH, + E_OP_SYM_STAR, + E_OP_SYM_FORWARD_SLASH, + E_OP_SYM_PERCENTAGE, + E_OP_SYM_EQUAL_x2, + E_OP_SYM_EXCLAMATION_EQUAL, + E_OP_SYM_LEFT_ANGLED, + E_OP_SYM_RIGHT_ANGLED, + E_OP_SYM_LEFT_ANGLED_EQUAL, + E_OP_SYM_RIGHT_ANGLED_EQUAL, + E_OP_SYM_EXCLAMATION, + E_OP_SYM_LEFT_ANGLED_x2, + E_OP_SYM_RIGHT_ANGLED_x2, + E_OP_AMPERSAND_x2, + E_OP_PIPE_x2, + E_OP_S_ALL, + E_OP_S_POP, + E_OP_S_CLR, + E_OP_S_L, + E_OP_SCRIPT, + E_OP_KILL, + E_OP_SCENE, + E_OP_DEL_CLR, + E_OP_WW_PRESET, + E_OP_WW_POS, + E_OP_WW_SYNC, + E_OP_WW_START, + E_OP_WW_END, + E_OP_WW_PMODE, + E_OP_WW_PATTERN, + E_OP_WW_QPATTERN, + E_OP_WW_MUTE1, + E_OP_WW_MUTE2, + E_OP_WW_MUTE3, + E_OP_WW_MUTE4, + E_OP_WW_MUTEA, + E_OP_WW_MUTEB, + E_OP_MP_PRESET, + E_OP_MP_RESET, + E_OP_MP_SYNC, + E_OP_MP_MUTE, + E_OP_MP_UNMUTE, + E_OP_MP_FREEZE, + E_OP_MP_UNFREEZE, + E_OP_MP_STOP, + E_OP_ES_PRESET, + E_OP_ES_MODE, + E_OP_ES_CLOCK, + E_OP_ES_RESET, + E_OP_ES_PATTERN, + E_OP_ES_TRANS, + E_OP_ES_STOP, + E_OP_ES_TRIPLE, + E_OP_ES_MAGIC, + E_OP_OR_TRK, + E_OP_OR_CLK, + E_OP_OR_DIV, + E_OP_OR_PHASE, + E_OP_OR_RST, + E_OP_OR_WGT, + E_OP_OR_MUTE, + E_OP_OR_SCALE, + E_OP_OR_BANK, + E_OP_OR_PRESET, + E_OP_OR_RELOAD, + E_OP_OR_ROTS, + E_OP_OR_ROTW, + E_OP_OR_GRST, + E_OP_OR_CVA, + E_OP_OR_CVB, + E_OP_KR_PRESET, + E_OP_KR_PATTERN, + E_OP_KR_SCALE, + E_OP_KR_PERIOD, + E_OP_KR_POS, + E_OP_KR_LOOP_ST, + E_OP_KR_LOOP_LEN, + E_OP_KR_RESET, + E_OP_MP_PRESET1, + E_OP_MP_RESET1, + E_OP_MP_STOP1, + E_OP_MP_SCALE, + E_OP_MP_PERIOD, + E_OP_LV_PRESET, + E_OP_LV_RESET, + E_OP_LV_POS, + E_OP_LV_L_ST, + E_OP_LV_L_LEN, + E_OP_LV_L_DIR, + E_OP_LV_CV, + E_OP_CY_PRESET, + E_OP_CY_RESET, + E_OP_CY_POS, + E_OP_CY_REV, + E_OP_CY_CV, + E_OP_MID_SHIFT, + E_OP_MID_SLEW, + E_OP_ARP_STYLE, + E_OP_ARP_HOLD, + E_OP_ARP_RPT, + E_OP_ARP_GATE, + E_OP_ARP_DIV, + E_OP_ARP_RESET, + E_OP_ARP_SHIFT, + E_OP_ARP_SLEW, + E_OP_ARP_FILL, + E_OP_ARP_ROT, + E_OP_ARP_ER, + E_OP_JF_TR, + E_OP_JF_RMODE, + E_OP_JF_RUN, + E_OP_JF_SHIFT, + E_OP_JF_VTR, + E_OP_JF_MODE, + E_OP_JF_TICK, + E_OP_JF_VOX, + E_OP_JF_NOTE, + E_OP_JF_GOD, + E_OP_JF_TUNE, + E_OP_JF_QT, + E_OP_TO_TR, + E_OP_TO_TR_TOG, + E_OP_TO_TR_PULSE, + E_OP_TO_TR_TIME, + E_OP_TO_TR_TIME_S, + E_OP_TO_TR_TIME_M, + E_OP_TO_TR_POL, + E_OP_TO_KILL, + E_OP_TO_TR_PULSE_DIV, + E_OP_TO_TR_M, + E_OP_TO_TR_M_S, + E_OP_TO_TR_M_M, + E_OP_TO_TR_M_BPM, + E_OP_TO_TR_M_ACT, + E_OP_TO_TR_M_SYNC, + E_OP_TO_TR_WIDTH, + E_OP_TO_TR_M_COUNT, + E_OP_TO_CV, + E_OP_TO_CV_SLEW, + E_OP_TO_CV_SLEW_S, + E_OP_TO_CV_SLEW_M, + E_OP_TO_CV_SET, + E_OP_TO_CV_OFF, + E_OP_TO_CV_QT, + E_OP_TO_CV_QT_SET, + E_OP_TO_CV_N, + E_OP_TO_CV_N_SET, + E_OP_TO_CV_SCALE, + E_OP_TO_CV_INIT, + E_OP_TO_TR_INIT, + E_OP_TO_INIT, + E_OP_TO_TR_P, + E_OP_TO_TR_P_DIV, + E_OP_TO_OSC, + E_OP_TO_OSC_SET, + E_OP_TO_OSC_QT, + E_OP_TO_OSC_QT_SET, + E_OP_TO_OSC_FQ, + E_OP_TO_OSC_FQ_SET, + E_OP_TO_OSC_N, + E_OP_TO_OSC_N_SET, + E_OP_TO_OSC_LFO, + E_OP_TO_OSC_LFO_SET, + E_OP_TO_OSC_WAVE, + E_OP_TO_OSC_SYNC, + E_OP_TO_OSC_PHASE, + E_OP_TO_OSC_WIDTH, + E_OP_TO_OSC_RECT, + E_OP_TO_OSC_SLEW, + E_OP_TO_OSC_SLEW_S, + E_OP_TO_OSC_SLEW_M, + E_OP_TO_OSC_SCALE, + E_OP_TO_OSC_CYC, + E_OP_TO_OSC_CYC_S, + E_OP_TO_OSC_CYC_M, + E_OP_TO_OSC_CYC_SET, + E_OP_TO_OSC_CYC_S_SET, + E_OP_TO_OSC_CYC_M_SET, + E_OP_TO_ENV_ACT, + E_OP_TO_ENV_ATT, + E_OP_TO_ENV_ATT_S, + E_OP_TO_ENV_ATT_M, + E_OP_TO_ENV_DEC, + E_OP_TO_ENV_DEC_S, + E_OP_TO_ENV_DEC_M, + E_OP_TO_ENV_TRIG, + E_OP_TI_PARAM, + E_OP_TI_PARAM_QT, + E_OP_TI_PARAM_N, + E_OP_TI_PARAM_SCALE, + E_OP_TI_PARAM_MAP, + E_OP_TI_IN, + E_OP_TI_IN_QT, + E_OP_TI_IN_N, + E_OP_TI_IN_SCALE, + E_OP_TI_IN_MAP, + E_OP_TI_PARAM_CALIB, + E_OP_TI_IN_CALIB, + E_OP_TI_STORE, + E_OP_TI_RESET, + E_OP_TI_PARAM_INIT, + E_OP_TI_IN_INIT, + E_OP_TI_INIT, + E_OP_TI_PRM, + E_OP_TI_PRM_QT, + E_OP_TI_PRM_N, + E_OP_TI_PRM_SCALE, + E_OP_TI_PRM_MAP, + E_OP_TI_PRM_INIT, + E_OP__LENGTH, +} tele_op_idx_t; + +typedef enum { + E_MOD_IF, + E_MOD_ELIF, + E_MOD_ELSE, + E_MOD_L, + E_MOD_PROB, + E_MOD_DEL, + E_MOD_S, + E_MOD__LENGTH, +} tele_mod_idx_t; + +#endif diff --git a/src/ops/orca.c b/src/ops/orca.c new file mode 100644 index 00000000..1c23732f --- /dev/null +++ b/src/ops/orca.c @@ -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); diff --git a/src/ops/orca.h b/src/ops/orca.h new file mode 100644 index 00000000..cc5927ef --- /dev/null +++ b/src/ops/orca.h @@ -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 diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 8d736696..14cc0098 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -4,78 +4,40 @@ #include "teletype.h" #include "teletype_io.h" -static void op_P_N_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_N_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_L_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_L_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_I_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_I_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_HERE_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_HERE_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_NEXT_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_NEXT_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_PREV_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_PREV_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_WRAP_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_WRAP_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_START_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_P_START_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_P_END_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_END_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_INS_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_RM_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_PUSH_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_P_POP_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_PN_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_PN_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); - -// clang-format off -const tele_op_t op_P = MAKE_GET_SET_OP(P , op_P_get , op_P_set , 1, true); -const tele_op_t op_P_HERE = MAKE_GET_SET_OP(P.HERE , op_P_HERE_get , op_P_HERE_set , 0, true); -const tele_op_t op_P_END = MAKE_GET_SET_OP(P.END , op_P_END_get , op_P_END_set , 0, true); -const tele_op_t op_P_I = MAKE_GET_SET_OP(P.I , op_P_I_get , op_P_I_set , 0, true); -const tele_op_t op_P_L = MAKE_GET_SET_OP(P.L , op_P_L_get , op_P_L_set , 0, true); -const tele_op_t op_P_N = MAKE_GET_SET_OP(P.N , op_P_N_get , op_P_N_set , 0, true); -const tele_op_t op_P_NEXT = MAKE_GET_SET_OP(P.NEXT , op_P_NEXT_get , op_P_NEXT_set , 0, true); -const tele_op_t op_P_PREV = MAKE_GET_SET_OP(P.PREV , op_P_PREV_get , op_P_PREV_set , 0, true); -const tele_op_t op_P_START = MAKE_GET_SET_OP(P.START, op_P_START_get, op_P_START_set, 0, true); -const tele_op_t op_P_WRAP = MAKE_GET_SET_OP(P.WRAP , op_P_WRAP_get , op_P_WRAP_set , 0, true); -const tele_op_t op_PN = MAKE_GET_SET_OP(PN , op_PN_get , op_PN_set , 2, true); - -const tele_op_t op_P_INS = MAKE_GET_OP(P.INS , op_P_INS_get , 2, false); -const tele_op_t op_P_RM = MAKE_GET_OP(P.RM , op_P_RM_get , 1, true ); -const tele_op_t op_P_PUSH = MAKE_GET_OP(P.PUSH , op_P_PUSH_get , 1, false); -const tele_op_t op_P_POP = MAKE_GET_OP(P.POP , op_P_POP_get , 0, true ); -// clang-format on +//////////////////////////////////////////////////////////////////////////////// +// Helpers ///////////////////////////////////////////////////////////////////// + +// limit pn to within 0 and 3 inclusive +static int16_t normalise_pn(const int16_t pn) { + if (pn < 0) + return 0; + else if (pn >= PATTERN_COUNT) + return PATTERN_COUNT - 1; + else + return pn; +} + +// ensure that the pattern index is within bounds +// also adjust for negative indices (they index from the back) +static int16_t normalise_idx(scene_state_t *ss, const int16_t pn, int16_t idx) { + const int16_t len = ss_get_pattern_len(ss, pn); + if (idx < 0) { + if (idx == len) + idx = 0; + else if (idx < -len) + idx = 0; + else + idx = len + idx; + } + + if (idx >= PATTERN_LENGTH) idx = PATTERN_LENGTH - 1; + + return idx; +} + +//////////////////////////////////////////////////////////////////////////////// +// P.N ///////////////////////////////////////////////////////////////////////// static void op_P_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -85,363 +47,614 @@ static void op_P_N_get(const void *NOTUSED(data), scene_state_t *ss, static void op_P_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); - if (a < 0) - a = 0; - else if (a > 3) - a = 3; - ss->variables.p_n = a; + ss->variables.p_n = normalise_pn(a); +} + +const tele_op_t op_P_N = MAKE_GET_SET_OP(P.N, op_P_N_get, op_P_N_set, 0, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P and PN //////////////////////////////////////////////////////////////////// + +// Get +static int16_t p_get(scene_state_t *ss, int16_t pn, int16_t idx) { + pn = normalise_pn(pn); + idx = normalise_idx(ss, pn, idx); + return ss_get_pattern_val(ss, pn, idx); +} + +static void op_P_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = ss->variables.p_n; + int16_t a = cs_pop(cs); + cs_push(cs, p_get(ss, pn, a)); +} + +static void op_PN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t a = cs_pop(cs); + cs_push(cs, p_get(ss, pn, a)); +} + +// Set +static void p_set(scene_state_t *ss, int16_t pn, int16_t idx, int16_t val) { + pn = normalise_pn(pn); + idx = normalise_idx(ss, pn, idx); + ss_set_pattern_val(ss, pn, idx, val); +} + +static void op_P_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = ss->variables.p_n; + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + p_set(ss, pn, a, b); + tele_pattern_updated(); +} + +static void op_PN_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t a = cs_pop(cs); + int16_t b = cs_pop(cs); + p_set(ss, pn, a, b); + tele_pattern_updated(); } +// Make ops +const tele_op_t op_P = MAKE_GET_SET_OP(P, op_P_get, op_P_set, 1, true); +const tele_op_t op_PN = MAKE_GET_SET_OP(PN, op_PN_get, op_PN_set, 2, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.L and PN.L //////////////////////////////////////////////////////////////// + +// Get static void op_P_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_l(pn)); + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_len(ss, pn)); +} + +static void op_PN_L_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_len(ss, pn)); +} + +// Set +static void p_l_set(scene_state_t *ss, int16_t pn, int16_t l) { + pn = normalise_pn(pn); + if (l < 0) + ss_set_pattern_len(ss, pn, 0); + else if (l > PATTERN_LENGTH) + ss_set_pattern_len(ss, pn, PATTERN_LENGTH); + else + ss_set_pattern_len(ss, pn, l); } static void op_P_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); - if (a < 0) - tele_set_pattern_l(pn, 0); - else if (a > 64) - tele_set_pattern_l(pn, 64); - else - tele_set_pattern_l(pn, a); + p_l_set(ss, pn, a); + tele_pattern_updated(); +} + +static void op_PN_L_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t a = cs_pop(cs); + p_l_set(ss, pn, a); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_L = MAKE_GET_SET_OP(P.L, op_P_L_get, op_P_L_set, 0, true); +const tele_op_t op_PN_L = + MAKE_GET_SET_OP(PN.L, op_PN_L_get, op_PN_L_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.WRAP and PN.WRAP ////////////////////////////////////////////////////////// + +// Get +static void op_P_WRAP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_wrap(ss, pn)); } +static void op_PN_WRAP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_wrap(ss, pn)); +} + +// Set +static void op_P_WRAP_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = ss->variables.p_n; + int16_t a = cs_pop(cs); + ss_set_pattern_wrap(ss, pn, a >= 1); +} + +static void op_PN_WRAP_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + int16_t a = cs_pop(cs); + ss_set_pattern_wrap(ss, pn, a >= 1); +} + +// Make ops +const tele_op_t op_P_WRAP = + MAKE_GET_SET_OP(P.WRAP, op_P_WRAP_get, op_P_WRAP_set, 0, true); +const tele_op_t op_PN_WRAP = + MAKE_GET_SET_OP(PN.WRAP, op_PN_WRAP_get, op_PN_WRAP_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.START and PN.START //////////////////////////////////////////////////////// + +// Get +static void op_P_START_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_start(ss, pn)); +} + +static void op_P_START_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(ss->variables.p_n); + int16_t a = normalise_idx(ss, pn, cs_pop(cs)); + ss_set_pattern_start(ss, pn, a); + tele_pattern_updated(); +} + +// Set +static void op_PN_START_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_start(ss, pn)); +} + +static void op_PN_START_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + int16_t a = normalise_idx(ss, pn, cs_pop(cs)); + ss_set_pattern_start(ss, pn, a); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_START = + MAKE_GET_SET_OP(P.START, op_P_START_get, op_P_START_set, 0, true); +const tele_op_t op_PN_START = + MAKE_GET_SET_OP(PN.START, op_PN_START_get, op_PN_START_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.END and PN.END //////////////////////////////////////////////////////////// + +// Get +static void op_P_END_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_end(ss, pn)); +} + +static void op_PN_END_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_end(ss, pn)); +} + +// Set +static void op_P_END_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(ss->variables.p_n); + int16_t a = normalise_idx(ss, pn, cs_pop(cs)); + ss_set_pattern_end(ss, pn, a); + tele_pattern_updated(); +} + +static void op_PN_END_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + int16_t a = normalise_idx(ss, pn, cs_pop(cs)); + ss_set_pattern_end(ss, pn, a); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_END = + MAKE_GET_SET_OP(P.END, op_P_END_get, op_P_END_set, 0, true); +const tele_op_t op_PN_END = + MAKE_GET_SET_OP(PN.END, op_PN_END_get, op_PN_END_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.I and PN.I //////////////////////////////////////////////////////////////// + +// Get static void op_P_I_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_i(pn)); + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_idx(ss, pn)); +} + +static void op_PN_I_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_idx(ss, pn)); +} + +// Set +static void p_i_set(scene_state_t *ss, int16_t pn, int16_t i) { + pn = normalise_pn(pn); + i = normalise_idx(ss, pn, i); + int16_t len = ss_get_pattern_len(ss, pn); + if (i < 0) + ss_set_pattern_idx(ss, pn, 0); + else if (i > len) + ss_set_pattern_idx(ss, pn, len); + else + ss_set_pattern_idx(ss, pn, i); } static void op_P_I_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); - if (a < 0) - tele_set_pattern_i(pn, 0); - else if (a > tele_get_pattern_l(pn)) - tele_set_pattern_i(pn, tele_get_pattern_l(pn)); - else - tele_set_pattern_i(pn, a); - tele_pi(); + p_i_set(ss, pn, a); + tele_pattern_updated(); } +static void op_PN_I_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t a = cs_pop(cs); + p_i_set(ss, pn, a); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_I = MAKE_GET_SET_OP(P.I, op_P_I_get, op_P_I_set, 0, true); +const tele_op_t op_PN_I = + MAKE_GET_SET_OP(PN.I, op_PN_I_get, op_PN_I_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.HERE and PN.HERE ////////////////////////////////////////////////////////// + +// Get static void op_P_HERE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_val(pn, tele_get_pattern_i(pn))); + int16_t pn = normalise_pn(ss->variables.p_n); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); +} + +static void op_PN_HERE_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); } +// Set static void op_P_HERE_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; + int16_t pn = normalise_pn(ss->variables.p_n); int16_t a = cs_pop(cs); - tele_set_pattern_val(pn, tele_get_pattern_i(pn), a); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); } -static void op_P_NEXT_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - if ((tele_get_pattern_i(pn) == (tele_get_pattern_l(pn) - 1)) || - (tele_get_pattern_i(pn) == tele_get_pattern_end(pn))) { - if (tele_get_pattern_wrap(pn)) - tele_set_pattern_i(pn, tele_get_pattern_start(pn)); +static void op_PN_HERE_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + int16_t a = cs_pop(cs); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); +} + +// Make ops +const tele_op_t op_P_HERE = + MAKE_GET_SET_OP(P.HERE, op_P_HERE_get, op_P_HERE_set, 0, true); +const tele_op_t op_PN_HERE = + MAKE_GET_SET_OP(PN.HERE, op_PN_HERE_get, op_PN_HERE_set, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.NEXT ////////////////////////////////////////////////////////////////////// + +// Increment I obeying START, END, WRAP and L +static void p_next_inc_i(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + + const int16_t len = ss_get_pattern_len(ss, pn); + const int16_t start = ss_get_pattern_start(ss, pn); + const int16_t end = ss_get_pattern_end(ss, pn); + const uint16_t wrap = ss_get_pattern_wrap(ss, pn); + + int16_t idx = ss_get_pattern_idx(ss, pn); + + if ((idx == (len - 1)) || (idx == end)) { + if (wrap) idx = start; } else - tele_set_pattern_i(pn, tele_get_pattern_i(pn) + 1); - - if (tele_get_pattern_i(pn) > tele_get_pattern_l(pn)) - tele_set_pattern_i(pn, 0); + idx++; - cs_push(cs, tele_get_pattern_val(pn, tele_get_pattern_i(pn))); + if (idx > len || idx < 0 || idx >= PATTERN_LENGTH) idx = 0; - tele_pi(); + ss_set_pattern_idx(ss, pn, idx); } -static void op_P_NEXT_set(const void *NOTUSED(data), scene_state_t *ss, +// Get +static void op_P_NEXT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - if ((tele_get_pattern_i(pn) == (tele_get_pattern_l(pn) - 1)) || - (tele_get_pattern_i(pn) == tele_get_pattern_end(pn))) { - if (tele_get_pattern_wrap(pn)) - tele_set_pattern_i(pn, tele_get_pattern_start(pn)); - } - else - tele_set_pattern_i(pn, tele_get_pattern_i(pn) + 1); + const int16_t pn = normalise_pn(ss->variables.p_n); + p_next_inc_i(ss, pn); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); + tele_pattern_updated(); +} - if (tele_get_pattern_i(pn) > tele_get_pattern_l(pn)) - tele_set_pattern_i(pn, 0); +static void op_PN_NEXT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + const int16_t pn = normalise_pn(cs_pop(cs)); + p_next_inc_i(ss, pn); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); + tele_pattern_updated(); +} +// Set +static void op_P_NEXT_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + const int16_t pn = normalise_pn(ss->variables.p_n); int16_t a = cs_pop(cs); - tele_set_pattern_val(pn, tele_get_pattern_i(pn), a); + p_next_inc_i(ss, pn); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); +} - tele_pi(); +static void op_PN_NEXT_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + const int16_t pn = normalise_pn(cs_pop(cs)); + int16_t a = cs_pop(cs); + p_next_inc_i(ss, pn); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); } -static void op_P_PREV_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - if ((tele_get_pattern_i(pn) == 0) || - (tele_get_pattern_i(pn) == tele_get_pattern_start(pn))) { - if (tele_get_pattern_wrap(pn)) { - if (tele_get_pattern_end(pn) < tele_get_pattern_l(pn)) - tele_set_pattern_i(pn, tele_get_pattern_end(pn)); - else - tele_set_pattern_i(pn, tele_get_pattern_l(pn) - 1); - } - } - else - tele_set_pattern_i(pn, tele_get_pattern_i(pn) - 1); +// Make ops +const tele_op_t op_P_NEXT = + MAKE_GET_SET_OP(P.NEXT, op_P_NEXT_get, op_P_NEXT_set, 0, true); +const tele_op_t op_PN_NEXT = + MAKE_GET_SET_OP(PN.NEXT, op_PN_NEXT_get, op_PN_NEXT_set, 1, true); - cs_push(cs, tele_get_pattern_val(pn, tele_get_pattern_i(pn))); - tele_pi(); -} +//////////////////////////////////////////////////////////////////////////////// +// P.PREV ////////////////////////////////////////////////////////////////////// -static void op_P_PREV_set(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - if ((tele_get_pattern_i(pn) == 0) || - (tele_get_pattern_i(pn) == tele_get_pattern_start(pn))) { - if (tele_get_pattern_wrap(pn)) { - if (tele_get_pattern_end(pn) < tele_get_pattern_l(pn)) - tele_set_pattern_i(pn, tele_get_pattern_end(pn)); +// Increment I obeying START, END, WRAP and L +static void p_prev_dec_i(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + + const int16_t len = ss_get_pattern_len(ss, pn); + const int16_t start = ss_get_pattern_start(ss, pn); + const int16_t end = ss_get_pattern_end(ss, pn); + const uint16_t wrap = ss_get_pattern_wrap(ss, pn); + + int16_t idx = ss_get_pattern_idx(ss, pn); + + if ((idx == 0) || (idx == start)) { + if (wrap) { + if (end < len) + idx = end; else - tele_set_pattern_i(pn, tele_get_pattern_l(pn) - 1); + idx = len - 1; } } else - tele_set_pattern_i(pn, tele_get_pattern_i(pn) - 1); + idx--; - int16_t a = cs_pop(cs); - tele_set_pattern_val(pn, tele_get_pattern_i(pn), a); - - tele_pi(); + ss_set_pattern_idx(ss, pn, idx); } -static void op_P_WRAP_get(const void *NOTUSED(data), scene_state_t *ss, +// Get +static void op_P_PREV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_wrap(pn)); + const int16_t pn = normalise_pn(ss->variables.p_n); + p_prev_dec_i(ss, pn); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); + tele_pattern_updated(); } -static void op_P_WRAP_set(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - int16_t a = cs_pop(cs); - if (a < 0) - tele_set_pattern_wrap(pn, 0); - else if (a > 1) - tele_set_pattern_wrap(pn, 1); - else - tele_set_pattern_wrap(pn, a); +static void op_PN_PREV_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + const int16_t pn = cs_pop(cs); + p_prev_dec_i(ss, pn); + cs_push(cs, ss_get_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn))); + tele_pattern_updated(); } -static void op_P_START_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_start(pn)); +// Set +static void op_P_PREV_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + const int16_t pn = normalise_pn(ss->variables.p_n); + const int16_t a = cs_pop(cs); + p_prev_dec_i(ss, pn); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); } -static void op_P_START_set(const void *NOTUSED(data), scene_state_t *ss, +static void op_PN_PREV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - int16_t a = cs_pop(cs); - if (a < 0) - tele_set_pattern_start(pn, 0); - else if (a > 63) - tele_set_pattern_start(pn, 63); - else - tele_set_pattern_start(pn, a); + const int16_t pn = cs_pop(cs); + const int16_t a = cs_pop(cs); + p_prev_dec_i(ss, pn); + ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); } -static void op_P_END_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - cs_push(cs, tele_get_pattern_end(pn)); -} +// Make ops +const tele_op_t op_P_PREV = + MAKE_GET_SET_OP(P.PREV, op_P_PREV_get, op_P_PREV_set, 0, true); +const tele_op_t op_PN_PREV = + MAKE_GET_SET_OP(PN.PREV, op_PN_PREV_get, op_PN_PREV_set, 1, true); -static void op_P_END_set(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - int16_t a = cs_pop(cs); - if (a < 0) - tele_set_pattern_end(pn, 0); - else if (a > 63) - tele_set_pattern_end(pn, 63); - else - tele_set_pattern_end(pn, a); + +//////////////////////////////////////////////////////////////////////////////// +// P.INS /////////////////////////////////////////////////////////////////////// + +// Get +static void p_ins_get(scene_state_t *ss, int16_t pn, int16_t idx, int16_t val) { + pn = normalise_pn(pn); + idx = normalise_idx(ss, pn, idx); + const int16_t len = ss_get_pattern_len(ss, pn); + + if (len >= idx) { + for (int16_t i = len; i > idx; i--) { + int16_t v = ss_get_pattern_val(ss, pn, i - 1); + ss_set_pattern_val(ss, pn, i, v); + } + if (len < PATTERN_LENGTH - 1) { ss_set_pattern_len(ss, pn, len + 1); } + } + + ss_set_pattern_val(ss, pn, idx, val); } -static void op_P_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_P_INS_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); - if (a < 0) { - if (tele_get_pattern_l(pn) == 0) - a = 0; - else if (a < -tele_get_pattern_l(pn)) - a = 0; - else - a = tele_get_pattern_l(pn) + a; - } - if (a > 63) a = 63; + int16_t b = cs_pop(cs); + p_ins_get(ss, pn, a, b); - cs_push(cs, tele_get_pattern_val(pn, a)); + tele_pattern_updated(); } -static void op_P_set(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; + +static void op_PN_INS_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); - if (a < 0) { - if (tele_get_pattern_l(pn) == 0) - a = 0; - else if (a < -tele_get_pattern_l(pn)) - a = 0; - else - a = tele_get_pattern_l(pn) + a; - } - if (a > 63) a = 63; + p_ins_get(ss, pn, a, b); - tele_set_pattern_val(pn, a, b); - tele_pi(); + tele_pattern_updated(); } -static void op_P_INS_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - int16_t a, b, i; - a = cs_pop(cs); - b = cs_pop(cs); - - if (a < 0) { - if (tele_get_pattern_l(pn) == 0) - a = 0; - else if (a < -tele_get_pattern_l(pn)) - a = 0; - else - a = tele_get_pattern_l(pn) + a; - } - if (a > 63) a = 63; +// Make ops +const tele_op_t op_P_INS = MAKE_GET_OP(P.INS, op_P_INS_get, 2, false); +const tele_op_t op_PN_INS = MAKE_GET_OP(PN.INS, op_PN_INS_get, 3, false); - if (tele_get_pattern_l(pn) >= a) { - for (i = tele_get_pattern_l(pn); i > a; i--) { - int16_t v = tele_get_pattern_val(pn, i - 1); - tele_set_pattern_val(pn, i, v); - } - if (tele_get_pattern_l(pn) < 63) { - tele_set_pattern_l(pn, tele_get_pattern_l(pn) + 1); + +//////////////////////////////////////////////////////////////////////////////// +// P.RM //////////////////////////////////////////////////////////////////////// + +// Get +static int16_t p_rm_get(scene_state_t *ss, int16_t pn, int16_t idx) { + pn = normalise_pn(pn); + const int16_t len = ss_get_pattern_len(ss, pn); + + if (len > 0) { + idx = normalise_idx(ss, pn, idx); + int16_t ret = ss_get_pattern_val(ss, pn, idx); + + for (int16_t i = idx; i < len; i++) { + int16_t v = ss_get_pattern_val(ss, pn, i + 1); + ss_set_pattern_val(ss, pn, i, v); } + + ss_set_pattern_len(ss, pn, len - 1); + + return ret; } - tele_set_pattern_val(pn, a, b); - tele_pi(); + return 0; } static void op_P_RM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; - int16_t a, i; - a = cs_pop(cs); - - if (a < 0) { - if (tele_get_pattern_l(pn) == 0) - a = 0; - else if (a < -tele_get_pattern_l(pn)) - a = 0; - else - a = tele_get_pattern_l(pn) + a; - } - else if (a > tele_get_pattern_l(pn)) - a = tele_get_pattern_l(pn); - - if (tele_get_pattern_l(pn) > 0) { - cs_push(cs, tele_get_pattern_val(pn, a)); - for (i = a; i < tele_get_pattern_l(pn); i++) { - int16_t v = tele_get_pattern_val(pn, i + 1); - tele_set_pattern_val(pn, i, v); - } + int16_t a = cs_pop(cs); + cs_push(cs, p_rm_get(ss, pn, a)); + tele_pattern_updated(); +} - tele_set_pattern_l(pn, tele_get_pattern_l(pn) - 1); - } - else - cs_push(cs, 0); - tele_pi(); +static void op_PN_RM_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t a = cs_pop(cs); + cs_push(cs, p_rm_get(ss, pn, a)); + tele_pattern_updated(); } -static void op_P_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = ss->variables.p_n; - int16_t a; - a = cs_pop(cs); +// Make ops +const tele_op_t op_P_RM = MAKE_GET_OP(P.RM, op_P_RM_get, 1, true); +const tele_op_t op_PN_RM = MAKE_GET_OP(PN.RM, op_PN_RM_get, 2, true); - if (tele_get_pattern_l(pn) < 64) { - tele_set_pattern_val(pn, tele_get_pattern_l(pn), a); - tele_set_pattern_l(pn, tele_get_pattern_l(pn) + 1); - tele_pi(); + +//////////////////////////////////////////////////////////////////////////////// +// P.PUSH ////////////////////////////////////////////////////////////////////// + +// Get +static void p_push_get(scene_state_t *ss, int16_t pn, int16_t val) { + pn = normalise_pn(pn); + const int16_t len = ss_get_pattern_len(ss, pn); + + if (len < PATTERN_LENGTH) { + ss_set_pattern_val(ss, pn, len, val); + ss_set_pattern_len(ss, pn, len + 1); } } -static void op_P_POP_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_P_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; - if (tele_get_pattern_l(pn) > 0) { - tele_set_pattern_l(pn, tele_get_pattern_l(pn) - 1); - cs_push(cs, tele_get_pattern_val(pn, tele_get_pattern_l(pn))); - tele_pi(); - } - else - cs_push(cs, 0); + int16_t a = cs_pop(cs); + p_push_get(ss, pn, a); + tele_pattern_updated(); } -static void op_PN_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_PN_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); + p_push_get(ss, pn, a); + tele_pattern_updated(); +} - if (a < 0) - a = 0; - else if (a > 3) - a = 3; +// Make ops +const tele_op_t op_P_PUSH = MAKE_GET_OP(P.PUSH, op_P_PUSH_get, 1, false); +const tele_op_t op_PN_PUSH = MAKE_GET_OP(PN.PUSH, op_PN_PUSH_get, 2, false); - if (b < 0) { - if (tele_get_pattern_l(a) == 0) - b = 0; - else if (b < -tele_get_pattern_l(a)) - b = 0; - else - b = tele_get_pattern_l(a) + b; - } - if (b > 63) b = 63; +//////////////////////////////////////////////////////////////////////////////// +// P.POP /////////////////////////////////////////////////////////////////////// - cs_push(cs, tele_get_pattern_val(a, b)); +// Get +static int16_t p_pop_get(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + const int16_t len = ss_get_pattern_len(ss, pn); + if (len > 0) { + ss_set_pattern_len(ss, pn, len - 1); + return ss_get_pattern_val(ss, pn, len - 1); + } + else + return 0; } -static void op_PN_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a = cs_pop(cs); - int16_t b = cs_pop(cs); - int16_t c = cs_pop(cs); - - if (a < 0) - a = 0; - else if (a > 3) - a = 3; - - if (b < 0) { - if (tele_get_pattern_l(a) == 0) - b = 0; - else if (b < -tele_get_pattern_l(a)) - b = 0; - else - b = tele_get_pattern_l(a) + b; - } - if (b > 63) b = 63; +static void op_P_POP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, p_pop_get(ss, ss->variables.p_n)); + tele_pattern_updated(); +} - tele_set_pattern_val(a, b, c); - tele_pi(); +static void op_PN_POP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + cs_push(cs, p_pop_get(ss, pn)); + tele_pattern_updated(); } + +// Make ops +const tele_op_t op_P_POP = MAKE_GET_OP(P.POP, op_P_POP_get, 0, true); +const tele_op_t op_PN_POP = MAKE_GET_OP(PN.POP, op_PN_POP_get, 1, true); diff --git a/src/ops/patterns.h b/src/ops/patterns.h index 7e555d91..87748884 100644 --- a/src/ops/patterns.h +++ b/src/ops/patterns.h @@ -3,22 +3,33 @@ #include "ops/op.h" +extern const tele_op_t op_P_N; extern const tele_op_t op_P; -extern const tele_op_t op_P_HERE; +extern const tele_op_t op_PN; +extern const tele_op_t op_P_L; +extern const tele_op_t op_PN_L; +extern const tele_op_t op_P_WRAP; +extern const tele_op_t op_PN_WRAP; +extern const tele_op_t op_P_START; +extern const tele_op_t op_PN_START; extern const tele_op_t op_P_END; +extern const tele_op_t op_PN_END; extern const tele_op_t op_P_I; -extern const tele_op_t op_P_L; -extern const tele_op_t op_P_N; +extern const tele_op_t op_PN_I; +extern const tele_op_t op_P_HERE; +extern const tele_op_t op_PN_HERE; extern const tele_op_t op_P_NEXT; +extern const tele_op_t op_PN_NEXT; extern const tele_op_t op_P_PREV; -extern const tele_op_t op_P_START; -extern const tele_op_t op_P_WRAP; -extern const tele_op_t op_PN; +extern const tele_op_t op_PN_PREV; extern const tele_op_t op_P_INS; +extern const tele_op_t op_PN_INS; extern const tele_op_t op_P_RM; +extern const tele_op_t op_PN_RM; extern const tele_op_t op_P_PUSH; +extern const tele_op_t op_PN_PUSH; extern const tele_op_t op_P_POP; - +extern const tele_op_t op_PN_POP; #endif diff --git a/src/ops/queue.c b/src/ops/queue.c index bc94bd5d..9af5ee60 100644 --- a/src/ops/queue.c +++ b/src/ops/queue.c @@ -40,9 +40,9 @@ static void op_Q_AVG_get(const void *NOTUSED(data), scene_state_t *ss, int16_t *q = ss->variables.q; int16_t q_n = ss->variables.q_n; for (int16_t i = 0; i < q_n; i++) { avg += q[i]; } - avg /= q_n; - cs_push(cs, avg); + int16_t out = q_n != 0 ? avg / q_n : 0; + cs_push(cs, out); } static void op_Q_AVG_set(const void *NOTUSED(data), scene_state_t *ss, diff --git a/src/ops/stack.c b/src/ops/stack.c index 80f1eb5e..93be3801 100644 --- a/src/ops/stack.c +++ b/src/ops/stack.c @@ -5,7 +5,7 @@ #include "teletype_io.h" static void mod_S_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, - tele_command_t *sub_command); + const tele_command_t *post_command); static void op_S_ALL_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_S_POP_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -24,28 +24,30 @@ const tele_op_t op_S_L = MAKE_GET_OP(S.L, op_S_L_get, 0, true); static void mod_S_func(scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs), - tele_command_t *sub_command) { + const tele_command_t *post_command) { if (ss->stack_op.top < STACK_OP_SIZE) { - copy_command(&ss->stack_op.commands[ss->stack_op.top], sub_command); + copy_command(&ss->stack_op.commands[ss->stack_op.top], post_command); ss->stack_op.top++; - if (ss->stack_op.top == 1) tele_s(1); + tele_has_stack(ss->stack_op.top > 0); } } static void op_S_ALL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *NOTUSED(cs)) { - for (int16_t i = 0; i < ss->stack_op.top; i++) - process(es, &ss->stack_op.commands[ss->stack_op.top - i - 1]); + for (int16_t i = 0; i < ss->stack_op.top; i++) { + process_command(ss, es, + &ss->stack_op.commands[ss->stack_op.top - i - 1]); + } ss->stack_op.top = 0; - tele_s(0); + tele_has_stack(false); } static void op_S_POP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *NOTUSED(cs)) { if (ss->stack_op.top) { ss->stack_op.top--; - process(es, &ss->stack_op.commands[ss->stack_op.top]); - if (ss->stack_op.top == 0) tele_s(0); + process_command(ss, es, &ss->stack_op.commands[ss->stack_op.top]); + if (ss->stack_op.top == 0) tele_has_stack(false); } } @@ -53,7 +55,7 @@ static void op_S_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { ss->stack_op.top = 0; - tele_s(0); + tele_has_stack(false); } static void op_S_L_get(const void *NOTUSED(data), scene_state_t *ss, diff --git a/src/ops/telex.c b/src/ops/telex.c index 9c3dd71a..b8b1efa2 100644 --- a/src/ops/telex.c +++ b/src/ops/telex.c @@ -135,6 +135,13 @@ static void op_TO_ENV_DEC_M_get(const void *data, scene_state_t *ss, static void op_TO_ENV_TRIG_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_TO_CV_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TO_TR_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TO_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + // TXi Methods static void op_TI_PARAM_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -167,6 +174,13 @@ static void op_TI_STORE_get(const void *data, scene_state_t *ss, static void op_TI_RESET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_TI_PARAM_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TI_IN_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TI_INIT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + // clang-format off // TXo Operators @@ -237,6 +251,14 @@ const tele_op_t op_TO_ENV_DEC_S = MAKE_GET_OP(TO.ENV.DEC.S , op_TO_ const tele_op_t op_TO_ENV_DEC_M = MAKE_GET_OP(TO.ENV.DEC.M , op_TO_ENV_DEC_M_get , 2, false); const tele_op_t op_TO_ENV_TRIG = MAKE_GET_OP(TO.ENV.TRIG , op_TO_ENV_TRIG_get , 1, false); +const tele_op_t op_TO_CV_INIT = MAKE_GET_OP(TO.CV.INIT , op_TO_CV_INIT_get , 1, false); +const tele_op_t op_TO_TR_INIT = MAKE_GET_OP(TO.TR.INIT , op_TO_TR_INIT_get , 1, false); +const tele_op_t op_TO_INIT = MAKE_GET_OP(TO.INIT , op_TO_INIT_get , 1, false); + +// TXo Ailiases +const tele_op_t op_TO_TR_P = MAKE_ALIAS_OP(TO.TR.P , op_TO_TR_PULSE_get , NULL, 1, false); +const tele_op_t op_TO_TR_P_DIV = MAKE_ALIAS_OP(TO.TR.P.DIV , op_TO_TR_PULSE_DIV_get , NULL, 2, false); + // TXi Operators const tele_op_t op_TI_PARAM = MAKE_GET_OP(TI.PARAM , op_TI_PARAM_get , 1, true); const tele_op_t op_TI_PARAM_QT = MAKE_GET_OP(TI.PARAM.QT , op_TI_PARAM_QT_get , 1, true); @@ -255,6 +277,17 @@ const tele_op_t op_TI_IN_CALIB = MAKE_GET_OP(TI.IN.CALIB , op_TI_ const tele_op_t op_TI_STORE = MAKE_GET_OP(TI.STORE , op_TI_STORE_get , 1, false); const tele_op_t op_TI_RESET = MAKE_GET_OP(TI.RESET , op_TI_RESET_get , 1, false); +const tele_op_t op_TI_PARAM_INIT = MAKE_GET_OP(TI.PARAM.INIT , op_TI_PARAM_INIT_get , 1, false); +const tele_op_t op_TI_IN_INIT = MAKE_GET_OP(TI.IN.INIT , op_TI_IN_INIT_get , 1, false); +const tele_op_t op_TI_INIT = MAKE_GET_OP(TI.INIT , op_TI_INIT_get , 1, false); + +// TXi Aliases +const tele_op_t op_TI_PRM = MAKE_ALIAS_OP(TI.PRM , op_TI_PARAM_get , NULL, 1, true); +const tele_op_t op_TI_PRM_QT = MAKE_ALIAS_OP(TI.PRM.QT , op_TI_PARAM_QT_get , NULL, 1, true); +const tele_op_t op_TI_PRM_N = MAKE_ALIAS_OP(TI.PRM.N , op_TI_PARAM_N_get , NULL, 1, true); +const tele_op_t op_TI_PRM_SCALE = MAKE_ALIAS_OP(TI.PRM.SCALE , op_TI_PARAM_SCALE_get , NULL, 2, false); +const tele_op_t op_TI_PRM_MAP = MAKE_ALIAS_OP(TI.PRM.MAP , op_TI_PARAM_MAP_get , NULL, 3, false); +const tele_op_t op_TI_PRM_INIT = MAKE_ALIAS_OP(TI.PRM.INIT , op_TI_PARAM_INIT_get , NULL, 1, false); // clang-format on @@ -300,7 +333,7 @@ void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { // tell the device what value you are going to query uint8_t buffer[2]; buffer[0] = port; - tele_ii_tx_now(address, buffer, 1); + tele_ii_tx(address, buffer, 1); // now read the vaule buffer[0] = 0; buffer[1] = 0; @@ -308,6 +341,42 @@ void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { int16_t value = (buffer[0] << 8) + buffer[1]; cs_push(cs, value); } +// Temporary Init Functions (will refactor to the TELEX soon) +void TRInit(uint8_t output) { + TXSend(TO, TO_TR_POL, output, 1, true); + TXSend(TO, TO_TR, output, 0, true); + TXSend(TO, TO_TR_TIME, output, 100, true); + TXSend(TO, TO_TR_PULSE_DIV, output, 1, true); + TXSend(TO, TO_TR_M_ACT, output, 0, true); + TXSend(TO, TO_TR_M, output, 1000, true); +} +void CVInit(uint8_t output) { + TXSend(TO, TO_CV_SET, output, 0, true); + TXSend(TO, TO_CV_OFF, output, 0, true); + TXSend(TO, TO_CV_SLEW, output, 0, true); + TXSend(TO, TO_CV_SCALE, output, 0, true); + + TXSend(TO, TO_OSC_FQ_SET, output, 0, true); + TXSend(TO, TO_OSC_SCALE, output, 0, true); + TXSend(TO, TO_OSC_WAVE, output, 0, true); + TXSend(TO, TO_OSC_PHASE, output, 0, true); + TXSend(TO, TO_OSC_RECT, output, 0, true); + TXSend(TO, TO_OSC_SLEW, output, 0, true); + + TXSend(TO, TO_ENV_ACT, output, 0, true); + TXSend(TO, TO_ENV_ATT, output, 12, true); + TXSend(TO, TO_ENV_DEC, output, 250, true); +} +void INInit(uint8_t input) { + TXSend(TI, TI_IN_SCALE, input, 0, true); + TXSend(TI, TI_IN_TOP, input, 16383, true); + TXSend(TI, TI_IN_BOT, input, -16384, true); +} +void PRMInit(uint8_t input) { + TXSend(TI, TI_PARAM_SCALE, input, 0, true); + TXSend(TI, TI_PARAM_TOP, input, 16383, true); + TXSend(TI, TI_PARAM_BOT, input, 0, true); +} // TELEX get and set methods // TXo @@ -583,6 +652,24 @@ static void op_TO_ENV_TRIG_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { TXCmd(TO, TO_ENV_TRIG, cs_pop(cs)); } +static void op_TO_CV_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + CVInit(cs_pop(cs)); +} +static void op_TO_TR_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + TRInit(cs_pop(cs)); +} +static void op_TO_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t end = cs_pop(cs) * 4; + uint8_t start = end - 3; + uint8_t i; + for (i = start; i <= end; i++) { + CVInit(i); + TRInit(i); + } +} // TXi static void op_TI_PARAM_get(const void *NOTUSED(data), scene_state_t *ss, @@ -651,4 +738,23 @@ static void op_TI_STORE_get(const void *NOTUSED(data), scene_state_t *ss, static void op_TI_RESET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { TXCmd(TI, TI_RESET, cs_pop(cs)); -} \ No newline at end of file +} +static void op_TI_PARAM_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), + command_state_t *cs) { + PRMInit(cs_pop(cs)); +} +static void op_TI_IN_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + INInit(cs_pop(cs)); +} +static void op_TI_INIT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t end = cs_pop(cs) * 4; + uint8_t start = end - 3; + uint8_t i; + for (i = start; i <= end; i++) { + PRMInit(i); + INInit(i); + } +} diff --git a/src/ops/telex.h b/src/ops/telex.h index f9062b4b..5b9c803c 100644 --- a/src/ops/telex.h +++ b/src/ops/telex.h @@ -73,6 +73,14 @@ extern const tele_op_t op_TO_ENV_DEC_S; extern const tele_op_t op_TO_ENV_DEC_M; extern const tele_op_t op_TO_ENV_TRIG; +extern const tele_op_t op_TO_CV_INIT; +extern const tele_op_t op_TO_TR_INIT; +extern const tele_op_t op_TO_INIT; + +extern const tele_op_t op_TO_TR_P; +extern const tele_op_t op_TO_TR_P_DIV; + + // TXi Operators extern const tele_op_t op_TI_PARAM; extern const tele_op_t op_TI_PARAM_QT; @@ -91,12 +99,28 @@ extern const tele_op_t op_TI_IN_CALIB; extern const tele_op_t op_TI_STORE; extern const tele_op_t op_TI_RESET; +extern const tele_op_t op_TI_PARAM_INIT; +extern const tele_op_t op_TI_IN_INIT; +extern const tele_op_t op_TI_INIT; + +extern const tele_op_t op_TI_PRM; +extern const tele_op_t op_TI_PRM_QT; +extern const tele_op_t op_TI_PRM_N; +extern const tele_op_t op_TI_PRM_SCALE; +extern const tele_op_t op_TI_PRM_MAP; +extern const tele_op_t op_TI_PRM_INIT; + // helpers void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, bool set); void TXCmd(uint8_t model, uint8_t command, uint8_t output); void TXSet(uint8_t model, uint8_t command, command_state_t *cs); void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift); +// temporary init functions +void TRInit(uint8_t output); +void CVInit(uint8_t output); +void INInit(uint8_t input); +void PRMInit(uint8_t input); // constants diff --git a/src/ops/variables.c b/src/ops/variables.c index 5978eff0..cd64e074 100644 --- a/src/ops/variables.c +++ b/src/ops/variables.c @@ -28,12 +28,10 @@ const tele_op_t op_DRUNK_MAX = MAKE_SIMPLE_VARIABLE_OP(DRUNK.MAX , variables.dr const tele_op_t op_DRUNK_MIN = MAKE_SIMPLE_VARIABLE_OP(DRUNK.MIN , variables.drunk_min ); const tele_op_t op_DRUNK_WRAP = MAKE_SIMPLE_VARIABLE_OP(DRUNK.WRAP, variables.drunk_wrap); const tele_op_t op_I = MAKE_SIMPLE_VARIABLE_OP(I , variables.i ); -const tele_op_t op_IN = MAKE_SIMPLE_VARIABLE_OP(IN , variables.in ); const tele_op_t op_O_INC = MAKE_SIMPLE_VARIABLE_OP(O.INC , variables.o_inc ); const tele_op_t op_O_MAX = MAKE_SIMPLE_VARIABLE_OP(O.MAX , variables.o_max ); const tele_op_t op_O_MIN = MAKE_SIMPLE_VARIABLE_OP(O.MIN , variables.o_min ); const tele_op_t op_O_WRAP = MAKE_SIMPLE_VARIABLE_OP(O.WRAP , variables.o_wrap ); -const tele_op_t op_PARAM = MAKE_SIMPLE_VARIABLE_OP(PARAM , variables.param ); const tele_op_t op_T = MAKE_SIMPLE_VARIABLE_OP(T , variables.t ); const tele_op_t op_TIME = MAKE_SIMPLE_VARIABLE_OP(TIME , variables.time ); const tele_op_t op_TIME_ACT = MAKE_SIMPLE_VARIABLE_OP(TIME.ACT , variables.time_act ); diff --git a/src/ops/variables.h b/src/ops/variables.h index 78e367e1..6bb1d1c9 100644 --- a/src/ops/variables.h +++ b/src/ops/variables.h @@ -13,13 +13,11 @@ extern const tele_op_t op_DRUNK_MIN; extern const tele_op_t op_DRUNK_WRAP; extern const tele_op_t op_FLIP; extern const tele_op_t op_I; -extern const tele_op_t op_IN; extern const tele_op_t op_O; extern const tele_op_t op_O_INC; extern const tele_op_t op_O_MAX; extern const tele_op_t op_O_MIN; extern const tele_op_t op_O_WRAP; -extern const tele_op_t op_PARAM; extern const tele_op_t op_T; extern const tele_op_t op_TIME; extern const tele_op_t op_TIME_ACT; @@ -27,5 +25,4 @@ extern const tele_op_t op_X; extern const tele_op_t op_Y; extern const tele_op_t op_Z; - #endif diff --git a/src/ops/whitewhale.c b/src/ops/whitewhale.c new file mode 100644 index 00000000..b486f727 --- /dev/null +++ b/src/ops/whitewhale.c @@ -0,0 +1,18 @@ +#include "whitewhale.h" + +#include "ii.h" + +const tele_op_t op_WW_PRESET = MAKE_SIMPLE_I2C_OP(WW.PRESET, WW_PRESET); +const tele_op_t op_WW_POS = MAKE_SIMPLE_I2C_OP(WW.POS, WW_POS); +const tele_op_t op_WW_SYNC = MAKE_SIMPLE_I2C_OP(WW.SYNC, WW_SYNC); +const tele_op_t op_WW_START = MAKE_SIMPLE_I2C_OP(WW.START, WW_START); +const tele_op_t op_WW_END = MAKE_SIMPLE_I2C_OP(WW.END, WW_END); +const tele_op_t op_WW_PMODE = MAKE_SIMPLE_I2C_OP(WW.PMODE, WW_PMODE); +const tele_op_t op_WW_PATTERN = MAKE_SIMPLE_I2C_OP(WW.PATTERN, WW_PATTERN); +const tele_op_t op_WW_QPATTERN = MAKE_SIMPLE_I2C_OP(WW.QPATTERN, WW_QPATTERN); +const tele_op_t op_WW_MUTE1 = MAKE_SIMPLE_I2C_OP(WW.MUTE1, WW_MUTE1); +const tele_op_t op_WW_MUTE2 = MAKE_SIMPLE_I2C_OP(WW.MUTE2, WW_MUTE2); +const tele_op_t op_WW_MUTE3 = MAKE_SIMPLE_I2C_OP(WW.MUTE3, WW_MUTE3); +const tele_op_t op_WW_MUTE4 = MAKE_SIMPLE_I2C_OP(WW.MUTE4, WW_MUTE4); +const tele_op_t op_WW_MUTEA = MAKE_SIMPLE_I2C_OP(WW.MUTEA, WW_MUTEA); +const tele_op_t op_WW_MUTEB = MAKE_SIMPLE_I2C_OP(WW.MUTEB, WW_MUTEB); diff --git a/src/ops/whitewhale.h b/src/ops/whitewhale.h new file mode 100644 index 00000000..db06ffa4 --- /dev/null +++ b/src/ops/whitewhale.h @@ -0,0 +1,21 @@ +#ifndef _OPS_WHITEWHALE_H_ +#define _OPS_WHITEWHALE_H_ + +#include "ops/op.h" + +extern const tele_op_t op_WW_PRESET; +extern const tele_op_t op_WW_POS; +extern const tele_op_t op_WW_SYNC; +extern const tele_op_t op_WW_START; +extern const tele_op_t op_WW_END; +extern const tele_op_t op_WW_PMODE; +extern const tele_op_t op_WW_PATTERN; +extern const tele_op_t op_WW_QPATTERN; +extern const tele_op_t op_WW_MUTE1; +extern const tele_op_t op_WW_MUTE2; +extern const tele_op_t op_WW_MUTE3; +extern const tele_op_t op_WW_MUTE4; +extern const tele_op_t op_WW_MUTEA; +extern const tele_op_t op_WW_MUTEB; + +#endif diff --git a/src/scanner.h b/src/scanner.h new file mode 100644 index 00000000..8739f99b --- /dev/null +++ b/src/scanner.h @@ -0,0 +1,11 @@ +#ifndef _SCANNER_H_ +#define _SCANNER_H_ + +#include + +#include "teletype.h" + +error_t scanner(const char *cmd, tele_command_t *out, + char error_msg[TELE_ERROR_MSG_LENGTH]); + +#endif diff --git a/src/scanner.rl b/src/scanner.rl new file mode 100644 index 00000000..b388a80b --- /dev/null +++ b/src/scanner.rl @@ -0,0 +1,132 @@ +#include "scanner.h" + +#include +#include +#include + +#include "command.h" +#include "match_token.h" +#include "teletype.h" + +const size_t kMaxTokenLength = 32; + +%%{ + machine scanner; # declare our ragel machine + write data; # write any ragel data here +}%% + +error_t scanner(const char *data, tele_command_t *out, + char error_msg[TELE_ERROR_MSG_LENGTH]) { + const size_t len = strlen(data); + + // required ragel declarations + int cs; // machine state + int act; // used with '=>' + const char* ts; // token start + const char* te; // token end + + const char* p = data; // pointer to data + const char* pe = data + len; // pointer to end of data + const char* eof = pe; // pointer to eof + (void)scanner_en_main; // fix unused variable warning + + // reset outputs + error_msg[0] = 0; + out->length = 0; + out->separator = -1; + + %%{ + separator = [ \n\t]; + pre_separator = ': '; + sub_seperator = '; '; + invalid_pre = ':'; + invalid_sub = ';'; + + token = any+ -- (separator + | pre_separator | sub_seperator + | invalid_pre | invalid_sub); + + action token { + // token matched + + // copy the matched token to buf + char buf[kMaxTokenLength]; + size_t len = te-ts; + if (len > kMaxTokenLength) len = kMaxTokenLength; + memcpy(buf, ts, len); + buf[len] = '\0'; + + tele_data_t tele_data; + if (match_token(buf, len, &tele_data)) { + // if we have a match, copy data to the the command + out->data[out->length] = tele_data; + + // increase the command length + out->length++; + + // if the command length is now too long, abort + if (out->length >= COMMAND_MAX_LENGTH) return E_LENGTH; + } + else { + // can't match the token, fail + strcpy(error_msg, buf); + return E_PARSE; + } + } + + action pre_separator { + // ';' pre separator matched + + // it's a PRE_SEP, we need to record it's position + // (validate checks for too many PRE_SEP tokens) + out->data[out->length].tag = PRE_SEP; + out->data[out->length].value = 0; + out->separator = out->length; + + // increase the command length + out->length++; + + // if the command length is now too long, abort + if (out->length >= COMMAND_MAX_LENGTH) return E_LENGTH; + } + + action sub_separator { + // ':' mod separator matched + out->data[out->length].tag = SUB_SEP; + out->data[out->length].value = 0; + + // increase the command length + out->length++; + + // if the command length is now too long, abort + if (out->length >= COMMAND_MAX_LENGTH) return E_LENGTH; + } + + action invalid_pre { + return E_NEED_SPACE_PRE_SEP; + } + + action invalid_sub { + return E_NEED_SPACE_SUB_SEP; + } + + main := |* + separator; + pre_separator => pre_separator; + sub_seperator => sub_separator; + invalid_pre => invalid_pre; + invalid_sub => invalid_sub; + token => token; + *|; + + write init; # write initialisation + write exec; # run the machine + }%% + + if (cs == scanner_error || cs < scanner_first_final) { + strcpy(error_msg, "SCAN!"); + return E_PARSE; + } + + return E_OK; +} diff --git a/src/state.c b/src/state.c index 775b7f87..69de8281 100644 --- a/src/state.c +++ b/src/state.c @@ -1,10 +1,252 @@ #include "state.h" +#include + +#include "teletype_io.h" + + +//////////////////////////////////////////////////////////////////////////////// +// SCENE STATE ///////////////////////////////////////////////////////////////// + +// scene init + +void ss_init(scene_state_t *ss) { + ss_variables_init(ss); + ss_patterns_init(ss); + ss->delay.count = 0; + for (size_t i = 0; i < TR_COUNT; i++) { ss->tr_pulse_timer[i] = 0; } + ss->stack_op.top = 0; + memset(&ss->scripts, 0, ss_scripts_size()); +} + +void ss_variables_init(scene_state_t *ss) { + const scene_variables_t default_variables = { + // variables that haven't been explicitly initialised, will be set to 0 + .a = 1, + .b = 2, + .c = 3, + .cv_slew = { 1, 1, 1, 1 }, + .d = 4, + .drunk_min = 0, + .drunk_max = 255, + .m = 1000, + .m_act = 1, + .o_inc = 1, + .o_min = 0, + .o_max = 63, + .o_wrap = 1, + .q_n = 1, + .time_act = 1, + .tr_pol = { 1, 1, 1, 1 }, + .tr_time = { 100, 100, 100, 100 } + }; + + memcpy(&ss->variables, &default_variables, sizeof(default_variables)); +} + +void ss_patterns_init(scene_state_t *ss) { + for (size_t i = 0; i < PATTERN_COUNT; i++) { ss_pattern_init(ss, i); } +} + +void ss_pattern_init(scene_state_t *ss, size_t pattern_no) { + if (pattern_no >= PATTERN_COUNT) return; + + scene_pattern_t *p = &ss->patterns[pattern_no]; + p->idx = 0; + p->len = 0; + p->wrap = 1; + p->start = 0; + p->end = 63; + for (size_t i = 0; i < PATTERN_LENGTH; i++) { p->val[i] = 0; } +} + +// external variable setting + +void ss_set_in(scene_state_t *ss, int16_t value) { + ss->variables.in = value; +} + +void ss_set_param(scene_state_t *ss, int16_t value) { + ss->variables.param = value; +} + +void ss_set_scene(scene_state_t *ss, int16_t value) { + ss->variables.scene = value; +} + +// mutes + +bool ss_get_mute(scene_state_t *ss, size_t idx) { + return ss->variables.mutes[idx]; +} + +void ss_set_mute(scene_state_t *ss, size_t idx, bool value) { + ss->variables.mutes[idx] = value; + tele_mute(); +} + +// pattern getters and setters + +int16_t ss_get_pattern_idx(scene_state_t *ss, size_t pattern) { + return ss->patterns[pattern].idx; +} + +void ss_set_pattern_idx(scene_state_t *ss, size_t pattern, int16_t i) { + ss->patterns[pattern].idx = i; +} + +int16_t ss_get_pattern_len(scene_state_t *ss, size_t pattern) { + return ss->patterns[pattern].len; +} + +void ss_set_pattern_len(scene_state_t *ss, size_t pattern, int16_t l) { + ss->patterns[pattern].len = l; +} + +uint16_t ss_get_pattern_wrap(scene_state_t *ss, size_t pattern) { + return ss->patterns[pattern].wrap; +} + +void ss_set_pattern_wrap(scene_state_t *ss, size_t pattern, uint16_t wrap) { + ss->patterns[pattern].wrap = wrap; +} + +int16_t ss_get_pattern_start(scene_state_t *ss, size_t pattern) { + return ss->patterns[pattern].start; +} + +void ss_set_pattern_start(scene_state_t *ss, size_t pattern, int16_t start) { + ss->patterns[pattern].start = start; +} + +int16_t ss_get_pattern_end(scene_state_t *ss, size_t pattern) { + return ss->patterns[pattern].end; +} + +void ss_set_pattern_end(scene_state_t *ss, size_t pattern, int16_t end) { + ss->patterns[pattern].end = end; +} + +int16_t ss_get_pattern_val(scene_state_t *ss, size_t pattern, size_t idx) { + return ss->patterns[pattern].val[idx]; +} + +void ss_set_pattern_val(scene_state_t *ss, size_t pattern, size_t idx, + int16_t val) { + ss->patterns[pattern].val[idx] = val; +} + +scene_pattern_t *ss_patterns_ptr(scene_state_t *ss) { + return ss->patterns; +} + +size_t ss_patterns_size() { + return sizeof(scene_pattern_t) * PATTERN_COUNT; +} + +// script manipulation + +uint8_t ss_get_script_len(scene_state_t *ss, size_t idx) { + return ss->scripts[idx].l; +} + +// private +static void ss_set_script_len(scene_state_t *ss, size_t idx, uint8_t l) { + ss->scripts[idx].l = l; +} + +const tele_command_t *ss_get_script_command(scene_state_t *ss, + size_t script_idx, size_t c_idx) { + return &ss->scripts[script_idx].c[c_idx]; +} + +// private +static void ss_set_script_command(scene_state_t *ss, size_t script_idx, + size_t c_idx, const tele_command_t *cmd) { + memcpy(&ss->scripts[script_idx].c[c_idx], cmd, sizeof(tele_command_t)); +} + +void ss_overwrite_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx, + const tele_command_t *cmd) { + if (command_idx >= SCRIPT_MAX_COMMANDS) return; + + ss_set_script_command(ss, script_idx, command_idx, cmd); + + const uint8_t script_len = ss_get_script_len(ss, script_idx); + + if (script_len < SCRIPT_MAX_COMMANDS && command_idx >= script_len) { + ss_set_script_len(ss, script_idx, script_len + 1); + } +} + +void ss_insert_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx, const tele_command_t *cmd) { + if (command_idx >= SCRIPT_MAX_COMMANDS) return; + + uint8_t script_len = ss_get_script_len(ss, script_idx); + if (script_len == SCRIPT_MAX_COMMANDS) { // no room to insert + ss_delete_script_command(ss, script_idx, script_len - 1); // make room + script_len = ss_get_script_len(ss, script_idx); + } + + // shuffle down + for (size_t i = script_len; i > command_idx; i--) { + const tele_command_t *cmd = + ss_get_script_command(ss, script_idx, i - 1); + ss_set_script_command(ss, script_idx, i, cmd); + } + + // increase length + ss_set_script_len(ss, script_idx, script_len + 1); + + // overwrite at command_idx + ss_overwrite_script_command(ss, script_idx, command_idx, cmd); +} + +void ss_delete_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx) { + if (command_idx >= SCRIPT_MAX_COMMANDS) return; + + uint8_t script_len = ss_get_script_len(ss, script_idx); + if (script_len && + ss_get_script_command(ss, script_idx, command_idx)->length) { + script_len--; + ss_set_script_len(ss, script_idx, script_len); + + for (size_t n = command_idx; n < script_len; n++) { + const tele_command_t *cmd = + ss_get_script_command(ss, script_idx, n + 1); + ss_set_script_command(ss, script_idx, n, cmd); + } + + tele_command_t blank_command; + blank_command.length = 0; + ss_set_script_command(ss, script_idx, script_len, &blank_command); + } +} + +scene_script_t *ss_scripts_ptr(scene_state_t *ss) { + return ss->scripts; +} + +size_t ss_scripts_size() { + return sizeof(scene_script_t) * SCRIPT_COUNT; +} + + +//////////////////////////////////////////////////////////////////////////////// +// EXEC STATE ////////////////////////////////////////////////////////////////// void es_init(exec_state_t *es) { - es->if_else_condition = false; + es->if_else_condition = true; + es->exec_depth = 0; } + +//////////////////////////////////////////////////////////////////////////////// +// COMMAND STATE /////////////////////////////////////////////////////////////// + void cs_init(command_state_t *cs) { cs->stack.top = 0; } diff --git a/src/state.h b/src/state.h index 0812c1e8..ebd0518a 100644 --- a/src/state.h +++ b/src/state.h @@ -2,6 +2,7 @@ #define _STATE_H_ #include +#include #include #include "command.h" @@ -10,11 +11,13 @@ #define CV_COUNT 4 #define Q_LENGTH 16 #define TR_COUNT 4 +#define TRIGGER_INPUTS 8 #define DELAY_SIZE 8 #define STACK_OP_SIZE 8 #define PATTERN_COUNT 4 #define PATTERN_LENGTH 64 #define SCRIPT_MAX_COMMANDS 6 +#define SCRIPT_COUNT 10 #define METRO_SCRIPT 8 #define INIT_SCRIPT 9 @@ -39,7 +42,8 @@ typedef struct { int16_t i; int16_t in; int16_t m; - int16_t m_act; + bool m_act; + bool mutes[TRIGGER_INPUTS]; int16_t o; int16_t o_inc; int16_t o_min; @@ -62,12 +66,12 @@ typedef struct { } scene_variables_t; typedef struct { - int16_t i; - uint16_t l; + int16_t idx; + uint16_t len; uint16_t wrap; int16_t start; int16_t end; - int16_t v[PATTERN_LENGTH]; + int16_t val[PATTERN_LENGTH]; } scene_pattern_t; typedef struct { @@ -92,14 +96,61 @@ typedef struct { scene_delay_t delay; scene_stack_op_t stack_op; int16_t tr_pulse_timer[TR_COUNT]; - scene_script_t scripts[10]; + scene_script_t scripts[SCRIPT_COUNT]; } scene_state_t; +extern void ss_init(scene_state_t *ss); +extern void ss_variables_init(scene_state_t *ss); +extern void ss_patterns_init(scene_state_t *ss); +extern void ss_pattern_init(scene_state_t *ss, size_t pattern_no); + +extern void ss_set_in(scene_state_t *ss, int16_t value); +extern void ss_set_param(scene_state_t *ss, int16_t value); +extern void ss_set_scene(scene_state_t *ss, int16_t value); + +extern bool ss_get_mute(scene_state_t *ss, size_t idx); +extern void ss_set_mute(scene_state_t *ss, size_t idx, bool value); + +extern int16_t ss_get_pattern_idx(scene_state_t *ss, size_t pattern); +extern void ss_set_pattern_idx(scene_state_t *ss, size_t pattern, int16_t i); +extern int16_t ss_get_pattern_len(scene_state_t *ss, size_t pattern); +extern void ss_set_pattern_len(scene_state_t *ss, size_t pattern, int16_t l); +extern uint16_t ss_get_pattern_wrap(scene_state_t *ss, size_t pattern); +extern void ss_set_pattern_wrap(scene_state_t *ss, size_t pattern, + uint16_t wrap); +extern int16_t ss_get_pattern_start(scene_state_t *ss, size_t pattern); +extern void ss_set_pattern_start(scene_state_t *ss, size_t pattern, + int16_t start); +extern int16_t ss_get_pattern_end(scene_state_t *ss, size_t pattern); +extern void ss_set_pattern_end(scene_state_t *ss, size_t pattern, int16_t end); +extern int16_t ss_get_pattern_val(scene_state_t *ss, size_t pattern, + size_t idx); +extern void ss_set_pattern_val(scene_state_t *ss, size_t pattern, size_t idx, + int16_t val); +extern scene_pattern_t *ss_patterns_ptr(scene_state_t *ss); +extern size_t ss_patterns_size(void); + +uint8_t ss_get_script_len(scene_state_t *ss, size_t idx); +const tele_command_t *ss_get_script_command(scene_state_t *ss, + size_t script_idx, size_t c_idx); +void ss_overwrite_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx, const tele_command_t *cmd); +void ss_insert_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx, const tele_command_t *cmd); +void ss_delete_script_command(scene_state_t *ss, size_t script_idx, + size_t command_idx); + +scene_script_t *ss_scripts_ptr(scene_state_t *ss); +size_t ss_scripts_size(void); + //////////////////////////////////////////////////////////////////////////////// // EXEC STATE ////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -typedef struct { bool if_else_condition; } exec_state_t; +typedef struct { + bool if_else_condition; + uint8_t exec_depth; +} exec_state_t; extern void es_init(exec_state_t *es); diff --git a/src/teletype.c b/src/teletype.c index d0d0ef04..45405070 100644 --- a/src/teletype.c +++ b/src/teletype.c @@ -1,83 +1,30 @@ -#include // isdigit #include // types #include // printf -#include // rand, strtol #include +#include // ssize_t #include "helpers.h" #include "ops/op.h" +#include "scanner.h" #include "table.h" #include "teletype.h" #include "teletype_io.h" #include "util.h" -#ifdef SIM -#define DBG printf("%s", dbg); -#else -#include "print_funcs.h" -#define DBG print_dbg(dbg); -#endif - -// static char dbg[32]; - -static const char *errordesc[] = { "OK", - WELCOME, - "UNKNOWN WORD", - "COMMAND TOO LONG", - "NOT ENOUGH PARAMS", - "TOO MANY PARAMS", - "MOD NOT ALLOWED HERE", - "EXTRA SEPARATOR", - "NEED SEPARATOR", - "BAD SEPARATOR", - "MOVE LEFT" }; - -const char *tele_error(error_t e) { - return errordesc[e]; -} - - -///////////////////////////////////////////////////////////////// -// STATE //////////////////////////////////////////////////////// - -// eventually these will not be global variables -static scene_state_t scene_state = { - // variables that haven't been explicitly initialised, will be set to 0 - .variables = {.a = 1, - .b = 2, - .c = 3, - .cv_slew = { 1, 1, 1, 1 }, - .d = 4, - .drunk_min = 0, - .drunk_max = 255, - .m = 1000, - .m_act = 1, - .o_inc = 1, - .o_min = 0, - .o_max = 63, - .o_wrap = 1, - .q_n = 1, - .time_act = 1, - .tr_pol = { 1, 1, 1, 1 }, - .tr_time = { 100, 100, 100, 100 } } -}; ///////////////////////////////////////////////////////////////// // DELAY //////////////////////////////////////////////////////// -void clear_delays(void) { - for (int16_t i = 0; i < TR_COUNT; i++) { - scene_state.tr_pulse_timer[i] = 0; - } +void clear_delays(scene_state_t *ss) { + for (int16_t i = 0; i < TR_COUNT; i++) { ss->tr_pulse_timer[i] = 0; } - for (int16_t i = 0; i < DELAY_SIZE; i++) { scene_state.delay.time[i] = 0; } + for (int16_t i = 0; i < DELAY_SIZE; i++) { ss->delay.time[i] = 0; } - scene_state.delay.count = 0; + ss->delay.count = 0; + ss->stack_op.top = 0; - scene_state.stack_op.top = 0; - - tele_delay(0); - tele_s(0); + tele_has_delays(false); + tele_has_stack(false); } @@ -85,88 +32,28 @@ void clear_delays(void) { // PARSE //////////////////////////////////////////////////////// error_t parse(const char *cmd, tele_command_t *out, - char error_msg[ERROR_MSG_LENGTH]) { - error_msg[0] = 0; - char cmd_copy[32]; - strcpy(cmd_copy, cmd); - const char *delim = " \n"; - const char *s = strtok(cmd_copy, delim); - - uint8_t n = 0; - out->l = n; - out->separator = -1; - - while (s) { - // CHECK IF NUMBER - if (isdigit(s[0]) || s[0] == '-') { - out->data[n].t = NUMBER; - out->data[n].v = strtol(s, NULL, 0); - } - else if (s[0] == ':') { - out->data[n].t = SEP; - out->separator = n; - } - else { - int16_t i = -1; - - if (i == -1) { - // CHECK AGAINST OPS - i = OPS; - - while (i--) { - if (!strcmp(s, tele_ops[i]->name)) { - out->data[n].t = OP; - out->data[n].v = i; - break; - } - } - } - - if (i == -1) { - // CHECK AGAINST MOD - i = MODS; - - while (i--) { - if (!strcmp(s, tele_mods[i]->name)) { - out->data[n].t = MOD; - out->data[n].v = i; - break; - } - } - } - - if (i == -1) { - strcpy(error_msg, s); - return E_PARSE; - } - } - - s = strtok(NULL, delim); - - n++; - out->l = n; - - if (n == COMMAND_MAX_LENGTH) return E_LENGTH; - } - - return E_OK; + char error_msg[TELE_ERROR_MSG_LENGTH]) { + // call the Ragel generated scanner function + return scanner(cmd, out, error_msg); } ///////////////////////////////////////////////////////////////// // VALIDATE ///////////////////////////////////////////////////// -error_t validate(const tele_command_t *c, char error_msg[ERROR_MSG_LENGTH]) { +error_t validate(const tele_command_t *c, + char error_msg[TELE_ERROR_MSG_LENGTH]) { error_msg[0] = 0; int16_t stack_depth = 0; - uint8_t idx = c->l; + uint8_t idx = c->length; int8_t sep_count = 0; while (idx--) { // process words right to left - tele_word_t word_type = c->data[idx].t; - int16_t word_value = c->data[idx].v; + tele_word_t word_type = c->data[idx].tag; + int16_t word_value = c->data[idx].value; // A first_cmd is either at the beginning of the command or immediately - // after the SEP - bool first_cmd = idx == 0 || c->data[idx - 1].t == SEP; + // after the PRE_SEP or COMMAND_SEP + bool first_cmd = idx == 0 || c->data[idx - 1].tag == PRE_SEP || + c->data[idx - 1].tag == SUB_SEP; if (word_type == NUMBER) { stack_depth++; } else if (word_type == OP) { @@ -199,7 +86,7 @@ error_t validate(const tele_command_t *c, char error_msg[ERROR_MSG_LENGTH]) { if (idx != 0) mod_error = E_NO_MOD_HERE; else if (c->separator == -1) - mod_error = E_NEED_SEP; + mod_error = E_NEED_PRE_SEP; else if (stack_depth < tele_mods[word_value]->params) mod_error = E_NEED_PARAMS; else if (stack_depth > tele_mods[word_value]->params) @@ -212,17 +99,26 @@ error_t validate(const tele_command_t *c, char error_msg[ERROR_MSG_LENGTH]) { stack_depth = 0; } - else if (word_type == SEP) { + else if (word_type == PRE_SEP) { sep_count++; - if (sep_count > 1) - return E_MANY_SEP; - else if (idx == 0) - return E_PLACE_SEP; - - if (stack_depth > 1) - return E_EXTRA_PARAMS; - else - stack_depth = 0; + if (sep_count > 1) return E_MANY_PRE_SEP; + + if (idx == 0) return E_PLACE_PRE_SEP; + + if (c->data[0].tag != MOD) return E_PLACE_PRE_SEP; + + if (stack_depth > 1) return E_EXTRA_PARAMS; + + // reset the stack depth + stack_depth = 0; + } + else if (word_type == SUB_SEP) { + if (sep_count > 0) return E_NO_SUB_SEP_IN_PRE; + + if (stack_depth > 1) return E_EXTRA_PARAMS; + + // reset the stack depth + stack_depth = 0; } } @@ -235,57 +131,128 @@ error_t validate(const tele_command_t *c, char error_msg[ERROR_MSG_LENGTH]) { ///////////////////////////////////////////////////////////////// // RUN ////////////////////////////////////////////////////////// -process_result_t run_script(size_t script_no) { - process_result_t result = {.has_value = false, .value = 0 }; +process_result_t run_script(scene_state_t *ss, size_t script_no) { exec_state_t es; es_init(&es); - for (size_t i = 0; i < tele_get_script_l(script_no); i++) { - result = process(&es, tele_get_script_c(script_no, i)); + return run_script_with_exec_state(ss, &es, script_no); +} + +process_result_t run_script_with_exec_state(scene_state_t *ss, exec_state_t *es, + size_t script_no) { + process_result_t result = {.has_value = false, .value = 0 }; + + // increase the execution depth on each call (e.g. from SCRIPT) + es->exec_depth++; + // only allow the depth to reach 8 + // (if we want to allow this number to be any bigger we really should + // convert this recursive call to use some sort of trampoline!) + if (es->exec_depth > 8) { return result; } + + for (size_t i = 0; i < ss_get_script_len(ss, script_no); i++) { + result = + process_command(ss, es, ss_get_script_command(ss, script_no, i)); } + + // decrease the depth once the commands have been run + es->exec_depth--; + return result; } -process_result_t run_command(const tele_command_t *cmd) { +process_result_t run_command(scene_state_t *ss, const tele_command_t *cmd) { exec_state_t es; es_init(&es); - return process(&es, cmd); + return process_command(ss, &es, cmd); } ///////////////////////////////////////////////////////////////// // PROCESS ////////////////////////////////////////////////////// -process_result_t process(exec_state_t *es, const tele_command_t *c) { +// run a single command inside a given exec_state +process_result_t process_command(scene_state_t *ss, exec_state_t *es, + const tele_command_t *c) { command_state_t cs; - cs_init(&cs); - - // if the command has a MOD, only process it - // allow the MOD to deal with processing the remainder - int16_t idx = c->separator == -1 ? c->l : c->separator; - - while (idx--) { // process from right to left - tele_word_t word_type = c->data[idx].t; - int16_t word_value = c->data[idx].v; + cs_init(&cs); // initialise this here as well as inside the loop, in case + // the command has 0 length + + // 1. Do we have a PRE seperator? + // ------------------------------ + // if we do then only process the PRE part, the MOD will determine if the + // POST should be run and take care of running it + ssize_t start_idx = 0; + ssize_t end_idx = c->separator == -1 ? c->length : c->separator; + + // 2. Determine the location of all the SUB commands + // ------------------------------------------------- + // an array of structs to hold the start and end of each sub command + struct sub_idx { + ssize_t start; + ssize_t end; + } subs[COMMAND_MAX_LENGTH]; + + ssize_t sub_len = 0; + ssize_t sub_start = 0; + + // iterate through c->data to find all the SUB_SEPs and add to the array + for (ssize_t idx = start_idx; idx < end_idx; idx++) { + tele_word_t word_type = c->data[idx].tag; + if (word_type == SUB_SEP && idx > sub_start) { + subs[sub_len].start = sub_start; + subs[sub_len].end = idx - 1; + sub_len++; + sub_start = idx + 1; + } + } - if (word_type == NUMBER) { cs_push(&cs, word_value); } - else if (word_type == OP) { - const tele_op_t *op = tele_ops[word_value]; + // the last sub command won't have been added, manually add it here + if (end_idx > sub_start) { + subs[sub_len].start = sub_start; + subs[sub_len].end = end_idx - 1; + sub_len++; + } - // if we're in the first command position, and there is a set fn - // pointer and we have enough params, then run set, else run get - if (idx == 0 && op->set != NULL && - cs_stack_size(&cs) >= op->params + 1) - op->set(op->data, &scene_state, es, &cs); - else - op->get(op->data, &scene_state, es, &cs); - } - else if (word_type == MOD) { - tele_command_t sub_command; - copy_sub_command(&sub_command, c); - tele_mods[word_value]->func(&scene_state, es, &cs, &sub_command); + // 3. Loop through each sub command and execute it + // ----------------------------------------------- + // iterate through sub commands from left to right + for (ssize_t sub_idx = 0; sub_idx < sub_len; sub_idx++) { + const ssize_t sub_start = subs[sub_idx].start; + const ssize_t sub_end = subs[sub_idx].end; + + // initialise the command state for each sub, otherwise a value left on + // the stack for the previous sub, can cause the set fn to trigger when + // it shouldn't + cs_init(&cs); + + // as we are using a stack based language, we must process commands from + // right to left + for (ssize_t idx = sub_end; idx >= sub_start; idx--) { + const tele_word_t word_type = c->data[idx].tag; + const int16_t word_value = c->data[idx].value; + + if (word_type == NUMBER) { cs_push(&cs, word_value); } + else if (word_type == OP) { + const tele_op_t *op = tele_ops[word_value]; + + // if we're in the first command position, and there is a set fn + // pointer and we have enough params, then run set, else run get + if (idx == sub_start && op->set != NULL && + cs_stack_size(&cs) >= op->params + 1) + op->set(op->data, ss, es, &cs); + else + op->get(op->data, ss, es, &cs); + } + else if (word_type == MOD) { + tele_command_t post_command; + copy_post_command(&post_command, c); + tele_mods[word_value]->func(ss, es, &cs, &post_command); + } } } + // 4. Return + // --------- + // sometimes we have single value left of the stack, if so return it if (cs_stack_size(&cs)) { process_result_t o = {.has_value = true, .value = cs_pop(&cs) }; return o; @@ -296,148 +263,64 @@ process_result_t process(exec_state_t *es, const tele_command_t *c) { } } -///////////////////////////////////////////////////////////////// -// GETTERS & SETTERS //////////////////////////////////////////// - -void tele_set_in(int16_t value) { - scene_state.variables.in = value; -} - -void tele_set_param(int16_t value) { - scene_state.variables.param = value; -} - -void tele_set_scene(int16_t value) { - scene_state.variables.scene = value; -} - -int16_t tele_get_pattern_i(size_t pattern) { - return scene_state.patterns[pattern].i; -} - -void tele_set_pattern_i(size_t pattern, int16_t i) { - scene_state.patterns[pattern].i = i; -} - -int16_t tele_get_pattern_l(size_t pattern) { - return scene_state.patterns[pattern].l; -} - -void tele_set_pattern_l(size_t pattern, int16_t l) { - scene_state.patterns[pattern].l = l; -} - -uint16_t tele_get_pattern_wrap(size_t pattern) { - return scene_state.patterns[pattern].wrap; -} - -void tele_set_pattern_wrap(size_t pattern, uint16_t wrap) { - scene_state.patterns[pattern].wrap = wrap; -} - -int16_t tele_get_pattern_start(size_t pattern) { - return scene_state.patterns[pattern].start; -} - -void tele_set_pattern_start(size_t pattern, int16_t start) { - scene_state.patterns[pattern].start = start; -} - -int16_t tele_get_pattern_end(size_t pattern) { - return scene_state.patterns[pattern].end; -} - -void tele_set_pattern_end(size_t pattern, int16_t end) { - scene_state.patterns[pattern].end = end; -} - -int16_t tele_get_pattern_val(size_t pattern, size_t idx) { - return scene_state.patterns[pattern].v[idx]; -} - -void tele_set_pattern_val(size_t pattern, size_t idx, int16_t val) { - scene_state.patterns[pattern].v[idx] = val; -} - -scene_pattern_t *tele_patterns_ptr() { - return scene_state.patterns; -} - -size_t tele_patterns_size() { - return sizeof(scene_state.patterns); -} - -uint8_t tele_get_script_l(size_t idx) { - return scene_state.scripts[idx].l; -} - -void tele_set_script_l(size_t idx, uint8_t l) { - scene_state.scripts[idx].l = l; -} - -const tele_command_t *tele_get_script_c(size_t script_idx, size_t c_idx) { - return &scene_state.scripts[script_idx].c[c_idx]; -} - -void tele_set_script_c(size_t script_idx, size_t c_idx, - const tele_command_t *cmd) { - memcpy(&scene_state.scripts[script_idx].c[c_idx], cmd, - sizeof(tele_command_t)); -} - -scene_script_t *tele_script_ptr() { - return scene_state.scripts; -} - -size_t tele_script_size() { - return sizeof(scene_state.scripts); -} ///////////////////////////////////////////////////////////////// // TICK ///////////////////////////////////////////////////////// -void tele_tick(uint8_t time) { +void tele_tick(scene_state_t *ss, uint8_t time) { // inc time - if (scene_state.variables.time_act) scene_state.variables.time += time; + if (ss->variables.time_act) ss->variables.time += time; // process delays for (int16_t i = 0; i < DELAY_SIZE; i++) { - if (scene_state.delay.time[i]) { - scene_state.delay.time[i] -= time; - if (scene_state.delay.time[i] <= 0) { - // sprintf(dbg,"\r\ndelay %d", i); - // DBG - run_command(&scene_state.delay.commands[i]); - scene_state.delay.time[i] = 0; - scene_state.delay.count--; - if (scene_state.delay.count == 0) tele_delay(0); + if (ss->delay.time[i]) { + ss->delay.time[i] -= time; + if (ss->delay.time[i] <= 0) { + run_command(ss, &ss->delay.commands[i]); + ss->delay.time[i] = 0; + ss->delay.count--; + if (ss->delay.count == 0) tele_has_delays(false); } } } // process tr pulses for (int16_t i = 0; i < TR_COUNT; i++) { - if (scene_state.tr_pulse_timer[i]) { - scene_state.tr_pulse_timer[i] -= time; - if (scene_state.tr_pulse_timer[i] <= 0) { - scene_state.tr_pulse_timer[i] = 0; - scene_state.variables.tr[i] = - scene_state.variables.tr_pol[i] == 0; - tele_tr(i, scene_state.variables.tr[i]); + if (ss->tr_pulse_timer[i]) { + // prevent tr_pulse_timer from being greater than tr_time + int16_t tr_time = ss->variables.tr_time[i]; + if (tr_time < 0) tr_time = 0; + if (ss->tr_pulse_timer[i] > tr_time) + ss->tr_pulse_timer[i] = tr_time; + + ss->tr_pulse_timer[i] -= time; + + if (ss->tr_pulse_timer[i] <= 0) { + ss->tr_pulse_timer[i] = 0; + ss->variables.tr[i] = ss->variables.tr_pol[i] == 0; + tele_tr(i, ss->variables.tr[i]); } } } } ///////////////////////////////////////////////////////////////// -// INIT ///////////////////////////////////////////////////////// - -void tele_init() { - for (size_t i = 0; i < 4; i++) { - tele_set_pattern_i(i, 0); - tele_set_pattern_l(i, 0); - tele_set_pattern_wrap(i, 1); - tele_set_pattern_start(i, 0); - tele_set_pattern_end(i, 63); - } +// ERROR MESSAGES /////////////////////////////////////////////// + +const char *tele_error(error_t e) { + const char *error_string[] = { "OK", + "UNKNOWN WORD", + "COMMAND TOO LONG", + "NOT ENOUGH PARAMS", + "TOO MANY PARAMS", + "MOD NOT ALLOWED HERE", + "EXTRA PRE SEPARATOR", + "NEED PRE SEPARATOR", + "BAD PRE SEPARATOR", + "NO SUB SEP IN PRE", + "MOVE LEFT", + "NEED SPACE AFTER :", + "NEED SPACE AFTER ;" }; + + return error_string[e]; } diff --git a/src/teletype.h b/src/teletype.h index 98978574..66569301 100644 --- a/src/teletype.h +++ b/src/teletype.h @@ -8,23 +8,23 @@ #include "command.h" #include "state.h" -#define ERROR_MSG_LENGTH 16 - -#define WELCOME "TELETYPE 1.4.1" - +#define TELETYPE_VERSION "TELETYPE 2.0b9" +#define TELE_ERROR_MSG_LENGTH 16 typedef enum { E_OK, - E_WELCOME, E_PARSE, E_LENGTH, E_NEED_PARAMS, E_EXTRA_PARAMS, E_NO_MOD_HERE, - E_MANY_SEP, - E_NEED_SEP, - E_PLACE_SEP, - E_NOT_LEFT + E_MANY_PRE_SEP, + E_NEED_PRE_SEP, + E_PLACE_PRE_SEP, + E_NO_SUB_SEP_IN_PRE, + E_NOT_LEFT, + E_NEED_SPACE_PRE_SEP, + E_NEED_SPACE_SUB_SEP } error_t; typedef struct { @@ -34,43 +34,19 @@ typedef struct { error_t parse(const char *cmd, tele_command_t *out, - char error_msg[ERROR_MSG_LENGTH]); -error_t validate(const tele_command_t *c, char error_msg[ERROR_MSG_LENGTH]); -process_result_t run_script(size_t script_no); -process_result_t run_command(const tele_command_t *cmd); -process_result_t process(exec_state_t *es, const tele_command_t *c); - -void tele_tick(uint8_t); - -void clear_delays(void); - -void tele_init(void); - -void tele_set_in(int16_t value); -void tele_set_param(int16_t value); -void tele_set_scene(int16_t value); - -int16_t tele_get_pattern_i(size_t pattern); -void tele_set_pattern_i(size_t pattern, int16_t i); -int16_t tele_get_pattern_l(size_t pattern); -void tele_set_pattern_l(size_t pattern, int16_t l); -uint16_t tele_get_pattern_wrap(size_t pattern); -void tele_set_pattern_wrap(size_t pattern, uint16_t wrap); -int16_t tele_get_pattern_start(size_t pattern); -void tele_set_pattern_start(size_t pattern, int16_t start); -int16_t tele_get_pattern_end(size_t pattern); -void tele_set_pattern_end(size_t pattern, int16_t end); -int16_t tele_get_pattern_val(size_t pattern, size_t idx); -void tele_set_pattern_val(size_t pattern, size_t idx, int16_t val); -scene_pattern_t *tele_patterns_ptr(void); -size_t tele_patterns_size(void); -uint8_t tele_get_script_l(size_t idx); -void tele_set_script_l(size_t idx, uint8_t l); -const tele_command_t *tele_get_script_c(size_t script_idx, size_t c_idx); -void tele_set_script_c(size_t script_idx, size_t c_idx, - const tele_command_t *cmd); -scene_script_t *tele_script_ptr(void); -size_t tele_script_size(void); + char error_msg[TELE_ERROR_MSG_LENGTH]); +error_t validate(const tele_command_t *c, + char error_msg[TELE_ERROR_MSG_LENGTH]); +process_result_t run_script(scene_state_t *ss, size_t script_no); +process_result_t run_script_with_exec_state(scene_state_t *ss, exec_state_t *es, + size_t script_no); +process_result_t run_command(scene_state_t *ss, const tele_command_t *cmd); +process_result_t process_command(scene_state_t *ss, exec_state_t *es, + const tele_command_t *c); + +void tele_tick(scene_state_t *ss, uint8_t); + +void clear_delays(scene_state_t *ss); const char *tele_error(error_t); diff --git a/src/teletype_io.h b/src/teletype_io.h index 83179408..7a2f0a18 100644 --- a/src/teletype_io.h +++ b/src/teletype_io.h @@ -7,22 +7,32 @@ // These functions are for interacting with the teletype hardware, each target // must provide it's own implementation -extern void tele_metro(int16_t, int16_t, uint8_t); +// called when M or M.ACT are updated +extern void tele_metro_updated(void); + +// called by M.RESET +extern void tele_metro_reset(void); + extern void tele_tr(uint8_t i, int16_t v); extern void tele_cv(uint8_t i, int16_t v, uint8_t s); extern void tele_cv_slew(uint8_t i, int16_t v); -extern void tele_delay(uint8_t i); -extern void tele_s(uint8_t i); + +// inform target if there are delays +extern void tele_has_delays(bool has_delays); + +// inform target if the stack has entries +extern void tele_has_stack(bool has_stack); + extern void tele_cv_off(uint8_t i, int16_t v); -extern void tele_ii(uint8_t i, int16_t d); extern void tele_ii_tx(uint8_t addr, uint8_t *data, uint8_t l); -extern void tele_ii_tx_now(uint8_t addr, uint8_t *data, uint8_t l); extern void tele_ii_rx(uint8_t addr, uint8_t *data, uint8_t l); extern void tele_scene(uint8_t i); -extern void tele_pi(void); -extern void tele_script(uint8_t a); + +// called when a pattern is updated +extern void tele_pattern_updated(void); + extern void tele_kill(void); -extern void tele_mute(uint8_t, uint8_t); +extern void tele_mute(void); extern bool tele_get_input_state(uint8_t); #endif diff --git a/tests/Makefile b/tests/Makefile index b918bd5e..669d6aae 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,17 +1,28 @@ .PHONY: clean test -CFLAGS = -std=c99 -g -Wall -DSIM -I../src -I../libavr32/src +CFLAGS = -std=c99 -g -Wall -fno-common -DSIM -I../src -I../libavr32/src -tests: main.o parser_tests.o process_tests.o \ +tests: main.o \ + match_token_tests.o op_mod_tests.o \ + parser_tests.o process_tests.o \ ../src/teletype.o ../src/command.o ../src/helpers.o \ + ../src/match_token.o ../src/scanner.o \ ../src/state.o ../src/table.o \ - ../src/ops/op.o ../src/ops/constants.o ../src/ops/controlflow.o \ - ../src/ops/delay.o ../src/ops/hardware.o ../src/ops/metronome.o \ - ../src/ops/maths.o ../src/ops/patterns.o ../src/ops/queue.o \ - ../src/ops/stack.o ../src/ops/telex.o ../src/ops/variables.o \ + ../src/ops/op.o ../src/ops/ansible.c ../src/ops/controlflow.o \ + ../src/ops/delay.o ../src/ops/earthsea.o ../src/ops/hardware.o \ + ../src/ops/justfriends.o ../src/ops/meadowphysics.o \ + ../src/ops/metronome.o ../src/ops/maths.o ../src/ops/orca.o \ + ../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \ + ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.c \ ../libavr32/src/euclidean/data.o ../libavr32/src/euclidean/euclidean.o \ ../libavr32/src/util.o $(CC) -o $@ $^ $(CFLAGS) +../src/match_token.c: ../src/match_token.rl + ragel -C -G2 ../src/match_token.rl -o ../src/match_token.c + +../src/scanner.c: ../src/scanner.rl + ragel -C -G2 ../src/scanner.rl -o ../src/scanner.c + test: tests @./tests | greatest/greenest @@ -23,3 +34,5 @@ clean: rm -f ../src/ops/*.o rm -f ../libavr32/src/euclidean/*.o rm -f ../libavr32/src/*.o + rm -f ../src/match_token.c + rm -f ../src/scanner.c diff --git a/tests/main.c b/tests/main.c index 96a01a89..705d7c99 100644 --- a/tests/main.c +++ b/tests/main.c @@ -5,25 +5,25 @@ #include "teletype.h" #include "teletype_io.h" +#include "match_token_tests.h" +#include "op_mod_tests.h" #include "parser_tests.h" #include "process_tests.h" -void tele_metro(int16_t m, int16_t m_act, uint8_t m_reset) {} +void tele_metro_updated() {} +void tele_metro_reset() {} void tele_tr(uint8_t i, int16_t v) {} void tele_cv(uint8_t i, int16_t v, uint8_t s) {} void tele_cv_slew(uint8_t i, int16_t v) {} -void tele_delay(uint8_t i) {} -void tele_s(uint8_t i) {} +void tele_has_delays(bool i) {} +void tele_has_stack(bool i) {} void tele_cv_off(uint8_t i, int16_t v) {} -void tele_ii(uint8_t i, int16_t d) {} void tele_ii_tx(uint8_t addr, uint8_t *data, uint8_t l) {} -void tele_ii_tx_now(uint8_t addr, uint8_t *data, uint8_t l) {} void tele_ii_rx(uint8_t addr, uint8_t *data, uint8_t l) {} void tele_scene(uint8_t i) {} -void tele_pi() {} -void tele_script(uint8_t a) {} +void tele_pattern_updated() {} void tele_kill() {} -void tele_mute(uint8_t i, uint8_t s) {} +void tele_mute() {} bool tele_get_input_state(uint8_t n) { return false; } @@ -33,6 +33,8 @@ GREATEST_MAIN_DEFS(); int main(int argc, char **argv) { GREATEST_MAIN_BEGIN(); + RUN_SUITE(match_token_suite); + RUN_SUITE(op_mod_suite); RUN_SUITE(parser_suite); RUN_SUITE(process_suite); diff --git a/tests/match_token_tests.c b/tests/match_token_tests.c new file mode 100644 index 00000000..f9d95f1a --- /dev/null +++ b/tests/match_token_tests.c @@ -0,0 +1,44 @@ +#include "match_token_tests.h" + +#include + +#include "greatest/greatest.h" + +#include "match_token.h" +#include "ops/op.h" +#include "ops/op_enum.h" + +// This test asserts that match_token always returns the correct op, it does +// this by starting with the op in question, extracting the name and running +// that through match_token. +TEST match_token_should_return_op() { + for (size_t i = 0; i < E_OP__LENGTH; i++) { + const tele_op_t* op = tele_ops[i]; + const char* text = op->name; + tele_data_t data; + bool result = match_token(text, strlen(text), &data); + ASSERT_EQm(text, result, true); + ASSERT_EQm(text, data.tag, OP); + ASSERT_EQm(text, data.value, (int16_t)i); + } + PASS(); +} + +// As match_token_should_return_op, but for mods. +TEST match_token_should_return_mod() { + for (size_t i = 0; i < E_MOD__LENGTH; i++) { + const tele_mod_t* mod = tele_mods[i]; + const char* text = mod->name; + tele_data_t data; + bool result = match_token(text, strlen(text), &data); + ASSERT_EQm(text, result, true); + ASSERT_EQm(text, data.tag, MOD); + ASSERT_EQm(text, data.value, (int16_t)i); + } + PASS(); +} + +SUITE(match_token_suite) { + RUN_TEST(match_token_should_return_op); + RUN_TEST(match_token_should_return_mod); +} diff --git a/tests/match_token_tests.h b/tests/match_token_tests.h new file mode 100644 index 00000000..ef3284d0 --- /dev/null +++ b/tests/match_token_tests.h @@ -0,0 +1,8 @@ +#ifndef _MATCH_TOKEN_TESTS_H_ +#define _MATCH_TOKEN_TESTS_H_ + +#include "greatest/greatest.h" + +SUITE_EXTERN(match_token_suite); + +#endif diff --git a/tests/op_mod_tests.c b/tests/op_mod_tests.c new file mode 100644 index 00000000..54b84e11 --- /dev/null +++ b/tests/op_mod_tests.c @@ -0,0 +1,125 @@ +#include "op_mod_tests.h" + +#include "greatest/greatest.h" + +#include "ops/op.h" +#include "teletype.h" + +// Check every op has a unique name +TEST unique_ops() { + for (size_t i = 0; i < E_OP__LENGTH; i++) { + for (size_t j = 0; j < E_OP__LENGTH; j++) { + if (i == j) continue; + ASSERTm(tele_ops[i]->name, + strcmp(tele_ops[i]->name, tele_ops[j]->name) != 0); + } + } + PASS(); +} + +// Check every mod has a unique name +TEST unique_mods() { + for (size_t i = 0; i < E_MOD__LENGTH; i++) { + for (size_t j = 0; j < E_MOD__LENGTH; j++) { + if (i == j) continue; + ASSERTm(tele_mods[i]->name, + strcmp(tele_mods[i]->name, tele_mods[j]->name) != 0); + } + } + PASS(); +} + +// Check every op manipulates the stack correctly +TEST op_stack_size() { + for (size_t i = 0; i < E_OP__LENGTH; i++) { + const tele_op_t *op = tele_ops[i]; + + if (op->get != NULL) { + scene_state_t ss = {}; // initalise to empty + // (needs dedicated initaliser) + exec_state_t es; + es_init(&es); + command_state_t cs; + cs_init(&cs); + + // add params to stack (plus an extra 2, to check that too many + // values aren't removed, warning: note the maximum stack size in + // state.h) + const int16_t stack_extra = 2; + for (int j = 0; j < op->params + stack_extra; j++) cs_push(&cs, 0); + + // execute get + op->get(op->data, &ss, &es, &cs); + + // check that the stack has the correct number of items in it + if (op->returns) { + ASSERT_EQm(op->name, cs_stack_size(&cs), stack_extra + 1); + } + else { + ASSERT_EQm(op->name, cs_stack_size(&cs), stack_extra); + } + } + + if (op->set != NULL) { + scene_state_t ss = {}; // initalise to empty + // (needs dedicated initaliser) + exec_state_t es; + es_init(&es); + command_state_t cs; + cs_init(&cs); + + // add params to stack (plus an extra 2, to check that too many + // values aren't removed, warning: note the maximum stack size in + // state.h) + // set functions require an extra value on the stack + const int16_t stack_extra = 2; + for (int j = 0; j < op->params + stack_extra + 1; j++) + cs_push(&cs, 0); + + // execute get + op->set(op->data, &ss, &es, &cs); + + // check that the stack has the correct number of items in it + ASSERT_EQm(op->name, cs_stack_size(&cs), stack_extra); + } + } + PASS(); +} + +// Check every mod manipulates the stack correctly +TEST mod_stack_size() { + for (size_t i = 0; i < E_MOD__LENGTH; i++) { + const tele_mod_t *mod = tele_mods[i]; + + scene_state_t ss = {}; // initalise to empty + // (needs dedicated initaliser) + exec_state_t es; + es_init(&es); + command_state_t cs; + cs_init(&cs); + + // add params to stack (plus an extra 2, to check that too many + // values aren't removed, warning: note the maximum stack size in + // state.h) + const int16_t stack_extra = 2; + for (int j = 0; j < mod->params + stack_extra; j++) cs_push(&cs, 0); + + // execute func + const tele_command_t sub_command = {.length = 1, + .separator = 0, + .data = { {.tag = OP, + .value = E_OP_A } } }; + mod->func(&ss, &es, &cs, &sub_command); + + // check that the stack has the correct number of items in it + ASSERT_EQm(mod->name, cs_stack_size(&cs), stack_extra); + } + PASS(); +} + +SUITE(op_mod_suite) { + RUN_TEST(unique_ops); + RUN_TEST(unique_mods); + RUN_TEST(op_stack_size); + RUN_TEST(mod_stack_size); +} diff --git a/tests/op_mod_tests.h b/tests/op_mod_tests.h new file mode 100644 index 00000000..aa9ce1dc --- /dev/null +++ b/tests/op_mod_tests.h @@ -0,0 +1,8 @@ +#ifndef _OP_MOD_TESTS_H_ +#define _OP_MOD_TESTS_H_ + +#include "greatest/greatest.h" + +SUITE_EXTERN(op_mod_suite); + +#endif diff --git a/tests/parser_tests.c b/tests/parser_tests.c index 907c4efc..6c25b6f0 100644 --- a/tests/parser_tests.c +++ b/tests/parser_tests.c @@ -2,162 +2,165 @@ #include "greatest/greatest.h" +#include "ops/op.h" +#include "ops/op_enum.h" #include "teletype.h" +#define CORPUS_COUNT 141 +char corpus[CORPUS_COUNT][32] = { "CV 1 ADD N P.HERE Z", + "CV 1 N P.HERE", + "CV 1 N P.NEXT", + "CV 1 N QT RAND 36 3", + "CV 2 ADD CV 2 Z", + "CV 2 N ADD Y PN P.N Z", + "CV 2 N P.NEXT", + "CV 2 N PN 1 P.HERE", + "CV 2 N PN P.N ADD Z X", + "CV 3 N ADD Y P.HERE", + "CV 3 N P.NEXT", + "CV 3 N PN 2 P.HERE", + "CV 3 N WRAP X 0 48", + "CV 3 V RAND 5", + "CV 4 0", + "CV 4 N PN 3 P.HERE", + "CV 4 N WRAP 0 0 11", + "CV 4 V 8", + "CV 4 V RAND TOSS", + "CV 4 VV P.NEXT", + "CV.SET 3 V RAND 5", + "CV.SET 4 0", + "CV.SET 4 V RAND TOSS", + "CV.SLEW 2 1000", + "CV.SLEW 3 5", + "CV.SLEW 3 500", + "CV.SLEW 4 200", + "CV.SLEW 4 T", + "CV.SLEW 4 Y", + "DEL ADD 40 Y: TR B 0", + "DEL MUL T 4: TR.PULSE A", + "DEL MUL T 7: TR.PULSE A", + "DEL MUL T RRAND 1 5: TR.TOG A", + "DEL RAND Y: TR.PULSE B", + "DEL T: TR.PULSE C", + "DEL T: TR.PULSE D", + "DRUNK 12", + "ELIF EQ 0 MOD X 3: P.N 0", + "ELIF EQ X 4: P.N 2", + "ELIF TOSS: P.PREV", + "ELSE: P.N 1", + "ELSE: P.NEXT", + "IF EQ X 6: P.N 3", + "IF TOSS: P.NEXT", + "IF X: P.PREV", + "ES.CLOCK 1", + "ES.MODE Z", + "ES.PATTERN X", + "ES.PRESET X", + "ES.RESET 1", + "ES.STOP 1", + "ES.TRANS X", + "MP.FREEZE 1", + "MP.PRESET X", + "MP.RESET 1", + "MP.SYNC 1", + "MP.UNFREEZE 1", + "WW.MUTE1 0", + "WW.MUTE1 1", + "WW.MUTE2 0", + "WW.MUTE2 1", + "WW.MUTE3 0", + "WW.MUTE3 1", + "WW.MUTE4 0", + "WW.MUTE4 1", + "WW.PATTERN 0", + "WW.POS X", + "WW.PRESET X", + "WW.QPATTERN X", + "WW.SYNC X", + "L 1 4: CV.SLEW 50", + "L 1 4: CV.SLEW I 12", + "L 1 4: TR I 0", + "L 1 8: MP.MUTE I", + "L 1 8: MP.UNMUTE I", + "L A B: TR.TIME I 25", + "L A B: TR.TIME I 40", + "L A D: TR.PULSE I", + "L A D: TR.TIME 25", + "L A D: TR.TIME 30", + "M 750", + "M SUB 320 RSH PARAM 6", + "P 0", + "P 0 0", + "P.END RRAND 1 7", + "P.END WRAP SUB P.END 1 1 7", + "P.I 0", + "P.I ADD P.I RRAND -2 1", + "P.I P.END", + "P.I WRAP ADD P.I 1 0 14", + "P.I WRAP ADD P.I 2 0 14", + "P.I WRAP ADD P.I 3 0 14", + "P.I WRAP SUB P.I 1 0 14", + "P.N 0", + "P.N 1", + "P.N 2", + "P.N 3", + "P.N WRAP ADD P.N 1 0 3", + "P.NEXT", + "PN 0 0", + "PN 0 0 0", + "PROB 12: X ADD X RRAND -8 8", + "PROB 20: TR.PULSE D", + "PROB 25: X ADD X RRAND -4 4", + "PROB 50: TR.PULSE A", + "PROB 50: TR.PULSE C", + "PROB 50: X ADD X RRAND -2 2", + "PROB 6: X ADD X RRAND -16 16", + "PROB 70: TR.PULSE 3", + "PROB 80: TR.PULSE B", + "S: CV 1 N PN 0 X", + "S: CV 2 ADD N P.HERE V 1", + "S: CV 2 CV 1", + "S: TR.PULSE B", + "S.ALL", + "S.POP", + "T 93", + "T RRAND 10 10000", + "TR A TOSS", + "TR.PULSE A", + "TR.PULSE A", + "TR.PULSE B", + "TR.PULSE C", + "TR.PULSE D", + "TR.TOG D", + "X 0", + "X ADD X RRAND -1 1", + "X EZ X", + "X RSH PARAM 10", + "X; Y; Z", + "X WRAP ADD X 1 0 6", + "X WRAP ADD X 1 0 7", + "X WRAP ADD X 3 0 6", + "X WRAP SUB X 1 0 6", + "X WRAP SUB X 2 0 6", + "Y ADD 200 RSH PARAM 4", + "Y PN 0 X", + "Z ADD 2 MUL 4 TOSS", + "Z EZ Z", + "Z IN", + "Z V RRAND -2 2" }; + error_t parse_and_validate_helper(char* text) { tele_command_t cmd; - char error_msg[ERROR_MSG_LENGTH]; + char error_msg[TELE_ERROR_MSG_LENGTH]; error_t result = parse(text, &cmd, error_msg); if (result != E_OK) { return result; } return validate(&cmd, error_msg); } -#define SPV_COMMANDS 140 TEST should_parse_and_validate() { - char commands[SPV_COMMANDS][31] = { "CV 1 ADD N P.HERE Z", - "CV 1 N P.HERE", - "CV 1 N P.NEXT", - "CV 1 N QT RAND 36 3", - "CV 2 ADD CV 2 Z", - "CV 2 N ADD Y PN P.N Z", - "CV 2 N P.NEXT", - "CV 2 N PN 1 P.HERE", - "CV 2 N PN P.N ADD Z X", - "CV 3 N ADD Y P.HERE", - "CV 3 N P.NEXT", - "CV 3 N PN 2 P.HERE", - "CV 3 N WRAP X 0 48", - "CV 3 V RAND 5", - "CV 4 0", - "CV 4 N PN 3 P.HERE", - "CV 4 N WRAP 0 0 11", - "CV 4 V 8", - "CV 4 V RAND TOSS", - "CV 4 VV P.NEXT", - "CV.SET 3 V RAND 5", - "CV.SET 4 0", - "CV.SET 4 V RAND TOSS", - "CV.SLEW 2 1000", - "CV.SLEW 3 5", - "CV.SLEW 3 500", - "CV.SLEW 4 200", - "CV.SLEW 4 T", - "CV.SLEW 4 Y", - "DEL ADD 40 Y : TR B 0", - "DEL MUL T 4 : TR.PULSE A", - "DEL MUL T 7 : TR.PULSE A", - "DEL MUL T RRAND 1 5 : TR.TOG A", - "DEL RAND Y : TR.PULSE B", - "DEL T : TR.PULSE C", - "DEL T : TR.PULSE D", - "DRUNK 12", - "ELIF EQ 0 MOD X 3 : P.N 0", - "ELIF EQ X 4 : P.N 2", - "ELIF TOSS : P.PREV", - "ELSE : P.N 1", - "ELSE : P.NEXT", - "IF EQ X 6 : P.N 3", - "IF TOSS : P.NEXT", - "IF X : P.PREV", - "II ES.CLOCK 1", - "II ES.MODE Z", - "II ES.PATTERN X", - "II ES.PRESET X", - "II ES.RESET 1", - "II ES.STOP 1", - "II ES.TRANS X", - "II MP.FREEZE 1", - "II MP.PRESET X", - "II MP.RESET 1", - "II MP.SYNC 1", - "II MP.UNFREEZE 1", - "II WW.MUTE1 0", - "II WW.MUTE1 1", - "II WW.MUTE2 0", - "II WW.MUTE2 1", - "II WW.MUTE3 0", - "II WW.MUTE3 1", - "II WW.MUTE4 0", - "II WW.MUTE4 1", - "II WW.PATTERN 0", - "II WW.POS X", - "II WW.PRESET X", - "II WW.QPATTERN X", - "II WW.SYNC X", - "L 1 4 : CV.SLEW 50", - "L 1 4 : CV.SLEW I 12", - "L 1 4 : TR I 0", - "L 1 8 : II MP.MUTE I", - "L 1 8 : II MP.UNMUTE I", - "L A B : TR.TIME I 25", - "L A B : TR.TIME I 40", - "L A D : TR.PULSE I", - "L A D : TR.TIME 25", - "L A D : TR.TIME 30", - "M 750", - "M SUB 320 RSH PARAM 6", - "P 0", - "P 0 0", - "P.END RRAND 1 7", - "P.END WRAP SUB P.END 1 1 7", - "P.I 0", - "P.I ADD P.I RRAND -2 1", - "P.I P.END", - "P.I WRAP ADD P.I 1 0 14", - "P.I WRAP ADD P.I 2 0 14", - "P.I WRAP ADD P.I 3 0 14", - "P.I WRAP SUB P.I 1 0 14", - "P.N 0", - "P.N 1", - "P.N 2", - "P.N 3", - "P.N WRAP ADD P.N 1 0 3", - "P.NEXT", - "PN 0 0", - "PN 0 0 0", - "PROB 12 : X ADD X RRAND -8 8", - "PROB 20 : TR.PULSE D", - "PROB 25 : X ADD X RRAND -4 4", - "PROB 50 : TR.PULSE A", - "PROB 50 : TR.PULSE C", - "PROB 50 : X ADD X RRAND -2 2", - "PROB 6 : X ADD X RRAND -16 16", - "PROB 70 : TR.PULSE 3", - "PROB 80 : TR.PULSE B", - "S : CV 1 N PN 0 X", - "S : CV 2 ADD N P.HERE V 1", - "S : CV 2 CV 1", - "S : TR.PULSE B", - "S.ALL", - "S.POP", - "T 93", - "T RRAND 10 10000", - "TR A TOSS", - "TR.PULSE A", - "TR.PULSE A", - "TR.PULSE B", - "TR.PULSE C", - "TR.PULSE D", - "TR.TOG D", - "X 0", - "X ADD X RRAND -1 1", - "X EZ X", - "X RSH PARAM 10", - "X WRAP ADD X 1 0 6", - "X WRAP ADD X 1 0 7", - "X WRAP ADD X 3 0 6", - "X WRAP SUB X 1 0 6", - "X WRAP SUB X 2 0 6", - "Y ADD 200 RSH PARAM 4", - "Y PN 0 X", - "Z ADD 2 MUL 4 TOSS", - "Z EZ Z", - "Z IN", - "Z V RRAND -2 2" }; - - for (size_t i = 0; i < SPV_COMMANDS; i++) { - char* command = commands[i]; + for (size_t i = 0; i < CORPUS_COUNT; i++) { + char* command = corpus[i]; error_t result = parse_and_validate_helper(command); ASSERT_EQm(command, result, E_OK); } @@ -165,6 +168,79 @@ TEST should_parse_and_validate() { PASS(); } +TEST parser_test_sub_commands() { + ASSERT_EQ(parse_and_validate_helper("X 1; Y 2"), E_OK); + ASSERT_EQ(parse_and_validate_helper("X 1; Y 2 ; ; "), E_OK); + ASSERT_EQ(parse_and_validate_helper("IF 1: X 1; Y 2"), E_OK); + ASSERT_EQ(parse_and_validate_helper("IF 1; Z 1: X 1"), E_NO_SUB_SEP_IN_PRE); + ASSERT_EQ(parse_and_validate_helper("IF 1; Z 1: X 1 ; Y 2"), + E_NO_SUB_SEP_IN_PRE); + // possibly the following should return E_NO_SUB_SEP_IN_PRE one day + ASSERT_EQ(parse_and_validate_helper("Z 1; IF 1: X 1"), E_PLACE_PRE_SEP); + ASSERT_EQ(parse_and_validate_helper("X;Y"), E_NEED_SPACE_SUB_SEP); + + PASS(); +} + +// This test asserts that the parser always returns the correct op, it does this +// by starting with the op in question, extracting the name and running that +// through the parser. Then asserting that only 1 op is returned in +// tele_command_t and that it's value matches the op. +TEST parser_should_return_op() { + for (size_t i = 0; i < E_OP__LENGTH; i++) { + const tele_op_t* op = tele_ops[i]; + const char* text = op->name; + tele_command_t cmd; + char error_msg[TELE_ERROR_MSG_LENGTH]; + error_t result = parse(text, &cmd, error_msg); + ASSERT_EQm(text, result, E_OK); + ASSERT_EQm(text, cmd.length, 1); + ASSERT_EQm(text, cmd.data[0].tag, OP); + ASSERT_EQm(text, cmd.data[0].value, (int16_t)i); + } + PASS(); +} + +// As parser_should_return_op, but for mods. +TEST parser_should_return_mod() { + for (size_t i = 0; i < E_MOD__LENGTH; i++) { + const tele_mod_t* mod = tele_mods[i]; + const char* text = mod->name; + tele_command_t cmd; + char error_msg[TELE_ERROR_MSG_LENGTH]; + error_t result = parse(text, &cmd, error_msg); + ASSERT_EQm(text, result, E_OK); + ASSERT_EQm(text, cmd.length, 1); + ASSERT_EQm(text, cmd.data[0].tag, MOD); + ASSERT_EQm(text, cmd.data[0].value, (int16_t)i); + } + PASS(); +} + +// Check that print_command returns each of the corpus commands unchanged +TEST print_command_corpus_should_be_unchanged() { + for (size_t i = 0; i < CORPUS_COUNT; i++) { + char* text = corpus[i]; + tele_command_t cmd; + char error_msg[TELE_ERROR_MSG_LENGTH]; + error_t result = parse(text, &cmd, error_msg); + ASSERT_EQm(text, result, E_OK); + char out[32]; + print_command(&cmd, out); + char message[256]; + strcpy(message, text); + strcat(message, " == "); + strcat(message, out); + ASSERT_EQm(message, strcmp(text, out), 0); + } + + PASS(); +} + SUITE(parser_suite) { RUN_TEST(should_parse_and_validate); + RUN_TEST(parser_test_sub_commands); + RUN_TEST(parser_should_return_op); + RUN_TEST(parser_should_return_mod); + RUN_TEST(print_command_corpus_should_be_unchanged); } diff --git a/tests/process_tests.c b/tests/process_tests.c index dfd38424..522dc753 100644 --- a/tests/process_tests.c +++ b/tests/process_tests.c @@ -1,31 +1,61 @@ #include "process_tests.h" +#include +#include +#include // ssize_t + #include "greatest/greatest.h" #include "teletype.h" - // runs multiple lines of commands and then asserts that the final answer is -// correct -TEST process_helper(size_t n, char* lines[], int16_t answer) { +// correct (allows contiuation of state) +TEST process_helper_state(scene_state_t* ss, size_t n, char* lines[], + int16_t answer) { process_result_t result = {.has_value = false, .value = 0 }; exec_state_t es; es_init(&es); for (size_t i = 0; i < n; i++) { tele_command_t cmd; - char error_msg[ERROR_MSG_LENGTH]; + char error_msg[TELE_ERROR_MSG_LENGTH]; error_t error = parse(lines[i], &cmd, error_msg); if (error != E_OK) { FAIL(); } if (validate(&cmd, error_msg) != E_OK) { FAIL(); } - result = process(&es, &cmd); + result = process_command(ss, &es, &cmd); } + ASSERT_EQ(result.has_value, true); - ASSERT_EQ(result.value, answer); + + // prep a message for the test + ssize_t size = 0; + for (size_t i = 0; i < n; i++) { + size += strlen(lines[i]) + 3; // 3 extra chars fo ' | ' + } + char* message = calloc(size + 1, sizeof(char)); + for (size_t i = 0; i < n; i++) { + strcat(message, lines[i]); + if (i < n - 1) strcat(message, " | "); + } + + ASSERT_EQm(message, result.value, answer); + + free(message); + + PASS(); +} + + +// runs multiple lines of commands and then asserts that the final answer is +// correct +TEST process_helper(size_t n, char* lines[], int16_t answer) { + scene_state_t ss; + ss_init(&ss); + + CHECK_CALL(process_helper_state(&ss, n, lines, answer)); PASS(); } TEST test_numbers() { - // beware of global state!!! char* test1[1] = { "1" }; CHECK_CALL(process_helper(1, test1, 1)); @@ -42,7 +72,6 @@ TEST test_numbers() { } TEST test_ADD() { - // beware of global state!!! char* test1[1] = { "ADD 5 6" }; CHECK_CALL(process_helper(1, test1, 11)); @@ -53,92 +82,105 @@ TEST test_ADD() { } TEST test_IF() { - // beware of global state!!! - char* test1[3] = { "X 0", "IF 1 : X 1", "X" }; + char* test1[3] = { "X 0", "IF 1: X 1", "X" }; CHECK_CALL(process_helper(3, test1, 1)); - char* test2[3] = { "X 0", "IF 0 : X 1", "X" }; + char* test2[3] = { "X 0", "IF 0: X 1", "X" }; CHECK_CALL(process_helper(3, test2, 0)); - char* test3[3] = { "PN 0 0 0", "IF 1 : PN 0 0 1", "PN 0 0" }; + char* test3[3] = { "PN 0 0 0", "IF 1: PN 0 0 1", "PN 0 0" }; CHECK_CALL(process_helper(3, test3, 1)); - char* test4[3] = { "PN 0 0 0", "IF 0 : PN 0 0 1", "PN 0 0" }; + char* test4[3] = { "PN 0 0 0", "IF 0: PN 0 0 1", "PN 0 0" }; CHECK_CALL(process_helper(3, test4, 0)); + char* test5[3] = { "X 0", "ELSE: X 1", "X" }; + CHECK_CALL(process_helper(3, test5, 0)); + + char* test6[3] = { "X 0", "ELIF 1: X 1", "X" }; + CHECK_CALL(process_helper(3, test6, 0)); + + char* test7[4] = { "X 0", "ELIF 1: X 1", "ELSE: X 1", "X" }; + CHECK_CALL(process_helper(4, test7, 0)); + + char* test8[4] = { "X 0", "IF 0: X 2", "ELSE: X 1", "X" }; + CHECK_CALL(process_helper(4, test8, 1)); + + char* test9[4] = { "X 0", "IF 0: X 2", "ELIF 1: X 1", "X" }; + CHECK_CALL(process_helper(4, test9, 1)); + + char* test10[5] = { "X 0", "IF 1: X 1", "ELIF 1: X 2", "ELSE: X 3", "X" }; + CHECK_CALL(process_helper(5, test10, 1)); + + char* test11[5] = { "X 0", "IF 0: X 1", "ELIF 1: X 2", "ELSE: X 3", "X" }; + CHECK_CALL(process_helper(5, test11, 2)); + + char* test12[5] = { "X 0", "IF 0: X 1", "ELIF 0: X 2", "ELSE: X 3", "X" }; + CHECK_CALL(process_helper(5, test12, 3)); + PASS(); } TEST test_FLIP() { - // beware of global state!!! char* test1[2] = { "FLIP 0", "FLIP" }; CHECK_CALL(process_helper(2, test1, 0)); char* test2[1] = { "FLIP" }; - CHECK_CALL(process_helper(1, test2, 1)); + CHECK_CALL(process_helper(1, test2, 0)); - char* test3[1] = { "FLIP" }; - CHECK_CALL(process_helper(1, test3, 0)); + char* test3[2] = { "FLIP", "FLIP" }; + CHECK_CALL(process_helper(2, test3, 1)); - char* test4[2] = { "FLIP 1", "FLIP" }; + char* test4[2] = { "FLIP 100", "FLIP" }; CHECK_CALL(process_helper(2, test4, 1)); - char* test5[1] = { "FLIP" }; - CHECK_CALL(process_helper(1, test5, 0)); - - char* test6[2] = { "FLIP 100", "FLIP" }; - CHECK_CALL(process_helper(2, test6, 1)); - - char* test7[1] = { "FLIP" }; - CHECK_CALL(process_helper(1, test7, 0)); - PASS(); } TEST test_L() { - // beware of global state!!! - char* test1[3] = { "X 0", "L 1 10 : X I", "X" }; + char* test1[3] = { "X 0", "L 1 10: X I", "X" }; CHECK_CALL(process_helper(3, test1, 10)); - char* test2[3] = { "X 0", "L 1 -10 : X I", "X" }; + char* test2[3] = { "X 0", "L 1 -10: X I", "X" }; CHECK_CALL(process_helper(3, test2, -10)); - char* test3[3] = { "X 0", "L 1 10 : X ADD X I", "X" }; + char* test3[3] = { "X 0", "L 1 10: X ADD X I", "X" }; CHECK_CALL(process_helper(3, test3, 55)); PASS(); } TEST test_O() { - // beware of global state!!! + scene_state_t ss; + ss_init(&ss); + char* test1[6] = { "O.MIN 0", "O.MAX 63", "O.INC 1", "O.WRAP 1", "O 0", "O" }; - CHECK_CALL(process_helper(6, test1, 0)); + CHECK_CALL(process_helper_state(&ss, 6, test1, 0)); char* test2[1] = { "O" }; - CHECK_CALL(process_helper(1, test2, 1)); + CHECK_CALL(process_helper_state(&ss, 1, test2, 1)); char* test3[2] = { "O 0", "O" }; - CHECK_CALL(process_helper(2, test3, 0)); + CHECK_CALL(process_helper_state(&ss, 2, test3, 0)); char* test4[2] = { "O 63", "O" }; - CHECK_CALL(process_helper(2, test4, 63)); + CHECK_CALL(process_helper_state(&ss, 2, test4, 63)); char* test5[1] = { "O" }; - CHECK_CALL(process_helper(1, test5, 0)); + CHECK_CALL(process_helper_state(&ss, 1, test5, 0)); char* test6[4] = { "O 0", "O.INC -1", "O", "O" }; - CHECK_CALL(process_helper(4, test6, 63)); + CHECK_CALL(process_helper_state(&ss, 4, test6, 63)); char* test7[4] = { "O 0", "O.WRAP 0", "O", "O" }; - CHECK_CALL(process_helper(4, test7, 0)); + CHECK_CALL(process_helper_state(&ss, 4, test7, 0)); PASS(); } TEST test_P() { - // beware of global state!!! char* test1[2] = { "P 0 1", "P 0" }; CHECK_CALL(process_helper(2, test1, 1)); @@ -149,7 +191,6 @@ TEST test_P() { } TEST test_PN() { - // beware of global state!!! char* test1[2] = { "PN 0 0 1", "PN 0 0" }; CHECK_CALL(process_helper(2, test1, 1)); @@ -166,9 +207,11 @@ TEST test_PN() { } TEST test_Q() { - // beware of global state!!! + scene_state_t ss; + ss_init(&ss); + char* test1[2] = { "Q.N 16", "Q.N" }; - CHECK_CALL(process_helper(2, test1, 16)); + CHECK_CALL(process_helper_state(&ss, 2, test1, 16)); for (int i = 1; i <= 16; i++) { char buf1[20]; @@ -176,35 +219,34 @@ TEST test_Q() { sprintf(buf1, "Q.N %d", i); sprintf(buf2, "Q %d", i); char* test2[3] = { buf1, buf2, "Q" }; - CHECK_CALL(process_helper(3, test2, 1)); + CHECK_CALL(process_helper_state(&ss, 3, test2, 1)); } for (int i = 1; i <= 16; i++) { char buf1[20]; sprintf(buf1, "Q.N %d", i); char* test3[2] = { buf1, "Q" }; - CHECK_CALL(process_helper(2, test3, 17 - i)); + CHECK_CALL(process_helper_state(&ss, 2, test3, 17 - i)); } // 1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16 = 136 // 136 / 16 = 8.5 // TODO fix Q.AVG to return 9 in this circumstance char* test4[1] = { "Q.AVG" }; - CHECK_CALL(process_helper(1, test4, 8)); + CHECK_CALL(process_helper_state(&ss, 1, test4, 8)); char* test5[2] = { "Q.AVG 5", "Q.AVG" }; - CHECK_CALL(process_helper(2, test5, 5)); + CHECK_CALL(process_helper_state(&ss, 2, test5, 5)); for (int i = 1; i <= 16; i++) { char* test6[1] = { "Q" }; - CHECK_CALL(process_helper(1, test6, 5)); + CHECK_CALL(process_helper_state(&ss, 1, test6, 5)); } PASS(); } TEST test_X() { - // beware of global state!!! char* test1[2] = { "X 0", "X" }; CHECK_CALL(process_helper(2, test1, 0)); @@ -217,6 +259,41 @@ TEST test_X() { PASS(); } +TEST test_sub_commands() { + char* test1[2] = { "X 10; Y 20; Z 30", "ADD X ADD Y Z" }; + CHECK_CALL(process_helper(2, test1, 60)); + + char* test2[2] = { "IF 1: X 1; Y 2; Z 3", "ADD X ADD Y Z" }; + CHECK_CALL(process_helper(2, test2, 6)); + + char* test3[3] = { "X 0; Y 0; Z 0", "IF 0: X 1; Y 2; Z 3", + "ADD X ADD Y Z" }; + CHECK_CALL(process_helper(3, test3, 0)); + + PASS(); +} + +TEST test_blank_command() { + scene_state_t ss; + ss_init(&ss); + exec_state_t es; + es_init(&es); + tele_command_t cmd; + char error_msg[TELE_ERROR_MSG_LENGTH]; + + char* test = ""; + error_t error = parse(test, &cmd, error_msg); + if (error != E_OK) { FAIL(); } + if (validate(&cmd, error_msg) != E_OK) { FAIL(); } + + process_result_t result = process_command(&ss, &es, &cmd); + + ASSERT_EQ(result.has_value, false); + ASSERT_EQ(result.value, 0); + + PASS(); +} + SUITE(process_suite) { RUN_TEST(test_numbers); RUN_TEST(test_ADD); @@ -228,4 +305,6 @@ SUITE(process_suite) { RUN_TEST(test_Q); RUN_TEST(test_PN); RUN_TEST(test_X); + RUN_TEST(test_sub_commands); + RUN_TEST(test_blank_command); } diff --git a/utils/op_enums.py b/utils/op_enums.py new file mode 100755 index 00000000..35aded5b --- /dev/null +++ b/utils/op_enums.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +from os import path +import re + +THIS_FILE = path.realpath(__file__) +THIS_DIR = path.dirname(THIS_FILE) +OP_C = path.abspath(path.join(THIS_DIR, "../src/ops/op.c")) +OP_ENUM_H = path.abspath(path.join(THIS_DIR, "../src/ops/op_enum.h")) + +HEADER_PRE = """// clang-format off + +#ifndef _OP_ENUM_H_ +#define _OP_ENUM_H_ + +// This file has been autogenerated by 'utils/op_enums.py' + +""" +HEADER_POST = "#endif\n" + + +def is_not_comment(line): + s = line.lstrip() + return not (s.startswith("//") or s.startswith("/*")) + + +def remove_comments(op_c): + out = op_c.splitlines() + out = filter(is_not_comment, out) + return "\n".join(out) + + +def find_ops(op_c): + raw = re.findall("&op_[a-zA-Z0-9_]+", op_c) + stripped = [s[4:] for s in raw] + return stripped + + +def find_mods(op_c): + raw = re.findall("&mod_[a-zA-Z0-9_]+", op_c) + stripped = [s[5:] for s in raw] + return stripped + + +def make_enum(name, prefix, entries): + entries = list(entries) # make a copy + entries.append("_LENGTH") # add a final entry for length + output = "" + output += "typedef enum {\n" + for e in entries: + output += f" {prefix}{e},\n" + output += "}} {};\n\n".format(name) + return output + + +def main(): + print("reading: {}".format(OP_C)) + print("generating: {}".format(OP_ENUM_H)) + with open(OP_C, "r") as f: + op_c = remove_comments(f.read()) + ops = find_ops(op_c) + mods = find_mods(op_c) + op_enum = make_enum("tele_op_idx_t", "E_OP_", ops) + mod_enum = make_enum("tele_mod_idx_t", "E_MOD_", mods) + header = HEADER_PRE + op_enum + mod_enum + HEADER_POST + with open(OP_ENUM_H, "w") as g: + g.write(header) + + +if __name__ == '__main__': + main()