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