1/* 2 * configurable RSSI LED control daemon for OpenWrt 3 * (c) 2012 Allnet GmbH, Daniel Golle <dgolle@allnet.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * The author may be reached as dgolle@allnet.de, or 20 * ALLNET GmbH 21 * Maistr. 2 22 * D-82110 Germering 23 * Germany 24 * 25 */ 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <sys/stat.h> 30#include <fcntl.h> 31#include <signal.h> 32#include <unistd.h> 33#include <syslog.h> 34 35#include "iwinfo.h" 36 37#define RUN_DIR "/var/run" 38#define LEDS_BASEPATH "/sys/class/leds/" 39#define BACKEND_RETRY_DELAY 500000 40 41char *ifname; 42int qual_max; 43 44struct led { 45 char *sysfspath; 46 FILE *controlfd; 47 unsigned char state; 48}; 49 50typedef struct rule rule_t; 51struct rule { 52 struct led *led; 53 int minq; 54 int maxq; 55 int boffset; 56 int bfactor; 57 rule_t *next; 58}; 59 60void log_rules(rule_t *rules) 61{ 62 rule_t *rule = rules; 63 while (rule) 64 { 65 syslog(LOG_INFO, " %s r: %d..%d, o: %d, f: %d\n", 66 rule->led->sysfspath, 67 rule->minq, rule->maxq, 68 rule->boffset, rule->bfactor); 69 rule = rule->next; 70 } 71} 72 73int set_led(struct led *led, unsigned char value) 74{ 75 char buf[8]; 76 77 if ( ! led ) 78 return -1; 79 80 if ( ! led->controlfd ) 81 return -1; 82 83 if ( led->state == value ) 84 return 0; 85 86 snprintf(buf, 8, "%d", value); 87 88 rewind(led->controlfd); 89 90 if ( ! fwrite(buf, sizeof(char), strlen(buf), led->controlfd) ) 91 return -2; 92 93 fflush(led->controlfd); 94 led->state=value; 95 96 return 0; 97} 98 99int init_led(struct led **led, char *ledname) 100{ 101 struct led *newled; 102 struct stat statbuffer; 103 int status; 104 char *bp; 105 FILE *bfp; 106 107 bp = calloc(sizeof(char), strlen(ledname) + strlen(LEDS_BASEPATH) + 12); 108 if ( ! bp ) 109 goto return_error; 110 111 sprintf(bp, "%s%s/brightness", LEDS_BASEPATH, ledname); 112 113 status = stat(bp, &statbuffer); 114 if ( status ) 115 goto cleanup_fname; 116 117 bfp = fopen( bp, "w" ); 118 if ( !bfp ) 119 goto cleanup_fname; 120 121 if ( ferror(bfp) ) 122 goto cleanup_fp; 123 124 /* sysfs path exists and, allocate LED struct */ 125 newled = calloc(sizeof(struct led),1); 126 if ( !newled ) 127 goto cleanup_fp; 128 129 newled->sysfspath = bp; 130 newled->controlfd = bfp; 131 132 *led = newled; 133 134 if ( set_led(newled, 255) ) 135 goto cleanup_fp; 136 137 if ( set_led(newled, 0) ) 138 goto cleanup_fp; 139 140 return 0; 141 142cleanup_fp: 143 fclose(bfp); 144cleanup_fname: 145 free(bp); 146return_error: 147 syslog(LOG_CRIT, "can't open LED %s\n", ledname); 148 *led = NULL; 149 return -1; 150} 151 152void close_led(struct led **led) 153{ 154 fclose((*led)->controlfd); 155 free((*led)->sysfspath); 156 free((*led)); 157 (*led)=NULL; 158} 159 160 161int quality(const struct iwinfo_ops *iw, const char *ifname) 162{ 163 int qual; 164 165 if ( ! iw ) return -1; 166 167 if (qual_max < 1) 168 if (iw->quality_max(ifname, &qual_max)) 169 return -1; 170 171 if (iw->quality(ifname, &qual)) 172 return -1; 173 174 return ( qual * 100 ) / qual_max ; 175} 176 177int open_backend(const struct iwinfo_ops **iw, const char *ifname) 178{ 179 *iw = iwinfo_backend(ifname); 180 181 if (!(*iw)) 182 return 1; 183 184 return 0; 185} 186 187void update_leds(rule_t *rules, int q) 188{ 189 rule_t *rule = rules; 190 while (rule) 191 { 192 int b; 193 /* offset and factore correction according to rule */ 194 b = ( q + rule->boffset ) * rule->bfactor; 195 if ( b < 0 ) 196 b=0; 197 if ( b > 255 ) 198 b=255; 199 200 if ( q >= rule->minq && q <= rule->maxq ) 201 set_led(rule->led, (unsigned char)b); 202 else 203 set_led(rule->led, 0); 204 205 rule = rule->next; 206 } 207} 208 209int main(int argc, char **argv) 210{ 211 int i,q,q0,r,s; 212 const struct iwinfo_ops *iw = NULL; 213 rule_t *headrule = NULL, *currentrule = NULL; 214 215 if (argc < 9 || ( (argc-4) % 5 != 0 ) ) 216 { 217 printf("syntax: %s (ifname) (refresh) (threshold) (rule) [rule] ...\n", argv[0]); 218 printf(" rule: (sysfs-name) (minq) (maxq) (offset) (factore)\n"); 219 return 1; 220 } 221 222 ifname = argv[1]; 223 224 /* refresh interval */ 225 if ( sscanf(argv[2], "%d", &r) != 1 ) 226 return 1; 227 228 /* sustain threshold */ 229 if ( sscanf(argv[3], "%d", &s) != 1 ) 230 return 1; 231 232 openlog("rssileds", LOG_PID, LOG_DAEMON); 233 syslog(LOG_INFO, "monitoring %s, refresh rate %d, threshold %d\n", ifname, r, s); 234 235 currentrule = headrule; 236 for (i=4; i<argc; i=i+5) { 237 if (! currentrule) 238 { 239 /* first element in the list */ 240 currentrule = calloc(sizeof(rule_t),1); 241 headrule = currentrule; 242 } 243 else 244 { 245 /* follow-up element */ 246 currentrule->next = calloc(sizeof(rule_t),1); 247 currentrule = currentrule->next; 248 } 249 250 if ( init_led(&(currentrule->led), argv[i]) ) 251 return 1; 252 253 if ( sscanf(argv[i+1], "%d", &(currentrule->minq)) != 1 ) 254 return 1; 255 256 if ( sscanf(argv[i+2], "%d", &(currentrule->maxq)) != 1 ) 257 return 1; 258 259 if ( sscanf(argv[i+3], "%d", &(currentrule->boffset)) != 1 ) 260 return 1; 261 262 if ( sscanf(argv[i+4], "%d", &(currentrule->bfactor)) != 1 ) 263 return 1; 264 } 265 log_rules(headrule); 266 267 q0 = -1; 268 do { 269 q = quality(iw, ifname); 270 if ( q < q0 - s || q > q0 + s ) { 271 update_leds(headrule, q); 272 q0=q; 273 }; 274 // re-open backend... 275 if ( q == -1 && q0 == -1 ) { 276 if (iw) { 277 iwinfo_finish(); 278 iw=NULL; 279 usleep(BACKEND_RETRY_DELAY); 280 } 281 while (open_backend(&iw, ifname)) 282 usleep(BACKEND_RETRY_DELAY); 283 } 284 usleep(r); 285 } while(1); 286 287 iwinfo_finish(); 288 289 return 0; 290} 291