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 LedPatternRX44 : LedPattern {
20 public List<LedCommandRX44> engine_r;
21 public List<LedCommandRX44> engine_g;
22 public List<LedCommandRX44> engine_b;
24 public override void parse (string line) throws LedPatternError {
25 string[] key_value = line.split ("=");
27 if (key_value.length != 2)
28 throw new LedPatternError.INVALID_PATTERN ("pattern line does not contain '=': " + line);
32 string[] p = key_value[1].split (";");
34 throw new LedPatternError.INVALID_PATTERN ("%s does not contain 6 components: %d".printf (name, p.length));
36 if (p[3].length > 16*4 || p[4].length > 16*4 || p[5].length > 16*4)
37 throw new LedPatternError.INVALID_PATTERN ("%s engine pattern too long!".printf (name));
39 if (p[3].length % 4 != 0 || p[4].length % 4 != 0 || p[5].length % 4 != 0)
40 throw new LedPatternError.INVALID_PATTERN ("%s engine pattern not an even number of bytes!".printf (name));
42 priority = p[0].to_int ();
43 screen_on = p[1].to_int ();
44 timeout = p[2].to_int ();
45 engine_r = parse_pattern (p[3]);
46 engine_g = parse_pattern (p[4]);
47 engine_b = parse_pattern (p[5]);
52 private List<LedCommandRX44> parse_pattern (string pattern) {
53 var list = new List<LedCommandRX44> ();
54 var length = pattern.length;
59 char *p = ((char*) pattern) + length - 4;
60 while (p >= (char*) pattern) {
61 var command = new LedCommandRX44.with_code ((uint16) ((string) p).to_ulong (null, 16));
62 command.changed.connect (on_changed);
63 list.prepend (command);
71 public override string dump () {
72 return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout,
73 dump_pattern (engine_r), dump_pattern (engine_g), dump_pattern (engine_b));
76 private string dump_pattern (List<LedCommandRX44> list) {
78 foreach (LedCommandRX44 command in list) {
79 result += "%04x".printf (command.code);
84 public LedPatternRX44 copy () {
85 var pattern = new LedPatternRX44 ();
87 pattern.name = name.dup ();
88 pattern.priority = priority;
89 pattern.screen_on = screen_on;
90 pattern.timeout = timeout;
92 pattern.duration = duration;
94 pattern.engine_r = deep_copy (pattern, engine_r);
95 pattern.engine_g = deep_copy (pattern, engine_g);
96 pattern.engine_b = deep_copy (pattern, engine_b);
101 public List<LedCommandRX44> deep_copy (LedPatternRX44 pattern, List<LedCommandRX44> list) {
102 var list2 = new List<LedCommandRX44> ();
104 foreach (LedCommandRX44 command in list) {
105 var command2 = command.copy ();
106 command2.changed.connect (pattern.on_changed);
107 list2.append (command2);
113 public void replace_with (LedPatternRX44 pattern) {
115 priority = pattern.priority;
116 screen_on = pattern.screen_on;
117 timeout = pattern.timeout;
119 duration = pattern.duration;
121 engine_r = deep_copy (this, pattern.engine_r);
122 engine_g = deep_copy (this, pattern.engine_g);
123 engine_b = deep_copy (this, pattern.engine_b);
128 public void on_changed () {
129 bool unresolved = calculate_timing ();
131 unresolved = calculate_timing ();
133 Hildon.Banner.show_information (null, null, "Timing unresolved");
137 private bool calculate_timing () {
138 bool unresolved = false;
139 // Calculate timing and level info for red engine
142 foreach (LedCommandRX44 command in engine_r) {
144 if (command.type == CommandType.SET_PWM) {
145 level = command.level;
147 command.level = level;
148 level += command.steps;
150 if (command.type == CommandType.TRIGGER &&
151 (command.code & 0x0180) != 0) {
152 command.duration = wait_for_trigger (time, engine_g);
153 if (command.duration == 0)
155 command.duration += 16 * LedCommandRX44.CYCLE_TIME_MS;
157 time += command.duration;
164 // Calculate timing and level info for green engine
167 foreach (LedCommandRX44 command in engine_g) {
169 if (command.type == CommandType.SET_PWM) {
170 level = command.level;
172 command.level = level;
173 level += command.steps;
175 if (command.type == CommandType.TRIGGER &&
176 (command.code & 0x0180) != 0) {
177 command.duration = wait_for_trigger (time, engine_r);
178 if (command.duration == 0)
180 command.duration += 16 * LedCommandRX44.CYCLE_TIME_MS;
182 time += command.duration;
193 double wait_for_trigger (double time, List<LedCommandRX44> engine) {
196 foreach (LedCommandRX44 command in engine) {
197 duration = command.time + command.duration;
198 if (command.type == CommandType.TRIGGER &&
199 (command.code & 0x0006) != 0 && command.time > time) {
200 return command.time - time;
202 if (command.type == CommandType.GO_TO_START) {
207 if (repeat) foreach (LedCommandRX44 command in engine) {
208 if (command.type == CommandType.TRIGGER &&
209 (command.code & 0x0006) != 0 && (duration + command.time) > time) {
210 return duration + command.time - time;
217 class LedCommandRX44 : LedCommand {
218 internal const double CYCLE_TIME_MS = 1000.0 / 32768.0;
222 public LedCommandRX44 () {
225 public LedCommandRX44.with_code (uint16 _code) {
227 duration = 16 * CYCLE_TIME_MS;
228 if ((code & 0x8000) == 0) {
229 if (code == 0x0000) {
230 type = CommandType.GO_TO_START;
231 } else if ((code & 0x3e00) != 0) {
232 type = CommandType.RAMP_WAIT;
234 step_time = code >> 8;
235 if ((code & 0x4000) == 0)
236 step_time = (code >> 9) * 16 * CYCLE_TIME_MS;
238 step_time = ((code & 0x3e00) >> 9) * 512 * CYCLE_TIME_MS;
240 duration = step_time * (steps + 1);
241 if ((code & 0x80) != 0)
244 type = CommandType.SET_PWM;
248 if ((code & ~0x1f8f) == 0xa000) {
249 type = CommandType.BRANCH;
250 // 0x1f80: (loop count - 1) << 7
251 // 0x000f: step number
252 } else if ((code & ~0x1800) == 0xc000) {
253 type = CommandType.END;
255 if ((code & 0x0800) != 0) // Reset
257 } else if ((code & ~ 0x13fe) == 0xe000) {
258 type = CommandType.TRIGGER;
260 // 0x0380: wait B G R
267 public override void set_pwm (int _level) {
268 code = 0x4000 | _level;
269 base.set_pwm (_level);
272 public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= (16 * CYCLE_TIME_MS)) {
274 if (_step_time < 32 * (16 * CYCLE_TIME_MS)) {
275 step_time = (int) ((_step_time + 0.001) / (16 * CYCLE_TIME_MS));
276 code = (uint16) step_time << 8;
277 _step_time = step_time * (16 * CYCLE_TIME_MS);
278 } else if (_step_time < 32*(512 * CYCLE_TIME_MS)) {
279 step_time = (int) ((_step_time + 0.001) / (512 * CYCLE_TIME_MS));
280 code = 0x4000 | (step_time << 8);
281 _step_time = step_time * (512 * CYCLE_TIME_MS);
286 code |= 0x80 | (-_steps);
290 base.ramp_wait (_step_time, _steps);
293 public override void go_to_start () {
298 public override void end (bool reset) {
305 public LedCommandRX44 copy () {
306 var command = new LedCommandRX44 ();
310 command.step_time = step_time;
311 command.duration = duration;
312 command.level = level;
313 command.steps = steps;