openwrtv3/package/rssileds/src/rssileds.c
Gabor Juhos 02cf95877e new package: rssileds daemon
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.

This is a slightly improved version of rssileds, now quality values are
in percent and stuff is written to syslog.

Signed-off-by: Daniel Golle <dgolle@allnet.de>

SVN-Revision: 33163
2012-08-13 14:01:34 +00:00

280 lines
5.4 KiB
C

/*
* 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;
}