/branches/gl-inet/package/network/utils/rssileds/src/rssileds.c |
@@ -0,0 +1,290 @@ |
/* |
* 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 set_led(struct led *led, unsigned char value) |
{ |
char buf[8]; |
|
if ( ! led ) |
return -1; |
|
if ( ! led->controlfd ) |
return -1; |
|
if ( led->state == value ) |
return 0; |
|
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 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; |
|
if ( set_led(newled, 255) ) |
goto cleanup_fp; |
|
if ( set_led(newled, 0) ) |
goto cleanup_fp; |
|
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 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; |
} |