/* 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 . */ bool sysfs_write (string filename, string contents) { var f = FileStream.open (filename, "w"); if (f == null) { stderr.printf ("failed to open '%s' for writing\n", filename); return false; } f.printf ("%s", contents); return true; } 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_map1 = 0x000; int led_map2 = 0x000; if ("r" in p[3]) led_map1 |= 0x001; if ("R" in p[3]) led_map2 |= 0x001; if ("g" in p[3]) led_map1 |= 0x010; if ("G" in p[3]) led_map2 |= 0x010; if ("b" in p[3]) led_map1 |= 0x100; if ("B" in p[3]) led_map2 |= 0x100; if ((led_map1 & led_map2) != 0) { stderr.printf ("pattern assigns a led to both channels: '%s'\n", p[3]); return false; } string led_map = ""; if (0x001 in led_map1) led_map += "r"; if (0x001 in led_map2) led_map += "R"; if (0x010 in led_map1) led_map += "g"; if (0x010 in led_map2) led_map += "G"; if (0x100 in led_map1) led_map += "b"; if (0x100 in led_map2) led_map += "B"; if (led_map != p[3]) { stderr.printf ("pattern contains invalid led map: '%s\n", p[3]); return false; } string[] led_currents = { "2", "2", "2" }; switch (led_map1 | led_map2) { case 0x001: led_currents = { "8", "0", "2" }; break; case 0x010: led_currents = { "2", "2", "2" }; break; case 0x100: led_currents = { "2", "2", "2" }; break; case 0x011: led_currents = { "20", "2", "0" }; break; case 0x101: // TODO: led_currents? break; case 0x110: // TODO: led_currents? break; case 0x111: led_currents = { "8", "2", "2" }; break; } if (p[4].length > 16*4 || p[5].length > 16*4) { stderr.printf ("engine1 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].length > 16*4 || p[5].length > 16*4) { stderr.printf ("engine2 pattern too long!\n"); return false; } if (!(p[5].has_prefix ("9d80"))) { stderr.printf ("engine2 pattern doesn't start with reset mux command\n"); return false; } if (!(p[5].has_suffix ("0000")) && !(p[5].has_suffix ("c000"))) { stderr.printf ("engine2 pattern doesn't end with repeat or stop command\n"); return false; } if (apply == false) return true; string mux1 = "0000%03x00\n".printf (led_map1); string mux2 = "0000%03x00\n".printf (led_map2); string pattern1 = p[4]; string pattern2 = p[5]; sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine1_mode", "disabled"); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine2_mode", "disabled"); sysfs_write ("/sys/class/leds/lp5523:r/brightness", "0"); sysfs_write ("/sys/class/leds/lp5523:g/brightness", "0"); sysfs_write ("/sys/class/leds/lp5523:b/brightness", "0"); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine1_mode", "load"); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine1_leds", mux1); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine1_load", pattern1); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine2_mode", "load"); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine2_leds", mux2); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine2_load", pattern2); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine2_mode", "run"); sysfs_write ("/sys/class/i2c-adapter/i2c-2/2-0032/engine1_mode", "run"); sysfs_write ("/sys/class/leds/lp5523:r/led_current", led_currents[0]); sysfs_write ("/sys/class/leds/lp5523:g/led_current", led_currents[1]); sysfs_write ("/sys/class/leds/lp5523:b/led_current", led_currents[2]); 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 \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; }