mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-25 20:55:30 +02:00
c8a92d23e8
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> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33163 3c298f89-4303-0410-b956-a3cf2f4a3e73
281 lines
5.4 KiB
C
281 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;
|
|
}
|