/* 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 .
*/
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;
}
int[] 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 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%03x00\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]);
if (led_map2 != 0x000) {
f = FileStream.open (Path.build_filename (i2c_dev, "engine2_mode"), "w");
if (f == null) {
stderr.printf ("failed to set engine2 to load mode\n");
return false;
}
f.printf ("load\n");
for (int i = 0; i < retries; i++) {
f = FileStream.open (Path.build_filename (i2c_dev, "engine2_leds"), "w");
if (f != null)
break;
}
if (f == null) {
stderr.printf ("failed to set engine2 mux\n");
return false;
}
f.printf ("0000%03x00\n", led_map2);
f = FileStream.open (Path.build_filename (i2c_dev, "engine2_load"), "w");
if (f == null) {
stderr.printf ("failed to load engine1 pattern\n");
return false;
}
f.printf ("%s\n", p[5]);
f = FileStream.open (Path.build_filename (i2c_dev, "engine2_mode"), "w");
if (f == null) {
stderr.printf ("failed to set engine2 to run mode\n");
return false;
}
f.printf ("run\n");
}
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 \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;
}