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 void 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");
62 private void parse_led_map (string led_map, out LedColor color1, out LedColor color2) {
63 color1 = LedColor.OFF;
64 color2 = LedColor.OFF;
79 private List<LedCommandRX51> parse_pattern (string pattern) {
80 var list = new List<LedCommandRX51> ();
81 var length = pattern.length;
86 char *p = ((char*) pattern) + length - 4;
87 while (p >= (char*) pattern) {
88 var command = new LedCommandRX51.with_code ((uint16) ((string) p).to_ulong (null, 16));
89 command.changed.connect (on_changed);
90 list.prepend (command);
98 public string dump () {
99 return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, dump_led_map (),
100 dump_pattern (engine1), dump_pattern (engine2));
103 private string dump_led_map () {
105 if (LedColor.R in color1)
107 if (LedColor.R in color2)
109 if (LedColor.G in color1)
111 if (LedColor.G in color2)
113 if (LedColor.B in color1)
115 if (LedColor.B in color2)
120 private string dump_pattern (List<LedCommandRX51> list) {
122 foreach (LedCommandRX51 command in list) {
123 result += "%04x".printf (command.code);
128 public LedPatternRX51 copy () {
129 var pattern = new LedPatternRX51 ();
131 pattern.name = name.dup ();
132 pattern.priority = priority;
133 pattern.screen_on = screen_on;
134 pattern.timeout = timeout;
136 pattern.duration = duration;
138 pattern.color1 = color1;
139 pattern.color2 = color2;
140 pattern.engine1 = deep_copy (pattern, engine1);
141 pattern.engine2 = deep_copy (pattern, engine2);
146 public List<LedCommandRX51> deep_copy (LedPatternRX51 pattern, List<LedCommandRX51> list) {
147 var list2 = new List<LedCommandRX51> ();
149 foreach (LedCommandRX51 command in list) {
150 var command2 = command.copy ();
151 command2.changed.connect (pattern.on_changed);
152 list2.append (command2);
158 public void replace_with (LedPatternRX51 pattern) {
160 priority = pattern.priority;
161 screen_on = pattern.screen_on;
162 timeout = pattern.timeout;
164 duration = pattern.duration;
166 color1 = pattern.color1;
167 color2 = pattern.color2;
168 engine1 = deep_copy (this, pattern.engine1);
169 engine2 = deep_copy (this, pattern.engine2);
174 public void on_changed () {
175 bool unresolved = calculate_timing ();
177 unresolved = calculate_timing ();
179 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;