From a21a24cec968e5f5fc6787527154eaaf0c8fd69b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 27 May 2010 18:07:59 +0200 Subject: [PATCH] Add LED pattern class for RX44 --- Makefile | 1 + src/led-pattern-rx44.vala | 322 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 src/led-pattern-rx44.vala diff --git a/Makefile b/Makefile index 341a8ce..d8f6ba4 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,7 @@ led_pattern_editor_VALASOURCES = \ src/led-color-widgets.vala \ src/led-command-widget.vala \ src/led-pattern.vala \ + src/led-pattern-rx44.vala \ src/led-pattern-rx51.vala \ src/led-pattern-dialog.vala \ src/led-pattern-button.vala \ diff --git a/src/led-pattern-rx44.vala b/src/led-pattern-rx44.vala new file mode 100644 index 0000000..93244ee --- /dev/null +++ b/src/led-pattern-rx44.vala @@ -0,0 +1,322 @@ +/* This file is part of LED Pattern Editor. + * + * Copyright (C) 2010 Philipp Zabel + * + * LED Pattern Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LED Pattern Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LED Pattern Editor. If not, see . + */ + +class LedPatternRX44 : LedPattern { + public List engine_r; + public List engine_g; + public List engine_b; + + public bool parse (string line) { + string[] key_value = line.split ("="); + + if (key_value.length != 2) { + print ("pattern line does not contain '=': %s\n", line); + return false; + } + + string[] p = key_value[1].split (";"); + if (p.length != 6) { + print ("pattern does not contain 6 components: %d\n", p.length); + return false; + } + + if (p[3].length > 16*4 || p[4].length > 16*4 || p[5].length > 16*4) { + print ("pattern too long!\n"); + return false; + } + + name = key_value[0]; + priority = p[0].to_int (); + screen_on = p[1].to_int (); + timeout = p[2].to_int (); + engine_r = parse_pattern (p[3]); + engine_g = parse_pattern (p[4]); + engine_b = parse_pattern (p[5]); + + on_changed (); + return true; + } + + private List parse_pattern (string pattern) { + var list = new List (); + var length = pattern.length; + + if (length % 4 != 0) + return list; + + char *p = ((char*) pattern) + length - 4; + while (p >= (char*) pattern) { + var command = new LedCommandRX44.with_code ((uint16) ((string) p).to_ulong (null, 16)); + command.changed.connect (on_changed); + list.prepend (command); + p[0] = '\0'; + p -= 4; + } + + return list; + } + + public string dump () { + return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, + dump_pattern (engine_r), dump_pattern (engine_g), dump_pattern (engine_b)); + } + + private string dump_pattern (List list) { + string result = ""; + foreach (LedCommandRX44 command in list) { + result += "%04x".printf (command.code); + } + return result; + } + + public LedPatternRX44 copy () { + var pattern = new LedPatternRX44 (); + + pattern.name = name.dup (); + pattern.priority = priority; + pattern.screen_on = screen_on; + pattern.timeout = timeout; + + pattern.duration = duration; + + pattern.engine_r = deep_copy (pattern, engine_r); + pattern.engine_g = deep_copy (pattern, engine_g); + pattern.engine_b = deep_copy (pattern, engine_b); + + return pattern; + } + + public List deep_copy (LedPatternRX44 pattern, List list) { + var list2 = new List (); + + foreach (LedCommandRX44 command in list) { + var command2 = command.copy (); + command2.changed.connect (pattern.on_changed); + list2.append (command2); + } + + return list2; + } + + public void replace_with (LedPatternRX44 pattern) { + name = pattern.name; + priority = pattern.priority; + screen_on = pattern.screen_on; + timeout = pattern.timeout; + + duration = pattern.duration; + + engine_r = deep_copy (this, pattern.engine_r); + engine_g = deep_copy (this, pattern.engine_g); + engine_b = deep_copy (this, pattern.engine_b); + + changed (); + } + + public void on_changed () { + bool unresolved = calculate_timing (); + if (unresolved) + unresolved = calculate_timing (); + if (unresolved) + Hildon.Banner.show_information (null, null, "Timing unresolved"); + changed (); + } + + private bool calculate_timing () { + bool unresolved = false; + // Calculate timing and level info for red engine + double time = 0; + int level = 0; + foreach (LedCommandRX44 command in engine_r) { + command.time = time; + if (command.type == CommandType.SET_PWM) { + level = command.level; + } else { + command.level = level; + level += command.steps; + } + if (command.type == CommandType.TRIGGER && + (command.code & 0x0180) != 0) { + command.duration = wait_for_trigger (time, engine_g); + if (command.duration == 0) + unresolved = true; + command.duration += 16 * LedCommandRX44.CYCLE_TIME_MS; + } + time += command.duration; + if (level < 0) + level = 0; + if (level > 255) + level = 255; + } + duration = time; + // Calculate timing and level info for green engine + time = 0; + level = 0; + foreach (LedCommandRX44 command in engine_g) { + command.time = time; + if (command.type == CommandType.SET_PWM) { + level = command.level; + } else { + command.level = level; + level += command.steps; + } + if (command.type == CommandType.TRIGGER && + (command.code & 0x0180) != 0) { + command.duration = wait_for_trigger (time, engine_r); + if (command.duration == 0) + unresolved = true; + command.duration += 16 * LedCommandRX44.CYCLE_TIME_MS; + } + time += command.duration; + if (level < 0) + level = 0; + if (level > 255) + level = 255; + } + if (time > duration) + duration = time; + return unresolved; + } + + double wait_for_trigger (double time, List engine) { + double duration = 0; + bool repeat = false; + foreach (LedCommandRX44 command in engine) { + duration = command.time + command.duration; + if (command.type == CommandType.TRIGGER && + (command.code & 0x0006) != 0 && command.time > time) { + return command.time - time; + } + if (command.type == CommandType.GO_TO_START) { + repeat = true; + break; + } + } + if (repeat) foreach (LedCommandRX44 command in engine) { + if (command.type == CommandType.TRIGGER && + (command.code & 0x0006) != 0 && (duration + command.time) > time) { + return duration + command.time - time; + } + } + return 0; + } +} + +class LedCommandRX44 : LedCommand { + internal const double CYCLE_TIME_MS = 1000.0 / 32768.0; + + public uint16 code; + + public LedCommandRX44 () { + } + + public LedCommandRX44.with_code (uint16 _code) { + code = _code; + duration = 16 * CYCLE_TIME_MS; + if ((code & 0x8000) == 0) { + if (code == 0x0000) { + type = CommandType.GO_TO_START; + } else if ((code & 0x3e00) != 0) { + type = CommandType.RAMP_WAIT; + steps = code & 0x7f; + step_time = code >> 8; + if ((code & 0x4000) == 0) + step_time = (code >> 9) * 16 * CYCLE_TIME_MS; + else { + step_time = ((code & 0x3e00) >> 9) * 512 * CYCLE_TIME_MS; + } + duration = step_time * (steps + 1); + if ((code & 0x80) != 0) + steps = -steps; + } else { + type = CommandType.SET_PWM; + level = code & 0xff; + } + } else { + if ((code & ~0x1f8f) == 0xa000) { + type = CommandType.BRANCH; + // 0x1f80: (loop count - 1) << 7 + // 0x000f: step number + } else if ((code & ~0x1800) == 0xc000) { + type = CommandType.END; + // 0x1000: interrupt + if ((code & 0x0800) != 0) // Reset + steps = -255; + } else if ((code & ~ 0x13fe) == 0xe000) { + type = CommandType.TRIGGER; + // 0x1000: wait ext + // 0x0380: wait B G R + // 0x0040: set ext + // 0x000e: set B G R + } + } + } + + public override void set_pwm (int _level) { + code = 0x4000 | _level; + base.set_pwm (_level); + } + + public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= (16 * CYCLE_TIME_MS)) { + int step_time; + if (_step_time < 32 * (16 * CYCLE_TIME_MS)) { + step_time = (int) ((_step_time + 0.001) / (16 * CYCLE_TIME_MS)); + code = (uint16) step_time << 8; + _step_time = step_time * (16 * CYCLE_TIME_MS); + } else if (_step_time < 32*(512 * CYCLE_TIME_MS)) { + step_time = (int) ((_step_time + 0.001) / (512 * CYCLE_TIME_MS)); + code = 0x4000 | (step_time << 8); + _step_time = step_time * (512 * CYCLE_TIME_MS); + } else { + return; + } + if (_steps < 0) { + code |= 0x80 | (-_steps); + } else { + code |= _steps; + } + base.ramp_wait (_step_time, _steps); + } + + public override void go_to_start () { + code = 0x0000; + base.go_to_start (); + } + + public override void end (bool reset) { + code = 0xc000; + if (reset) + code |= 0x0800; + base.end (reset); + } + + public LedCommandRX44 copy () { + var command = new LedCommandRX44 (); + + command.type = type; + command.time = time; + command.step_time = step_time; + command.duration = duration; + command.level = level; + command.steps = steps; + + command.code = code; + + return command; + } +} -- 1.7.9.5