Large diffs are not rendered by default.

@@ -28,33 +28,34 @@ static void mod_S_func(scene_state_t *ss, exec_state_t *NOTUSED(es),
if (ss->stack_op.top < STACK_OP_SIZE) {
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_command(es, &ss->stack_op.commands[ss->stack_op.top - i - 1]);
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_command(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);
}
}

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,
@@ -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);
@@ -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
@@ -6,6 +6,6 @@
#include "teletype.h"

error_t scanner(const char *cmd, tele_command_t *out,
char error_msg[ERROR_MSG_LENGTH]);
char error_msg[TELE_ERROR_MSG_LENGTH]);

#endif
@@ -16,7 +16,7 @@ const size_t kMaxTokenLength = 32;
}%%

error_t scanner(const char *data, tele_command_t *out,
char error_msg[ERROR_MSG_LENGTH]) {
char error_msg[TELE_ERROR_MSG_LENGTH]) {
const size_t len = strlen(data);

// required ragel declarations
@@ -37,10 +37,14 @@ error_t scanner(const char *data, tele_command_t *out,

%%{
separator = [ \n\t];
pre_separator = ' : ';
sub_seperator = ' ; ';
pre_separator = ': ';
sub_seperator = '; ';
invalid_pre = ':';
invalid_sub = ';';

token = any+ -- (separator | pre_separator | sub_seperator);
token = any+ -- (separator
| pre_separator | sub_seperator
| invalid_pre | invalid_sub);

action token {
// token matched
@@ -98,10 +102,20 @@ error_t scanner(const char *data, tele_command_t *out,
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;
*|;

@@ -1,10 +1,252 @@
#include "state.h"

#include <string.h>

#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;
for (size_t i = 0; i < SCRIPT_COUNT; i++) { ss->scripts[i].l = 0; }
}

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);
}

// 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_script_ptr(scene_state_t *ss) {
return ss->scripts;
}

size_t ss_script_size() {
return sizeof(scene_script_t);
}


////////////////////////////////////////////////////////////////////////////////
// EXEC STATE //////////////////////////////////////////////////////////////////

void es_init(exec_state_t *es) {
es->if_else_condition = false;
es->exec_depth = 0;
}


////////////////////////////////////////////////////////////////////////////////
// COMMAND STATE ///////////////////////////////////////////////////////////////

void cs_init(command_state_t *cs) {
cs->stack.top = 0;
}
@@ -2,6 +2,7 @@
#define _STATE_H_

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#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_script_ptr(scene_state_t *ss);
size_t ss_script_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);

@@ -11,90 +11,37 @@
#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 PRE SEPARATOR",
"NEED PRE SEPARATOR",
"BAD PRE SEPARATOR",
"NO SUB SEP IN PRE",
"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;
}

for (int16_t i = 0; i < DELAY_SIZE; i++) { scene_state.delay.time[i] = 0; }
void clear_delays(scene_state_t *ss) {
for (int16_t i = 0; i < TR_COUNT; i++) { ss->tr_pulse_timer[i] = 0; }

scene_state.delay.count = 0;
for (int16_t i = 0; i < DELAY_SIZE; i++) { ss->delay.time[i] = 0; }

scene_state.stack_op.top = 0;
ss->delay.count = 0;
ss->stack_op.top = 0;

tele_delay(0);
tele_s(0);
tele_has_delays(false);
tele_has_stack(false);
}


/////////////////////////////////////////////////////////////////
// PARSE ////////////////////////////////////////////////////////

error_t parse(const char *cmd, tele_command_t *out,
char error_msg[ERROR_MSG_LENGTH]) {
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->length;
@@ -184,28 +131,43 @@ 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_command(&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));
}
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_command(&es, cmd);
return process_command(ss, &es, cmd);
}


/////////////////////////////////////////////////////////////////
// PROCESS //////////////////////////////////////////////////////

// run a single command inside a given exec_state
process_result_t process_command(exec_state_t *es, const tele_command_t *c) {
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);

@@ -266,15 +228,14 @@ process_result_t process_command(exec_state_t *es, const tele_command_t *c) {
// 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, &scene_state, es, &cs);
op->set(op->data, ss, es, &cs);
else
op->get(op->data, &scene_state, es, &cs);
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(&scene_state, es, &cs,
&post_command);
tele_mods[word_value]->func(ss, es, &cs, &post_command);
}
}
}
@@ -292,148 +253,57 @@ process_result_t process_command(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]) {
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];
}
@@ -8,14 +8,11 @@
#include "command.h"
#include "state.h"

#define ERROR_MSG_LENGTH 16

#define WELCOME "TELETYPE 2.0b"

#define TELETYPE_VERSION "TELETYPE 2.0b2"
#define TELE_ERROR_MSG_LENGTH 16

typedef enum {
E_OK,
E_WELCOME,
E_PARSE,
E_LENGTH,
E_NEED_PARAMS,
@@ -25,7 +22,9 @@ typedef enum {
E_NEED_PRE_SEP,
E_PLACE_PRE_SEP,
E_NO_SUB_SEP_IN_PRE,
E_NOT_LEFT
E_NOT_LEFT,
E_NEED_SPACE_PRE_SEP,
E_NEED_SPACE_SUB_SEP
} error_t;

typedef struct {
@@ -35,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_command(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);

@@ -7,22 +7,34 @@
// 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
@@ -7,11 +7,12 @@ tests: main.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/ansible.c ../src/ops/constants.o \
../src/ops/controlflow.o ../src/ops/delay.o ../src/ops/hardware.o \
../src/ops/justfriends.o ../src/ops/metronome.o ../src/ops/maths.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/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)
@@ -10,22 +10,22 @@
#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;
}

Large diffs are not rendered by default.

@@ -3,29 +3,38 @@
#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_command(&es, &cmd);
result = process_command(ss, &es, &cmd);
}
ASSERT_EQ(result.has_value, true);
ASSERT_EQ(result.value, answer);

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);

return process_helper_state(&ss, n, lines, answer);
}

TEST test_numbers() {
// beware of global state!!!
char* test1[1] = { "1" };
CHECK_CALL(process_helper(1, test1, 1));

@@ -42,7 +51,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,7 +61,6 @@ TEST test_ADD() {
}

TEST test_IF() {
// beware of global state!!!
char* test1[3] = { "X 0", "IF 1 : X 1", "X" };
CHECK_CALL(process_helper(3, test1, 1));

@@ -70,33 +77,22 @@ TEST test_IF() {
}

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" };
CHECK_CALL(process_helper(3, test1, 10));

@@ -110,35 +106,36 @@ TEST test_L() {
}

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 +146,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,45 +162,46 @@ 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];
char buf2[20];
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));