Add LED pattern helper
authorPhilipp Zabel <philipp.zabel@gmail.com>
Wed, 24 Feb 2010 17:15:01 +0000 (18:15 +0100)
committerPhilipp Zabel <philipp.zabel@gmail.com>
Wed, 24 Feb 2010 18:10:22 +0000 (19:10 +0100)
Makefile
src/led-pattern-helper.vala [new file with mode: 0644]

index 9bc5d32..96cdc74 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,16 @@
 .PHONY: all clean install
 
+bindir=/usr/bin
 pluginlibdir=`pkg-config hildon-control-panel --variable pluginlibdir`
 plugindesktopentrydir=`pkg-config hildon-control-panel --variable plugindesktopentrydir`
 
 HILDON_CFLAGS = `pkg-config --cflags hildon-1`
 OSSO_CFLAGS = `pkg-config --cflags libosso`
+GLIB_CFLAGS = `pkg-config --cflags glib-2.0 gobject-2.0`
 
 HILDON_LIBS = `pkg-config --libs hildon-1`
 OSSO_LIBS = `pkg-config --libs libosso`
+GLIB_LIBS = `pkg-config --libs glib-2.0 gobject-2.0`
 
 pluginlib_LTLIBRARY = \
        libled-pattern-editor.so
@@ -15,7 +18,10 @@ pluginlib_LTLIBRARY = \
 plugindesktopentry_DATA = \
        data/led-pattern-editor.desktop
 
-all: ${pluginlib_LTLIBRARY}
+bin_PROGRAM = \
+       led-pattern-helper
+
+all: ${pluginlib_LTLIBRARY} ${bin_PROGRAM}
 
 led_pattern_editor_SOURCES = $(patsubst %.vala,%.c,${led_pattern_editor_VALASOURCES})
 
@@ -36,12 +42,26 @@ ${pluginlib_LTLIBRARY}: ${led_pattern_editor_SOURCES}
 src/led-pattern-editor.c: ${led_pattern_editor_VALASOURCES}
        valac -C ${led_pattern_editor_VALAFLAGS} -o $@ $^
 
+led_pattern_helper_SOURCES = \
+       src/led-pattern-helper.c
+
+led_pattern_helper_VALASOURCES = \
+       src/led-pattern-helper.vala
+
+${bin_PROGRAM}: ${led_pattern_helper_SOURCES}
+       gcc ${GLIB_CFLAGS} -o $@ $^ ${GLIB_LIBS}
+
+src/led-pattern-helper.c: ${led_pattern_helper_VALASOURCES}
+       valac -C -o $@ $^
+
 clean:
-       rm ${pluginlib_LTLIBRARY} src/*.c
+       rm ${pluginlib_LTLIBRARY} ${bin_PROGRAM} src/*.c
 
 install:
        install -d ${DESTDIR}${pluginlibdir}
        install libled-pattern-editor.so ${DESTDIR}${pluginlibdir}/libled-pattern-editor.so
        install -d ${DESTDIR}${plugindesktopentrydir}
        install ${plugindesktopentry_DATA} ${DESTDIR}${plugindesktopentrydir}/`basename ${plugindesktopentry_DATA}`
+       install -d ${DESTDIR}${bindir}
+       install led-pattern-helper ${DESTDIR}${bindir}/led-pattern-helper
 
diff --git a/src/led-pattern-helper.vala b/src/led-pattern-helper.vala
new file mode 100644 (file)
index 0000000..cda11da
--- /dev/null
@@ -0,0 +1,295 @@
+/* This file is part of LED Pattern Editor.
+ *
+ * Copyright (C) 2010 Philipp Zabel
+ *
+ * LED Pattern Editor is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LED Pattern Editor is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LED Pattern Editor. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+public bool test_pattern (string pattern, bool apply) {
+       string[] key_value = pattern.split ("=");
+
+       if (key_value.length != 2) {
+               stderr.printf ("pattern does not contain '=': %s\n", pattern);
+               return false;
+       }
+
+       string[] p = key_value[1].split (";");
+       if (p.length != 6) {
+               stderr.printf ("pattern does not contain 6 components: %d\n", p.length);
+               return false;
+       }
+
+       if (p[0].has_prefix ("Pattern")) {
+               stderr.printf ("pattern name doesn't start with 'Pattern': '%s'\n", p[0]);
+               return false;
+       }
+
+       // priority = p[0].to_int ();
+       // screen_on = p[1].to_int ();
+       // timeout = p[2].to_int ();
+
+       int[] led_currents = { 2, 2, 2 };
+       string led_map1 = "000";
+       switch (p[3]) {
+       case "r":
+               led_map1 = "001";
+               led_currents = { 8, 0, 2 };
+               break;
+       case "g":
+               led_map1 = "010";
+               led_currents = { 2, 2, 2 };
+               break;
+       case "b":
+               led_map1 = "100";
+               led_currents = { 2, 2, 2 };
+               break;
+       case "rg":
+               led_map1 = "011";
+               led_currents = { 20, 2, 0 };
+               break;
+       case "rb":
+               led_map1 = "101";
+               // TODO: led_currents?
+               break;
+       case "gb":
+               led_map1 = "110";
+               // TODO: led_currents?
+               break;
+       case "rgb":
+               led_map1 = "111";
+               led_currents = { 8, 2, 2 };
+               break;
+       default:
+               stderr.printf ("only single-engine patterns supported for now\n");
+               return false;
+       }
+
+       if (p[4].length > 16*4 || p[5].length > 16*4) {
+               stderr.printf ("pattern too long!\n");
+               return false;
+       }
+
+       if (!(p[4].has_prefix ("9d80"))) {
+               stderr.printf ("engine1 pattern doesn't start with reset mux command\n");
+               return false;
+       }
+
+       if (!(p[4].has_suffix ("0000")) && !(p[4].has_suffix ("c000"))) {
+               stderr.printf ("engine1 pattern doesn't end with repeat or stop command\n");
+               return false;
+       }
+
+       if (p[5] != "9d800000") {
+               // FIXME
+               stderr.printf ("only single-engine patterns supported for now\n");
+               return false;
+       }
+
+       if (apply == false)
+               return true;
+
+       string i2c_dev = "/sys/bus/i2c/devices/2-0032";
+
+       var f = FileStream.open ("/sys/class/leds/lp5523:r/led_current", "w");
+       if (f == null) {
+               stderr.printf ("failed to set red led current\n");
+               return false;
+       }
+       f.printf ("%d\n", led_currents[0]);
+
+       f = FileStream.open ("/sys/class/leds/lp5523:g/led_current", "w");
+       if (f == null) {
+               stderr.printf ("failed to set green led current\n");
+               return false;
+       }
+       f.printf ("%d\n", led_currents[1]);
+
+       f = FileStream.open ("/sys/class/leds/lp5523:b/led_current", "w");
+       if (f == null) {
+               stderr.printf ("failed to set blue led current\n");
+               return false;
+       }
+       f.printf ("%d\n", led_currents[2]);
+
+       f = FileStream.open (Path.build_filename (i2c_dev, "engine1_mode"), "w");
+       if (f == null) {
+               stderr.printf ("failed to set engine1 to load mode\n");
+               return false;
+       }
+       f.printf ("load\n");
+
+       int retries = 100;
+       for (int i = 0; i < retries; i++) {
+               f = FileStream.open (Path.build_filename (i2c_dev, "engine1_leds"), "w");
+               if (f != null)
+                       break;
+       }
+       if (f == null) {
+               stderr.printf ("failed to set engine1 mux\n");
+               return false;
+       }
+       f.printf ("0000%s00\n", led_map1);
+
+       f = FileStream.open (Path.build_filename (i2c_dev, "engine1_load"), "w");
+       if (f == null) {
+               stderr.printf ("failed to load engine1 pattern\n");
+               return false;
+       }
+       f.printf ("%s\n", p[4]);
+
+       f = FileStream.open (Path.build_filename (i2c_dev, "engine1_mode"), "w");
+       if (f == null) {
+               stderr.printf ("failed to set engine1 to run mode\n");
+               return false;
+       }
+       f.printf ("run\n");
+
+       return true;
+}
+
+bool mce_ini_check (string new_mce_ini) {
+       var f = FileStream.open ("/etc/mce/mce.ini", "r");
+       var g = FileStream.open (new_mce_ini, "r");
+
+       if (f == null || g == null) {
+               stderr.printf ("failed to open /etc/mce/mce.ini and %s\n", new_mce_ini);
+               return false;
+       }
+
+       var line1 = f.read_line ();
+       var line2 = g.read_line ();
+       while (line1 != null && line2 != null) {
+               if (line1 == line2) {
+                       line1 = f.read_line ();
+                       line2 = g.read_line ();
+                       continue;
+               }
+
+               string[] key_value1 = line1.split ("=");
+               string[] key_value2 = line2.split ("=");
+
+               if (key_value1.length != 2 || key_value2.length != 2 || !line1.has_prefix ("Pattern")) {
+                       stderr.printf ("not allowed to change anything but led patterns:\n-%s\n+%s\n",
+                                      line1, line2);
+                       return false;
+               }
+
+               if (key_value1[0] != key_value2[0]) {
+                       stderr.printf ("not allowed to change pattern names\n-%s\n+%s\n",
+                                      line1, line2);
+                       return false;
+               }
+
+               if (!test_pattern (line2, false))
+                       return false;
+
+               line1 = f.read_line ();
+               line2 = g.read_line ();
+       }
+
+       if (line1 != line2) {
+               stderr.printf ("different number of lines\n");
+               return false;
+       }
+
+       return true;
+}
+
+int mce_copy (string source, string destination) {
+       var f = FileStream.open (source, "r");
+       var g = FileStream.open (destination, "w");
+
+       if (f == null || g == null) {
+               return 1;
+       }
+
+       var line = f.read_line ();
+       while (line != null) {
+               g.printf ("%s\n", line);
+               line = f.read_line ();
+       }
+
+       return 0;
+}
+
+public static int main (string[] args) {
+       string usage = "usage: led-pattern-helper test <Pattern>\n";
+
+       if (args.length != 3) {
+               stderr.printf (usage);
+               return -1;
+       }
+
+       if (args[1] == "test") {
+               if (!test_pattern (args[2], true))
+                       return -1;
+
+               return 0;
+       }
+
+       if (args[1] == "save") {
+               if (!FileUtils.test (args[2], FileTest.IS_REGULAR)) {
+                       stderr.printf ("not a regular file: %s\n", args[2]);
+                       return -1;
+               }
+
+               if (!mce_ini_check (args[2]))
+                       return -1;
+
+               // Ok, we're good to go
+               int result = mce_copy ("/etc/mce/mce.ini", "/etc/mce/mce.ini.led-pattern-old");
+               if (result != 0) {
+                       stderr.printf ("failed to copy old mce.ini to mce.ini.led-pattern-old\n");
+                       return -1;
+               }
+               result = mce_copy (args[2], "/etc/mce/mce.ini.led-pattern-new");
+               if (result != 0) {
+                       stderr.printf ("failed to copy new mce.ini to mce.ini.led-pattern-new\n");
+                       return -1;
+               }
+               result = FileUtils.rename ("/etc/mce/mce.ini.led-pattern-new", "/etc/mce/mce.ini");
+               if (result != 0) {
+                       stderr.printf ("failed to replace MCE configuration: %d\n", result);
+                       return -1;
+               }
+
+               // Moment of truth, restart MCE
+               try {
+                       int exit_status;
+                       string error;
+                       var command = "initctl stop mce";
+                       Process.spawn_command_line_sync (command, null, out error, out exit_status);
+                       if (exit_status != 0) {
+                               stderr.printf ("stopping mce failed: %d\n%s", exit_status, error);
+                               return -1;
+                       }
+                       command = "sleep 1";
+                       Process.spawn_command_line_sync (command, null, out error, out exit_status);
+                       command = "initctl start mce";
+                       Process.spawn_command_line_sync (command, null, out error, out exit_status);
+                       if (exit_status != 0) {
+                               stderr.printf ("starting mce failed: %d\n%s", exit_status, error);
+                               return -1;
+                       }
+               } catch (SpawnError e) {
+                       stderr.printf ("restarting mce failed: %s", e.message);
+                       return -1;
+               }
+
+               return 0;
+       }
+
+       stderr.printf (usage);
+       return -1;
+}