diff options
Diffstat (limited to 'package')
-rw-r--r-- | package/rssileds/Makefile | 47 | ||||
-rw-r--r-- | package/rssileds/files/rssileds.init | 75 | ||||
-rw-r--r-- | package/rssileds/src/rssileds.c | 280 |
3 files changed, 402 insertions, 0 deletions
diff --git a/package/rssileds/Makefile b/package/rssileds/Makefile new file mode 100644 index 0000000000..27354f0fe4 --- /dev/null +++ b/package/rssileds/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2011-2012 Daniel Golle <dgolle@allnet.de> +# +# 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 + +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 --git a/package/rssileds/files/rssileds.init b/package/rssileds/files/rssileds.init new file mode 100644 index 0000000000..b0d262725b --- /dev/null +++ b/package/rssileds/files/rssileds.init @@ -0,0 +1,75 @@ +#!/bin/sh /etc/rc.common +# (C) 2012 Daniel Golle, Allnet GmbH <dgolle@allnet.de> + +START=96 +STOP=96 +RSSILEDS_BIN="/usr/sbin/rssileds" + +SERVICE_DAEMONIZE=1 +SERVICE_WRITE_PID=1 + +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 )" + SERVICE_PID_FILE=/var/run/rssileds-$dev.pid + service_start $RSSILEDS_BIN $dev $refresh $threshold $leds +} + +stop_rssid() { + local dev + config_get dev $1 dev + SERVICE_PID_FILE=/var/run/rssileds-$dev.pid + service_stop $RSSILEDS_BIN +} + +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() { + config_load system + config_foreach stop_rssid rssid + config_foreach off_led led +} diff --git a/package/rssileds/src/rssileds.c b/package/rssileds/src/rssileds.c new file mode 100644 index 0000000000..2f25c846c9 --- /dev/null +++ b/package/rssileds/src/rssileds.c @@ -0,0 +1,280 @@ +/* + * configurable RSSI LED control daemon for OpenWrt + * (c) 2012 Allnet GmbH, Daniel Golle <dgolle@allnet.de> + * + * 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 dgolle@allnet.de, or + * ALLNET GmbH + * Maistr. 2 + * D-82110 Germering + * Germany + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#include <syslog.h> + +#include "iwinfo.h" + +#define RUN_DIR "/var/run" +#define LEDS_BASEPATH "/sys/class/leds/" +#define BACKEND_RETRY_DELAY 500000 + +char *ifname; +int qual_max; + +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 log_rules(rule_t *rules) +{ + rule_t *rule = rules; + while (rule) + { + syslog(LOG_INFO, " %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: + syslog(LOG_CRIT, "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 (qual_max < 1) + if (iw->quality_max(ifname, &qual_max)) + return -1; + + if (iw->quality(ifname, &qual)) + return -1; + + return ( qual * 100 ) / qual_max ; +} + +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; + + openlog("rssileds", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "monitoring %s, refresh rate %d, threshold %d\n", ifname, r, s); + + 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; + } + log_rules(headrule); + + 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; +} |