summaryrefslogtreecommitdiffstats
path: root/lp5523.vala
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2011-12-12 00:11:34 +0100
committerSebastian Reichel <sre@ring0.de>2011-12-12 00:11:34 +0100
commit90c9a148a94ed92c93d42110e45d8787f7ac1eff (patch)
tree447e0ec7bfa5c60a87468851c2fff741d6e645f2 /lp5523.vala
downloadlp5523-assembler-90c9a148a94ed92c93d42110e45d8787f7ac1eff.tar.bz2
initial import
Diffstat (limited to 'lp5523.vala')
-rw-r--r--lp5523.vala168
1 files changed, 168 insertions, 0 deletions
diff --git a/lp5523.vala b/lp5523.vala
new file mode 100644
index 0000000..f6d4c64
--- /dev/null
+++ b/lp5523.vala
@@ -0,0 +1,168 @@
+/* lp5523.vala
+ * Copyright 2011, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+namespace lp5523 {
+ public errordomain ParsingError {
+ INVALID_OPCODE,
+ INVALID_COMMAND,
+ OUT_OF_RANGE
+ }
+
+ public uint8 PROGSPACE_SIZE = 96;
+
+ public string disassemble(uint16 opcode) throws ParsingError {
+ opcode = opcode.to_big_endian();
+ uint8 byte1 = (uint8) opcode;
+ uint8 byte2 = (uint8) (opcode >> 8);
+ opcode = uint16.from_big_endian(opcode);
+
+ if(byte1 >= 0x02 && byte1 <= 0x3f) {
+ bool neg = (byte1 & 0x01) == 0x01;
+ uint8 time = (byte1 >> 1) - 0x01;
+ uint8 steps = byte2;
+ if(neg && steps == 0x00)
+ return "sleep %hhu".printf(time);
+ else
+ return "fade %hhu %c%hhu".printf(time, neg ? '-' : '+', steps);
+ } else if(byte1 == 0x40) {
+ return "set %hhu".printf(byte2);
+ } else if(byte1 >= 0x42 && byte1 <= 0x7f) {
+ bool neg = (byte1 & 0x01) == 0x01;
+ uint8 time = (byte1 >> 1) - 0x02;
+ uint8 steps = byte2;
+ if(neg && steps == 0x00)
+ return "sleep %hhu".printf(time);
+ else
+ return "fade %hhu %c%hhu".printf(time, neg ? '-' : '+', steps);
+ } else if(byte1 >= 0xa0 && byte1 <= 0xbf) {
+ uint8 count = (byte1 << 1) & ~0xc1;
+ if((byte2 & 0x80) == 0x80) count++;
+ uint8 pc = byte2 & ~0x80;
+ return "branch %hhu %hhu".printf(count, pc);
+ }
+
+ switch(opcode) {
+ case 0x0000: return "restart";
+ case 0x9d80: return "start";
+ case 0xc000: return "stop";
+ case 0xc800: return "stopr";
+ case 0xd000: return "stopi";
+ case 0xd800: return "stopri";
+ case 0xe002: return "send1";
+ case 0xe004: return "send2";
+ case 0xe008: return "send3";
+ case 0xe080: return "wait1";
+ case 0xe100: return "wait2";
+ case 0xe200: return "wait3";
+ default:
+ throw new ParsingError.INVALID_OPCODE("invalid opcode: %04hx".printf(opcode));
+ }
+ }
+
+ public uint16 assemble(string cmd) throws ParsingError {
+ MatchInfo m;
+
+ Regex REGEX_SET = /^set\s+(\d+)$/;
+ Regex REGEX_SLEEP = /^sleep\s+(\d+)$/;
+ Regex REGEX_FADE = /^fade\s+(\d+)\s+([\+\-])(\d+)$/;
+ Regex REGEX_BRANCH = /^branch\s+(\d+)\s+(\d+)$/;
+
+ if(REGEX_SLEEP.match(cmd, 0, out m)) {
+ uint16 time = (uint8) int.parse(m.fetch(1));
+
+ if(time < 31)
+ time += 0x01;
+ else if(time < 62)
+ time += 0x02;
+ else
+ throw new ParsingError.OUT_OF_RANGE("fade time out of range (0-61)");
+
+ time <<= 1;
+ time |= 0x01;
+ time <<= 8;
+
+ return time;
+ }
+
+ if(REGEX_FADE.match(cmd, 0, out m)) {
+ uint16 time = (uint8) int.parse(m.fetch(1));
+ bool neg = m.fetch(2).get(0) == '-';
+ uint8 steps = (uint8) int.parse(m.fetch(3));
+
+ if(time < 31)
+ time += 0x01;
+ else if(time < 62)
+ time += 0x02;
+ else
+ throw new ParsingError.OUT_OF_RANGE("fade time out of range (0-61)");
+
+ time <<= 1;
+
+ if(neg)
+ time |= 0x01;
+
+ time <<= 8;
+
+ return time + steps;
+ }
+
+ if(REGEX_SET.match(cmd, 0, out m)) {
+ uint16 byte1 = 0x4000;
+
+ uint level = int.parse(m.fetch(1));
+ if(level > 0xFF)
+ throw new ParsingError.OUT_OF_RANGE("brightness level is out of range (0-255)");
+
+ return byte1 + (uint8) level;
+ }
+
+ if(REGEX_BRANCH.match(cmd, 0, out m)) {
+ uint16 byte1 = (uint8) int.parse(m.fetch(1));
+ uint8 byte2 = (uint8) int.parse(m.fetch(2));
+
+ if((byte1 & 0x01) != 0x00)
+ byte2 |= 0x80;
+ else
+ byte2 &= ~0x80;
+
+ byte1 >>= 1; /* shift 1 right */
+ byte1 |= 0x80; /* set 1st bit */
+ byte1 &= ~0x40; /* clear 2nd bit */
+ byte1 |= 0x20; /* set 3rd bit */
+
+ byte1 <<= 8;
+
+ return byte1 + byte2;
+ }
+
+ switch(cmd) {
+ case "start": return 0x9d80;
+ case "restart": return 0x0000;
+ case "stop": return 0xc000;
+ case "stopr": return 0xc800;
+ case "stopi": return 0xd000;
+ case "stopri": return 0xd800;
+ case "send1": return 0xe002;
+ case "send2": return 0xe004;
+ case "send3": return 0xe008;
+ case "wait1": return 0xe080;
+ case "wait2": return 0xe100;
+ case "wait3": return 0xe200;
+ default:
+ throw new ParsingError.INVALID_COMMAND("invalid command: %s".printf(cmd));
+ }
+ }
+}