diff options
Diffstat (limited to 'package/rssileds/src')
-rw-r--r-- | package/rssileds/src/rssileds.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/package/rssileds/src/rssileds.c b/package/rssileds/src/rssileds.c new file mode 100644 index 000000000..2f25c846c --- /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; +} |