diff options
25 files changed, 541 insertions, 141 deletions
diff --git a/common/lightbar.c b/common/lightbar.c index f8dce75c50..b6360c18f2 100644 --- a/common/lightbar.c +++ b/common/lightbar.c @@ -927,6 +927,7 @@ static struct lightbar_program next_prog; static uint8_t pc; static uint8_t led_desc[NUM_LEDS][LB_CONT_MAX][3]; +static uint32_t lb_wait_delay; static uint32_t lb_ramp_delay; /* Get one byte of data pointed to by the pc and advance * the pc forward. @@ -957,6 +958,20 @@ static inline uint32_t decode_32(uint32_t *dest) return EC_SUCCESS; } +/* ON - turn on lightbar */ +static uint32_t lightbyte_ON(void) +{ + lb_on(); + return EC_SUCCESS; +} + +/* OFF - turn off lightbar */ +static uint32_t lightbyte_OFF(void) +{ + lb_off(); + return EC_SUCCESS; +} + /* JUMP xx - jump to immediate location * Changes the pc to the one-byte immediate argument. */ @@ -965,17 +980,72 @@ static uint32_t lightbyte_JUMP(void) return decode_8(&pc); } -/* DELAY xx xx xx xx - yield processor for some time - * Performs an interruptible wait for a number of microseconds - * given in the four-byte immediate. +/* JUMP_BATTERY aa bb - switch on battery level + * If the battery is low, changes pc to aa. + * If the battery is high, changes pc to bb. + * Otherwise, continues execution as normal. */ -static uint32_t lightbyte_DELAY(void) +static uint32_t lightbyte_JUMP_BATTERY(void) { - uint32_t delay_us; - if (decode_32(&delay_us) != EC_SUCCESS) + uint8_t low_pc, high_pc; + if (decode_8(&low_pc) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + if (decode_8(&high_pc) != EC_SUCCESS) return EC_RES_INVALID_PARAM; - WAIT_OR_RET(delay_us); + get_battery_level(); + if (st.battery_level == 0) + pc = low_pc; + else if (st.battery_level == 3) + pc = high_pc; + + return EC_SUCCESS; +} + +/* JUMP_IF_CHARGING xx - conditional jump to location + * Changes the pc to xx if the device is charging. + */ +static uint32_t lightbyte_JUMP_IF_CHARGING(void) +{ + uint8_t charge_pc; + if (decode_8(&charge_pc) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + + if (st.battery_is_charging) + pc = charge_pc; + + return EC_SUCCESS; +} + +/* SET_WAIT_DELAY xx xx xx xx - set up to yield processor + * Sets the wait delay to the given four-byte immediate, in + * microseconds. Future WAIT instructions will wait for this + * much time. + */ +static uint32_t lightbyte_SET_WAIT_DELAY(void) +{ + return decode_32(&lb_wait_delay); +} + +/* SET_RAMP_DELAY xx xx xx xx - change ramp speed + * This sets the length of time between ramp/cycle steps to + * the four-byte immediate argument, which represents a duration + * in milliseconds. + */ +static uint32_t lightbyte_SET_RAMP_DELAY(void) +{ + return decode_32(&lb_ramp_delay); +} + +/* WAIT - yield processor for some time + * Yields the processor for some amount of time set by the most + * recent SET_WAIT_DELAY instruction. + */ +static uint32_t lightbyte_WAIT(void) +{ + if (lb_wait_delay != 0) + WAIT_OR_RET(lb_wait_delay); + return EC_SUCCESS; } @@ -993,33 +1063,34 @@ static uint32_t lightbyte_SET_BRIGHTNESS(void) return EC_SUCCESS; } -/* SET_COLOR cc xx - * SET_COLOR cc rr gg bb +/* SET_COLOR_SINGLE cc xx + * SET_COLOR_RGB cc rr gg bb * Stores a color value in the led_desc structure. * cc is a bit-packed location to perform the action on. * - * The high four bits are used to describe an LED. If the - * value is less than NUM_LEDS, it describes a particular LED, - * and if it is greater than or equal to that value, it - * will perform the action on all LEDs. + * The high four bits are a bitset for which LEDs to operate on. + * LED 0 is the lowest of the four bits. * * The next two bits are the control bits. This should be a value * in lb_control that is not LB_CONT_MAX, and the corresponding * color will be the one the action is performed on. * - * The last two bits are the color bits. If this is LB_COL_RED, - * LB_COL_GREEN, or LB_COL_BLUE, then there is only one more byte - * to decode and this is a color value for that specific color - * channel. If it is LB_COL_ALL, then there are three more bytes, - * and it reads like a standard 24-bit color value. + * The last two bits are the color bits if this instruction is + * SET_COLOR_SINGLE. They correspond to a LB_COL value for the + * channel to set the color for using the next immediate byte. + * In SET_COLOR_RGB, these bits are don't-cares, as there should + * always be three bytes that follow, which correspond to a + * complete RGB specification. */ -static uint32_t lightbyte_SET_COLOR(void) +static uint32_t lightbyte_SET_COLOR_SINGLE(void) { uint8_t packed_loc, led, control, color, value; - int start_led, end_led, color_mask, i, j; + int i; if (decode_8(&packed_loc) != EC_SUCCESS) return EC_RES_INVALID_PARAM; + if (decode_8(&value) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; led = packed_loc >> 4; control = (packed_loc >> 2) & 0x3; @@ -1028,34 +1099,74 @@ static uint32_t lightbyte_SET_COLOR(void) if (control >= LB_CONT_MAX) return EC_RES_INVALID_PARAM; - if (led >= NUM_LEDS) { - start_led = 0; - end_led = NUM_LEDS - 1; - } else - start_led = end_led = led; + for (i = 0; i < NUM_LEDS; i++) + if (led & (1 << i)) + led_desc[i][control][color] = value; + + return EC_SUCCESS; +} + +static uint32_t lightbyte_SET_COLOR_RGB(void) +{ + uint8_t packed_loc, r, g, b, led, control; + int i; + + /* gross */ + if (decode_8(&packed_loc) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + if (decode_8(&r) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + if (decode_8(&g) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + if (decode_8(&b) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + + led = packed_loc >> 4; + control = (packed_loc >> 2) & 0x3; - color_mask = color == LB_COL_ALL ? 7 : (1 << color); + if (control >= LB_CONT_MAX) + return EC_RES_INVALID_PARAM; - for (i = 0; i < 3; i++) { - if (color_mask & (1 << i)) { - if (decode_8(&value) != EC_SUCCESS) - return EC_RES_INVALID_PARAM; - for (j = start_led; j <= end_led; j++) - led_desc[j][control][i] = value; + for (i = 0; i < NUM_LEDS; i++) + if (led & (1 << i)) { + led_desc[i][control][LB_COL_RED] = r; + led_desc[i][control][LB_COL_GREEN] = g; + led_desc[i][control][LB_COL_BLUE] = b; } - } return EC_SUCCESS; } -/* SET_DELAY_TIME xx xx xx xx - change ramp speed - * This sets the length of time between ramp/cycle steps to - * the four-byte immediate argument, which represents a duration - * in milliseconds. +/* GET_COLORS - take current colors and push them to the state + * Gets the current state of the LEDs and puts them in COLOR0. + * Good for the beginning of a program if you need to fade in. */ -static uint32_t lightbyte_SET_DELAY_TIME(void) +static uint32_t lightbyte_GET_COLORS(void) { - return decode_32(&lb_ramp_delay); + int i; + for (i = 0; i < NUM_LEDS; i++) + lb_get_rgb(i, &led_desc[i][LB_CONT_COLOR0][LB_COL_RED], + &led_desc[i][LB_CONT_COLOR0][LB_COL_GREEN], + &led_desc[i][LB_CONT_COLOR0][LB_COL_BLUE]); + + return EC_SUCCESS; +} + +/* SWAP_COLORS - swaps beginning and end colors in state + * Exchanges COLOR0 and COLOR1 on all LEDs. + */ +static uint32_t lightbyte_SWAP_COLORS(void) +{ + int i, j, tmp; + for (i = 0; i < NUM_LEDS; i++) + for (j = 0; j < 3; j++) { + tmp = led_desc[i][LB_CONT_COLOR0][j]; + led_desc[i][LB_CONT_COLOR0][j] = + led_desc[i][LB_CONT_COLOR1][j]; + led_desc[i][LB_CONT_COLOR1][j] = tmp; + } + + return EC_SUCCESS; } static inline int get_interp_value(int led, int color, int interp) @@ -1173,7 +1284,7 @@ static uint32_t lightbyte_HALT(void) #undef GET_INTERP_VALUE -#define OP(X) X +#define OP(NAME, BYTES, MNEMONIC) NAME, #include "lightbar_opcode_list.h" enum lightbyte_opcode { LIGHTBAR_OPCODE_TABLE @@ -1181,14 +1292,14 @@ enum lightbyte_opcode { }; #undef OP -#define OP(X) lightbyte_ ## X +#define OP(NAME, BYTES, MNEMONIC) lightbyte_ ## NAME, #include "lightbar_opcode_list.h" static uint32_t (*lightbyte_dispatch[])(void) = { LIGHTBAR_OPCODE_TABLE }; #undef OP -#define OP(X) # X +#define OP(NAME, BYTES, MNEMONIC) MNEMONIC, #include "lightbar_opcode_list.h" static const char * const lightbyte_names[] = { LIGHTBAR_OPCODE_TABLE @@ -1209,8 +1320,12 @@ static uint32_t sequence_PROGRAM(void) saved_brightness = lb_get_brightness(); pc = 0; memset(led_desc, 0, sizeof(led_desc)); + lb_wait_delay = 0; lb_ramp_delay = 0; + lb_on(); + lb_set_brightness(255); + /* decode-execute loop */ for (;;) { old_pc = pc; @@ -1582,6 +1697,7 @@ static int command_lightbar(int argc, char **argv) } #ifdef LIGHTBAR_SIMULATION + /* Load a program. */ if (argc >= 3 && !strcasecmp(argv[1], "program")) { return lb_load_program(argv[2], &next_prog); } diff --git a/extra/lightbar/programs/bad-decode-32.bin b/extra/lightbar/programs/bad-decode-32.bin index de2e71b327..1d5d0c6c75 100644 --- a/extra/lightbar/programs/bad-decode-32.bin +++ b/extra/lightbar/programs/bad-decode-32.bin @@ -1 +1 @@ -UUU
\ No newline at end of file +UUU
\ No newline at end of file diff --git a/extra/lightbar/programs/bad-decode-8.bin b/extra/lightbar/programs/bad-decode-8.bin Binary files differindex d8188da697..8352675d67 100644 --- a/extra/lightbar/programs/bad-decode-8.bin +++ b/extra/lightbar/programs/bad-decode-8.bin diff --git a/extra/lightbar/programs/bad-jump.bin b/extra/lightbar/programs/bad-jump.bin Binary files differindex d284cb97ce..b2c29a0bbf 100644 --- a/extra/lightbar/programs/bad-jump.bin +++ b/extra/lightbar/programs/bad-jump.bin diff --git a/extra/lightbar/programs/green-pulse.bin b/extra/lightbar/programs/green-pulse.bin Binary files differindex 9ea21f789a..0fdab712e9 100644 --- a/extra/lightbar/programs/green-pulse.bin +++ b/extra/lightbar/programs/green-pulse.bin diff --git a/extra/lightbar/programs/green-pulse.lbs b/extra/lightbar/programs/green-pulse.lbs new file mode 100644 index 0000000000..bccf3e5c9a --- /dev/null +++ b/extra/lightbar/programs/green-pulse.lbs @@ -0,0 +1,8 @@ + set.1 {0,1,2,3}.end.g 0xff + delay.r 7813 + delay.w 2000000 +L0001: on + cycle.1 + off + wait + jump L0001 diff --git a/extra/lightbar/programs/infinite-jump.bin b/extra/lightbar/programs/infinite-jump.bin Binary files differindex 09f370e38f..5407bf3ddf 100644 --- a/extra/lightbar/programs/infinite-jump.bin +++ b/extra/lightbar/programs/infinite-jump.bin diff --git a/extra/lightbar/programs/infinite-jump.lbs b/extra/lightbar/programs/infinite-jump.lbs new file mode 100644 index 0000000000..6174d7ffd4 --- /dev/null +++ b/extra/lightbar/programs/infinite-jump.lbs @@ -0,0 +1 @@ +L0001: jump L0001 diff --git a/extra/lightbar/programs/konami.bin b/extra/lightbar/programs/konami.bin Binary files differnew file mode 100644 index 0000000000..f7abfdc4ee --- /dev/null +++ b/extra/lightbar/programs/konami.bin diff --git a/extra/lightbar/programs/konami.lbs b/extra/lightbar/programs/konami.lbs new file mode 100644 index 0000000000..c9fa8d697a --- /dev/null +++ b/extra/lightbar/programs/konami.lbs @@ -0,0 +1,89 @@ +# Konami code easter egg + delay.w 100000 + set.rgb {1,2}.end 0xff 0xff 0x00 + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + set.rgb {1,2}.end 0x00 0x00 0x00 + set.1 {0,3}.end.b 0xff + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + set.1 {0,3}.end.b 0x00 + set.1 {0,1}.end.r 0xff + ramp.1 + wait + cycle.1 + wait + set.1 {0,1}.end.r 0x00 + set.1 {2,3}.end.g 0xff + ramp.1 + wait + cycle.1 + wait + set.1 {2,3}.end.g 0x00 + set.1 {0,1}.end.r 0xff + ramp.1 + wait + cycle.1 + wait + set.1 {0,1}.end.r 0x00 + set.1 {2,3}.end.g 0xff + ramp.1 + wait + cycle.1 + wait + set.1 {2,3}.end.g 0x00 + set.rgb {0,2}.end 0x00 0xff 0xff + ramp.1 + wait + cycle.1 + wait + delay.w 50000 + wait + set.rgb {0,2}.end 0x00 0x00 0x00 + set.rgb {1,3}.end 0xff 0x00 0xff + ramp.1 + wait + wait + cycle.1 + wait + delay.w 100000 + wait + wait + set.rgb {0,1,2,3}.end 0xff 0xff 0xff + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + halt diff --git a/extra/lightbar/programs/rainbow-shift-compact.bin b/extra/lightbar/programs/rainbow-shift-compact.bin Binary files differdeleted file mode 100644 index f5590c5820..0000000000 --- a/extra/lightbar/programs/rainbow-shift-compact.bin +++ /dev/null diff --git a/extra/lightbar/programs/rainbow-shift.bin b/extra/lightbar/programs/rainbow-shift.bin Binary files differindex 44e1af4b7d..a72c5b16d6 100644 --- a/extra/lightbar/programs/rainbow-shift.bin +++ b/extra/lightbar/programs/rainbow-shift.bin diff --git a/extra/lightbar/programs/rainbow-shift.lbs b/extra/lightbar/programs/rainbow-shift.lbs new file mode 100644 index 0000000000..e1cbcddc83 --- /dev/null +++ b/extra/lightbar/programs/rainbow-shift.lbs @@ -0,0 +1,8 @@ +# The rainbow cycle program. + set.rgb {0,1,2,3}.end 0xff 0xff 0xff + set.rgb {0}.phase 0x00 0x55 0xaa + set.rgb {1}.phase 0x40 0x95 0xea + set.rgb {2}.phase 0x80 0xd5 0x2a + set.rgb {3}.phase 0xc0 0x15 0x6a + delay.r 7813 + cycle diff --git a/extra/lightbar/programs/red-green-blink.bin b/extra/lightbar/programs/red-green-blink.bin Binary files differindex 305f3c53f9..6bece444dd 100644 --- a/extra/lightbar/programs/red-green-blink.bin +++ b/extra/lightbar/programs/red-green-blink.bin diff --git a/extra/lightbar/programs/red-green-blink.lbs b/extra/lightbar/programs/red-green-blink.lbs new file mode 100644 index 0000000000..d520b739bb --- /dev/null +++ b/extra/lightbar/programs/red-green-blink.lbs @@ -0,0 +1,14 @@ +# Blinks red and green with 1 second pauses. + set.rgb {0,1,2,3}.beg 0xff 0x00 0x00 + set.rgb {0,1,2,3}.end 0x00 0xff 0x00 + delay.w 250000 + delay.r 0 + cycle.1 + wait + ramp.1 + wait + cycle.1 + wait + ramp.1 + wait + halt diff --git a/extra/lightbar/programs/s0.bin b/extra/lightbar/programs/s0.bin Binary files differnew file mode 100644 index 0000000000..b20cecd8ee --- /dev/null +++ b/extra/lightbar/programs/s0.bin diff --git a/extra/lightbar/programs/s0.lbs b/extra/lightbar/programs/s0.lbs new file mode 100644 index 0000000000..364c3d595c --- /dev/null +++ b/extra/lightbar/programs/s0.lbs @@ -0,0 +1,22 @@ +# S0 sequence: Google colors, unless battery is low. + set.rgb {0}.end 0x33 0x69 0xe8 + set.rgb {1}.end 0xd5 0x0f 0x25 + set.rgb {2}.end 0xee 0xb2 0x11 + set.rgb {3}.end 0x00 0x99 0x25 + delay.r 1250 + ramp.1 + set.1 {0,1,2,3}.beg.r 0xff + delay.r 2500 + delay.w 1000000 + wait + jump L0003 +L0001: swap + ramp.1 +L0002: wait +L0003: jbat L0004 L0002 + jump L0002 +L0004: swap + ramp.1 +L0005: wait + jbat L0005 L0001 + jump L0001 diff --git a/extra/lightbar/programs/s0s3.bin b/extra/lightbar/programs/s0s3.bin Binary files differnew file mode 100644 index 0000000000..d1cb8a4af1 --- /dev/null +++ b/extra/lightbar/programs/s0s3.bin diff --git a/extra/lightbar/programs/s0s3.lbs b/extra/lightbar/programs/s0s3.lbs new file mode 100644 index 0000000000..ba141f338d --- /dev/null +++ b/extra/lightbar/programs/s0s3.lbs @@ -0,0 +1,16 @@ +# S0S3 sequence: Fade out, Google color ramp up/down. + get + delay.r 2000 + ramp.1 + swap + set.rgb {0}.end 0x33 0x69 0xe8 + set.rgb {1}.end 0xd5 0x0f 0x25 + set.rgb {2}.end 0xee 0xb2 0x11 + set.rgb {3}.end 0x00 0x99 0x25 + delay.r 1250 + ramp.1 + swap + delay.r 10000 + ramp.1 + off + halt diff --git a/extra/lightbar/programs/s3.bin b/extra/lightbar/programs/s3.bin Binary files differnew file mode 100644 index 0000000000..7e487bb8c9 --- /dev/null +++ b/extra/lightbar/programs/s3.bin diff --git a/extra/lightbar/programs/s3.lbs b/extra/lightbar/programs/s3.lbs new file mode 100644 index 0000000000..e8803a06bb --- /dev/null +++ b/extra/lightbar/programs/s3.lbs @@ -0,0 +1,17 @@ +# S3 sequence: Pulse red on low battery. + set.rgb {0,1,2,3}.end 0xff 0x00 0x00 + cycle.1 + delay.w 5000000 +L0001: off + wait + jcharge L0001 + jbat L0002 L0001 + jump L0001 +L0002: on + delay.r 1250 + ramp.1 + swap + delay.r 10000 + ramp.1 + swap + jump L0001 diff --git a/extra/lightbar/programs/s3s0.bin b/extra/lightbar/programs/s3s0.bin Binary files differnew file mode 100644 index 0000000000..b277752d25 --- /dev/null +++ b/extra/lightbar/programs/s3s0.bin diff --git a/extra/lightbar/programs/s3s0.lbs b/extra/lightbar/programs/s3s0.lbs new file mode 100644 index 0000000000..0cac96f208 --- /dev/null +++ b/extra/lightbar/programs/s3s0.lbs @@ -0,0 +1,11 @@ +# S3S0 sequence: Google color ramp up/down. + set.rgb {0}.end 0x33 0x69 0xe8 + set.rgb {1}.end 0xd5 0x0f 0x25 + set.rgb {2}.end 0xee 0xb2 0x11 + set.rgb {3}.end 0x00 0x99 0x25 + delay.r 1250 + ramp.1 + swap + delay.r 10000 + ramp.1 + halt diff --git a/include/lightbar_opcode_list.h b/include/lightbar_opcode_list.h index 83432c04e3..14ab23421c 100644 --- a/include/lightbar_opcode_list.h +++ b/include/lightbar_opcode_list.h @@ -4,13 +4,23 @@ * * This defines a list of lightbar opcodes for programmable sequences. */ -#define LIGHTBAR_OPCODE_TABLE \ - OP(JUMP), \ - OP(DELAY), \ - OP(SET_BRIGHTNESS), \ - OP(SET_COLOR), \ - OP(SET_DELAY_TIME), \ - OP(RAMP_ONCE), \ - OP(CYCLE_ONCE), \ - OP(CYCLE), \ - OP(HALT), + +/* NAME OPERAND BYTES MNEMONIC*/ +#define LIGHTBAR_OPCODE_TABLE \ + OP(ON, 0, "on" )\ + OP(OFF, 0, "off" )\ + OP(JUMP, 1, "jump" )\ + OP(JUMP_BATTERY, 2, "jbat" )\ + OP(JUMP_IF_CHARGING, 1, "jcharge" )\ + OP(SET_WAIT_DELAY, 4, "delay.w" )\ + OP(SET_RAMP_DELAY, 4, "delay.r" )\ + OP(WAIT, 0, "wait" )\ + OP(SET_BRIGHTNESS, 1, "bright" )\ + OP(SET_COLOR_SINGLE, 2, "set.1" )\ + OP(SET_COLOR_RGB, 4, "set.rgb" )\ + OP(GET_COLORS, 0, "get" )\ + OP(SWAP_COLORS, 0, "swap" )\ + OP(RAMP_ONCE, 0, "ramp.1" )\ + OP(CYCLE_ONCE, 0, "cycle.1" )\ + OP(CYCLE, 0, "cycle" )\ + OP(HALT, 0, "halt" ) diff --git a/util/lbcc.c b/util/lbcc.c index a5247dcccc..b34b21e53e 100644 --- a/util/lbcc.c +++ b/util/lbcc.c @@ -64,7 +64,7 @@ struct safe_lightbar_program { uint8_t zeros[LB_PROG_MAX_OPERANDS]; } __packed; -#define OP(X) X +#define OP(NAME, BYTES, MNEMONIC) NAME, #include "lightbar_opcode_list.h" enum lightbyte_opcode { LIGHTBAR_OPCODE_TABLE @@ -72,18 +72,25 @@ enum lightbyte_opcode { }; #undef OP +#define OP(NAME, BYTES, MNEMONIC) BYTES, +#include "lightbar_opcode_list.h" +static const int num_operands[] = { + LIGHTBAR_OPCODE_TABLE +}; +#undef OP + +#define OP(NAME, BYTES, MNEMONIC) MNEMONIC, +#include "lightbar_opcode_list.h" static const char const *opcode_sym[] = { - "jump", "wait", "bright", "color", - "step", "ramp.1", "cycle.1", "cycle", - "halt", + LIGHTBAR_OPCODE_TABLE }; -BUILD_ASSERT(ARRAY_SIZE(opcode_sym) == MAX_OPCODE); +#undef OP static const char const *control_sym[] = { "beg", "end", "phase", "<invalid>" }; static const char const *color_sym[] = { - "r", "g", "b", "rgb" + "r", "g", "b", "<invalid>" }; static void read_binary(FILE *fp, struct safe_lightbar_program *prog) @@ -111,35 +118,6 @@ static void read_binary(FILE *fp, struct safe_lightbar_program *prog) } } -/* Returns number of operands required by an opcode */ -static int num_operands(uint8_t cmd, uint8_t *arg) -{ - int operands = 0; - - switch (cmd) { - case JUMP: - case SET_BRIGHTNESS: - operands = 1; - break; - - case DELAY: - case SET_DELAY_TIME: - operands = 4; - break; - - case SET_COLOR: - if ((arg[0] & 0x03) == LB_COL_ALL) - operands = 4; - else - operands = 2; - break; - - default: - break; - } - return operands; -} - static uint32_t val32(uint8_t *ptr) { uint32_t val; @@ -147,13 +125,34 @@ static uint32_t val32(uint8_t *ptr) return val; } +static int is_jump(uint8_t op) +{ + /* TODO: probably should be a field in the opcode list */ + return op >= JUMP && op <= JUMP_IF_CHARGING; +} + +static void print_led_set(FILE *fp, uint8_t led) +{ + int i, first = 1; + + fprintf(fp, "{"); + for (i = 0; i < NUM_LEDS; i++) + if (led & (1 << i)) { + if (!first) + fprintf(fp, ","); + fprintf(fp, "%d", i); + first = 0; + } + fprintf(fp, "}"); +} + /* returns number of operands consumed */ static int print_op(FILE *fp, uint8_t addr, uint8_t cmd, uint8_t *arg) { uint8_t led, color, control; int i, operands; - operands = num_operands(cmd, arg); + operands = num_operands[cmd]; /* assume valid instruction for now */ is_instruction[addr] = 1; @@ -176,32 +175,44 @@ static int print_op(FILE *fp, uint8_t addr, uint8_t cmd, uint8_t *arg) switch (cmd) { case JUMP: + case JUMP_IF_CHARGING: fprintf(fp, "\tL00%02x\n", arg[0]); break; - case DELAY: - case SET_DELAY_TIME: + case JUMP_BATTERY: + fprintf(fp, "\tL00%02x L00%02x\n", arg[0], arg[1]); + break; + case SET_WAIT_DELAY: + case SET_RAMP_DELAY: fprintf(fp, "\t%d\n", val32(arg)); break; case SET_BRIGHTNESS: fprintf(fp, "\t%d\n", arg[0]); break; - case SET_COLOR: + case SET_COLOR_SINGLE: led = arg[0] >> 4; control = (arg[0] >> 2) & 0x03; color = arg[0] & 0x03; fprintf(fp, "\t"); - if (led >= NUM_LEDS) - fprintf(fp, "all"); - else - fprintf(fp, "%d", led); + + print_led_set(fp, led); fprintf(fp, ".%s", control_sym[control]); fprintf(fp, ".%s", color_sym[color]); - if (color == LB_COL_ALL) - fprintf(fp, "\t0x%02x 0x%02x 0x%02x\n", - arg[1], arg[2], arg[3]); - else - fprintf(fp, "\t0x%02x\n", arg[1]); + fprintf(fp, "\t0x%02x\n", arg[1]); break; + case SET_COLOR_RGB: + led = arg[0] >> 4; + control = (arg[0] >> 2) & 0x03; + fprintf(fp, "\t"); + + print_led_set(fp, led); + fprintf(fp, ".%s", control_sym[control]); + fprintf(fp, "\t0x%02x 0x%02x 0x%02x\n", arg[1], arg[2], arg[3]); + break; + case ON: + case OFF: + case WAIT: + case GET_COLORS: + case SWAP_COLORS: case RAMP_ONCE: case CYCLE_ONCE: case CYCLE: @@ -217,20 +228,31 @@ static int print_op(FILE *fp, uint8_t addr, uint8_t cmd, uint8_t *arg) return operands; } +static void set_jump_target(uint8_t targ) +{ + if (targ >= EC_LB_PROG_LEN) { + Warning("program jumps to 0x%02x, " + "which out of bounds\n", targ); + return; + } + is_jump_target[targ] = 1; +} + static void disassemble_prog(FILE *fp, struct safe_lightbar_program *prog) { int i; - uint8_t *ptr, targ; + uint8_t *ptr, op; /* Scan the program once to identify all the jump targets, * so we can print the labels when we encounter them. */ for (i = 0; i < prog->p.size; i++) { ptr = &prog->p.data[i]; - if (ptr[0] == JUMP) { - targ = ptr[1]; - is_jump_target[targ] = 1; - } - i += num_operands(*ptr, ptr + 1); + op = *ptr; + if (is_jump(op)) + set_jump_target(ptr[1]); + if (op == JUMP_BATTERY) + set_jump_target(ptr[2]); + i += num_operands[op]; } /* Now disassemble */ @@ -278,28 +300,60 @@ static int split_line(char *buf, char *delim, struct parse_s *elt, int max) return i; } -/* Decode color arg. Return 0 if bogus, number of additional args if okay. */ -static int is_color_arg(char *buf, uint32_t *valp) +/* Decode led set. Return 0 if bogus, 1 if okay. */ +static int is_led_set(char *buf, uint8_t *valp) +{ + uint8_t led = 0; + unsigned long int next_led; + char *ptr; + + if (!buf) + return 0; + + if (*buf != '{') + return 0; + + buf++; + for (;;) { + next_led = strtoul(buf, &ptr, 0); + if (buf == ptr) { + if (buf[0] == '}' && buf[1] == 0) { + *valp = led; + return 1; + } else + return 0; + } + + if (next_led >= NUM_LEDS) + return 0; + + led |= 1 << next_led; + + buf = ptr; + if (*buf == ',') + buf++; + } +} + +/* Decode color arg based on expected control param sections. + * Return 0 if bogus, 1 if okay. + */ +static int is_color_arg(char *buf, int expected, uint32_t *valp) { struct parse_s token[MAX_WORDS]; - uint8_t led, control, color, val; - int i; - int rv = 1; + uint8_t led, control, color; + int i; if (!buf) return 0; /* There should be three terms, separated with '.' */ - i = split_line(buf, ".,", token, MAX_WORDS); - if (i != 3) + i = split_line(buf, ".", token, MAX_WORDS); + if (i != expected) return 0; - if (!strcmp("all", token[0].word)) { - led = NUM_LEDS; - } else if (token[0].is_num) { - led = token[0].val; - } else { - Error("Invalid LED \"%s\"\n", token[0].word); + if (!is_led_set(token[0].word, &led)) { + Error("Invalid LED set \"%s\"\n", token[0].word); return 0; } @@ -311,22 +365,20 @@ static int is_color_arg(char *buf, uint32_t *valp) if (i >= LB_CONT_MAX) return 0; - for (i = 0; i < ARRAY_SIZE(color_sym); i++) - if (!strcmp(token[2].word, color_sym[i])) { - color = i; - break; - } - if (i >= ARRAY_SIZE(color_sym)) - return 0; - - - val = ((led & 0xF) << 4) | ((control & 0x3) << 2) | (color & 0x3); + if (expected == 3) { + for (i = 0; i < ARRAY_SIZE(color_sym); i++) + if (!strcmp(token[2].word, color_sym[i])) { + color = i; + break; + } + if (i >= ARRAY_SIZE(color_sym)) + return 0; + } else + color = 0; - *valp = val; - if (color == LB_COL_ALL) - rv = 3; - return rv; + *valp = ((led & 0xF) << 4) | ((control & 0x3) << 2) | (color & 0x3); + return 1; } static void fixup_symbols(struct safe_lightbar_program *prog) @@ -422,12 +474,29 @@ static void compile(FILE *fp, struct safe_lightbar_program *prog) /* Now we need operands. */ switch (opcode) { case JUMP: + case JUMP_IF_CHARGING: /* a label */ if (token[wnum].word) reloc_label[addr++] = strdup(token[wnum].word); else Error("Missing jump target at line %d\n", line); break; + case JUMP_BATTERY: + /* two labels*/ + if (token[wnum].word) + reloc_label[addr++] = strdup(token[wnum].word); + else { + Error("Missing first jump target " + "at line %d\n", line); + break; + } + wnum++; + if (token[wnum].word) + reloc_label[addr++] = strdup(token[wnum].word); + else + Error("Missing second jump target " + "at line %d\n", line); + break; case SET_BRIGHTNESS: /* one 8-bit arg */ @@ -437,8 +506,8 @@ static void compile(FILE *fp, struct safe_lightbar_program *prog) Error("Missing/invalid arg at line %d\n", line); break; - case DELAY: - case SET_DELAY_TIME: + case SET_WAIT_DELAY: + case SET_RAMP_DELAY: /* one 32-bit arg */ if (token[wnum].is_num) { prog->p.data[addr++] = @@ -454,17 +523,36 @@ static void compile(FILE *fp, struct safe_lightbar_program *prog) } break; - case SET_COLOR: - /* one magic word, then one or three more 8-bit args */ - i = is_color_arg(token[wnum].word, &token[wnum].val); + case SET_COLOR_SINGLE: + /* one magic word, then one more 8-bit arg */ + i = is_color_arg(token[wnum].word, 3, &token[wnum].val); + if (!i) { + Error("Missing/invalid arg at line %d\n", line); + break; + } + /* save the magic number */ + prog->p.data[addr++] = token[wnum++].val; + /* and the color immediate */ + if (token[wnum].is_num) { + prog->p.data[addr++] = + token[wnum++].val; + } else { + Error("Missing/Invalid arg " + "at line %d\n", line); + break; + } + break; + case SET_COLOR_RGB: + /* one magic word, then three more 8-bit args */ + i = is_color_arg(token[wnum].word, 2, &token[wnum].val); if (!i) { Error("Missing/invalid arg at line %d\n", line); break; } /* save the magic number */ prog->p.data[addr++] = token[wnum++].val; - while (i--) { - /* and the others */ + /* and the color immediates */ + for (i = 0; i < 3; i++) { if (token[wnum].is_num) { prog->p.data[addr++] = token[wnum++].val; |