84c7ca8b594a3becec055adfaa5c4ae8cbccba50
[led-pattern-ed] / src / led-pattern-rx51.vala
1 /* This file is part of LED Pattern Editor.
2  *
3  * Copyright (C) 2010 Philipp Zabel
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 class LedPatternRX51 : LedPattern {
20         public string led_map;
21         public List<LedCommandRX51> engine1;
22         public List<LedCommandRX51> engine2;
23
24         public void parse (string line) {
25                 string[] key_value = line.split ("=");
26
27                 if (key_value.length != 2) {
28                         print ("pattern line does not contain '=': %s\n", line);
29                         return;
30                 }
31
32                 string[] p = key_value[1].split (";");
33                 if (p.length != 6) {
34                         print ("pattern does not contain 6 components: %d\n", p.length);
35                         return;
36                 }
37
38                 if (p[4].length > 16*4 || p[5].length > 16*4) {
39                         print ("pattern too long!\n");
40                         return;
41                 }
42
43                 name = key_value[0];
44                 priority = p[0].to_int ();
45                 screen_on = p[1].to_int ();
46                 timeout = p[2].to_int ();
47                 led_map = p[3];
48                 engine1 = parse_pattern (p[4]);
49                 engine2 = parse_pattern (p[5]);
50
51                 if (engine1.first ().data.code != 0x9d80) {
52                         print ("engine1 pattern doesn't start with refresh mux command\n");
53                 }
54                 if (engine2.first ().data.code != 0x9d80) {
55                         print ("engine2 pattern doesn't start with refresh mux command\n");
56                 }
57
58                 on_changed ();
59         }
60
61         private List<LedCommandRX51> parse_pattern (string pattern) {
62                 var list = new List<LedCommandRX51> ();
63                 var length = pattern.length;
64
65                 if (length % 4 != 0)
66                         return list;
67
68                 char *p = ((char*) pattern) + length - 4;
69                 while (p >= (char*) pattern) {
70                         var command = new LedCommandRX51.with_code ((uint16) ((string) p).to_ulong (null, 16));
71                         command.changed.connect (on_changed);
72                         list.prepend (command);
73                         p[0] = '\0';
74                         p -= 4;
75                 }
76
77                 return list;
78         }
79
80         public string dump () {
81                 return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, led_map,
82                                                       dump_pattern (engine1), dump_pattern (engine2));
83         }
84
85         private string dump_pattern (List<LedCommandRX51> list) {
86                 string result = "";
87                 foreach (LedCommandRX51 command in list) {
88                         result += "%04x".printf (command.code);
89                 }
90                 return result;
91         }
92
93         public LedPatternRX51 copy () {
94                 var pattern = new LedPatternRX51 ();
95
96                 pattern.name = name.dup ();
97                 pattern.priority = priority;
98                 pattern.screen_on = screen_on;
99                 pattern.timeout = timeout;
100
101                 pattern.duration = duration;
102
103                 pattern.led_map = led_map;
104                 pattern.engine1 = deep_copy (pattern, engine1);
105                 pattern.engine2 = deep_copy (pattern, engine2);
106
107                 return pattern;
108         }
109
110         public List<LedCommandRX51> deep_copy (LedPatternRX51 pattern, List<LedCommandRX51> list) {
111                 var list2 = new List<LedCommandRX51> ();
112
113                 foreach (LedCommandRX51 command in list) {
114                         var command2 = command.copy ();
115                         command2.changed.connect (pattern.on_changed);
116                         list2.append (command2);
117                 }
118
119                 return list2;
120         }
121
122         public void replace_with (LedPatternRX51 pattern) {
123                 name = pattern.name;
124                 priority = pattern.priority;
125                 screen_on = pattern.screen_on;
126                 timeout = pattern.timeout;
127
128                 duration = pattern.duration;
129
130                 led_map = pattern.led_map;
131                 engine1 = deep_copy (this, pattern.engine1);
132                 engine2 = deep_copy (this, pattern.engine2);
133
134                 changed ();
135         }
136
137         void on_changed () {
138                 // calculate timing and level info
139                 double time = 0;
140                 int level = 0;
141                 foreach (LedCommandRX51 command in engine1) {
142                         command.time = time;
143                         time += command.duration;
144                         if (command.type == CommandType.SET_PWM) {
145                                 level = command.level;
146                         } else {
147                                 command.level = level;
148                                 level += command.steps;
149                         }
150                         if (level < 0)
151                                 level = 0;
152                         if (level > 255)
153                                 level = 255;
154                 }
155                 duration = time;
156                 changed ();
157         }
158 }
159
160 class LedCommandRX51 : LedCommand {
161         public uint16 code;
162
163         public LedCommandRX51 () {
164         }
165
166         public LedCommandRX51.with_code (uint16 _code) {
167                 code = _code;
168                 if ((code & 0x8000) == 0) {
169                         if (code == 0x0000) {
170                                 type = CommandType.REPEAT;
171                         } else if ((code & 0x3e00) != 0) {
172                                 type = CommandType.RAMP_WAIT;
173                                 steps = code & 0xff;
174                                 step_time = code >> 9;
175                                 if ((code & 0x4000) == 0)
176                                         step_time = (code >> 9) * 0.49;
177                                 else {
178                                         step_time = ((code & 0x3e00) >> 9) * 15.6;
179                                 }
180                                 duration = step_time * (steps + 1);
181                                 if ((code & 0x100) != 0)
182                                         steps = -steps;
183                         } else {
184                                 type = CommandType.SET_PWM;
185                                 level = code & 0xff;
186                         }
187                 } else {
188                         if (code == 0x9d80)
189                                 type = CommandType.RESET_MUX;
190                         if (code == 0xc000)
191                                 type = CommandType.STOP;
192                         //if (code == 0xe0??)
193                         //      type = CommandType.TRIGGER_WAIT;
194                 }
195         }
196
197         public override void set_pwm (int _level) {
198                 code = 0x4000 | _level;
199                 base.set_pwm (_level);
200         }
201
202         public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= 0.49) {
203                 int step_time;
204                 if (_step_time <= 31*0.49) {
205                         step_time = (int) ((_step_time + 0.001) / 0.49);
206                         code = (uint16) step_time << 9;
207                         _step_time = step_time * 0.49;
208                 } else if (_step_time <= 31*15.6) {
209                         step_time = (int) ((_step_time + 0.01) / 15.6);
210                         code = 0x4000 | (step_time << 9);
211                         _step_time = step_time * 15.6;
212                 } else {
213                         return;
214                 }
215                 if (_steps < 0) {
216                         code |= 0x100 | (-_steps);
217                 } else {
218                         code |= _steps;
219                 }
220                 base.ramp_wait (_step_time, _steps);
221         }
222
223         public LedCommandRX51 copy () {
224                 var command = new LedCommandRX51 ();
225
226                 command.type = type;
227                 command.time = time;
228                 command.step_time = step_time;
229                 command.duration = duration;
230                 command.level = level;
231                 command.steps = steps;
232
233                 command.code = code;
234
235                 return command;
236         }
237 }