From 90c9a148a94ed92c93d42110e45d8787f7ac1eff Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 12 Dec 2011 00:11:34 +0100 Subject: initial import --- lp5523.vala | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 lp5523.vala (limited to 'lp5523.vala') 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 + * + * 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)); + } + } +} -- cgit v1.2.3