rssileds is a small user-space process to control LEDs by polling the signal
quality reported by a WiFi interface.
By using the iwinfo library, rssileds is independent of the WiFi driver used.
It supports pwm controlled LEDs and may by used to nicely fade through all
colors in real-time of the rainbow while only wasting very little CPU time and
a small constant amount of system memory.
An example configuration for the ALL0258N will follow in the next patch.

Signed-off-by: Daniel Golle <[email protected]>

diff -ruN /dev/null package/rssileds/files/rssileds.init
--- /dev/null   1970-01-01 02:00:00.000000000 +0200
+++ package/rssileds/files/rssileds.init        2012-08-07 18:31:20.909931807 
+0300
@@ -0,0 +1,70 @@
+#!/bin/sh /etc/rc.common
+# (C) 2012 Daniel Golle, Allnet GmbH <[email protected]>
+
+START=96
+STOP=96
+RSSILEDS_BIN="/usr/sbin/rssileds"
+
+start_rssid() {
+       local name
+       local dev
+       local threshold
+       local refresh
+       local leds
+       config_get name $1 name
+       config_get dev $1 dev
+       config_get threshold $1 threshold
+       config_get refresh $1 refresh
+       leds="$( cur_iface=$1 ; config_foreach get_led led )"
+
+       ( $RSSILEDS_BIN $dev $refresh $threshold $leds ) &
+       echo $! > "/var/run/rssileds-$1.pid"
+}
+
+get_led() {
+       local name
+       local sysfs
+       local trigger
+       local iface
+       config_get sysfs $1 sysfs
+       config_get name $1 name "$sysfs"
+       config_get trigger $1 trigger "none"
+       config_get iface $1 iface
+       config_get minq $1 minq
+       config_get maxq $1 maxq
+       config_get offset $1 offset
+       config_get factor $1 factor
+       [ "$trigger" = "rssi" ] || return
+       [ "$iface" = "$cur_iface" ] || return
+       [ ! "$minq" ] || [ ! "$maxq" ] || [ ! "$offset" ] || [ ! "$factor" ] && 
return
+       echo "none" > /sys/class/leds/$sysfs/trigger
+       echo "$sysfs $minq $maxq $offset $factor"
+}
+
+off_led() {
+       local name
+       local sysfs
+       local trigger
+       config_get sysfs $1 sysfs
+       config_get name $1 name "$sysfs"
+       config_get trigger $1 trigger "none"
+       [ "$trigger" = "rssi" ] || return
+       echo "0" > /sys/class/leds/$sysfs/brightness
+}
+
+start() {
+       [ -e /sys/class/leds/ ] && [ -x "$RSSILEDS_BIN" ] && {
+               config_load system
+               config_foreach start_rssid rssid
+       }
+}
+
+stop() {
+       for pidfile in /var/run/rssileds*.pid ; do
+               [ -e "$pidfile" ] || break
+               kill -KILL $( cat $pidfile )
+               rm $pidfile
+       done
+       config_load system
+       config_foreach off_led led
+}
diff -ruN /dev/null package/rssileds/Makefile
--- /dev/null   1970-01-01 02:00:00.000000000 +0200
+++ package/rssileds/Makefile   2012-08-07 18:08:35.576587976 +0300
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2011-2012 Daniel Golle <[email protected]>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=rssileds
+PKG_VERSION:=0.1
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/rssileds
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=RSSI real-time LED indicator
+  DEPENDS:=libiwinfo
+endef
+
+define Package/rssileds/description
+  A small process written in C to update the signal-strength indicator LEDs
+endef
+
+define Build/Prepare
+       mkdir -p $(PKG_BUILD_DIR)
+       $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+       $(TARGET_CC) $(TARGET_CFLAGS) -Wall -liwinfo \
+               -o $(PKG_BUILD_DIR)/rssileds $(PKG_BUILD_DIR)/rssileds.c
+endef
+
+define Package/rssileds/install
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/rssileds.init $(1)/etc/init.d/rssileds
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/rssileds $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,rssileds))
diff -ruN /dev/null package/rssileds/src/rssileds.c
--- /dev/null   1970-01-01 02:00:00.000000000 +0200
+++ package/rssileds/src/rssileds.c     2012-08-07 18:24:52.206595485 +0300
@@ -0,0 +1,266 @@
+/*
+ * configurable RSSI LED control process for OpenWrt
+ *  (c) 2012 Allnet GmbH, Daniel Golle <[email protected]>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The author may be reached as [email protected], or
+ * ALLNET GmbH
+ * Maistr. 2
+ * D-82110 Germering
+ * Germany
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "iwinfo.h"
+
+#define LEDS_BASEPATH  "/sys/class/leds/"
+#define BACKEND_RETRY_DELAY    500000
+
+char *ifname;
+
+struct led {
+       char *sysfspath;
+       FILE *controlfd;
+       unsigned char state;
+};
+
+typedef struct rule rule_t;
+struct rule {
+       struct led *led;
+       int minq;
+       int maxq;
+       int boffset;
+       int bfactor;
+       rule_t *next;
+};
+
+void print_rules(rule_t *rules)
+{
+       rule_t *rule = rules;
+       while (rule)
+       {
+               printf(" %s r: %d..%d, o: %d, f: %d\n", 
+                       rule->led->sysfspath,
+                       rule->minq, rule->maxq,
+                       rule->boffset, rule->bfactor);
+               rule = rule->next;
+       }
+}
+
+int init_led(struct led **led, char *ledname)
+{
+       struct led *newled;
+       struct stat statbuffer;
+       int status;
+       char *bp;
+       FILE *bfp;
+
+       bp = calloc(sizeof(char), strlen(ledname) + strlen(LEDS_BASEPATH) + 12);
+       if ( ! bp )
+               goto return_error;
+
+       sprintf(bp, "%s%s/brightness", LEDS_BASEPATH, ledname);
+
+       status = stat(bp, &statbuffer);
+       if ( status )
+               goto cleanup_fname;
+
+       bfp = fopen( bp, "w" );
+       if ( !bfp )
+               goto cleanup_fname;
+
+       if ( ferror(bfp) )
+               goto cleanup_fp;
+
+       /* sysfs path exists and, allocate LED struct */
+       newled = calloc(sizeof(struct led),1);
+       if ( !newled )
+               goto cleanup_fp;
+
+       newled->sysfspath = bp;
+       newled->controlfd = bfp;
+       
+       *led = newled;
+       return 0;
+
+cleanup_fp:
+       fclose(bfp);
+cleanup_fname:
+       free(bp);
+return_error:
+       printf("can't open LED %s\n", ledname);
+       *led = NULL;
+       return -1;
+}
+
+void close_led(struct led **led)
+{
+       fclose((*led)->controlfd);
+       free((*led)->sysfspath);
+       free((*led));
+       (*led)=NULL;
+}
+
+int set_led(struct led *led, unsigned char value)
+{
+       char buf[8];
+
+       if ( ! led )
+               return -1;
+
+       if ( ! led->controlfd )
+               return -1;
+
+       snprintf(buf, 8, "%d", value);
+
+       rewind(led->controlfd);
+
+       if ( ! fwrite(buf, sizeof(char), strlen(buf), led->controlfd) )
+               return -2;
+
+       fflush(led->controlfd);
+       led->state=value;
+
+       return 0;
+}
+
+
+int quality(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int qual;
+
+       if ( ! iw ) return -1;
+
+       if (iw->quality(ifname, &qual))
+               qual = -1;
+
+       return qual;
+}
+
+int open_backend(const struct iwinfo_ops **iw, const char *ifname)
+{
+       *iw = iwinfo_backend(ifname);
+
+       if (!(*iw))
+               return 1;
+
+       return 0;
+}
+
+void update_leds(rule_t *rules, int q)
+{
+       rule_t *rule = rules;
+       while (rule)
+       {
+               int b;
+               /* offset and factore correction according to rule */
+               b = ( q + rule->boffset ) * rule->bfactor;
+               if ( b < 0 )
+                       b=0;
+               if ( b > 255 )
+                       b=255;
+
+               if ( q > rule->minq && q < rule->maxq )
+                       set_led(rule->led, (unsigned char)b);
+               else
+                       set_led(rule->led, 0);
+
+               rule = rule->next;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       int i,q,q0,r,s;
+       const struct iwinfo_ops *iw = NULL;
+       rule_t *headrule = NULL, *currentrule = NULL;
+
+       if (argc < 9 || ( (argc-4) % 5 != 0 ) )
+       {
+               printf("syntax: %s (ifname) (refresh) (threshold) (rule) [rule] 
...\n", argv[0]);
+               printf("  rule: (sysfs-name) (minq) (maxq) (offset) 
(factore)\n");
+               return 1;
+       }
+
+       ifname = argv[1];
+
+       /* refresh interval */
+       if ( sscanf(argv[2], "%d", &r) != 1 )
+               return 1;
+
+       /* sustain threshold */
+       if ( sscanf(argv[3], "%d", &s) != 1 )
+               return 1;
+
+       currentrule = headrule;
+       for (i=4; i<argc; i=i+5) {
+               if (! currentrule)
+               {
+                       /* first element in the list */
+                       currentrule = calloc(sizeof(rule_t),1);
+                       headrule = currentrule;
+               }
+               else
+               {
+                       /* follow-up element */
+                       currentrule->next = calloc(sizeof(rule_t),1);
+                       currentrule = currentrule->next;
+               }
+
+               if ( init_led(&(currentrule->led), argv[i]) )
+                       return 1;
+               
+               if ( sscanf(argv[i+1], "%d", &(currentrule->minq)) != 1 )
+                       return 1;
+
+               if ( sscanf(argv[i+2], "%d", &(currentrule->maxq)) != 1 )
+                       return 1;
+               
+               if ( sscanf(argv[i+3], "%d", &(currentrule->boffset)) != 1 )
+                       return 1;
+               
+               if ( sscanf(argv[i+4], "%d", &(currentrule->bfactor)) != 1 )
+                       return 1;
+       }
+
+       q0 = -1;
+       do {
+               q = quality(iw, ifname);
+               if ( q < q0 - s || q > q0 + s ) {
+                       update_leds(headrule, q);
+                       q0=q;
+               };
+               // re-open backend...
+               if ( q == -1 && q0 == -1 ) {
+                       if (iw) {
+                               iwinfo_finish();
+                               iw=NULL;
+                               usleep(BACKEND_RETRY_DELAY);
+                       }
+                       while (open_backend(&iw, ifname))
+                               usleep(BACKEND_RETRY_DELAY);
+               }
+               usleep(r);
+       } while(1);
+
+       iwinfo_finish();
+
+       return 0;
+}

Attachment: pgpOFNsT10sK4.pgp
Description: PGP signature

_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to