Several updates - added support for second pattern engine and adding commands
[led-pattern-ed] / src / led-pattern-rx51.vala
index fe2dc79..72f3638 100644 (file)
@@ -17,7 +17,8 @@
  */
 
 class LedPatternRX51 : LedPattern {
-       public string led_map;
+       public LedColor color1;
+       public LedColor color2;
        public List<LedCommandRX51> engine1;
        public List<LedCommandRX51> engine2;
 
@@ -44,7 +45,7 @@ class LedPatternRX51 : LedPattern {
                priority = p[0].to_int ();
                screen_on = p[1].to_int ();
                timeout = p[2].to_int ();
-               led_map = p[3];
+               parse_led_map (p[3], out color1, out color2);
                engine1 = parse_pattern (p[4]);
                engine2 = parse_pattern (p[5]);
 
@@ -58,6 +59,23 @@ class LedPatternRX51 : LedPattern {
                on_changed ();
        }
 
+       private void parse_led_map (string led_map, out LedColor color1, out LedColor color2) {
+               color1 = LedColor.OFF;
+               color2 = LedColor.OFF;
+               if ("r" in led_map)
+                       color1 |= LedColor.R;
+               if ("g" in led_map)
+                       color1 |= LedColor.G;
+               if ("b" in led_map)
+                       color1 |= LedColor.B;
+               if ("R" in led_map)
+                       color2 |= LedColor.R;
+               if ("G" in led_map)
+                       color2 |= LedColor.G;
+               if ("B" in led_map)
+                       color2 |= LedColor.B;
+       }
+
        private List<LedCommandRX51> parse_pattern (string pattern) {
                var list = new List<LedCommandRX51> ();
                var length = pattern.length;
@@ -78,10 +96,27 @@ class LedPatternRX51 : LedPattern {
        }
 
        public string dump () {
-               return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, led_map,
+               return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, dump_led_map (),
                                                      dump_pattern (engine1), dump_pattern (engine2));
        }
 
+       private string dump_led_map () {
+               string led_map = "";
+               if (LedColor.R in color1)
+                       led_map += "r";
+               if (LedColor.R in color2)
+                       led_map += "R";
+               if (LedColor.G in color1)
+                       led_map += "g";
+               if (LedColor.G in color2)
+                       led_map += "G";
+               if (LedColor.B in color1)
+                       led_map += "b";
+               if (LedColor.B in color2)
+                       led_map += "B";
+               return led_map;
+       }
+
        private string dump_pattern (List<LedCommandRX51> list) {
                string result = "";
                foreach (LedCommandRX51 command in list) {
@@ -100,7 +135,8 @@ class LedPatternRX51 : LedPattern {
 
                pattern.duration = duration;
 
-               pattern.led_map = led_map;
+               pattern.color1 = color1;
+               pattern.color2 = color2;
                pattern.engine1 = deep_copy (pattern, engine1);
                pattern.engine2 = deep_copy (pattern, engine2);
 
@@ -127,38 +163,105 @@ class LedPatternRX51 : LedPattern {
 
                duration = pattern.duration;
 
-               led_map = pattern.led_map;
+               color1 = pattern.color1;
+               color2 = pattern.color2;
                engine1 = deep_copy (this, pattern.engine1);
                engine2 = deep_copy (this, pattern.engine2);
 
                changed ();
        }
 
-       void on_changed () {
-               // calculate timing and level info
+       public void on_changed () {
+               bool unresolved = calculate_timing ();
+               if (unresolved)
+                       unresolved = calculate_timing ();
+               if (unresolved)
+                       Hildon.Banner.show_information (null, null, "Timing unresolved");
+               changed ();
+       }
+
+       private bool calculate_timing () {
+               bool unresolved = false;
+               // Calculate timing and level info for engine 1
                double time = 0;
                int level = 0;
                foreach (LedCommandRX51 command in engine1) {
                        command.time = time;
-                       time += command.duration;
                        if (command.type == CommandType.SET_PWM) {
                                level = command.level;
                        } else {
                                command.level = level;
                                level += command.steps;
                        }
+                       if (command.type == CommandType.TRIGGER &&
+                           (command.code & 0x0180) != 0) {
+                               command.duration = wait_for_trigger (time, engine2);
+                               if (command.duration == 0)
+                                       unresolved = true;
+                               command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
+                       }
+                       time += command.duration;
                        if (level < 0)
                                level = 0;
                        if (level > 255)
                                level = 255;
                }
                duration = time;
-               changed ();
+               // Calculate timing and level info for engine 2
+               time = 0;
+               level = 0;
+               foreach (LedCommandRX51 command in engine2) {
+                       command.time = time;
+                       if (command.type == CommandType.SET_PWM) {
+                               level = command.level;
+                       } else {
+                               command.level = level;
+                               level += command.steps;
+                       }
+                       if (command.type == CommandType.TRIGGER &&
+                           (command.code & 0x0180) != 0) {
+                               command.duration = wait_for_trigger (time, engine1);
+                               if (command.duration == 0)
+                                       unresolved = true;
+                               command.duration += 16 * LedCommandRX51.CYCLE_TIME_MS;
+                       }
+                       time += command.duration;
+                       if (level < 0)
+                               level = 0;
+                       if (level > 255)
+                               level = 255;
+               }
+               if (time > duration)
+                       duration = time;
+               return unresolved;
+       }
+
+       double wait_for_trigger (double time, List<LedCommandRX51> engine) {
+               double duration = 0;
+               bool repeat = false;
+               foreach (LedCommandRX51 command in engine) {
+                       duration = command.time + command.duration;
+                       if (command.type == CommandType.TRIGGER &&
+                           (command.code & 0x0006) != 0 && command.time > time) {
+                               return command.time - time;
+                       }
+                       if (command.type == CommandType.GO_TO_START) {
+                               repeat = true;
+                               break;
+                       }
+               }
+               if (repeat) foreach (LedCommandRX51 command in engine) {
+                       if (command.type == CommandType.TRIGGER &&
+                           (command.code & 0x0006) != 0 && (duration + command.time) > time) {
+                               return duration + command.time - time;
+                       }
+               }
+               return 0;
        }
 }
 
 class LedCommandRX51 : LedCommand {
-       private const double CYCLE_TIME_MS = 1000.0 / 32768.0;
+       internal const double CYCLE_TIME_MS = 1000.0 / 32768.0;
 
        public uint16 code;
 
@@ -199,12 +302,12 @@ class LedCommandRX51 : LedCommand {
                                // 0x1000: interrupt
                                if ((code & 0x0800) != 0) // Reset
                                        steps = -255;
-                       } else if ((code & ~ 0x13f0) == 0xe000) {
+                       } else if ((code & ~ 0x13fe) == 0xe000) {
                                type = CommandType.TRIGGER;
                                // 0x1000: wait ext
                                // 0x0380: wait B G R
                                // 0x0040: set ext
-                               // ??: set B G R
+                               // 0x000e: set B G R
                        }
                }
        }
@@ -216,12 +319,12 @@ class LedCommandRX51 : LedCommand {
 
        public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= (16 * CYCLE_TIME_MS)) {
                int step_time;
-               if (_step_time <= 31 * (16 * CYCLE_TIME_MS)) {
+               if (_step_time < 32 * (16 * CYCLE_TIME_MS)) {
                        step_time = (int) ((_step_time + 0.001) / (16 * CYCLE_TIME_MS));
                        code = (uint16) step_time << 9;
                        _step_time = step_time * (16 * CYCLE_TIME_MS);
-               } else if (_step_time <= 31*(512 * CYCLE_TIME_MS)) {
-                       step_time = (int) ((_step_time + 0.01) / (512 * CYCLE_TIME_MS));
+               } else if (_step_time < 32*(512 * CYCLE_TIME_MS)) {
+                       step_time = (int) ((_step_time + 0.001) / (512 * CYCLE_TIME_MS));
                        code = 0x4000 | (step_time << 9);
                        _step_time = step_time * (512 * CYCLE_TIME_MS);
                } else {
@@ -235,6 +338,18 @@ class LedCommandRX51 : LedCommand {
                base.ramp_wait (_step_time, _steps);
        }
 
+       public override void go_to_start () {
+               code = 0x0000;
+               base.go_to_start ();
+       }
+
+       public override void end (bool reset) {
+               code = 0xc000;
+               if (reset)
+                       code |= 0x0800;
+               base.end (reset);
+       }
+
        public LedCommandRX51 copy () {
                var command = new LedCommandRX51 ();