1 /* This file is part of LED Pattern Editor.
3 * Copyright (C) 2010 Philipp Zabel
5 * LED Pattern Editor is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * LED Pattern Editor is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with LED Pattern Editor. If not, see <http://www.gnu.org/licenses/>.
19 class LedPatternRX51 : LedPattern {
20 public LedColor color1;
21 public LedColor color2;
22 public List<LedCommandRX51> engine1;
23 public List<LedCommandRX51> engine2;
25 public bool parse (string line) {
26 string[] key_value = line.split ("=");
28 if (key_value.length != 2) {
29 print ("pattern line does not contain '=': %s\n", line);
33 string[] p = key_value[1].split (";");
35 print ("pattern does not contain 6 components: %d\n", p.length);
39 if (p[4].length > 16*4 || p[5].length > 16*4) {
40 print ("pattern too long!\n");
45 priority = p[0].to_int ();
46 screen_on = p[1].to_int ();
47 timeout = p[2].to_int ();
48 parse_led_map (p[3], out color1, out color2);
49 engine1 = parse_pattern (p[4]);
50 engine2 = parse_pattern (p[5]);
52 if (engine1.first ().data.code != 0x9d80) {
53 print ("engine1 pattern doesn't start with refresh mux command\n");
55 if (engine2.first ().data.code != 0x9d80) {
56 print ("engine2 pattern doesn't start with refresh mux command\n");
63 private void parse_led_map (string led_map, out LedColor color1, out LedColor color2) {
64 color1 = LedColor.OFF;
65 color2 = LedColor.OFF;
80 private List<LedCommandRX51> parse_pattern (string pattern) {
81 var list = new List<LedCommandRX51> ();
82 var length = pattern.length;
87 char *p = ((char*) pattern) + length - 4;
88 while (p >= (char*) pattern) {
89 var command = new LedCommandRX51.with_code ((uint16) ((string) p).to_ulong (null, 16));
90 command.changed.connect (on_changed);
91 list.prepend (command);
99 public string dump () {
100 return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, dump_led_map (),
101 dump_pattern (engine1), dump_pattern (engine2));
104 private string dump_led_map () {
106 if (LedColor.R in color1)
108 if (LedColor.R in color2)
110 if (LedColor.G in color1)
112 if (LedColor.G in color2)
114 if (LedColor.B in color1)
116 if (LedColor.B in color2)
121 private string dump_pattern (List<LedCommandRX51> list) {
123 foreach (LedCommandRX51 command in list) {
124 result += "%04x".printf (command.code);
129 public LedPatternRX51 copy () {
130 var pattern = new LedPatternRX51 ();
132 pattern.name = name.dup ();
133 pattern.priority = priority;
134 pattern.screen_on = screen_on;
135 pattern.timeout = timeout;
137 pattern.duration = duration;
139 pattern.color1 = color1;
140 pattern.color2 = color2;
141 pattern.engine1 = deep_copy (pattern, engine1);
142 pattern.engine2 = deep_copy (pattern, engine2);
147 public List<LedCommandRX51> deep_copy (LedPatternRX51 pattern, List<LedCommandRX51> list) {
148 var list2 = new List<LedCommandRX51> ();
150 foreach (LedCommandRX51 command in list) {
151 var command2 = command.copy ();
152 command2.changed.connect (pattern.on_changed);
153 list2.append (command2);
159 public void replace_with (LedPatternRX51 pattern) {
161 priority = pattern.priority;
162 screen_on = pattern.screen_on;
163 timeout = pattern.timeout;
165 duration = pattern.duration;
167 color1 = pattern.color1;
168 color2 = pattern.color2;
169 engine1 = deep_copy (this, pattern.engine1);
170 engine2 = deep_copy (this, pattern.engine2);
175 public void on_changed () {
176 bool unresolved = calculate_timing ();
178 unresolved = calculate_timing ();
180 Hildon.Banner.show_information (null, null, "Timing unresolved");
184 private bool calculate_timing () {
185 bool unresolved = false;
186 // Calculate timing and level info for engine 1
189 foreach (LedCommandRX51 command in engine1) {
191 if (command.type == CommandType.SET_PWM) {
192 level = command.level;
194 command.level = level;
195 level += command.steps;
197 if (command.type == CommandType.TRIGGER &&
198 (command.code & 0x0180) != 0) {
199 command.duration = wait_for_trigger (time, engine2);
200 if (command.duration == 0)
202 command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
204 time += command.duration;
211 // Calculate timing and level info for engine 2
214 foreach (LedCommandRX51 command in engine2) {
216 if (command.type == CommandType.SET_PWM) {
217 level = command.level;
219 command.level = level;
220 level += command.steps;
222 if (command.type == CommandType.TRIGGER &&
223 (command.code & 0x0180) != 0) {
224 command.duration = wait_for_trigger (time, engine1);
225 if (command.duration == 0)
227 command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
229 time += command.duration;
240 double wait_for_trigger (double time, List<LedCommandRX51> engine) {
243 foreach (LedCommandRX51 command in engine) {
244 duration = command.time + command.duration;
245 if (command.type == CommandType.TRIGGER &&
246 (command.code & 0x0006) != 0 && command.time > time) {
247 return command.time - time;
249 if (command.type == CommandType.GO_TO_START) {
254 if (repeat) foreach (LedCommandRX51 command in engine) {
255 if (command.type == CommandType.TRIGGER &&
256 (command.code & 0x0006) != 0 && (duration + command.time) > time) {
257 return duration + command.time - time;
264 class LedCommandRX51 : LedCommand {
265 internal const double CYCLE_TIME_MS = 1000.0 / 32768.0;
269 public LedCommandRX51 () {
272 public LedCommandRX51.with_code (uint16 _code) {
274 duration = 16 * CYCLE_TIME_MS;
275 if ((code & 0x8000) == 0) {
276 if (code == 0x0000) {
277 type = CommandType.GO_TO_START;
278 } else if ((code & 0x3e00) != 0) {
279 type = CommandType.RAMP_WAIT;
281 step_time = code >> 9;
282 if ((code & 0x4000) == 0)
283 step_time = (code >> 9) * 16 * CYCLE_TIME_MS;
285 step_time = ((code & 0x3e00) >> 9) * 512 * CYCLE_TIME_MS;
287 duration = step_time * (steps + 1);
288 if ((code & 0x100) != 0)
291 type = CommandType.SET_PWM;
295 if (code == 0x9d80) {
296 type = CommandType.RESET_MUX;
297 } else if ((code & ~0x1f8f) == 0xa000) {
298 type = CommandType.BRANCH;
299 // 0x1f80: (loop count - 1) << 7
300 // 0x000f: step number
301 } else if ((code & ~0x1800) == 0xc000) {
302 type = CommandType.END;
304 if ((code & 0x0800) != 0) // Reset
306 } else if ((code & ~ 0x13fe) == 0xe000) {
307 type = CommandType.TRIGGER;
309 // 0x0380: wait B G R
316 public override void set_pwm (int _level) {
317 code = 0x4000 | _level;
318 base.set_pwm (_level);
321 public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= (16 * CYCLE_TIME_MS)) {
323 if (_step_time < 32 * (16 * CYCLE_TIME_MS)) {
324 step_time = (int) ((_step_time + 0.001) / (16 * CYCLE_TIME_MS));
325 code = (uint16) step_time << 9;
326 _step_time = step_time * (16 * CYCLE_TIME_MS);
327 } else if (_step_time < 32*(512 * CYCLE_TIME_MS)) {
328 step_time = (int) ((_step_time + 0.001) / (512 * CYCLE_TIME_MS));
329 code = 0x4000 | (step_time << 9);
330 _step_time = step_time * (512 * CYCLE_TIME_MS);
335 code |= 0x100 | (-_steps);
339 base.ramp_wait (_step_time, _steps);
342 public override void go_to_start () {
347 public override void end (bool reset) {
354 public LedCommandRX51 copy () {
355 var command = new LedCommandRX51 ();
359 command.step_time = step_time;
360 command.duration = duration;
361 command.level = level;
362 command.steps = steps;