Нашел программу которая контролирует работу светодиодов сетевой платы на Banana Pi, вот код:
/*
* Configure ethernet adapter LEDs on BananaPi.
*
* Based on Roman Reichel's code and David A. Hinds's mii-tool <dhinds@pcmcia.sourceforge.org>
* More information on http://forum.lemaker.org/thread-1057-1-1-switch_off_the_leds_.html
*
* Copyright 2014 Laurent Faillie
*
* BananaLEDd is covered by
* Creative Commons Attribution-NonCommercial 3.0 License
* (http://creativecommons.org/licenses/by-nc/3.0/)
* Consequently, you're free to use if for personal or non-profit usage,
* professional or commercial usage REQUIRES a commercial licence.
*
* bPI_LEDd 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.
*
* -- V 1.0 --
* 16/11/2014 - LF - First version
* 17/11/2014 - LF - change default place for the configuration file
*
* -- V 1.1 ("Je suis Charlie" version) --
* 08/01/2014 - LF - Correct LOAD blinking
* Add MultBlink option
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/mii.h>
#include <time.h>
#include <sys/sysinfo.h>
#define VERSION "1.1 (\"Je suis Charlie\" version)"
#define DEFAULT_CONFIGURATION_FILE "/usr/local/etc/BananaLEDd.conf"
#define MAXLINE 1024
typedef enum { false=0, true } bool;
bool debug = false;
char *statfile = NULL;
enum LED { LGreen=0, LYellow, LBlue };
enum LMODE { M10=0, M100, G1, LACTIVITY, LSATA, LLOAD };
#define LSPEEDMASK ((1 << LACTIVITY) - 1)
#define LCUMULATIVE ((1 << LSATA) -1) /* mask for cumulative mode */
#define LMODESATA (1 << LSATA )
#define LMODELOAD (1 << LLOAD )
struct Config {
short Green;
short Yellow;
short Blue;
const char *device;
const char *disk;
short Sample;
short MinBlink;
short MultBlink;
} cfg;
/*
* Access to the device
* "not my code" :)
*/
static int skfd = -1;
static struct ifreq ifr;
static int mdio_read(int skfd, __u16 location) {
struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr.ifr_data;
mii->reg_num = location;
if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
return -1;
}
return mii->val_out;
}
static void mdio_write(int skfd, __u16 location, __u16 value) {
struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr.ifr_data;
mii->reg_num = location;
mii->val_in = value;
if (ioctl(skfd, SIOCSMIIREG, &ifr) < 0) {
fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
}
}
/*
* Helper functions
*/
char *removeLF(char *s){
size_t l=strlen(s);
if(l && s[--l] == '\n')
s[l] = 0;
return s;
}
char *striKWcmp( char *s, const char *kw ){
/* compare string s against kw
* Return :
* - remaining string if the keyword matches
* - NULL if the keyword is not found
*/
size_t klen = strlen(kw);
if( strncasecmp(s,kw,klen) )
return NULL;
else
return s+klen;
}
/*
* Reading the configuration
*/
short confled( char *a, const char *id ){
char *tok = strtok(a," \t");
short res=0;
while(tok){
if(!strcmp(tok, "10"))
res |= 1 << M10;
else if(!strcmp(tok, "100"))
res |= 1 << M100;
else if(!strcmp(tok, "1000"))
res |= 1 << G1;
else if(!strcasecmp(tok, "LINKED"))
res |= LSPEEDMASK; /* All speeds */
else if(!strcasecmp(tok, "NETWORK"))
res |= 1 << LACTIVITY;
else if(!strcasecmp(tok, "SATA"))
res |= 1 << LSATA;
else if(!strcasecmp(tok, "LOAD"))
res |= 1 << LLOAD;
else
printf("*W*\t%s : '%s' mode is ignored\n", id, tok);
tok = strtok(NULL, " \t");
}
if(debug)
printf("\t%s mode : %02x\n", id, res);
/* Check for compatibilies */
if(res & LCUMULATIVE && res & ~LCUMULATIVE){
fprintf(stderr,"%s : incompatible mode set\n", id);
exit(EXIT_FAILURE);
}
return res;
}
void read_configuration( const char *fch ){
FILE *f;
char l[MAXLINE];
char *arg;
/* Cleaning configuration */
cfg.Green = cfg.Yellow = cfg.Blue = 0;
if(cfg.device)
free((void *)cfg.device);
cfg.device = NULL;
if(cfg.disk)
free((void *)cfg.disk);
cfg.disk = NULL;
cfg.Sample=100;
cfg.MinBlink=2;
cfg.MultBlink=100;
/* Reading ... */
if(debug)
printf("Reading configuration file '%s'\n", fch);
if(!(f=fopen(fch, "r"))){
perror(fch);
exit(EXIT_FAILURE);
}
while(fgets(l, MAXLINE, f)){
if(*l == '#' || *l == '\n')
continue;
if((arg = striKWcmp(l,"Green=")))
cfg.Green = confled( removeLF(arg), "Green" );
else if((arg = striKWcmp(l,"Yellow=")))
cfg.Yellow = confled( removeLF(arg), "Yellow" );
else if((arg = striKWcmp(l,"Blue=")))
cfg.Blue = confled( removeLF(arg), "Blue" );
else if((arg = striKWcmp(l,"LEDDevice="))){
assert( cfg.device = strdup( removeLF(arg)) );
if(debug)
printf("\tUsing '%s' as LED device.\n", cfg.device);
} else if((arg = (char *)striKWcmp(l,"Disk="))){
assert( cfg.disk = strdup( removeLF(arg)) );
if(debug)
printf("\tMonitoring disk '%s'.\n", cfg.disk);
} else if((arg = striKWcmp(l,"Sample="))){
int res = atoi(arg);
if(res > 0){
cfg.Sample = res;
if(debug)
printf("\tUsing %dms sample time.\n", cfg.Sample);
}
} else if((arg = striKWcmp(l,"MinBlink="))){
int res = atoi(arg);
if(res > 0){
cfg.MinBlink = res;
if(debug)
printf("\tMinBlink is %d\n", cfg.MinBlink);
/* printf("\tMinBlink is %d -> %.1f blink(s) per second.\n", cfg.MinBlink, 500.0/(cfg.Sample * cfg.MinBlink)); */
}
} else if((arg = striKWcmp(l,"MultBlink="))){
int res = atoi(arg);
if(res > 0){
cfg.MultBlink = res;
if(debug)
printf("\tMultBlink is %d\n", cfg.MultBlink);
}
} else if(debug)
printf("*W* configuration line '%s' is ignored\n", removeLF(l));
}
fclose(f);
}
void configure_led( short v, int id ){
/* Set led's hardware configuration bits
* -> v : configuration bits
* -> id : Led
*/
__u16 reg, org;
/* Switch to "extension page 44" */
mdio_write(skfd, 0x1f, 0x0007);
mdio_write(skfd, 0x1e, 0x002c);
/* Speed */
org = reg = mdio_read(skfd, 28); /* Read current value */
reg &= ~(LSPEEDMASK << (id *4)); /* mask out this led bits */
reg |= (v & LSPEEDMASK) << (id *4); /* Set value for this led */
/* printf("speed for\t: %d : %02x => %04x\n", id, v & LSPEEDMASK, reg); */
if(org != reg)
mdio_write(skfd, 28, reg);
/* Activities */
org = reg = mdio_read(skfd, 26); /* Read current value */
reg &= ~(1 << (id + 4)); /* mask out this led bits */
if( v & (1 << LACTIVITY))
reg |= 1 << (id + 4); /* Set value for this led */
/* printf("activity for\t: %d : %02x => %04x\n", id, 1 << (id + 4), reg); */
if(org != reg)
mdio_write(skfd, 26, reg);
/* Back to normal register bank */
mdio_write(skfd, 0x1f, 0x0000);
}
unsigned long int diskcounter(const char *fch){
unsigned long int cr, cw, bidon;
FILE *f;
if(!(f = fopen(fch, "r"))){
if(debug)
perror(fch);
return 0;
}
assert(fscanf(f, "%ld %ld %ld %ld %ld", &cr, &bidon, &bidon, &bidon, &cw));
fclose(f);
return(cr + cw);
}
int getload(){
struct sysinfo sys_info;
if(sysinfo(&sys_info)){
if(debug)
perror("sysinfo()");
return 0;
}
return((int)(cfg.MultBlink *sys_info.loads[0] / (float)(1 << SI_LOAD_SHIFT)));
}
void cleaning(){
if(skfd >= 0)
close(skfd);
if(statfile)
free(statfile);
}
int main(int ac, char **av){
const char *conf_file = DEFAULT_CONFIGURATION_FILE;
int val, blkcnt = 0;
bool blkstatus = false;
unsigned long int diskcnt; /* Disk activity counter */
bool prevdisk = false;
const char *const statfilestring = "/sys/block/%s/stat";
struct timespec sleepvalue = {0};
if(ac > 0){
int i;
for(i=1; i<ac; i++){
if(!strcmp(av[i], "-h")){
fprintf(stderr, "%s (%s)\n"
"Control BananaPI ethernet LEDs\n"
"Known options are :\n"
"\t-h : this online help\n"
"\t-d : enable debug messages\n"
"\t-f<file> : read <file> for configuration\n"
"\t\t(default is '%s')\n",
basename(av[0]), VERSION, DEFAULT_CONFIGURATION_FILE
);
exit(EXIT_FAILURE);
} else if(!strcmp(av[i], "-d")){
debug = true;
puts("BananaLEDd (c) L.Faillie 2014");
puts("https://sourceforge.net/projects/bananacompanions/");
printf("%s (%s) starting ...\n", basename(av[0]), VERSION);
} else if(!strncmp(av[i], "-f", 2))
conf_file = av[i] + 2;
else {
fprintf(stderr, "Unknown option '%s'\n%s -h\n\tfor some help\n", av[i], av[0]);
exit(EXIT_FAILURE);
}
}
}
read_configuration( conf_file );
/* Open stat file */
val = strlen(statfilestring) + strlen(cfg.disk); /* EOS if compensated by '%s' */
assert(statfile = malloc(val));
sprintf(statfile, statfilestring, cfg.disk);
atexit(cleaning);
/*
* Accessing to the hardware
*/
if((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket");
exit(EXIT_FAILURE);
}
strncpy(ifr.ifr_name, cfg.device, IFNAMSIZ);
if(ioctl(skfd, SIOCGMIIPHY, &ifr) < 0){
fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", cfg.device, strerror(errno));
exit(EXIT_FAILURE);
}
/*
* Sanity check : ensure it's the right device
* Have a look on RTL8211E datasheet
*/
mdio_write(skfd, 0x1f, 0x0000);
val = mdio_read(skfd, 2);
if((val & 0xFFFF) != 0x001c){
fprintf(stderr, "unexpected PHYID1: 0x%x\n", val);
exit(EXIT_FAILURE);
}
val = mdio_read(skfd, 3);
if((val & 0xFC00) != 0xc800){
fprintf(stderr, "unexpected PHYID2: 0x%x\n", val);
exit(EXIT_FAILURE);
}
if(debug)
puts("Ok, let's go ...");
/* set one shots */
if(cfg.Green & LCUMULATIVE)
configure_led( cfg.Green, LGreen );
else
configure_led( 0, LGreen );
if(cfg.Yellow & LCUMULATIVE)
configure_led( cfg.Yellow, LYellow );
else
configure_led( 0, LYellow );
if(cfg.Blue & LCUMULATIVE)
configure_led( cfg.Blue, LBlue );
else
configure_led( 0, LBlue );
diskcnt = diskcounter( statfile );
sleepvalue.tv_nsec = cfg.Sample * 1000000L;
for(;;){
/* Handle disk activities */
unsigned long int dsk = diskcounter( statfile );
if(dsk){
if(dsk != diskcnt){ /* some disk activities */
diskcnt = dsk;
if(!prevdisk){
prevdisk = true;
if(cfg.Green == LMODESATA)
configure_led(LSPEEDMASK, LGreen);
if(cfg.Yellow == LMODESATA)
configure_led(LSPEEDMASK, LYellow);
if(cfg.Blue == LMODESATA)
configure_led(LSPEEDMASK, LBlue);
if(debug)
puts("disk on");
}
} else if(dsk == diskcnt && prevdisk) { /* Disk is quiet */
prevdisk = false;
if(cfg.Green == LMODESATA)
configure_led(0, LGreen);
if(cfg.Yellow == LMODESATA)
configure_led(0, LYellow);
if(cfg.Blue == LMODESATA)
configure_led(0, LBlue);
if(debug)
puts("disk off");
}
}
/* Handle system load */
if((val = getload()) < cfg.MinBlink)
val = cfg.MinBlink;
if(++blkcnt > val){
blkcnt = 0;
if(blkstatus){
blkstatus = false;
if(cfg.Green == LMODELOAD)
configure_led(0, LGreen);
if(cfg.Yellow == LMODELOAD)
configure_led(0, LYellow);
if(cfg.Blue == LMODELOAD)
configure_led(0, LBlue);
if(debug)
puts("Load off");
} else {
blkstatus = true;
if(cfg.Green == LMODELOAD)
configure_led(LSPEEDMASK, LGreen);
if(cfg.Yellow == LMODELOAD)
configure_led(LSPEEDMASK, LYellow);
if(cfg.Blue == LMODELOAD)
configure_led(LSPEEDMASK, LBlue);
if(debug)
puts("Load on");
}
}
nanosleep(&sleepvalue, NULL);
}
exit(EXIT_SUCCESS);
}
конфиг:
# BananaLEDd configuration file.
# LED's mode can be
# 10 - on when linked to 10M network
# 100 - on when linked to 100M network
# 1000 - on when linked to 1G network
# LINKED - on when linked to a network
# NETWORK - follow network activities
# SATA - follow SATA disk activities
# LOAD - System load
Blue=SATA
Yellow=LOAD
Green=LINKED NETWORK
# Adapter to use
LEDDevice=eth0
# Disk to monitor
Disk=sda
# Sample time (in ms)
# default 100 ms == 1/10s
Sample=100
# Minimum load blink time (ms)
# has to be a multiple of Sample
# Result is : MultBlink/2/(MinBlink * Sample)
# So default is about 2.5 blink per second
MinBlink=2
MultBlink=50
Принцип прост: проц простаивает - моргает быстро, нагружаю проц - моргает медленно, а мне нужно что бы работало наоборот. При простое время свечения = (MultBlink/2) / (MinBlink * Sample).
Не пойму где именно происходит эта математическая операция...