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 override void parse (string line) throws LedPatternError {
26 string[] key_value = line.split ("=");
28 if (key_value.length != 2)
29 throw new LedPatternError.INVALID_PATTERN ("pattern line does not contain '=': " + line);
33 string[] p = key_value[1].split (";");
35 throw new LedPatternError.INVALID_PATTERN ("%s does not contain 6 components: %d".printf (name, p.length));
37 if (p[4].length > 16*4 || p[5].length > 16*4)
38 throw new LedPatternError.INVALID_PATTERN ("%s engine pattern too long!".printf (name));
40 if (p[4].length % 4 != 0 || p[5].length % 4 != 0)
41 throw new LedPatternError.INVALID_PATTERN ("%s engine pattern not an even number of bytes!".printf (name));
43 priority = p[0].to_int ();
44 screen_on = p[1].to_int ();
45 timeout = p[2].to_int ();
46 parse_led_map (p[3], out color1, out color2);
47 engine1 = parse_pattern (p[4]);
48 engine2 = parse_pattern (p[5]);
50 if (engine1.first ().data.code != 0x9d80) {
51 print ("engine1 pattern doesn't start with refresh mux command\n");
53 if (engine2.first ().data.code != 0x9d80) {
54 print ("engine2 pattern doesn't start with refresh mux command\n");
60 private void parse_led_map (string led_map, out LedColor color1, out LedColor color2) {
61 color1 = LedColor.OFF;
62 color2 = LedColor.OFF;
77 private List<LedCommandRX51> parse_pattern (string pattern) {
78 var list = new List<LedCommandRX51> ();
79 var length = pattern.length;
84 char *p = ((char*) pattern) + length - 4;
85 while (p >= (char*) pattern) {
86 var command = new LedCommandRX51.with_code ((uint16) ((string) p).to_ulong (null, 16));
87 command.changed.connect (on_changed);
88 list.prepend (command);
96 public override string dump () {
97 return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, dump_led_map (),
98 dump_pattern (engine1), dump_pattern (engine2));
101 private string dump_led_map () {
103 if (LedColor.R in color1)
105 if (LedColor.R in color2)
107 if (LedColor.G in color1)
109 if (LedColor.G in color2)
111 if (LedColor.B in color1)
113 if (LedColor.B in color2)
118 private string dump_pattern (List<LedCommandRX51> list) {
120 foreach (LedCommandRX51 command in list) {
121 result += "%04x".printf (command.code);
126 public LedPatternRX51 copy () {
127 var pattern = new LedPatternRX51 ();
129 pattern.name = name.dup ();
130 pattern.priority = priority;
131 pattern.screen_on = screen_on;
132 pattern.timeout = timeout;
134 pattern.duration = duration;
136 pattern.color1 = color1;
137 pattern.color2 = color2;
138 pattern.engine1 = deep_copy (pattern, engine1);
139 pattern.engine2 = deep_copy (pattern, engine2);
144 public List<LedCommandRX51> deep_copy (LedPatternRX51 pattern, List<LedCommandRX51> list) {
145 var list2 = new List<LedCommandRX51> ();
147 foreach (LedCommandRX51 command in list) {
148 var command2 = command.copy ();
149 command2.changed.connect (pattern.on_changed);
150 list2.append (command2);
156 public void replace_with (LedPatternRX51 pattern) {
158 priority = pattern.priority;
159 screen_on = pattern.screen_on;
160 timeout = pattern.timeout;
162 duration = pattern.duration;
164 color1 = pattern.color1;
165 color2 = pattern.color2;
166 engine1 = deep_copy (this, pattern.engine1);
167 engine2 = deep_copy (this, pattern.engine2);
172 public void on_changed () {
173 bool unresolved = calculate_timing ();
175 unresolved = calculate_timing ();
178 Hildon.Banner.show_information (null, null, "Timing unresolved");
183 private bool calculate_timing () {
184 bool unresolved = false;
185 // Calculate timing and level info for engine 1
188 foreach (LedCommandRX51 command in engine1) {
190 if (command.type == CommandType.SET_PWM) {
191 level = command.level;
193 command.level = level;
194 level += command.steps;
196 if (command.type == CommandType.TRIGGER &&
197 (command.code & 0x0180) != 0) {
198 command.duration = wait_for_trigger (time, engine2);
199 if (command.duration == 0)
201 command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
203 time += command.duration;
210 // Calculate timing and level info for engine 2
213 foreach (LedCommandRX51 command in engine2) {
215 if (command.type == CommandType.SET_PWM) {
216 level = command.level;
218 command.level = level;
219 level += command.steps;
221 if (command.type == CommandType.TRIGGER &&
222 (command.code & 0x0180) != 0) {
223 command.duration = wait_for_trigger (time, engine1);
224 if (command.duration == 0)
226 command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
228 time += command.duration;
239 double wait_for_trigger (double time, List<LedCommandRX51> engine) {
242 foreach (LedCommandRX51 command in engine) {
243 duration = command.time + command.duration;
244 if (command.type == CommandType.TRIGGER &&
245 (command.code & 0x0006) != 0 && command.time > time) {
246 return command.time - time;
248 if (command.type == CommandType.GO_TO_START) {
253 if (repeat) foreach (LedCommandRX51 command in engine) {
254 if (command.type == CommandType.TRIGGER &&
255 (command.code & 0x0006) != 0 && (duration + command.time) > time) {
256 return duration + command.time - time;
263 class LedCommandRX51 : LedCommand {
264 internal const double CYCLE_TIME_MS = 1000.0 / 32768.0;
268 public LedCommandRX51 () {
271 public LedCommandRX51.with_code (uint16 _code) {
273 duration = 16 * CYCLE_TIME_MS;
274 if ((code & 0x8000) == 0) {
275 if (code == 0x0000) {
276 type = CommandType.GO_TO_START;
277 } else if ((code & 0x3e00) != 0) {
278 type = CommandType.RAMP_WAIT;
280 step_time = code >> 9;
281 if ((code & 0x4000) == 0)
282 step_time = (code >> 9) * 16 * CYCLE_TIME_MS;
284 step_time = ((code & 0x3e00) >> 9) * 512 * CYCLE_TIME_MS;
286 duration = step_time * (steps + 1);
287 if ((code & 0x100) != 0)
290 type = CommandType.SET_PWM;
294 if (code == 0x9d80) {
295 type = CommandType.RESET_MUX;
296 } else if ((code & ~0x1f8f) == 0xa000) {
297 type = CommandType.BRANCH;
298 // 0x1f80: (loop count - 1) << 7
299 // 0x000f: step number
300 } else if ((code & ~0x1800) == 0xc000) {
301 type = CommandType.END;
303 if ((code & 0x0800) != 0) // Reset
305 } else if ((code & ~ 0x13fe) == 0xe000) {
306 type = CommandType.TRIGGER;
308 // 0x0380: wait B G R
315 public override void set_pwm (int _level) {
316 code = 0x4000 | _level;
317 base.set_pwm (_level);
320 public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= (16 * CYCLE_TIME_MS)) {
322 if (_step_time < 32 * (16 * CYCLE_TIME_MS)) {
323 step_time = (int) ((_step_time + 0.001) / (16 * CYCLE_TIME_MS));
324 code = (uint16) step_time << 9;
325 _step_time = step_time * (16 * CYCLE_TIME_MS);
326 } else if (_step_time < 32*(512 * CYCLE_TIME_MS)) {
327 step_time = (int) ((_step_time + 0.001) / (512 * CYCLE_TIME_MS));
328 code = 0x4000 | (step_time << 9);
329 _step_time = step_time * (512 * CYCLE_TIME_MS);
334 code |= 0x100 | (-_steps);
338 base.ramp_wait (_step_time, _steps);
341 public override void go_to_start () {
346 public override void end (bool reset) {
353 public LedCommandRX51 copy () {
354 var command = new LedCommandRX51 ();
358 command.step_time = step_time;
359 command.duration = duration;
360 command.level = level;
361 command.steps = steps;