From 9f84e2d13760ba085fffecea34e887d1e47f91eb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 24 Feb 2010 18:15:01 +0100 Subject: [PATCH] Add LED pattern helper --- Makefile | 24 +++- src/led-pattern-helper.vala | 295 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 src/led-pattern-helper.vala diff --git a/Makefile b/Makefile index 9bc5d32..96cdc74 100644 --- 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 index 0000000..cda11da --- /dev/null +++ b/src/led-pattern-helper.vala @@ -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 . + */ + +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 \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; +} -- 1.7.9.5