aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile12
-rw-r--r--MatrixOrbital.c49
-rw-r--r--config.c98
-rw-r--r--config.h3
-rw-r--r--display.c57
-rw-r--r--display.h30
-rw-r--r--filter.c117
-rw-r--r--filter.h2
-rw-r--r--isdn.c98
-rw-r--r--isdn.h1
-rw-r--r--lcd2041.c314
-rw-r--r--lcd2041.h14
-rw-r--r--lcd4linux.c499
-rw-r--r--lcd4linux.h6
-rw-r--r--system.c306
-rw-r--r--system.h9
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);
diff --git a/isdn.c b/isdn.c
new file mode 100644
index 0000000..fab470a
--- /dev/null
+++ b/isdn.c
@@ -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();
+}
+
diff --git a/isdn.h b/isdn.h
new file mode 100644
index 0000000..62f1979
--- /dev/null
+++ b/isdn.h
@@ -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);