diff options
Diffstat (limited to '')
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | MatrixOrbital.c | 49 | ||||
-rw-r--r-- | config.c | 98 | ||||
-rw-r--r-- | config.h | 3 | ||||
-rw-r--r-- | display.c | 57 | ||||
-rw-r--r-- | display.h | 30 | ||||
-rw-r--r-- | filter.c | 117 | ||||
-rw-r--r-- | filter.h | 2 | ||||
-rw-r--r-- | isdn.c | 98 | ||||
-rw-r--r-- | isdn.h | 1 | ||||
-rw-r--r-- | lcd2041.c | 314 | ||||
-rw-r--r-- | lcd2041.h | 14 | ||||
-rw-r--r-- | lcd4linux.c | 499 | ||||
-rw-r--r-- | lcd4linux.h | 6 | ||||
-rw-r--r-- | system.c | 306 | ||||
-rw-r--r-- | system.h | 9 |
16 files changed, 1615 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..218e296 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +CC=gcc -m486 -g -Wall -I. -DVERSION=\"V0.5\" + +all: lcd4linux + +#lcd4linux: lcd4linux.c config.c lcd2041.c system.c isdn.c filter.c Makefile +# ${CC} -lm -o lcd4linux lcd4linux.c config.c lcd2041.c system.c isdn.c filter.c + +lcd4linux: display.c MatrixOrbital.c + ${CC} -lm -o lcd4linux display.c MatrixOrbital.c + +clean: + rm -f lcd4linux *.o *~ diff --git a/MatrixOrbital.c b/MatrixOrbital.c new file mode 100644 index 0000000..38c2d26 --- /dev/null +++ b/MatrixOrbital.c @@ -0,0 +1,49 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> + +#include "display.h" + + +int MO_init (void) +{ + printf ("initializing MatrixOrbital...\n"); + return 0; +} + +int MO_clear (void) +{ + return 0; +} + +int MO_put (int x, int y, char *text) +{ + return 0; +} + +int MO_bar (int type, int x, int y, int max, int len1, int len2) +{ + return 0; +} + +int MO_flush (void) +{ + return 0; +} + + +#define BARS ( BAR_L | BAR_R | BAR_U | BAR_D | BAR_S ) + +DISPLAY MatrixOrbital[] = { + { "LCD0821", 8, 2, 5, 8, BARS, MO_init, MO_clear, MO_put, MO_bar, MO_flush }, + { "LCD1621", 16, 2, 5, 8, BARS, MO_init, MO_clear, MO_put, MO_bar, MO_flush }, + { "LCD2021", 20, 2, 5, 8, BARS, MO_init, MO_clear, MO_put, MO_bar, MO_flush }, + { "LCD2041", 20, 4, 5, 8, BARS, MO_init, MO_clear, MO_put, MO_bar, MO_flush }, + { "LCD4021", 40, 2, 5, 8, BARS, MO_init, MO_clear, MO_put, MO_bar, MO_flush }, + { "" } +}; + diff --git a/config.c b/config.c new file mode 100644 index 0000000..c55d63c --- /dev/null +++ b/config.c @@ -0,0 +1,98 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "config.h" + +typedef struct { + char *key; + char *val; +} ENTRY; + +static ENTRY *Config=NULL; +static int nConfig=0; + +static char *strip (char *s) +{ + char *p; + + while (isblank(*s)) s++; + for (p=s; *p; p++) { + if (*p=='"') do p++; while (*p && *p!='\n' && *p!='"'); + if (*p=='\'') do p++; while (*p && *p!='\n' && *p!='\''); + if (*p=='#' || *p=='\n') { + *p='\0'; + break; + } + } + for (p--; p>s && isblank(*p); p--) *p='\0'; + return s; +} + +void set_cfg (char *key, char *val) +{ + int i; + + for (i=0; i<nConfig; i++) { + if (strcasecmp(Config[i].key, key)==0) { + if (Config[i].val) free (Config[i].val); + Config[i].val=strdup(val); + return; + } + } + nConfig++; + Config=realloc(Config, nConfig*sizeof(ENTRY)); + Config[i].key=strdup(key); + Config[i].val=strdup(val); +} + +char *get_cfg (char *key) +{ + int i; + + for (i=0; i<nConfig; i++) { + if (strcasecmp(Config[i].key, key)==0) { + return Config[i].val; + } + } + return NULL; +} + + +int read_cfg (char *file) +{ + FILE *stream; + char buffer[256]; + char *line, *p, *s; + + stream=fopen (file, "r"); + if (stream==NULL) { + fprintf (stderr, "open(%s) failed: %s\n", file, strerror(errno)); + return-1; + } + while ((line=fgets(buffer,256,stream))!=NULL) { + if (*(line=strip(line))=='\0') continue; + for (p=line; *p; p++) { + if (isblank(*p)) { + *p++='\0'; + break; + } + } + p=strip(p); + if (*p) for (s=p; *(s+1); s++); + else s=p; + if (*p=='"' && *s=='"') { + *s='\0'; + p++; + } + else if (*p=='\'' && *s=='\'') { + *s='\0'; + p++; + } + set_cfg (line, p); + } + fclose (stream); + return 0; +} + diff --git a/config.h b/config.h new file mode 100644 index 0000000..b07adc6 --- /dev/null +++ b/config.h @@ -0,0 +1,3 @@ +int read_cfg (char *file); +char *get_cfg (char *key); +void set_cfg (char *key, char *value); diff --git a/display.c b/display.c new file mode 100644 index 0000000..d154b67 --- /dev/null +++ b/display.c @@ -0,0 +1,57 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "display.h" + +extern DISPLAY MatrixOrbital[]; + +FAMILY Driver[] = { + { "MatrixOrbital", MatrixOrbital }, + { "" } +}; + + +static DISPLAY *Display = NULL; + +int lcd_init (char *display) +{ + int i, j; + for (i=0; Driver[i].name[0]; i++) { + for (j=0; Driver[i].Display[j].name[0]; j++) { + if (strcmp (Driver[i].Display[j].name, display)==0) { + Display=&Driver[i].Display[j]; + return Display->init(); + } + } + } + fprintf (stderr, "lcd_init(%s) failed: no such display\n", display); + return -1; +} + +int lcd_clear (void) +{ + return 0; +} + +int lcd_put (int x, int y, char *text) +{ + return 0; +} + +int lcd_bar (int type, int x, int y, int max, int len1, int len2) +{ + return 0; +} + +int lcd_flush (void) +{ + return 0; +} + +void main (void) { + int i, j; + + lcd_init ("junk"); + lcd_init ("LCD2041"); + +} diff --git a/display.h b/display.h new file mode 100644 index 0000000..0be2d50 --- /dev/null +++ b/display.h @@ -0,0 +1,30 @@ +#define BAR_L 1 +#define BAR_R 2 +#define BAR_U 4 +#define BAR_D 8 +#define BAR_S 256 + +typedef struct { + char name[16]; + int rows; + int cols; + int xres; + int yres; + int bars; + int (*init) (void); + int (*clear) (void); + int (*put) (int x, int y, char *text); + int (*bar) (int type, int x, int y, int max, int len1, int len2); + int (*flush) (void); +} DISPLAY; + +typedef struct { + char name[16]; + DISPLAY *Display; +} FAMILY; + +int lcd_init (char *display); +int lcd_clear (void); +int lcd_put (int x, int y, char *text); +int lcd_bar (int type, int x, int y, int max, int len1, int len2); +int lcd_flush (void); diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..f61a9ed --- /dev/null +++ b/filter.c @@ -0,0 +1,117 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <sys/time.h> + +#include "lcd4linux.h" +#include "filter.h" + +#define SLOTS 64 + +typedef struct { + char *name; + int slots; + struct timeval *time; + double *value; +} FILTER; + +#define SECONDS(x) (x.tv_sec+x.tv_usec/1000000.0) + +double smooth(char *name, int period, double value) +{ + static FILTER *Filter=NULL; + static int nFilter=0; + struct timeval now; + double t, v; + int i, j; + + gettimeofday (&now, NULL); + + for (i=0; i<nFilter; i++) { + if (strcmp(name, Filter[i].name)==0) + break; + } + + if (i==nFilter) { + int slots=(period+tick-1)/tick; + if (slots<2) + slots=2; + else if (slots>SLOTS) + slots=SLOTS; + + nFilter++; + Filter=realloc(Filter, nFilter*sizeof(FILTER)); + Filter[i].name=strdup(name); + Filter[i].slots=slots; + Filter[i].time=malloc(slots*sizeof(Filter[i].time[0])); + Filter[i].value=malloc(slots*sizeof(Filter[i].value[0])); + for (j=0; j<slots; j++) { + Filter[i].time[j]=now; + Filter[i].value[j]=value; + } + } + + for (j=Filter[i].slots-1; j>0; j--) { + Filter[i].time[j]=Filter[i].time[j-1]; + Filter[i].value[j]=Filter[i].value[j-1]; + } + Filter[i].time[0]=now; + Filter[i].value[0]=value; + + t = SECONDS(Filter[i].time[0]) - SECONDS(Filter[i].time[Filter[i].slots-1]); + v = Filter[i].value[0]-Filter[i].value[Filter[i].slots-1]; + + if (t==0.0 || v<0.0) + return 0; + else + return v/t; +} + +double damp(char *name, double value) +{ + static FILTER *Filter=NULL; + static int nFilter=0; + struct timeval now; + double max; + int i, j; + + gettimeofday (&now, NULL); + + for (i=0; i<nFilter; i++) { + if (strcmp(name, Filter[i].name)==0) + break; + } + + if (i==nFilter) { + int slots=log(100)*tau/tick; + if (slots<1) + slots=1; + else if (slots>SLOTS) + slots=SLOTS; + + nFilter++; + Filter=realloc(Filter, nFilter*sizeof(FILTER)); + Filter[i].name=strdup(name); + Filter[i].slots=slots; + Filter[i].time=malloc(slots*sizeof(Filter[i].time)); + Filter[i].value=malloc(slots*sizeof(Filter[i].value)); + for (j=0; j<slots; j++) { + Filter[i].time[j]=now; + Filter[i].value[j]=0; + } + } + + max=value; + for (j=Filter[i].slots-1; j>0; j--) { + double t = SECONDS(Filter[i].time[j]) - SECONDS(Filter[i].time[j-1]); + Filter[i].time[j]=Filter[i].time[j-1]; + Filter[i].value[j]=Filter[i].value[j-1]*exp(-t/tau); + if (Filter[i].value[j]>max) max=Filter[i].value[j]; + } + + Filter[i].time[0]=now; + Filter[i].value[0]=value; + + return max; +} diff --git a/filter.h b/filter.h new file mode 100644 index 0000000..a3b44a4 --- /dev/null +++ b/filter.h @@ -0,0 +1,2 @@ +double smooth (char *name, int period, double value); +double damp (char *name, double value); @@ -0,0 +1,98 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <linux/isdn.h> + +#include "isdn.h" +#include "filter.h" +#include "lcd4linux.h" + +typedef struct { + unsigned long in; + unsigned long out; +} CPS; + + +static int Usage (void) +{ + static int fd=0; + char buffer[4096], *p; + int i, usage; + + if (fd==-1) return 0; + + fd=open ("/dev/isdninfo", O_RDONLY | O_NDELAY); + if (fd==-1) { + perror ("open(/dev/isdninfo) failed"); + return 0; + } + + if (read (fd, buffer, sizeof(buffer))==-1) { + perror ("read(/dev/isdninfo) failed"); + fd=-1; + return 0; + } + + if (close(fd)==-1) { + perror ("close(/dev/isdninfo) failed"); + fd=-1; + return 0; + } + + p=strstr(buffer, "usage:"); + if (p==NULL) { + fprintf (stderr, "parse(/dev/isdninfo) failed: no usage line\n"); + fd=-1; + return 0; + } + p+=6; + + usage=0; + for (i=0; i<ISDN_MAX_CHANNELS; i++) { + usage|=strtol(p, &p, 10); + } + + return usage; +} + +int Isdn (int *rx, int *tx) +{ + static int fd=-2; + CPS cps[ISDN_MAX_CHANNELS]; + double cps_i, cps_o; + int i; + + *rx=0; + *tx=0; + + if (fd==-1) return 0; + + if (fd==-2) { + fd = open("/dev/isdninfo", O_RDONLY | O_NDELAY); + if (fd==-1) { + perror ("open(/dev/isdninfo) failed"); + return 0; + } + } + if (ioctl(fd, IIOCGETCPS, &cps)) { + perror("ioctl(IIOCGETCPS) failed"); + fd=-1; + return 0; + } + cps_i=0; + cps_o=0; + for (i=0; i<ISDN_MAX_CHANNELS; i++) { + cps_i+=cps[i].in; + cps_o+=cps[i].out; + } + + *rx=(int)smooth("isdn_rx", 1000, cps_i); + *tx=(int)smooth("isdn_tx", 1000, cps_o); + + return Usage(); +} + @@ -0,0 +1 @@ +int Isdn (int *rx, int *tx); diff --git a/lcd2041.c b/lcd2041.c new file mode 100644 index 0000000..4987697 --- /dev/null +++ b/lcd2041.c @@ -0,0 +1,314 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> + +#include "lcd2041.h" + +#define BAR_HORI 1 +#define BAR_VERT 2 +#define BAR_DUAL 3 + +static int lcd; +static char *lcd_device=NULL; +static int bar_mode=0; + +typedef struct { + int l1; + int l2; + int chr; +} SEGMENT; + +typedef struct { + int l1; + int l2; + int lru; +} CHARACTER; + +static SEGMENT Segment[COLS+1][ROWS+1]; +static CHARACTER Character[CHAR]; + +static int lcd_open(void) +{ + int fd; + struct termios portset; + + fd = open(lcd_device, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd==-1) { + fprintf (stderr, "open(%s) failed: %s\n", lcd_device, strerror(errno)); + return -1; + } + if (tcgetattr(fd, &portset)==-1) { + fprintf (stderr, "tcgetattr(%s) failed: %s\n", lcd_device, strerror(errno)); + return -1; + } + cfmakeraw(&portset); + cfsetospeed(&portset, B19200); + if (tcsetattr(fd, TCSANOW, &portset)==-1) { + fprintf (stderr, "tcsetattr(%s) failed: %s\n", lcd_device, strerror(errno)); + return -1; + } + return fd; +} + + +static void lcd_write (char *string, int len) +{ + if (lcd==-1) return; + if (write (lcd, string, len)==-1) { + if (errno==EAGAIN) { + usleep(1000); + if (write (lcd, string, len)>=0) return; + } + fprintf (stderr, "write(%s) failed: %s\n", lcd_device, strerror(errno)); + } +} + + +void lcd_clear (void) +{ + lcd_write ("\014", 1); +} + + +void lcd_put (int x, int y, char *string) +{ + char buffer[256]; + snprintf (buffer, sizeof(buffer), "\376G%c%c%s", x, y, string); + lcd_write (buffer, strlen(buffer)); +} + +void lcd_hbar (int x, int y, int dir, int max, int len) +{ + char buffer[COLS+5]; + char *p; + + if (bar_mode!=BAR_HORI) { + lcd_write ("\376h", 2); + bar_mode=BAR_HORI; + } + + if (len<1) len=1; + else if (len>max) len=max; + if (dir!=0) len=max-len; + + snprintf (buffer, sizeof(buffer), "\376G%c%c", x, y); + p=buffer+4; + + while (max>0 && p-buffer<sizeof(buffer)) { + if (len==0) { + *p=dir?255:32; + } else if (len>=XRES) { + *p=dir?32:255; + len-=XRES; + } else { + *p=dir?8-len:len-1; + len=0; + } + max-=XRES; + p++; + } + lcd_write (buffer, p-buffer); +} + + +void lcd_vbar (int x, int y, int dir, int max, int len) +{ + char buffer[6]; + unsigned char c; + + if (bar_mode!=BAR_VERT) { + lcd_write ("\376v", 2); + bar_mode=BAR_VERT; + } + + if (len<1) len=1; + else if (len>max) len=max; + + while (max>0 && y>0) { + if (len==0) { + c=32; + } else if (len>=XRES) { + c=255; + len-=XRES; + } else { + c=len; + len=0; + } + snprintf (buffer, sizeof(buffer), "\376G%c%c%c", x, y, c); + lcd_write (buffer, 5); + max-=XRES; + y--; + } +} + + +static void lcd_dbar_init (void) +{ + int x, y; + + bar_mode=BAR_DUAL; + + for (x=0; x<CHAR; x++) { + Character[x].l1=-1; + Character[x].l2=-1; + Character[x].lru=0; + } + + for (x=0; x<COLS; x++) { + for (y=0; y<ROWS; y++) { + Segment[x][y].l1=-1; + Segment[x][y].l2=-1; + } + } +} + +static int lcd_dbar_char (int l1, int l2) +{ + int i, j, min; + + if (l1==127) l1=0; + if (l2==127) l2=0; + + if (l1==0 && l2==0) return 32; + if (l1==XRES && l2==XRES) return 255; + + for (i=0; i<CHAR; i++) { + if (Character[i].l1==l1 && Character[i].l2==l2) { + Character[i].lru=2; + return i; + } + } + + for (i=0; i<CHAR; i++) { + if (Character[i].lru==0) { + printf ("creating char %d (%d/%d)\n", i, l1, l2); + Character[i].l1=l1; + Character[i].l2=l2; + Character[i].lru=2; + return i; + } + } + + min=XRES*YRES; + for (i=0; i<CHAR; i++) { + int diff; + if (l1==0 && Character[i].l1!=0) continue; + if (l2==0 && Character[i].l2!=0) continue; + if (l1==XRES && Character[i].l1!=XRES) continue; + if (l2==XRES && Character[i].l2!=XRES) continue; + diff=abs(Character[i].l1-l1)+abs(Character[i].l2-l2); + if (diff<min) { + min=diff; + j=i; + } + } + printf ("lcd_dbar: diff=%d\n", min); + return j; +} + +void lcd_dbar (int x, int y, int dir, int max, int len1, int len2) +{ + if (bar_mode!=BAR_DUAL) + lcd_dbar_init(); + + if (len1<1) len1=1; + else if (len1>max) len1=max; + + if (len2<1) len2=1; + else if (len2>max) len2=max; + + while (max>0 && x<=COLS) { + if (len1==0) { + Segment[x][y].l1=0; + } else if (len1>=XRES) { + Segment[x][y].l1=XRES; + len1-=XRES; + } else { + Segment[x][y].l1=len1; + len1=0; + } + if (len2==0) { + Segment[x][y].l2=0; + } else if (len2>=XRES) { + Segment[x][y].l2=XRES; + len2-=XRES; + } else { + Segment[x][y].l2=len2; + len2=0; + } + max-=XRES; + x++; + } +} + +void lcd_dbar_flush (void) +{ + int i, x, y; + + for (y=0; y<=ROWS; y++) { + for (x=0; x<=COLS; x++) { + if ((Segment[x][y].l1==0 && Segment[x][y].l2==XRES) || (Segment[x][y].l1==XRES && Segment[x][y].l2==0)) + Segment[x][y].chr=lcd_dbar_char(Segment[x][y].l1, Segment[x][y].l2); + } + } + for (y=0; y<=ROWS; y++) { + for (x=0; x<=COLS; x++) { + if (Segment[x][y].l1!=-1 || Segment[x][y].l2!=-1) + Segment[x][y].chr=lcd_dbar_char(Segment[x][y].l1, Segment[x][y].l2); + } + } + + for (i=0; i<CHAR; i++) { + if (Character[i].lru==2) { + char buffer[12]; + char pixel[XRES+1]={0, 16, 24, 28, 30, 31}; + char p0=pixel[Character[i].l1]; + char p1=pixel[Character[i].l2]; + snprintf (buffer, sizeof(buffer), "\376N%c%c%c%c%c%c%c%c%c", i, p0, p0, p0, p0, p1, p1, p1, p1); + lcd_write (buffer, 11); + } + if (Character[i].lru>0) + Character[i].lru--; + } + + for (y=0; y<=ROWS; y++) { + for (x=0; x<=COLS; x++) { + if (Segment[x][y].l1!=-1 || Segment[x][y].l2!=-1) { + char buffer[6]; + snprintf (buffer, sizeof(buffer), "\376G%c%c%c", x, y, Segment[x][y].chr); + lcd_write (buffer, 5); + } + } + } +} + + +int lcd_init (char *device) +{ + if (lcd_device) free (lcd_device); + lcd_device=strdup(device); + lcd=lcd_open(); + if (lcd==-1) return -1; + + lcd_clear(); + lcd_write ("\376B", 3); // backlight on + lcd_write ("\376K", 2); // cursor off + lcd_write ("\376T", 2); // blink off + lcd_write ("\376D", 2); // line wrapping off + lcd_write ("\376R", 2); // auto scroll off + lcd_write ("\376V", 2); // GPO off + + return 0; +} + +void lcd_contrast (int contrast) +{ + char buffer[4]; + snprintf (buffer, 4, "\376P%c", contrast); + lcd_write (buffer, 3); +} + diff --git a/lcd2041.h b/lcd2041.h new file mode 100644 index 0000000..4951d4e --- /dev/null +++ b/lcd2041.h @@ -0,0 +1,14 @@ +#define ROWS 4 +#define COLS 20 +#define XRES 5 +#define YRES 8 +#define CHAR 8 + +int lcd_init (char *device); +void lcd_contrast (int contrast); +void lcd_clear (void); +void lcd_put (int x, int y, char *string); +void lcd_hbar (int x, int y, int dir, int max, int len); +void lcd_vbar (int x, int y, int dir, int max, int len); +void lcd_dbar (int x, int y, int dir, int max, int len1, int len2); +void lcd_dbar_flush (void); diff --git a/lcd4linux.c b/lcd4linux.c new file mode 100644 index 0000000..9dbe92f --- /dev/null +++ b/lcd4linux.c @@ -0,0 +1,499 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <math.h> + +#include "config.h" +#include "lcd2041.h" +#include "system.h" +#include "isdn.h" + +int tick, tack, tau; +double overload; +double temp_min, temp_max; +char *sensor; +char *row[ROWS]; + +void usage(void) +{ + printf ("LCD4Linux " VERSION " (c) 1999 Michael Reinelt <reinelt@eunet.at>"); + printf ("usage: LCD4Linux [configuration]\n"); +} + +char *parse (char *string) +{ + static char buffer[256]; + char *s=string; + char *p=buffer; + + do { + if (*s=='%') { + if (strchr("orpmlLbtdDnNiI%", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown format <%%%c> in <%s>\n", *s, string); + continue; + } + *p='%'; + *(p+1)=*s; + switch (*s) { + case 'd': + if (strchr("rwmt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown disk tag <%%i%c> in <%s>\n", *s, string); + continue; + } + *(p+2)=*s; + p+=3; + break; + case 'n': + if (strchr("rwmt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown net tag <%%i%c> in <%s>\n", *s, string); + continue; + } + *(p+2)=*s; + p+=3; + break; + case 'i': + if (strchr("iomt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown ISDN tag <%%i%c> in <%s>\n", *s, string); + continue; + } + *(p+2)=*s; + p+=3; + break; + default: + p+=2; + } + + } else if (*s=='$') { + char hv, dir; + int len=0; + hv=*++s; + if (tolower(hv)!='h' && tolower(hv)!='v') { + fprintf (stderr, "invalid bar orientation '%c' in <%s>\n", hv, string); + continue; + } + s++; + if (isdigit(*s)) len=strtol(s, &s, 10); + if (len<1 || len>255) { + fprintf (stderr, "invalid bar length in <%s>\n", string); + continue; + } + dir=*s++; + if ((tolower(hv)=='h' && dir!='l' && dir !='r') || (tolower(hv)=='v' && dir!='u' && dir !='d')) { + fprintf (stderr, "invalid bar direction '%c' in <%s>\n", dir, string); + continue; + } + *p='$'; + *(p+1)=hv; + *(p+2)=len; + if (dir=='r' || dir=='u') *(p+3)='0'; + else *(p+3)='1'; + *(p+4)=*s; + switch (*s) { + case 'd': + if (strchr("rwmt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown disk tag <$i*%c> in <%s>\n", *s, string); + continue; + } + *(p+5)=*s; + p+=6; + break; + case 'n': + if (strchr("rwmt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown net tag <$i*%c> in <%s>\n", *s, string); + continue; + } + *(p+5)=*s; + p+=6; + break; + case 'i': + if (strchr("iomt", *++s)==NULL) { + fprintf (stderr, "WARNING: unknown ISDN tag <$i*%c> in <%s>\n", *s, string); + continue; + } + *(p+5)=*s; + p+=6; + break; + default: + p+=5; + } + + } else if (*s=='\\') { + unsigned int c=0; int n; + if (*(s+1)=='\\') { + *p++='\\'; + s+=2; + } else { + sscanf (s+1, "%3o%n", &c, &n); + if (c==0 || c>255) { + fprintf (stderr, "WARNING: illegal '\\' in <%s> <%s>\n", string, s); + continue; + } + *p++=c; + s+=n; + } + + } else { + *p++=*s; + } + + } while (*s++); + + return buffer; +} + + +void display (int smooth) { + static double disk_max=1.0; + static double net_max=1.0; + double busy, load, temp, disk, net, isdn; + int disk_r, disk_w; + int net_tx, net_rx; + int isdn_usage, isdn_in, isdn_out; + char buffer[256]; + int i; + + busy=Busy(); + load=Load(); + Disk (&disk_r, &disk_w); + Net (&net_rx, &net_tx); + temp=Temperature(); + isdn_usage=Isdn(&isdn_in, &isdn_out); + + if (disk_r>disk_max) disk_max=disk_r; + if (disk_w>disk_max) disk_max=disk_w; + + if (net_rx>net_max) net_max=net_rx; + if (net_tx>net_max) net_max=net_tx; + + for (i=0; i<ROWS; i++) { + char *s=row[i]; + char *p=buffer; + do { + if (*s=='%') { + switch (*++s) { + case '%': + *p++='%'; + break; + case 'o': + p+=sprintf (p, "%s", System()); + break; + case 'r': + p+=sprintf (p, "%s", Release()); + break; + case 'p': + p+=sprintf (p, "%s", Processor()); + break; + case 'm': + p+=sprintf (p, "%d", Memory()); + break; + case 'l': + if (load<10.0) + p+=sprintf (p, "%4.2f", load); + else + p+=sprintf (p, "%4.1f", load); + break; + case 'L': + *p++=load>overload?'!':' '; + break; + case 'b': + p+=sprintf (p, "%3.0f", 100.0*busy); + break; + case 'd': + switch (*++s) { + case 'r': + disk=disk_r; + break; + case 'w': + disk=disk_w; + break; + case 'm': + disk=disk_r>disk_w?disk_r:disk_w; + break; + default: + disk=disk_r+disk_w; + break; + } + disk/=1024; + if (disk<10.0) { + p+=sprintf (p, "%4.2f", disk); + } else if (disk<100.0) { + p+=sprintf (p, "%4.1f", disk); + } else { + p+=sprintf (p, "%4.0f", disk); + } + break; + case 'D': + if (disk_r+disk_w==0) + *p++=' '; + else + *p++=disk_r>disk_w?'\176':'\177'; + break; + case 'n': + switch (*++s) { + case 'r': + net=net_rx; + break; + case 'w': + net=net_tx; + break; + case 'm': + net=net_rx>net_tx?net_rx:net_tx; + break; + default: + net=net_rx+net_tx; + break; + } + net/=1024.0; + if (net<10.0) { + p+=sprintf (p, "%4.2f", net); + } else if (net<100.0) { + p+=sprintf (p, "%4.1f", net); + } else { + p+=sprintf (p, "%4.0f", net); + } + break; + case 'N': + if (net_rx+net_tx==0) + *p++=' '; + else + *p++=net_rx>net_tx?'\176':'\177'; + break; + case 't': + p+=sprintf (p, "%5.1f", temp); + break; + case 'i': + if (isdn_usage) { + switch (*++s) { + case 'i': + isdn=isdn_in; + break; + case 'o': + isdn=isdn_out; + break; + case 'm': + isdn=isdn_in>isdn_out?isdn_in:isdn_out; + break; + default: + isdn=isdn_in+isdn_out; + break; + } + isdn/=1024.0; + if (isdn<10.0) { + p+=sprintf (p, "%4.2f", isdn); + } else if (isdn<100.0) { + p+=sprintf (p, "%4.1f", isdn); + } else { + p+=sprintf (p, "%4.0f", isdn); + } + } else { + p+=sprintf (p, "----"); + s++; + } + break; + case 'I': + if (isdn_in+isdn_out==0) + *p++=' '; + else + *p++=isdn_in>isdn_out?'\176':'\177'; + break; + } + + } else if (*s=='$') { + double val; + int hv, len, dir; + hv=*++s; + len=*++s; + dir=*++s; + switch (*++s) { + case 'l': + val=load/overload; + break; + case 'b': + val=busy; + break; + case 'd': + switch (*++s) { + case 'r': + val=disk_r/disk_max; + break; + case 'w': + val=disk_w/disk_max; + break; + case 'm': + val=(disk_r>disk_w?disk_r:disk_w)/disk_max; + break; + default: + val=(disk_r+disk_w)/(2*disk_max); + break; + } + break; + case 'n': + switch (*++s) { + case 'r': + val=net_rx/net_max; + break; + case 'w': + val=net_tx/net_max; + break; + case 'm': + val=(net_rx>net_tx?net_rx:net_tx)/net_max; + break; + default: + val=(net_rx+net_tx)/(2*net_max); + break; + } + break; + case 't': + val=(temp-temp_min)/(temp_max-temp_min); + break; + case 'i': + switch (*++s) { + case 'i': + val=isdn_in; + break; + case 'o': + val=isdn_out; + break; + case 'm': + val=isdn_in>isdn_out?isdn_in:isdn_out; + break; + default: + val=isdn_in+isdn_out; + break; + } + val/=8000.0; + break; + default: + val=0.0; + } + switch (hv) { + case 'h': + lcd_hbar (p-buffer+1, i+1, dir-'0', len*XRES, val*len*XRES); + break; + case 'H': + lcd_hbar (p-buffer+1, i+1, dir-'0', len*XRES, (double)len*XRES*log(val*len*XRES+1)/log(len*XRES)); + break; + case 'v': + lcd_vbar (p-buffer+1, i+1, dir-'0', len*YRES, val*len*XRES); + break; + } + while (len-->0) { + *p++='\t'; + } + + } else { + *p++=*s; + } + } while (*s++); + + if (smooth==0) { + p=buffer; + while (*p) { + while (*p=='\t') p++; + for (s=p; *s; s++) { + if (*s=='\t') { + *s++='\0'; + break; + } + } + if (*p) { + lcd_put (p-buffer+1, i+1, p); + } + p=s; + } + } + } +} + + +void main (int argc, char *argv[]) +{ + char *cfg_file="/etc/lcd4linux.conf"; + char *port; + int i; + int contrast; + int smooth; + + if (argc>2) { + usage(); + exit (2); + } + if (argc==2) { + cfg_file=argv[1]; + } + + set_cfg ("row1", "*** %o %r ***"); + set_cfg ("row2", "%p CPU %m MB RAM"); + set_cfg ("row3", "Busy %b%% $r50b"); + set_cfg ("row4", "Load %l$r50l"); + + set_cfg ("tick", "100"); + set_cfg ("tack", "500"); + set_cfg ("tau", "500"); + set_cfg ("contrast", "140"); + set_cfg ("overload", "2.0"); + set_cfg ("temp_min", "20"); + set_cfg ("temp_max", "70"); + + set_cfg ("fifo", "/var/run/LCD4Linux"); + + if (read_cfg (cfg_file)==-1) + exit (1); + + port=get_cfg("port"); + sensor=get_cfg("temperature"); + tick=atoi(get_cfg("tick")); + tack=atoi(get_cfg("tack")); + tau=atoi(get_cfg("tau")); + contrast=atoi(get_cfg("contrast")); + overload=atof(get_cfg("overload")); + temp_min=atof(get_cfg("temp_min")); + temp_max=atof(get_cfg("temp_max")); + + if (port==NULL || *port=='\0') { + fprintf (stderr, "%s: missing 'port' entry!\n", cfg_file); + exit (1); + } + + for (i=0; i<ROWS; i++) { + char buffer[8]; + snprintf (buffer, sizeof(buffer), "row%d", i+1); + row[i]=strdup(parse(get_cfg(buffer))); + } + + lcd_init(port); + lcd_clear(); + lcd_contrast (contrast); + + lcd_put (1, 1, "** LCD4Linux " VERSION " **"); + lcd_put (1, 3, "(c) 1999 M. Reinelt"); + + + { + int a, b, c, d; + + lcd_dbar_init(); + for (a=0; a<40; a++) { + b=40-a; + c=2*a; + d=c+a; + lcd_dbar (2, 1, 0, 80, a, b); + lcd_dbar (2, 2, 0, 80, c, d); + lcd_dbar_flush(); + usleep( 300*1000); + } + } + + sleep (2); + lcd_clear(); + + smooth=0; + while (1) { + display(smooth); + smooth+=tick; + if (smooth>tack) smooth=0; + usleep(1000*tick); + } +} diff --git a/lcd4linux.h b/lcd4linux.h new file mode 100644 index 0000000..f7c91ae --- /dev/null +++ b/lcd4linux.h @@ -0,0 +1,6 @@ +extern int tick; +extern int tack; +extern int tau; +extern char *sensor; + + diff --git a/system.c b/system.c new file mode 100644 index 0000000..0d3679f --- /dev/null +++ b/system.c @@ -0,0 +1,306 @@ +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <ctype.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <asm/param.h> + +#include "system.h" +#include "filter.h" +#include "lcd4linux.h" + +char *System(void) +{ + static char buffer[32]=""; + struct utsname ubuf; + + if (*buffer=='\0') { + if (uname(&ubuf)==-1) { + perror ("uname() failed"); + strcpy (buffer, "unknown"); + } else { + strncpy (buffer, ubuf.sysname, sizeof(buffer)); + } + } + return buffer; +} + +char *Release(void) +{ + static char buffer[32]=""; + struct utsname ubuf; + + if (*buffer=='\0') { + if (uname(&ubuf)==-1) { + perror ("uname() failed"); + strcpy (buffer, "unknown"); + } else { + strncpy (buffer, ubuf.release, sizeof(buffer)); + } + } + return buffer; +} + + +char *Processor(void) +{ + static char buffer[16]=""; + struct utsname ubuf; + + if (*buffer=='\0') { + if (uname(&ubuf)==-1) { + perror ("uname() failed"); + strcpy (buffer, "unknown"); + } else { + strncpy (buffer, ubuf.machine, sizeof(buffer)); + } + } + return buffer; +} + + +int Memory(void) +{ + static int value=-1; + struct stat buf; + + if (value==-1) { + if (stat("/proc/kcore", &buf)==-1) { + perror ("stat(/proc/kcore) failed"); + value=0; + } else { + value=buf.st_size>>20; + } + } + return value; +} + + +double Load (void) +{ + static int fd=-2; + char buffer[16]; + static double value=0; + static time_t now=0; + + if (fd==-1) return 0; + + if (time(NULL)==now) return value; + time(&now); + + if (fd==-2) { + fd=open("/proc/loadavg", O_RDONLY); + if (fd==-1) { + perror ("open(/proc/loadavg) failed"); + return 0; + } + } + if (lseek(fd, 0L, SEEK_SET)!=0) { + perror("lseek(/proc/loadavg) failed"); + fd=-1; + return 0; + } + if (read (fd, &buffer, sizeof(buffer)-1)==-1) { + perror("read(/proc/loadavg) failed"); + fd=-1; + return 0; + } + if (sscanf(buffer, "%lf", &value)<1) { + fprintf(stderr, "scanf(/proc/loadavg) failed\n"); + fd=-1; + return 0; + } + return (value); +} + + +double Busy (void) +{ + static int fd=-2; + char buffer[64]; + unsigned long v1, v2, v3, v4; + double busy, idle; + + if (fd==-1) return 0; + + if (fd==-2) { + fd=open("/proc/stat", O_RDONLY); + if (fd==-1) { + perror ("open(proc/stat) failed"); + return 0; + } + } + if (lseek(fd, 0L, SEEK_SET)!=0) { + perror ("lseek(/proc/stat) failed"); + fd=-1; + return 0; + } + if (read (fd, &buffer, sizeof(buffer)-1)==-1) { + perror ("read(/proc/stat) failed"); + fd=-1; + return 0; + } + if (sscanf(buffer, "%*s %lu %lu %lu %lu\n", &v1, &v2, &v3, &v4)<4) { + fprintf (stderr, "scanf(/proc/stat) failed\n"); + fd=-1; + return 0; + } + + busy=smooth("cpu_busy", 500, v1+v2+v3); + idle=smooth("cpu_idle", 500, v4); + + if (busy+idle==0.0) + return 0.0; + else + return busy/(busy+idle); +} + + +int Disk (int *r, int *w) +{ + char buffer[4096], *p; + static int fd=-2; + unsigned long r1, r2, r3, r4; + unsigned long w1, w2, w3, w4; + + *r=0; + *w=0; + + if (fd==-1) return 0; + + if (fd==-2) { + fd = open("/proc/stat", O_RDONLY | O_NDELAY); + if (fd==-1) { + perror ("open(/proc/stat) failed"); + return 0; + } + } + + if (lseek(fd, 0L, SEEK_SET)!=0) { + perror ("lseek(/proc/stat) failed"); + fd=-1; + return 0; + } + if (read (fd, &buffer, sizeof(buffer)-1)==-1) { + perror ("read(/proc/stat) failed"); + fd=-1; + return 0; + } + p=strstr(buffer, "disk_rblk"); + if (p==NULL) { + fprintf (stderr, "parse(/proc/stat) failed: no disk_rblk line\n"); + fd=-1; + return 0; + } + if (sscanf(p+9, "%lu %lu %lu %lu\n", &r1, &r2, &r3, &r4)<4) { + fprintf (stderr, "scanf(/proc/stat) failed\n"); + fd=-1; + return 0; + } + p=strstr(buffer, "disk_wblk"); + if (p==NULL) { + fprintf (stderr, "parse(/proc/stat) failed: no disk_wblk line\n"); + fd=-1; + return 0; + } + if (sscanf(p+9, "%lu %lu %lu %lu\n", &w1, &w2, &w3, &w4)<4) { + fprintf (stderr, "scanf(/proc/stat) failed\n"); + fd=-1; + return 0; + } + + *r=smooth ("disk_r", 500, r1+r2+r3+r4); + *w=smooth ("disk_w", 500, w1+w2+w3+w4); + + return *r+*w; +} + + +int Net (int *rx, int *tx) +{ + char buffer[4096], *p, *s; + static int fd=-2; + unsigned long pkg_rx, pkg_tx; + + *rx=0; + *tx=0; + + if (fd==-1) return 0; + + if (fd==-2) { + fd = open("/proc/net/dev", O_RDONLY | O_NDELAY); + if (fd==-1) { + perror ("open(/proc/net/dev) failed"); + return 0; + } + } + + if (lseek(fd, 0L, SEEK_SET)!=0) { + perror ("lseek(/proc/net/dev) failed"); + fd=-1; + return 0; + } + if (read (fd, &buffer, sizeof(buffer)-1)==-1) { + perror ("read(/proc/net/dev) failed"); + fd=-1; + return 0; + } + pkg_rx=0; + pkg_tx=0; + p=buffer; + while ((s=strsep(&p, "\n"))) { + unsigned long r, t; + if (sscanf (s, " eth%*d:%*d: %ld %*d %*d %*d %*d %ld", &r, &t)==2 || + sscanf (s, " eth%*d: %ld %*d %*d %*d %*d %ld", &r, &t)==2) { + pkg_rx+=r; + pkg_tx+=t; + } + } + *rx=smooth("net_rx", 500, pkg_rx); + *tx=smooth("net_tx", 500, pkg_tx); + + return *rx+*tx; +} + + +double Temperature (void) +{ + static int fd=-2; + char buffer[32]; + static double value=0.0; + static time_t now=0; + + if (fd==-1) return 0; + + if (time(NULL)==now) return value; + time(&now); + + if (fd==-2) { + fd=open(sensor, O_RDONLY); + if (fd==-1) { + fprintf (stderr, "open (%s) failed: %s\n", sensor, strerror(errno)); + return 0; + } + } + if (lseek(fd, 0L, SEEK_SET)!=0) { + fprintf (stderr, "lseek(%s) failed: %s\n", sensor, strerror(errno)); + fd=-1; + return 0; + } + if (read (fd, &buffer, sizeof(buffer)-1)==-1) { + fprintf (stderr, "read(%s) failed: %s\n", sensor, strerror(errno)); + fd=-1; + return 0; + } + if (sscanf(buffer, "%*f %*f %lf", &value)<1) { + fprintf (stderr, "scanf(%s) failed\n", sensor); + fd=-1; + return 0; + } + return (value); +} diff --git a/system.h b/system.h new file mode 100644 index 0000000..d3e3e28 --- /dev/null +++ b/system.h @@ -0,0 +1,9 @@ +char *System (void); +char *Release (void); +char *Processor (void); +int Memory (void); +double Load (void); +double Busy (void); +int Disk (int *r, int *w); +int Net (int *r, int *w); +double Temperature (void); |