Initial revision
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
Object methods and properties and some vars
|
||||
|
||||
Tcomms
|
||||
Properties
|
||||
int InboundFD (for select to watch if>0)
|
||||
IMODE imode {none,polled,fd} (method for reading data)
|
||||
Tconfig config
|
||||
Methods
|
||||
ParseConfig(TConfig config)
|
||||
Init
|
||||
poll
|
||||
writechar
|
||||
writestr
|
||||
|
||||
Tserial
|
||||
Private Vars
|
||||
char port[]
|
||||
int speed
|
||||
Properties
|
||||
|
||||
|
||||
|
||||
Tdriver
|
||||
Properties
|
||||
Tconfig config
|
||||
int backlight_state
|
||||
int disp_width
|
||||
int disp_height
|
||||
Methods
|
||||
Init
|
||||
ClearScr
|
||||
NewCustomChar(struct CustChar defination)
|
||||
PutCustChar(zoff,yoff,char)
|
||||
PutChar(xoff,yoff,char)
|
||||
PlaceString(xoff,yoff,string)
|
||||
DrawHorizBar(xoff,yoff,chwidth,percentage)
|
||||
DrawVertBar(xoff,yoff,chheight,percentage)
|
||||
|
||||
|
||||
|
||||
Tdisplay
|
||||
Properties
|
||||
Tdriver driver
|
||||
Tconfig config
|
||||
int RefreshInterval (for clock would be 500 for every half second)
|
||||
Methods
|
||||
HardInit (called once on prog start)
|
||||
Init (called on every new cycle)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
LCDproc suggestion object hierarchy
|
||||
|
||||
Tdriver
|
||||
TVirtualDriver
|
||||
TMtxOrbDriver
|
||||
TTextDriver
|
||||
|
||||
Tcomms
|
||||
TSerial
|
||||
TParallel
|
||||
TSCSI
|
||||
|
||||
Tdisplay
|
||||
Tclock_dsp
|
||||
Tmail_dsp
|
||||
Tcpustate_dsp
|
||||
Tcpugraph_dsp
|
||||
Tmeminf_dsp
|
||||
Tuptime_dsp
|
||||
Txload_dsp
|
||||
Tcredits_dsp
|
||||
Theartbeat_dsp
|
||||
Tstub_dsp
|
||||
Tusercfg_dsp
|
||||
|
||||
Tremote
|
||||
Ttcpsockd
|
||||
TUNIXsockd
|
||||
|
||||
Tchannel
|
||||
Ttcpsocket
|
||||
TUNIXsocket
|
||||
|
||||
Tconfig
|
||||
|
||||
Tfeedback
|
||||
TMtxOrb_keypad
|
||||
Tserial_buttons
|
||||
|
||||
Tschedular
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
Object brief descriptions
|
||||
|
||||
Tdriver (and decendants) provide manipulation of the physical
|
||||
LCD panel including backlight, typeface loading, etc.
|
||||
Tdriver will provide default methods for tasks such as
|
||||
text centering
|
||||
scrolling
|
||||
screen clearing
|
||||
etc
|
||||
TVirtualDriver could act as a frame buffer / virtual display.
|
||||
This would allow several display objects to access the (virtual)
|
||||
display in a single cycle and then the virtual driver can flush
|
||||
the changes from the last display (delta display) in a single pass.
|
||||
This provides a portable way to implement display objects
|
||||
(like the heartbeat which only changes one character at a time)
|
||||
but overlap a standard full screen display
|
||||
|
||||
|
||||
Tcomms (and decendants) transmit and receive all data to and
|
||||
from the communications interfaces. Tdriver and Tfeedback will
|
||||
use these objects directly.
|
||||
|
||||
Tdisplay (and decendants) generate the actual display information
|
||||
by manipulating the Tdriver object which has been given to it.
|
||||
The Tdriver object should usually be a TVirtualDriver descendant.
|
||||
|
||||
Tremote (and decendants) create, keep track of and ultimately destroy
|
||||
Tchannel objects. Each Tchannel can potentitally be an external
|
||||
connection to a remote client. The remote client can generate
|
||||
either complete screens in a similar style to a Tdisplay object with
|
||||
Tchannel using a Tstub_dsp to generate the screen based on info
|
||||
supplied to it or it can feed data into an existing Tdisplay object
|
||||
(Tchannel will do this by setting Tdisplay properties).
|
||||
|
||||
Tconfig is responsible for parsing the command line and reading/re-reading
|
||||
the contents of a configuration file.
|
||||
|
||||
Tfeedback (and its descendants) may communicate with a Tcomms object to
|
||||
retrieve information from a keypad or other input device.
|
||||
|
||||
Tschedular is responsible for the overall co-ordination of everything.
|
||||
|
||||
|
||||
Other notes:
|
||||
I can't decide things like "should scroll stuff be down to Tdriver
|
||||
or Tdisplay?".
|
||||
Some sort of Thash would be a useful way of passing data from
|
||||
sockets to display objects as well
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/***********************************************
|
||||
**
|
||||
** cfg.c v0.01
|
||||
**
|
||||
** Generic config file handler
|
||||
** (c) Gareth Watts 1998
|
||||
** gareth@omnipotent.net
|
||||
**
|
||||
** Alpha code as of 980601
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg.h"
|
||||
|
||||
|
||||
|
||||
/**************************
|
||||
* PUBLIC METHODS
|
||||
*/
|
||||
|
||||
void cfg_free(cfg *self) {
|
||||
struct cfg_node *ptr, *nextptr;
|
||||
int i;
|
||||
|
||||
for(i=0;i<CFG_HASHSIZE;i++) {
|
||||
if(self->cfg_hash[i]) {
|
||||
for(ptr=self->cfg_hash[i];ptr;ptr=nextptr) {
|
||||
nextptr=ptr->next;
|
||||
free(ptr->optname);
|
||||
free(ptr->optvalue);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(self->filename);
|
||||
free(self->lasterror);
|
||||
self->_queuefree(self);
|
||||
free(self);
|
||||
}
|
||||
|
||||
|
||||
#define CFG_BUZSIZE 4096
|
||||
int cfg_openfile(cfg *self,char *fn,int mode) {
|
||||
char buffer[CFG_BUZSIZE];
|
||||
char *keyname,*keyvalue;
|
||||
int comment;
|
||||
FILE *fh;
|
||||
|
||||
self->filename=strdup(fn);
|
||||
fh=fopen(fn,"r");
|
||||
if (!fh) {
|
||||
if (mode==CFG_READONLY) {
|
||||
self->lasterror=strdup(strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
return(0); /* read/write but file not found */
|
||||
}
|
||||
|
||||
// READ AND PARSE FILE HERE
|
||||
while(feof(fh)==0) {
|
||||
fgets(buffer,CFG_BUZSIZE-1,fh);
|
||||
if (strlen(buffer)) {
|
||||
if (buffer[strlen(buffer)-1]=='\n') {
|
||||
buffer[strlen(buffer)-1]='\0';
|
||||
}
|
||||
if (buffer[0]=='#') {
|
||||
comment=1;
|
||||
} else {
|
||||
comment=0;
|
||||
}
|
||||
} else { comment=1;}
|
||||
if (!comment&&self->_splitline(self,buffer,&keyname,&keyvalue)) {
|
||||
return(1); /* memory error or somesuch */
|
||||
}
|
||||
if (!comment&&keyname&&keyvalue) {
|
||||
if (!self->_lookup(self,keyname)) {
|
||||
self->_insert(self,keyname,keyvalue,0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
char *cfg_getstring(cfg *self,char *keyname) {
|
||||
return(self->_lookup(self,keyname));
|
||||
}
|
||||
|
||||
|
||||
int cfg_getint(cfg *self,char *keyname) {
|
||||
int result=0;
|
||||
char *keydata;
|
||||
|
||||
keydata=self->_lookup(self,keyname);
|
||||
if (keydata)
|
||||
sscanf(keydata,"%d",&result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/* This is virtually useless due to rounding errors */
|
||||
float cfg_getfloat(cfg *self,char *keyname) {
|
||||
float result=0.0;
|
||||
char *keydata;
|
||||
|
||||
keydata=self->_lookup(self,keyname);
|
||||
if (keydata)
|
||||
sscanf(keydata,"%f",&result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
int cfg_setstring(cfg *self,char *keyname, char *keyvalue) {
|
||||
return(self->_set(self,keyname,keyvalue));
|
||||
}
|
||||
|
||||
|
||||
int cfg_setint(cfg *self,char *keyname, int keyvalue) {
|
||||
char buffer[200];
|
||||
|
||||
sprintf(buffer,"%d",keyvalue);
|
||||
return(self->_set(self,keyname,buffer));
|
||||
}
|
||||
|
||||
int cfg_setfloat(cfg *self,char *keyname, float keyvalue) {
|
||||
char buffer[200];
|
||||
|
||||
sprintf(buffer,"%f",keyvalue);
|
||||
return(self->_set(self,keyname,buffer));
|
||||
}
|
||||
|
||||
int cfg_flush(cfg *self) {
|
||||
if (self->filemode==CFG_READONLY) {
|
||||
return(0);
|
||||
} else {
|
||||
return(self->_flush(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int cfg_autoflush(cfg *self,int aflush) {
|
||||
self->aflush=(aflush>0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************
|
||||
* PRIVATE/INTERNAL METHODS
|
||||
*/
|
||||
|
||||
int _cfg_init(cfg *self) {
|
||||
memset(self->cfg_hash,0,sizeof(self->cfg_hash));
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int _cfg_queuepush(cfg *self, struct cfg_node *node) {
|
||||
struct cfg_queuenode *ptr;
|
||||
|
||||
ptr=(struct cfg_queuenode *)calloc(1,sizeof(struct cfg_queuenode));
|
||||
if (!ptr) return(1);
|
||||
ptr->ref=node;
|
||||
if (self->cfg_newsttail) {
|
||||
self->cfg_newsttail->next=ptr;
|
||||
self->cfg_newsttail=ptr;
|
||||
} else {
|
||||
self->cfg_newsthead=self->cfg_newsttail=ptr;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
struct cfg_queuenode *_cfg_queuenext(cfg *self, struct cfg_queuenode *last) {
|
||||
if (last) {
|
||||
return(last->next);
|
||||
} else {
|
||||
return(self->cfg_newsthead);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int _cfg_queuefree(cfg *self) {
|
||||
struct cfg_queuenode *ptr,*next;
|
||||
|
||||
for(ptr=self->cfg_newsthead;ptr;ptr=next) {
|
||||
next=ptr->next;
|
||||
free(ptr);
|
||||
}
|
||||
self->cfg_newsthead=self->cfg_newsttail=NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int _cfg_getkey(cfg *self,char *str) {
|
||||
unsigned int total;
|
||||
int i=1;
|
||||
int j=0;
|
||||
|
||||
total=(*str)-0x20;
|
||||
str++;
|
||||
while(*str) {
|
||||
total+=i*((*str)-0x20);
|
||||
str++;
|
||||
i+=(33+j++)*j;
|
||||
}
|
||||
return(total % CFG_HASHSIZE);
|
||||
}
|
||||
|
||||
|
||||
int _cfg_insert(cfg *self,char *keyname, char *keyval,int dirty) {
|
||||
int key,match=0;
|
||||
struct cfg_node *ptr,*nextptr;;
|
||||
|
||||
key=self->_getkey(self,keyname);
|
||||
if (!self->cfg_hash[key]) {
|
||||
self->cfg_hash[key]=(struct cfg_node *)calloc(1,sizeof(struct cfg_node));
|
||||
if (!(self->cfg_hash[key]->optname=strdup(keyname))) {
|
||||
return(1);
|
||||
}
|
||||
if (!(self->cfg_hash[key]->optvalue=strdup(keyval))) {
|
||||
return(1);
|
||||
}
|
||||
if (dirty) self->_queuepush(self,self->cfg_hash[key]);
|
||||
} else {
|
||||
for(nextptr=self->cfg_hash[key];(nextptr)&&(!match);nextptr=ptr->next) {
|
||||
ptr=nextptr;
|
||||
match=(strcasecmp(ptr->optname,keyname)==0);
|
||||
}
|
||||
|
||||
if (match) { /* node already exists / overwrite */
|
||||
free(ptr->optvalue);
|
||||
ptr->dirty=dirty;
|
||||
} else { /* new node */
|
||||
ptr->next=(struct cfg_node *)calloc(1,sizeof(struct cfg_node));
|
||||
ptr=ptr->next;
|
||||
if (!(ptr->optname=strdup(keyname))) {
|
||||
return(1);
|
||||
}
|
||||
if (dirty) self->_queuepush(self,ptr);
|
||||
}
|
||||
if (!(ptr->optvalue=strdup(keyval))) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
struct cfg_node *_cfg_getnode(cfg *self, char *keyname) {
|
||||
int key;
|
||||
struct cfg_node *ptr,*next;
|
||||
int match=0;
|
||||
|
||||
key=self->_getkey(self,keyname);
|
||||
if (!self->cfg_hash[key])
|
||||
return(NULL);
|
||||
for(next=self->cfg_hash[key];next&&!match;next=ptr->next) {
|
||||
ptr=next;
|
||||
match=(strcasecmp(ptr->optname,keyname)==0);
|
||||
}
|
||||
if (match)
|
||||
return(ptr);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
char *_cfg_lookup(cfg *self,char *keyname) {
|
||||
struct cfg_node *ptr;
|
||||
|
||||
ptr=self->_getnode(self,keyname);
|
||||
if (ptr)
|
||||
return(ptr->optvalue);
|
||||
else
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
int _cfg_cleardirty(cfg *self,struct cfg_node *ptr) {
|
||||
ptr->dirty=0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int _cfg_set(cfg *self,char *keyname,char *keyvalue) {
|
||||
int key;
|
||||
|
||||
key=self->_getkey(self,keyname);
|
||||
if (self->_insert(self,keyname,keyvalue,1)!=0) {
|
||||
return(1); /* error */
|
||||
}
|
||||
if (self->aflush) {
|
||||
return(self->flush(self));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int _cfg_splitline(cfg *self,char *src, char **f, char **s) {
|
||||
char *brkpoint;
|
||||
int offset,slen,fpos;
|
||||
static char first[4096],second[4096];
|
||||
|
||||
*f=*s=NULL;
|
||||
if ((brkpoint=strchr(src,'='))==NULL) {
|
||||
return(0);
|
||||
}
|
||||
offset=brkpoint-src;
|
||||
slen=strlen(src);
|
||||
if (offset==slen-1) {
|
||||
return(0);
|
||||
}
|
||||
if (offset>4094) {offset=4094;}
|
||||
|
||||
memset(first,0,4096);
|
||||
memset(second,0,4096);
|
||||
strncpy(first,src,offset);
|
||||
strncpy(second,brkpoint+1,4095);
|
||||
|
||||
fpos=strlen(first)-1;
|
||||
while((first[fpos]==' ')&&fpos) {
|
||||
first[fpos]='\0';
|
||||
fpos--;
|
||||
}
|
||||
*f=first;
|
||||
for(*s=second;(**s)&&(**s==' ');(*s)++);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CFGF_MAXLINES 50000
|
||||
#define CFGF_LINELEN 4096
|
||||
int _cfg_realflush(cfg *self) {
|
||||
char *outbuf[CFGF_MAXLINES];
|
||||
char buffer[CFGF_LINELEN];
|
||||
int linenum=0;
|
||||
int comment,i;
|
||||
char *keyname,*keyvalue;
|
||||
struct cfg_queuenode *qptr;
|
||||
struct cfg_node *ptr;
|
||||
FILE *fh;
|
||||
char *rd;
|
||||
|
||||
fh=fopen(self->filename,"r");
|
||||
if (fh) {
|
||||
while((feof(fh)==0)&&(linenum<CFGF_MAXLINES)) {
|
||||
rd=fgets(buffer,CFGF_LINELEN-1,fh);
|
||||
if (rd&&strlen(buffer)) {
|
||||
if (buffer[strlen(buffer)-1]=='\n') {
|
||||
buffer[strlen(buffer)-1]='\0';
|
||||
}
|
||||
if (buffer[0]=='#') {
|
||||
comment=1;
|
||||
} else {
|
||||
comment=0;
|
||||
}
|
||||
if (comment) {
|
||||
outbuf[linenum]=strdup(buffer);
|
||||
} else {
|
||||
if (self->_splitline(self,buffer,&keyname,&keyvalue)) {
|
||||
fclose(fh);
|
||||
return(1); /* memory error or somesuch */
|
||||
}
|
||||
if ((keyname)&&(ptr=self->_getnode(self,keyname))&&(ptr->dirty)) {
|
||||
sprintf(buffer,"%s = %s",ptr->optname,ptr->optvalue);
|
||||
outbuf[linenum]=strdup(buffer);
|
||||
self->_cleardirty(self,ptr);
|
||||
} else {
|
||||
outbuf[linenum]=strdup(buffer);
|
||||
}
|
||||
}
|
||||
linenum++;
|
||||
}
|
||||
}
|
||||
fclose(fh);
|
||||
}
|
||||
for(qptr=self->_queuenext(self,NULL);qptr;qptr=self->_queuenext(self,qptr)) {
|
||||
sprintf(buffer,"%s=%s",qptr->ref->optname,qptr->ref->optvalue);
|
||||
outbuf[linenum]=strdup(buffer);
|
||||
linenum++;
|
||||
}
|
||||
fh=fopen(self->filename,"w");
|
||||
if (!fh) {
|
||||
self->lasterror=strdup(strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
for(i=0;i<linenum;i++) {
|
||||
fprintf(fh,"%s\n",outbuf[i]);
|
||||
free(outbuf[i]);
|
||||
}
|
||||
fclose(fh);
|
||||
self->_queuefree(self);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************
|
||||
* THE CONSTRUCTOR
|
||||
*/
|
||||
|
||||
cfg *cfg_new() {
|
||||
cfg *ptr;
|
||||
|
||||
ptr=(cfg *)calloc(1,sizeof(cfg));
|
||||
if (!ptr) return(NULL);
|
||||
|
||||
ptr->getstring=cfg_getstring;
|
||||
ptr->getint=cfg_getint;
|
||||
ptr->getfloat=cfg_getfloat;
|
||||
ptr->openfile=cfg_openfile;
|
||||
ptr->setstring=cfg_setstring;
|
||||
ptr->setint=cfg_setint;
|
||||
ptr->setfloat=cfg_setfloat;
|
||||
ptr->flush=cfg_flush;
|
||||
ptr->autoflush=cfg_autoflush;
|
||||
ptr->free=cfg_free;
|
||||
|
||||
ptr->_getkey=_cfg_getkey;
|
||||
ptr->_insert=_cfg_insert;
|
||||
ptr->_lookup=_cfg_lookup;
|
||||
ptr->_cleardirty=_cfg_cleardirty;
|
||||
ptr->_set=_cfg_set;
|
||||
ptr->_splitline=_cfg_splitline;
|
||||
ptr->_queuepush=_cfg_queuepush;
|
||||
ptr->_queuenext=_cfg_queuenext;
|
||||
ptr->_queuefree=_cfg_queuefree;
|
||||
ptr->_getnode=_cfg_getnode;
|
||||
ptr->_flush=_cfg_realflush;
|
||||
|
||||
if (_cfg_init(ptr)) return(NULL);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/***********************************************
|
||||
**
|
||||
** cfg.h v0.01
|
||||
**
|
||||
** Generic config file handler
|
||||
** (c) Gareth Watts 1998
|
||||
*/
|
||||
|
||||
|
||||
#define CFG_READONLY 1
|
||||
#define CFG_READWRITE 2
|
||||
|
||||
|
||||
struct cfg_node {
|
||||
char *optname;
|
||||
char *optvalue;
|
||||
int dirty;
|
||||
struct cfg_node *next;
|
||||
};
|
||||
|
||||
|
||||
struct cfg_queuenode {
|
||||
struct cfg_node *ref;
|
||||
struct cfg_queuenode *next;
|
||||
};
|
||||
|
||||
|
||||
#define CFG_HASHSIZE 1297
|
||||
typedef struct cfg {
|
||||
|
||||
// PUBLIC METHODS
|
||||
void (*free)(struct cfg *self);
|
||||
int (*openfile)(struct cfg *self,char *fn,int mode);
|
||||
int (*autoflush)(struct cfg *self,int flushmode);
|
||||
char *(*getstring)(struct cfg *self,char *key);
|
||||
int (*getint)(struct cfg *self,char *key);
|
||||
float (*getfloat)(struct cfg *self,char *key);
|
||||
int (*setstring)(struct cfg *self,char *key, char *value);
|
||||
int (*setint)(struct cfg *self,char *key, int value);
|
||||
int (*setfloat)(struct cfg *self,char *key, float value);
|
||||
int (*flush)(struct cfg *self);
|
||||
|
||||
// PUBLIC DATA
|
||||
char *lasterror;
|
||||
|
||||
|
||||
// PRIVATE METHODS
|
||||
int (*_init)(struct cfg *self);
|
||||
int (*_getkey)(struct cfg *self,char *str);
|
||||
int (*_insert)(struct cfg *self,char *keyname,char *keyval,int dirty);
|
||||
struct cfg_node *(*_getnode)(struct cfg *self,char *keyname);
|
||||
char *(*_lookup)(struct cfg *self,char *keyname);
|
||||
int (*_cleardirty)(struct cfg *self,struct cfg_node *ptr);
|
||||
int (*_splitline)(struct cfg *self,char *src, char **f, char **s);
|
||||
int (*_set)(struct cfg *self, char *keyname, char *keyvalue);
|
||||
int (*_queuepush)(struct cfg *self, struct cfg_node *node);
|
||||
struct cfg_queuenode *(*_queuenext)(struct cfg *self, struct cfg_queuenode *last);
|
||||
int (*_queuefree)(struct cfg *self);
|
||||
int (*_flush)(struct cfg *self);
|
||||
|
||||
// PRIVATE DATA
|
||||
struct cfg_node *cfg_hash[CFG_HASHSIZE];
|
||||
struct cfg_queuenode *cfg_newsthead;
|
||||
struct cfg_queuenode *cfg_newsttail;
|
||||
char *filename;
|
||||
int filemode;
|
||||
int aflush;
|
||||
} cfg;
|
||||
|
||||
cfg *cfg_new();
|
||||
@@ -0,0 +1,76 @@
|
||||
/*********************************************
|
||||
** cfg.c example
|
||||
** gareth@omnipotent.net 1/June/1998
|
||||
**
|
||||
** This code will create cfg_testfile.cfg if
|
||||
** it doesn't already exist and set some
|
||||
** values within it. Simple really.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cfg.h"
|
||||
|
||||
|
||||
#define TESTFILE "cfg_testfile.cfg"
|
||||
|
||||
int main() {
|
||||
cfg *cfgfile;
|
||||
|
||||
/* First create our object */
|
||||
if ((cfgfile=cfg_new())==NULL) {
|
||||
printf("Error creating config object\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
/* Then find a config file to open */
|
||||
if (cfgfile->openfile(cfgfile,TESTFILE,CFG_READWRITE)!=0) {
|
||||
printf("Error reading file: %s\n",cfgfile->lasterror);
|
||||
cfgfile->free(cfgfile);
|
||||
}
|
||||
|
||||
/* Save to disk on every update */
|
||||
cfgfile->autoflush(cfgfile,1);
|
||||
|
||||
/* print out the current settings - Will return NULL if */
|
||||
/* they don't currently exist (eg. new file) */
|
||||
printf("'A test string' is set to '%s'\n",
|
||||
cfgfile->getstring(cfgfile,"A test string"));
|
||||
printf("'A test integer' is set to %d\n\n",
|
||||
cfgfile->getint(cfgfile,"A test integer"));
|
||||
|
||||
/* set to some new values */
|
||||
cfgfile->setstring(cfgfile,"A test string","Marvin the paranoid android");
|
||||
cfgfile->setint(cfgfile,"A test integer",42);
|
||||
|
||||
/* print out the new settings */
|
||||
printf("'A test string' is now set to '%s'\n",
|
||||
cfgfile->getstring(cfgfile,"A test string"));
|
||||
printf("'A test integer' is now set to %d\n\n",
|
||||
cfgfile->getint(cfgfile,"A test integer"));
|
||||
|
||||
|
||||
/* set the values to something else with autoflush off */
|
||||
cfgfile->autoflush(cfgfile,0);
|
||||
cfgfile->setstring(cfgfile,"A test string","Life, don't talk to me about life");
|
||||
cfgfile->setint(cfgfile,"A test integer",417362);
|
||||
|
||||
/* print out the new settings */
|
||||
printf("'A test string' is finally set to '%s'\n",
|
||||
cfgfile->getstring(cfgfile,"A test string"));
|
||||
printf("'A test integer' is finally set to %d\n\n",
|
||||
cfgfile->getint(cfgfile,"A test integer"));
|
||||
|
||||
/* flush the last set of data to disk as autoflush is off */
|
||||
cfgfile->flush(cfgfile);
|
||||
|
||||
|
||||
/* cleanup */
|
||||
|
||||
cfgfile->free(cfgfile);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
##########################
|
||||
# Test file thingy! #
|
||||
##########################
|
||||
|
||||
# A string of some sort...
|
||||
A test string = Life, don't talk to me about life
|
||||
# An integer...
|
||||
A test integer = 417362
|
||||
|
||||
My flag = yes
|
||||
My other flag = true
|
||||
|
||||
#################### Here's a big-ass comment! ############################################################################################ See, it goes on for a long time! ####################################################
|
||||
|
||||
And stuff = Hell, yeah!
|
||||
@@ -0,0 +1,73 @@
|
||||
1998-04-26: Scott
|
||||
all: Implemented logical/physical drivers.. Whew!
|
||||
main.c, mode.c, lcd.* have changed, and I've added text.* and
|
||||
MtxOrb.* driver files...
|
||||
New commandline option "-l driver" selects a driver.
|
||||
|
||||
1998-04-21: Scott
|
||||
all: Lots of updates... (patches, etc)
|
||||
Implemented a frame buffer, and custom characters...
|
||||
Added lots of comments, and cleaned a few things...
|
||||
Added a few function to lcd.c
|
||||
|
||||
1998-03-22: Scott
|
||||
main.c: Should exit cleanly now, always... It sometimes wouldn't, if killed
|
||||
by init at shutdown... (it would get stuck in a usleep for too
|
||||
long, and then get killed instead of shutting down)
|
||||
main.c: Changed timing method... Sequences now specify their length in
|
||||
TIME_UNITs. A time unit is 1/8th of a second. This should make
|
||||
blinking and other such things easy...
|
||||
main.c: Removed command line options to specify timings... Why would the
|
||||
user really need to change that anyway?
|
||||
main.c: A few mode-feedback things are implemented: blinking, and backlight
|
||||
on/off stuff...
|
||||
mode.c: Xload_screen now sends feedback to toggle blinking for a high load,
|
||||
or turn the backlight off for no load...
|
||||
|
||||
1998-03-13: Scott
|
||||
Makefile: Installs man page in /usr/local/man/man1...
|
||||
main.c: Now detects previously running lcdproc.
|
||||
lock.?: New files for detecting another lcdproc...
|
||||
Now detects an already-running process, and gets its pid. So far,
|
||||
it just exits when this happens.
|
||||
|
||||
1998-02-28: Scott
|
||||
Makefile: Now handles installation with "make install".
|
||||
main.c: New command line stuff... (in man page) Also, default contrast is
|
||||
140 now. Looks better from all angles, at least on my machine. :)
|
||||
lcd.1: Man page. New.. :)
|
||||
mode.c: Rearranged memory screen.. Shows Memory and Swap space separately,
|
||||
with two graphs.
|
||||
|
||||
1998-02-24: Scott
|
||||
mode.c: Rearranged memory screen. Worked around hbar bios bug. Added swap
|
||||
info to this screen also, so get_mem_info is back to its former
|
||||
state. (call it on an array)
|
||||
mode.c: Fixed xload screen. It was displaying things one space to the left.
|
||||
main.c: Changed command line style from "mode num_times delay_time" to
|
||||
"mode total_time delay_time". Is this better or worse?
|
||||
|
||||
1998-02-22: Scott
|
||||
main.c: Now handles SIGINT (Ctrl-C) and SIGTERM (kill) for a clean exit.
|
||||
main.c: Default device now works. (device[] was getting overwritten by
|
||||
argv[0], which would always be "lcd")
|
||||
mode.c: Fixed CPU load meter. Decreased cpu buffer size back to 4.
|
||||
mode.c: Made goodbye_screen() do something...
|
||||
mode.c: Fixed am/pm on clock_screen(). Was previously displaying 12:xx:xxA
|
||||
during the noon hour, instead of 12:xx:xxP.
|
||||
|
||||
1998-02-18: Scott
|
||||
mode.c: Fixed crash on memory screen; commented out last two lines of
|
||||
get_mem_info, which accessed a non-existent variable.
|
||||
mode.c: Added "rep" parameter to all screen functions. Specifies how many times
|
||||
that screen has been run. Using 0 will force screen clear/redraw, and
|
||||
the time-based ones also use this to determine if colons should be drawn.
|
||||
main.c: Implemented simple command-line parameters. Example:
|
||||
lcd m 4 .5 /dev/cua1 x 1 2
|
||||
uses /dev/cua1 for lcd, displaying memory info 4 times at .5 seconds each,
|
||||
and the xload screen once for 2 seconds; then loops.
|
||||
mode.c & lcd.c: created "NOLCD" preprocessor switch. When defined, lcd uses
|
||||
text output (stdout) instead of the com port.
|
||||
mode.c: Changed clock string generation to use "%02d" to achieve that
|
||||
"02:37:06" look. (hint: printf can pad numbers with leading 0's)
|
||||
main.c: Added minimal command-line help.
|
||||
+429
@@ -0,0 +1,429 @@
|
||||
#include <stdio.h> // for NULL definition
|
||||
#include "llistd.h" // function prototypes
|
||||
|
||||
/*****************************************************************************
|
||||
* AUTHOR: Scott Scriven, SSN: 523-21-9640, CLASS: CS151.003, DATE: 96-11-21
|
||||
******************************************************************************
|
||||
* Doubly Linked Lists! (some of my really old code, commented for this class)
|
||||
* This code will handle "generic" Doubly-Linked Lists. These lists can be
|
||||
* any type as long as they satisfy a few requirements:
|
||||
* Your structure must start with two integer pointers:
|
||||
* struct mystruct {
|
||||
* int *next, *prev;
|
||||
* ...
|
||||
* };
|
||||
* That's all, pretty much.
|
||||
*
|
||||
* Most of the functions take integer pointers. This means you will have to
|
||||
* call them in one of the following ways:
|
||||
* function((int *)&mystruct);
|
||||
* function((int *)mystruct);
|
||||
* function(&mystruct.next);
|
||||
*
|
||||
******************************************************************************
|
||||
* If I'm not mistaken, this code should work regardless of your machine's
|
||||
* integer size (16/32/64/etc... bit)
|
||||
******************************************************************************
|
||||
* Note that we have to do NULL checking to make sure we don't try to write
|
||||
* to protected areas of memory if we reach the beginning/end of a list.
|
||||
*
|
||||
* We also do some circular-link checking to avoid infinite loops.
|
||||
* These loops will work fine:
|
||||
* a <-> b <-> c <-> a <-> b...
|
||||
* a <-> b <-> c -> c -> c...
|
||||
* This loop might make this code puke:
|
||||
* a <-> b <-> c <-> d -> c d <- e <-> f <-> g
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLMakeFirstNode()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Makes a node stand alone; creates the first node of a list. You must do
|
||||
* the memory/node allocation manually. It returns the parameter you send it.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* None.
|
||||
*****************************************************************************/
|
||||
int * LLMakeFirstNode(int * first) // Make a standalone node...
|
||||
{
|
||||
(int *)first[0] = NULL;
|
||||
(int *)first[1] = NULL;
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLFindFirst()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Given a node of a list, it returns the first node of the list (assuming
|
||||
* that the first node either points to NULL or itself). If list is circular,
|
||||
* it returns *next* node in the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindPrev See below...
|
||||
*****************************************************************************/
|
||||
int * LLFindFirst(int * current) // returns address of First node
|
||||
{
|
||||
int *prev=current;
|
||||
|
||||
// If prev[1] (pointer to previous node) is NULL, we hit the beginning.
|
||||
// If prev[1] is the same as current, we've got a circular linked list...
|
||||
while((int *)prev[1] != NULL && (int *)prev[1] != current)
|
||||
{
|
||||
prev = LLFindPrev(prev);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLFindNext()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Returns the address of the next node in the list, or NULL if we're at the
|
||||
* end of the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* None.
|
||||
*****************************************************************************/
|
||||
int * LLFindNext(int * current) // returns address of next node
|
||||
{
|
||||
// Return the address of the next node
|
||||
if((int *)current[0] != current)
|
||||
return (int *)current[0];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLFindPrev()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Returns the address of the previous node in the list, or NULL if we're
|
||||
* at the beginning of the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* None.
|
||||
*****************************************************************************/
|
||||
int * LLFindPrev(int * current) // returns address of prev node
|
||||
{
|
||||
// Return the address of the previous node
|
||||
if((int *)current[1] != current)
|
||||
return (int *)current[1];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLFindLast()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Given any node, returns the address of the last node of that list. This
|
||||
* works just like LLFindFirst(), but in reverse.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindNext See above...
|
||||
*****************************************************************************/
|
||||
int * LLFindLast(int * current) // returns address of last node
|
||||
{
|
||||
int *next = current;
|
||||
|
||||
// If next[0] (pointer to next node) is NULL, we hit the end.
|
||||
// If next[0] is the same as current, we've got a circular linked list...
|
||||
while((int *)next[0] != NULL && (int *)next[0] != current)
|
||||
{
|
||||
next = LLFindNext(next);
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLAddNode()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Inserts a node in the list *after* the "current" node. It updates the
|
||||
* list neighbors accordingly.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindNext See above...
|
||||
*****************************************************************************/
|
||||
int * LLAddNode(int * current, int * add) // Adds node AFTER current one
|
||||
{
|
||||
int *next;
|
||||
|
||||
if(current == add) return current; // We can't add a node to itself...
|
||||
|
||||
next = LLFindNext(current); // Get the next node address
|
||||
|
||||
(int *)current[0] = add; // Point the current node to the new node
|
||||
(int *)add[0] = next; // Point the new node to next node
|
||||
(int *)add[1] = current; // Make new node point back to the current node
|
||||
|
||||
if(next != NULL)
|
||||
(int *)next[1] = add; // Point next node back to the new node
|
||||
|
||||
return add; // Return the address of the new node
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLInsertNode()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Inserts a node in the list *before* the "current" node. It updates the
|
||||
* list neighbors accordingly.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindPrev See above...
|
||||
*****************************************************************************/
|
||||
int * LLInsertNode(int * current, int * add) // Adds node BEFORE current one
|
||||
{
|
||||
int *prev;
|
||||
|
||||
if(current == add) return current; // We can't add a node to itself...
|
||||
|
||||
prev = LLFindPrev(current); // Get the previous node's address
|
||||
|
||||
if(prev != NULL)
|
||||
(int *)prev[0] = add; // Previous node points to new node
|
||||
(int *)add[0] = current; // New node points to current node
|
||||
(int *)add[1] = prev; // New node points back to previous node
|
||||
(int *)current[1] = add; // Current node points back to new node
|
||||
|
||||
return add; // Return the address of the new node
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLCutNode()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Removes a node from the list, and joins its neighbors. Returns the
|
||||
* address of the cut node. You must deallocate the node manually, if
|
||||
* you want to free its memory.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindPrev See Above...
|
||||
* LLFindNext See Above...
|
||||
*****************************************************************************/
|
||||
int * LLCutNode(int * cut) // Removes a node from the link
|
||||
{
|
||||
int * prev, * next;
|
||||
|
||||
prev = LLFindPrev(cut); // Find surrounding nodes...
|
||||
next = LLFindNext(cut);
|
||||
|
||||
(int *)cut[0] = NULL; // Make the removed node point nowhere
|
||||
(int *)cut[1] = NULL;
|
||||
|
||||
if(prev != NULL) // Join the surrounding nodes...
|
||||
(int *)prev[0] = next;
|
||||
if(next != NULL)
|
||||
(int *)next[1] = prev;
|
||||
|
||||
return cut; // Return the address of the node that has been cut...
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLPush()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Inserts a node at the end of the whole list. "Current" can be any node
|
||||
* in the list, and "add" is the node you want to add.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindLast() See above...
|
||||
* LLAddNode() See above...
|
||||
*****************************************************************************/
|
||||
int * LLPush(int * current, int * add) // Add node to end of list
|
||||
{
|
||||
int *last;
|
||||
|
||||
last = LLFindLast(current);
|
||||
|
||||
return LLAddNode(last, add);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLPop()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Pops (removes) a node off the end of the list. Returns the address of
|
||||
* the node we chopped off. "current" can be any node in the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindLast See above...
|
||||
* LLCutNode See above...
|
||||
*****************************************************************************/
|
||||
int * LLPop(int * current) // Remove node from end of list
|
||||
{
|
||||
int *last;
|
||||
|
||||
last = LLFindLast(current);
|
||||
|
||||
return LLCutNode(last);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLShift()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Pops (removes) a node from the beginning of the list. Returns the address
|
||||
* of the node we cut off.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindFirst See above...
|
||||
* LLCutNode See above...
|
||||
*****************************************************************************/
|
||||
int * LLShift(int * current) // Remove node from start of list
|
||||
{
|
||||
int *begin;
|
||||
|
||||
begin = LLFindFirst(current);
|
||||
|
||||
return LLCutNode(begin);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLUnshift()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Inserts a node at the beginning of the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindFirst See above...
|
||||
* LLInsertNode See above...
|
||||
*****************************************************************************/
|
||||
int * LLUnshift(int * current, int * add) // Add node to beginning of list
|
||||
{
|
||||
int *begin;
|
||||
|
||||
begin = LLFindFirst(current);
|
||||
|
||||
return LLInsertNode(begin, add);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLSwapNodes()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Switches two nodes' positions in the linked list. It can handle cases
|
||||
* when the nodes are complete seperate, cases when the nodes are each
|
||||
* other's neighbors, and cases when the two nodes are the same one.
|
||||
* No return value.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindNext See Above...
|
||||
* LLFindPrev See above...
|
||||
*****************************************************************************/
|
||||
void LLSwapNodes(int * one, int * two) // Switch two nodes' positions...
|
||||
{
|
||||
int *firstprev, *firstnext;
|
||||
int *secondprev, *secondnext;
|
||||
|
||||
if(one == two) return; // if they're the same, do nothing
|
||||
|
||||
firstprev = LLFindPrev(one); // Store the addresses of their neighbors...
|
||||
firstnext = LLFindNext(one);
|
||||
secondprev = LLFindPrev(two);
|
||||
secondnext = LLFindNext(two);
|
||||
|
||||
if(firstprev != NULL) (int *)firstprev[0] = two; // Swap their
|
||||
if(firstnext != NULL) (int *)firstnext[1] = two; // Neighbors' pointers
|
||||
if(secondprev != NULL) (int *)secondprev[0] = one;
|
||||
if(secondnext != NULL) (int *)secondnext[1] = one;
|
||||
|
||||
(int *)one[0] = secondnext; // Swap the two nodes' pointers
|
||||
(int *)one[1] = secondprev;
|
||||
(int *)two[0] = firstnext;
|
||||
(int *)two[1] = firstprev;
|
||||
|
||||
if(firstnext == two) (int *)one[1] = two; // Fix things if they were
|
||||
if(firstprev == two) (int *)one[0] = two; // next to each other...
|
||||
if(secondprev == one) (int *)two[0] = one;
|
||||
if(secondnext == one) (int *)two[1] = one;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLCountNodes()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Traverses the entire list and returns the number of nodes it finds.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLFindFirst See above...
|
||||
* LLFindNext See above...
|
||||
*****************************************************************************/
|
||||
int LLCountNodes(int * current) // Returns # of nodes in entire list
|
||||
{
|
||||
int numnodes=1;
|
||||
int *first, *next;
|
||||
|
||||
first = LLFindFirst(current); // Get the first node...
|
||||
next = first;
|
||||
|
||||
|
||||
// If next[0] (pointer to next node) is NULL, we hit the end.
|
||||
// If next[0] is the same as current, we've got a circular linked list...
|
||||
while((int *)next[0] != NULL && (int *)next[0] != first)
|
||||
{
|
||||
numnodes++;
|
||||
next = LLFindNext(next);
|
||||
}
|
||||
|
||||
return numnodes;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function: LLSelectSort()
|
||||
******************************************************************************
|
||||
* Description:
|
||||
* Given any node in a list, sorts the whole list using a selection sort
|
||||
* algorithm. You must supply a function to compare two nodes. The
|
||||
* return value is the address of the new first node in the list.
|
||||
******************************************************************************
|
||||
* Function Calls:
|
||||
* LLCountNodes See above...
|
||||
* LLFindLast See above...
|
||||
* LLFindFirst See above...
|
||||
* LLFindNext See above...
|
||||
* LLFindPrev See above...
|
||||
* LLSwapNodes See above...
|
||||
* compare The user-defined function which compares two nodes.
|
||||
* If you've ever used qsort, this should be familiar.
|
||||
*****************************************************************************/
|
||||
// Sorts the list and returns a pointer to the first node
|
||||
int * LLSelectSort(int * current, int compare(void *, void *))
|
||||
{
|
||||
int i,j; // Junk / loop variables
|
||||
int numnodes; // number of nodes in list
|
||||
int *best, *last; // best match and last node in the list
|
||||
|
||||
numnodes = LLCountNodes(current); // get the number of nodes...
|
||||
last = LLFindLast(current); // Find the last node.
|
||||
|
||||
for(i=numnodes-1; i>1; i--)
|
||||
{
|
||||
current = LLFindFirst(current); // get the first node again
|
||||
best = last; // reset our "best" node
|
||||
|
||||
for(j=0; j<i; j++)
|
||||
{
|
||||
if(compare(current, best) > 0) // If we found a better match...
|
||||
{
|
||||
best = current; // keep track of the "best" match
|
||||
}
|
||||
current = LLFindNext(current); // Go to the next node.
|
||||
}
|
||||
|
||||
LLSwapNodes(last, best); // Switch two nodes...
|
||||
last = LLFindPrev(best); // And go backwards by one node.
|
||||
}
|
||||
|
||||
return LLFindFirst(current); // return pointer to the first node.
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef LLISTD_H
|
||||
#define LLISTD_H
|
||||
/*****************************************************************************
|
||||
* AUTHOR: Scott Scriven, SSN: 523-21-9640, CLASS: CS151.003, DATE: 96-11-21
|
||||
******************************************************************************
|
||||
* Doubly Linked Lists!
|
||||
* This code will handle "generic" Doubly-Linked Lists. These lists can be
|
||||
* any type as long as they satisfy a few requirements:
|
||||
* Your structure must start with two integer pointers:
|
||||
* struct mystruct {
|
||||
* int *next, *prev;
|
||||
* ...
|
||||
* };
|
||||
* That's all, pretty much.
|
||||
*
|
||||
* Most of the functions take integer pointers. This means you will have to
|
||||
* call them in one of the following ways:
|
||||
* function((int *)&mystruct);
|
||||
* function((int *)mystruct);
|
||||
* function(&mystruct.next);
|
||||
*
|
||||
******************************************************************************
|
||||
* If I'm not mistaken, this code should work regardless of your machine's
|
||||
* integer size (16/32/64/etc... bit)
|
||||
******************************************************************************
|
||||
* Note that we have to do NULL checking to make sure we don't try to write
|
||||
* to protected areas of memory if we reach the beginning/end of a list.
|
||||
*
|
||||
* We also do some circular-link checking to avoid infinite loops.
|
||||
* These loops will work fine:
|
||||
* a <-> b <-> c <-> a <-> b...
|
||||
* a <-> b <-> c -> c -> c...
|
||||
* This loop might make this code puke:
|
||||
* a <-> b <-> c <-> d -> c d <- e <-> f <-> g
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
// See llistd.c for detailed descriptions of these functions.
|
||||
|
||||
int * LLMakeFirstNode(int * first); // Make a standalone node...
|
||||
|
||||
int * LLFindFirst(int * current); // returns address of First node
|
||||
int * LLFindNext(int * current); // returns address of next node
|
||||
int * LLFindPrev(int * current); // returns address of prev node
|
||||
int * LLFindLast(int * current); // returns address of last node
|
||||
|
||||
int * LLAddNode(int * current, int * add); // Adds node AFTER current one
|
||||
int * LLInsertNode(int * current, int * add); // Adds node BEFORE current one
|
||||
int * LLCutNode(int * cut); // Removes a node from the link
|
||||
|
||||
int * LLPush(int * current, int * add); // Add node to end of list
|
||||
int * LLPop(int * current); // Remove node from end of list
|
||||
int * LLShift(int * current); // Remove node from start of list
|
||||
int * LLUnshift(int * current, int * add); // Add node to beginning of list
|
||||
|
||||
void LLSwapNodes(int * one, int * two); // Switch two nodes positions...
|
||||
|
||||
int LLCountNodes(int * current); // Returns # of nodes in entire list
|
||||
|
||||
// "Selection Sort"s the list and returns a pointer to the first node
|
||||
int * LLSelectSort(int * current, int compare(void *, void *));
|
||||
|
||||
#endif
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "lcd.h"
|
||||
#include "mode.h"
|
||||
//#include "lock.h"
|
||||
#include "sockets.h"
|
||||
|
||||
|
||||
// TODO: Commenting... Everything!
|
||||
|
||||
|
||||
char version[] = "v0.3.4";
|
||||
char build_date[] = "1998-06-20";
|
||||
int Quit = 0;
|
||||
|
||||
/*
|
||||
Mode List:
|
||||
See below... (default_sequence[])
|
||||
*/
|
||||
|
||||
typedef struct mode {
|
||||
char which;
|
||||
int num_times;
|
||||
int delay_time;
|
||||
} mode;
|
||||
|
||||
void HelpScreen();
|
||||
void exit_program(int val);
|
||||
void main_loop(mode *sequence);
|
||||
|
||||
#define MAX_SEQUENCE 256
|
||||
// 1/8th second is a single time unit...
|
||||
#define TIME_UNIT 125000
|
||||
|
||||
|
||||
// Contains a list of modes to run
|
||||
mode default_sequence[] =
|
||||
{
|
||||
{ 'C', 32, 1, },// [C]PU
|
||||
{ 'M', 8, 4, },// [M]emory
|
||||
{ 'X', 1, 32, },// [X]-load (load histogram)
|
||||
{ 'T', 8, 4, },// [T]ime/Date
|
||||
{ 'D', 32, 1, },// [D]isk stats
|
||||
{ 'A', 1, 16, },// [A]bout (credits)
|
||||
|
||||
{ 1 , 0, 0, },// Modes after this line will not be run by default...
|
||||
// ... all non-default modes must be in here!
|
||||
// ... they will not show up otherwise.
|
||||
{ 'O', 8, 4, },// [O]ld Timescreen
|
||||
{ 'U', 8, 4, },// Old [U]ptime Screen
|
||||
{ 'B', 32, 1, },// [B]attery Status
|
||||
{ 'G', 32, 1, },// Cpu histogram [G]raph
|
||||
{ 0, 0, 0, },// No more.. all done.
|
||||
};
|
||||
|
||||
// TODO: Clean up main()... It is still way too big.
|
||||
|
||||
// TODO: Socket language, client handling...
|
||||
// TODO: Config file; not just command line
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char device[256] = "/dev/lcd";
|
||||
char cfgfile[256] = "/etc/lcdproc.cf";
|
||||
mode sequence[MAX_SEQUENCE];
|
||||
char driver[256] = "MtxOrb";
|
||||
int i, j, k;
|
||||
int already_running = 0;
|
||||
int contrast = 140;
|
||||
int tmp;
|
||||
|
||||
memset(sequence, 0, sizeof(mode) * MAX_SEQUENCE);
|
||||
|
||||
// Ctrl-C will cause a clean exit...
|
||||
signal(SIGINT, exit_program);
|
||||
// and "kill"...
|
||||
signal(SIGTERM, exit_program);
|
||||
// and "kill -HUP" (hangup)...
|
||||
signal(SIGHUP, exit_program);
|
||||
// and just in case, "kill -KILL" (which cannot be trapped; but oh well)
|
||||
signal(SIGKILL, exit_program);
|
||||
|
||||
// Check to see if we are already running...
|
||||
// already_running = CheckForLock();
|
||||
already_running = PingLCDport();
|
||||
if(already_running < 0)
|
||||
{
|
||||
printf("Error checking for another LCDproc.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Communicate with the previously running LCDproc
|
||||
if(already_running > 0)
|
||||
{
|
||||
// "already_running" holds the pid of the LCDproc we want to talk to...
|
||||
|
||||
// Do the command line ("lcd pet status", or "lcd contrast 50")
|
||||
// And stuff...
|
||||
// ...Then exit
|
||||
printf("Detected another LCDproc. (%i) Exiting...\n", already_running);
|
||||
// Remove me ^^^^
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = StartSocketServer();
|
||||
if (tmp <= 0)
|
||||
{
|
||||
printf("Error starting socket server.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Command line
|
||||
memcpy(sequence, default_sequence, sizeof(default_sequence));
|
||||
for(i=1, j=0; i<argc; i++)
|
||||
{
|
||||
if(argv[i][0] == '-') switch(argv[i][1])
|
||||
{
|
||||
// "C is for cookie (erm, contrast), and that is good enough for me..."
|
||||
case 'C':
|
||||
case 'c': if(argc < i+1) HelpScreen();
|
||||
contrast = atoi(argv[++i]);
|
||||
if(contrast <= 0) HelpScreen();
|
||||
break;
|
||||
// D for Device...
|
||||
case 'D':
|
||||
case 'd': if(argc < i+1) HelpScreen();
|
||||
strcpy(device, argv[++i]);
|
||||
break;
|
||||
case 'L':
|
||||
case 'l': if(argc < i+1) HelpScreen();
|
||||
strcpy(driver, argv[++i]);
|
||||
break;
|
||||
|
||||
// otherwise... Get help!
|
||||
default: HelpScreen(); break;
|
||||
}
|
||||
// Parse command line here... read the man page.
|
||||
else if(strlen(argv[i]) == 1)
|
||||
{
|
||||
// Grab the mode letter...
|
||||
sequence[j].which = argv[i][0];
|
||||
|
||||
// If we have just a letter with no numbers...
|
||||
// Set the defaults...
|
||||
for(tmp=0, k=0; default_sequence[k].which; k++)
|
||||
{
|
||||
if(toupper(sequence[j].which) == default_sequence[k].which)
|
||||
{
|
||||
memcpy(&sequence[j], &default_sequence[k], sizeof(mode));
|
||||
tmp=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!tmp) { printf("Invalid Mode: %c\n", argv[i][0]); exit(0); }
|
||||
|
||||
j++;
|
||||
// Set the last element to 0...
|
||||
memset(sequence + j, 0, sizeof(mode));
|
||||
} // End if(strlen(argv == 1))
|
||||
else
|
||||
{
|
||||
// A multicharacter parameter by itself is assumed to be a config file..
|
||||
strcpy(cfgfile, argv[i]);
|
||||
printf("Ignoring config file: %s\n", cfgfile);
|
||||
}
|
||||
}
|
||||
|
||||
// Init the com port
|
||||
if(lcd_init(device, driver) < 1)
|
||||
{
|
||||
printf("Cannot initialize %s.\n", device);
|
||||
exit(1);
|
||||
}
|
||||
mode_init();
|
||||
lcd.contrast(contrast);
|
||||
|
||||
main_loop(sequence);
|
||||
|
||||
// Clean up
|
||||
exit_program(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void HelpScreen()
|
||||
{
|
||||
printf("LCDproc, %s\n", version);
|
||||
printf("Usage: lcdproc [-d device] [-c contrast] [modelist]\n");
|
||||
printf("\tOptions in []'s are optional.\n");
|
||||
printf("\t-l driver is the output driver to use:\n");
|
||||
printf("\t\tMtxOrb, curses, text, debug\n");
|
||||
printf("\t-d device is what the lcd display is hooked to. (/dev/cua0?)\n");
|
||||
printf("\t-c contrast sets the screen contrast (0 - 255)\n");
|
||||
printf("\tmodelist is \"mode [mode mode ...]\"\n");
|
||||
printf("\tMode letters: [C]pu [G]raph [T]ime [M]emory [X]load [D]isk [B]attery [O]ld Time screen [U]ptime [A]bout\n");
|
||||
printf("\n");
|
||||
printf("\tUse \"man lcdproc\" for more info.\n");
|
||||
printf("Example:\n");
|
||||
printf("\tlcdproc -d /dev/cua1 C M X -l MtxOrb\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Called upon TERM and INTR signals...
|
||||
//
|
||||
void exit_program(int val)
|
||||
{
|
||||
Quit = 1;
|
||||
//unlock(); // Not needed any more...
|
||||
CloseAllConnections();
|
||||
goodbye_screen(0);
|
||||
lcd.flush();
|
||||
lcd.backlight(1);
|
||||
lcd.close();
|
||||
mode_close();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Main program loop...
|
||||
//
|
||||
void main_loop(mode *sequence)
|
||||
{
|
||||
int i, j, k;
|
||||
int Quit=0;
|
||||
int status=0;
|
||||
int timer=0;
|
||||
|
||||
int blink=0;
|
||||
int hold=0;
|
||||
int heartbeat=1;
|
||||
|
||||
// Main loop
|
||||
// Run whatever screen we want, then wait. Woo-hoo!
|
||||
for(i=0; !Quit; )
|
||||
{
|
||||
timer=0;
|
||||
for(j=0; hold || (j<sequence[i].num_times && !Quit); j++)
|
||||
{
|
||||
switch(sequence[i].which)
|
||||
{
|
||||
case 'g':
|
||||
case 'G': status = cpu_graph_screen(j); break;
|
||||
case 'c':
|
||||
case 'C': status = cpu_screen(j); break;
|
||||
case 'o':
|
||||
case 'O': status = clock_screen(j); break;
|
||||
case 'm':
|
||||
case 'M': status = mem_screen(j); break;
|
||||
case 'u':
|
||||
case 'U': status = uptime_screen(j); break;
|
||||
case 't':
|
||||
case 'T': status = time_screen(j); break;
|
||||
case 'd':
|
||||
case 'D': status = disk_screen(j); break;
|
||||
case 'x':
|
||||
case 'X': status = xload_screen(j); break;
|
||||
case 'b':
|
||||
case 'B': status = battery_screen(j); break;
|
||||
case 'a':
|
||||
case 'A': status = credit_screen(j); break;
|
||||
default: status = dumbass_screen(j); break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for(k=0; k<sequence[i].delay_time; k++)
|
||||
{
|
||||
usleep(TIME_UNIT); timer++;
|
||||
// Modify lcd status here... (blinking, for example)
|
||||
switch(status)
|
||||
{
|
||||
case BLINK_ON : blink=1; break;
|
||||
case BLINK_OFF: blink=0; lcd.backlight(1); break;
|
||||
case BACKLIGHT_OFF: blink=0; lcd.backlight(0); break;
|
||||
case BACKLIGHT_ON : blink=0; lcd.backlight(1); break;
|
||||
case HOLD_SCREEN : hold=1; break;
|
||||
case CONTINUE : hold=0; break;
|
||||
}
|
||||
status=0;
|
||||
|
||||
if(blink) lcd.backlight(! ((timer&15) == 15));
|
||||
|
||||
if(heartbeat)
|
||||
{
|
||||
// Set this to pulsate like a real heart beat...
|
||||
// (binary is fun... :)
|
||||
lcd.icon(!((timer+4)&5), 0);
|
||||
lcd.chr(lcd.wid, 1, 0);
|
||||
}
|
||||
|
||||
lcd.flush();
|
||||
|
||||
PollSockets();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if(sequence[i].which < 2) i=0;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
extern char version[];
|
||||
extern char build_date[];
|
||||
extern int Quit;
|
||||
|
||||
#define BLINK_ON 0x10
|
||||
#define BLINK_OFF 0x11
|
||||
#define BACKLIGHT_OFF 0x20
|
||||
#define BACKLIGHT_ON 0x21
|
||||
#define HOLD_SCREEN 0x30
|
||||
#define CONTINUE 0x31
|
||||
|
||||
|
||||
#endif
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#include "menu.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
// THIS IS NOT READY YET!
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Read menu.h to find out how this works.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// Internal record of all important menu info...
|
||||
typedef struct MenuInfo
|
||||
{
|
||||
MenuItem *menu; // User-specified menu information
|
||||
struct MenuInfo *parent; // NULL if root-level
|
||||
int items; // number of items in the menu
|
||||
int sel; // selected item
|
||||
} MenuInfo;
|
||||
|
||||
|
||||
|
||||
// Main menu function...
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent);
|
||||
|
||||
|
||||
void FillMenuInfo(MenuInfo *m, MenuItem *menu, MenuInfo *parent);
|
||||
|
||||
void DrawMenu(MenuInfo *m);
|
||||
void DrawMenuItem(MenuInfo *m, int item);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// User-callable function...
|
||||
//
|
||||
int menu(MenuItem *menu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
CreateArrows(); // Set custom characters for menu use...
|
||||
|
||||
ret = do_menu(menu, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent)
|
||||
{
|
||||
int current;
|
||||
int uparrow;
|
||||
int downarrow;
|
||||
|
||||
int key;
|
||||
int err=0;
|
||||
|
||||
|
||||
while(! err)
|
||||
{
|
||||
// Draw the menu...
|
||||
|
||||
// Wait for input
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent)
|
||||
{
|
||||
int i;
|
||||
int items;
|
||||
MenuInfo ThisMenu;
|
||||
int old_sel;
|
||||
int redraw=1;
|
||||
int ret=0;
|
||||
|
||||
FillMenuInfo(&ThisMenu, menu, parent);
|
||||
|
||||
//FIXME: Get input here... Move the selection thingy
|
||||
|
||||
DrawMenu(&ThisMenu);
|
||||
|
||||
|
||||
do{
|
||||
//FIXME: Get input here... Move the selection thingy
|
||||
|
||||
// Figure out which button should be highlighted...
|
||||
|
||||
// And... if the "execute" button was pressed...
|
||||
if()
|
||||
{
|
||||
ThisMenu.sel = i;
|
||||
}
|
||||
|
||||
DrawMenu(&ThisMenu);
|
||||
redraw = 0;
|
||||
|
||||
// Dismiss menu?
|
||||
if( // cancel was pressed...
|
||||
)
|
||||
ret = GUI_CONT;
|
||||
|
||||
// pop up another menu?
|
||||
if( // execute was pressed...
|
||||
&&ThisMenu.sel >= 0
|
||||
&&ThisMenu.menu[ThisMenu.sel].child)
|
||||
{
|
||||
i = do_menu(ThisMenu.menu[ThisMenu.sel].child, &ThisMenu);
|
||||
if(i == GUI_OK) ret = GUI_OK;
|
||||
}
|
||||
|
||||
// Or call a function?
|
||||
else if( // execute was pressed...
|
||||
&&ThisMenu.sel >= 0
|
||||
&&ThisMenu.menu[ThisMenu.sel].func)
|
||||
{
|
||||
ret = ThisMenu.menu[ThisMenu.sel].func();
|
||||
//ret = GUI_OK;
|
||||
}
|
||||
|
||||
} while(! ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Initializes a menu...
|
||||
//
|
||||
void FillMenuInfo(MenuInfo *m, MenuItem *menu, MenuInfo * parent)
|
||||
{
|
||||
m->menu = menu;
|
||||
m->parent = parent;
|
||||
m->sel = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DrawMenu(MenuInfo *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<m->items; i++)
|
||||
DrawMenuItem(m, i);
|
||||
}
|
||||
|
||||
void DrawMenuItem(MenuInfo *m, int item)
|
||||
{
|
||||
// Figure out how much to scroll down...
|
||||
// Write each menu item...
|
||||
// Put arrows where needed (next to current item, and up/down arrow)
|
||||
// m->menu[item].text holds the text string...
|
||||
}
|
||||
|
||||
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// THIS IS NOT READY YET!
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
||||
Pull-down menus...
|
||||
|
||||
To use a menu, first define it; then call menu().
|
||||
|
||||
To define a menu, just declare an array of MenuItems. The last element
|
||||
must have all NULL fields.
|
||||
|
||||
MenuItem FileMenu[] =
|
||||
{
|
||||
"Open", OpenFile_proc, NULL,
|
||||
"Close", CloseFile_proc, NULL,
|
||||
"Save", SaveFile_proc, NULL,
|
||||
"Save As...", NULL, SaveAsMenu,
|
||||
"Quit", Quit_proc, NULL,
|
||||
NULL, NULL, NULL,
|
||||
};
|
||||
|
||||
The first field is the text for the menu item.
|
||||
The second field is a function to call when the item is picked.
|
||||
The function should take no parameters, and return an int.
|
||||
The return values are:
|
||||
MENU_OK Normal return value. Menu will close.
|
||||
MENU_CONT Menu will stay up after function returns.
|
||||
The third field is the child menu to display when the item is picked.
|
||||
|
||||
Note that either the second or third field must be NULL. If both are
|
||||
NULL, the item is considered to be just a label. (for example, a title)
|
||||
It will be non-pickable if both are NULL.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define MENU_OK 1
|
||||
#define MENU_CONT 2
|
||||
|
||||
typedef struct MenuItem
|
||||
{
|
||||
char *text;
|
||||
int (*func)();
|
||||
struct MenuItem *child;
|
||||
} MenuItem;
|
||||
|
||||
|
||||
|
||||
// This does a pull-down menu...
|
||||
int menu(MenuItem *menu);
|
||||
|
||||
|
||||
#endif
|
||||
+1107
File diff suppressed because it is too large
Load Diff
+30
@@ -0,0 +1,30 @@
|
||||
#ifndef MODE_H
|
||||
#define MODE_H
|
||||
|
||||
|
||||
//TODO: Net stats screen...
|
||||
//TODO: "Who"
|
||||
//TODO: biff / mail checking
|
||||
|
||||
// Character to use for padding title bars, etc...
|
||||
extern int PAD;
|
||||
// Character for the "..." symbol.
|
||||
extern int ELLIPSIS;
|
||||
|
||||
int mode_init();
|
||||
void mode_close();
|
||||
|
||||
int cpu_screen(int rep);
|
||||
int cpu_graph_screen(int rep);
|
||||
int clock_screen(int rep);
|
||||
int mem_screen(int rep);
|
||||
int uptime_screen(int rep);
|
||||
int time_screen(int rep);
|
||||
int disk_screen(int rep);
|
||||
int xload_screen(int rep);
|
||||
int battery_screen(int rep);
|
||||
int credit_screen(int rep);
|
||||
int dumbass_screen(int rep);
|
||||
int goodbye_screen(int rep);
|
||||
|
||||
#endif
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "sockets.h"
|
||||
|
||||
|
||||
/**************************************************
|
||||
LCDproc sockets code...
|
||||
|
||||
This is messy, and needs to be finished.
|
||||
**************************************************/
|
||||
|
||||
fd_set active_fd_set, read_fd_set;
|
||||
int sock;
|
||||
|
||||
// Length of longest transmission allowed at once...
|
||||
#define MAXMSG 8192
|
||||
|
||||
|
||||
|
||||
int init_sockaddr (sockaddr_in *name,
|
||||
const char *hostname,
|
||||
unsigned short int port)
|
||||
{
|
||||
struct hostent *hostinfo;
|
||||
|
||||
name->sin_family = AF_INET;
|
||||
name->sin_port = htons (port);
|
||||
hostinfo = gethostbyname (hostname);
|
||||
if (hostinfo == NULL)
|
||||
{
|
||||
fprintf (stderr,"Unknown host %s.\n", hostname);
|
||||
return -1;
|
||||
}
|
||||
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// Creates a socket as a file...
|
||||
int CreateNamedSocket(char *filename)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
size_t size;
|
||||
|
||||
sock=socket(PF_FILE, SOCK_STREAM, 0);
|
||||
if(sock < 0) return -1;
|
||||
|
||||
|
||||
name.sun_family = AF_FILE;
|
||||
strcpy (name.sun_path, filename);
|
||||
|
||||
/* The size of the address is
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte. */
|
||||
size = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
|
||||
if (bind (sock, (struct sockaddr *) &name, size) < 0)
|
||||
return -1;
|
||||
|
||||
return sock;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Creates a socket in internet space
|
||||
int CreateInetSocket(unsigned short int port)
|
||||
{
|
||||
struct sockaddr_in name;
|
||||
|
||||
/* Create the socket. */
|
||||
//fprintf(stderr,"Creating Inet Socket\n");
|
||||
sock = socket (PF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
/* Give the socket a name. */
|
||||
//fprintf(stderr,"Binding Inet Socket\n");
|
||||
name.sin_family = AF_INET;
|
||||
name.sin_port = htons (port);
|
||||
name.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
|
||||
return -1;
|
||||
|
||||
return sock;
|
||||
|
||||
}
|
||||
|
||||
// Checks the LCDproc port for a response...
|
||||
int PingLCDport()
|
||||
{
|
||||
struct sockaddr_in servername;
|
||||
int err=0;
|
||||
char ping[16] = {0xFE, 0x01, 0};
|
||||
|
||||
|
||||
//fprintf(stderr,"Creating socket (client)\n");
|
||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(sock < 0)
|
||||
{
|
||||
fprintf(stderr,"Error creating socket (client)\n");
|
||||
return sock;
|
||||
}
|
||||
//else fprintf(stderr,"Created socket (%i) (client)\n", sock);
|
||||
|
||||
|
||||
init_sockaddr(&servername, "localhost", LCDPORT);
|
||||
|
||||
err = connect (sock,
|
||||
(struct sockaddr *) &servername,
|
||||
sizeof (servername));
|
||||
if(err<0)
|
||||
{
|
||||
//fprintf (stderr,"connect failed (client)\n");
|
||||
shutdown(sock, 2);
|
||||
return 0; // Normal exit if server doesn't exist...
|
||||
}
|
||||
|
||||
err = write (sock, ping, strlen(ping) + 1);
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf (stderr,"socket write error (client)");
|
||||
shutdown(sock, 2);
|
||||
return err;
|
||||
}
|
||||
|
||||
shutdown(sock, 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ConnectAsClient()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StartSocketServer()
|
||||
{
|
||||
|
||||
/* Create the socket and set it up to accept connections. */
|
||||
sock = CreateInetSocket (LCDPORT);
|
||||
if(sock < 0)
|
||||
{
|
||||
fprintf(stderr,"Error creating socket (server)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (listen (sock, 1) < 0)
|
||||
{
|
||||
fprintf (stderr,"Listen error (server)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the set of active sockets. */
|
||||
FD_ZERO (&active_fd_set);
|
||||
FD_SET (sock, &active_fd_set);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
int PollSockets()
|
||||
{
|
||||
int i;
|
||||
struct sockaddr_in clientname;
|
||||
size_t size;
|
||||
struct timeval t;
|
||||
|
||||
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 0;
|
||||
|
||||
/* Block until input arrives on one or more active sockets. */
|
||||
read_fd_set = active_fd_set;
|
||||
|
||||
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0)
|
||||
{
|
||||
fprintf (stderr,"Select error (server)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Service all the sockets with input pending. */
|
||||
for (i = 0; i < FD_SETSIZE; ++i)
|
||||
if (FD_ISSET (i, &read_fd_set))
|
||||
{
|
||||
if (i == sock)
|
||||
{
|
||||
/* Connection request on original socket. */
|
||||
int new;
|
||||
size = sizeof (clientname);
|
||||
new = accept (sock,
|
||||
(struct sockaddr *) &clientname,
|
||||
&size);
|
||||
if (new < 0)
|
||||
{
|
||||
fprintf (stderr,"Accept error (server)\n");
|
||||
return -1;
|
||||
}
|
||||
fprintf (stderr,"Server: connect from host %s, port %hd.\n",
|
||||
inet_ntoa (clientname.sin_addr),
|
||||
ntohs (clientname.sin_port));
|
||||
FD_SET (new, &active_fd_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Data arriving on an already-connected socket. */
|
||||
if (read_from_client (i) < 0)
|
||||
{
|
||||
close (i);
|
||||
FD_CLR (i, &active_fd_set);
|
||||
fprintf(stderr,"Closed connection %i\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int read_from_client (int filedes)
|
||||
{
|
||||
char buffer[MAXMSG];
|
||||
int nbytes;
|
||||
|
||||
nbytes = read (filedes, buffer, MAXMSG);
|
||||
buffer[nbytes] = 0;
|
||||
buffer[nbytes+1] = 0;
|
||||
|
||||
if (nbytes < 0) // Read error
|
||||
{
|
||||
fprintf (stderr,"Read error (server)\n");
|
||||
return -1;
|
||||
}
|
||||
else if (nbytes == 0) // EOF
|
||||
return -1;
|
||||
else // Data Read
|
||||
{
|
||||
fprintf (stderr,"Server: got message: `%s'\n", buffer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CloseAllConnections()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Service all the sockets with input pending. */
|
||||
for (i = 0; i < FD_SETSIZE; ++i)
|
||||
if (FD_ISSET (i, &read_fd_set))
|
||||
{
|
||||
/* Data arriving on an already-connected socket. */
|
||||
close (i);
|
||||
FD_CLR (i, &active_fd_set);
|
||||
fprintf(stderr,"Closed connection %i\n", i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#define LCDPORT 13666
|
||||
|
||||
/**********************************************************************
|
||||
LCDproc socket interface grammar:
|
||||
|
||||
RawText Print whatever you send, at whatever the current position is.
|
||||
|
||||
or...
|
||||
|
||||
0xFE Command prefix, followed by...
|
||||
|
||||
0x00 EOT. End of transmission, where applicicable.
|
||||
0x01 Ping. Will respond with a "pong".
|
||||
'k',x Send "keypad" input, character x (A-Z)
|
||||
|
||||
?,x,...,EOT Send new mode sequence (x,...)...
|
||||
?,x Switch to new mode x immediately
|
||||
?,xxxx Pause in current mode for x frames/seconds (0=infinite)
|
||||
? Play -- continue mode cycle.
|
||||
?,x,y,...,EOT
|
||||
Send raw text to be displayed. x is style (raw, wrapped),
|
||||
and y is num frames between lines displayed.
|
||||
|
||||
?,... Send MtxOrb-like control commands (bargraphs, etc)
|
||||
|
||||
... more to come later ...
|
||||
**********************************************************************/
|
||||
|
||||
/*****************************************************************
|
||||
LCDproc command line interface: (while running)
|
||||
|
||||
-command
|
||||
Tells LCDproc to interpret stdin as raw commands to send through
|
||||
the socket. Input must be formatted as above, in socket interface.
|
||||
-function f
|
||||
Runs LCDproc external function f, where f is one of the predefined
|
||||
functions which can be assigned to keypad keys. (like NEXTMODE, etc)
|
||||
-key x
|
||||
Simulates keypad press of key 'x', where 'x' is (A-Z).
|
||||
-print [time]
|
||||
Prints stdin on LCD one line at a time, with no line-wrapping (raw),
|
||||
with [time] frames between updates (lines).
|
||||
-wrap [time]
|
||||
Prints stdin as with "-print", but with line wrapping when possible.
|
||||
-contrast xxx
|
||||
Sets contrast to xxx (decimal)
|
||||
-backlight [on/off]
|
||||
Turns backlight [on/off/auto], or toggles it.
|
||||
If [off], stays off.
|
||||
If [on], stays on.
|
||||
If [auto], LCDproc controls backlight based on load, etc...
|
||||
-exit
|
||||
-quit
|
||||
Duh... :)
|
||||
|
||||
******************************************************************/
|
||||
|
||||
/*****************************************************************
|
||||
LCDproc stuff supported in config file (loose approximation):
|
||||
|
||||
Grammar is tcl-style. I.e., "command arg1 arg2 ...".
|
||||
Spaces are used as argument separators, *until* it thinks it has the final
|
||||
argument. So, "function thing shell myprogram arg1 arg2 arg3" would be
|
||||
split into "function", "thing", "shell", and "myprogram arg1 arg2 arg3".
|
||||
|
||||
User-definable functions (use built-in's to create new ones?):
|
||||
Function mp3NextSong Shell /usr/local/bin/mp3player -next
|
||||
Function MySequence Sequence cpu mem xload
|
||||
Function OtherSequence Sequence time cd xload
|
||||
|
||||
Keypad keys can be bound to any _function_:
|
||||
Key A mp3NextSong
|
||||
Key B HaltSystem
|
||||
Key C Menu
|
||||
Key D Next/+
|
||||
Key E OtherSequence
|
||||
|
||||
|
||||
******************************************************************/
|
||||
|
||||
typedef struct sockaddr_in sockaddr_in;
|
||||
|
||||
int init_sockaddr (sockaddr_in *name,
|
||||
const char *hostname,
|
||||
unsigned short int port);
|
||||
|
||||
// Creates a socket in internet space
|
||||
int CreateInetSocket(unsigned short int port);
|
||||
|
||||
// Checks the LCDproc port for a response...
|
||||
int PingLCDport();
|
||||
|
||||
int StartSocketServer();
|
||||
|
||||
int PollSockets();
|
||||
|
||||
int read_from_client (int filedes);
|
||||
|
||||
int CloseAllConnections();
|
||||
+644
@@ -0,0 +1,644 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "stat.h"
|
||||
#include "lcd.h"
|
||||
|
||||
|
||||
/*
|
||||
Don't use this yet! It's barely even started...
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct load { unsigned long total, user, system, nice, idle; };
|
||||
struct meminfo { int total, cache, buffers, free, shared; };
|
||||
static char buffer[1024];
|
||||
|
||||
// Nothing else can see these...
|
||||
static int meminfo_fd, load_fd, loadavg_fd, uptime_fd;
|
||||
|
||||
static char kver[SYS_NMLN];
|
||||
static char sysname[SYS_NMLN];
|
||||
|
||||
static void reread(int f, char *errmsg);
|
||||
static int getentry(const char *tag, const char *bufptr);
|
||||
static void get_mem_info(struct meminfo *result);
|
||||
static double get_loadavg(void);
|
||||
static double get_uptime(void);
|
||||
static void get_load(struct load * result);
|
||||
|
||||
|
||||
|
||||
int stat_init()
|
||||
{
|
||||
struct utsname *unamebuf =
|
||||
(struct utsname *) malloc( sizeof(struct utsname) );
|
||||
|
||||
meminfo_fd = open("/proc/meminfo",O_RDONLY);
|
||||
loadavg_fd = open("/proc/loadavg",O_RDONLY);
|
||||
load_fd = open("/proc/stat",O_RDONLY);
|
||||
uptime_fd = open("/proc/uptime",O_RDONLY);
|
||||
|
||||
#if 0
|
||||
kversion_fd = open("/proc/sys/kernel/osrelease",O_RDONLY);
|
||||
|
||||
reread(kversion_fd, "main:");
|
||||
sscanf(buffer, "%s", kver);
|
||||
|
||||
close(kversion_fd);
|
||||
# endif
|
||||
|
||||
/* Get OS name and version from uname() */
|
||||
if( uname( unamebuf ) != 0 ) {
|
||||
perror( "Error calling uname:" );
|
||||
}
|
||||
strcpy( kver, unamebuf->release );
|
||||
strcpy( sysname, unamebuf->sysname );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stat_close()
|
||||
{
|
||||
close(meminfo_fd);
|
||||
close(loadavg_fd);
|
||||
close(load_fd);
|
||||
close(uptime_fd);
|
||||
}
|
||||
|
||||
|
||||
static void reread(int f, char *errmsg)
|
||||
{
|
||||
if (lseek(f, 0L, 0) == 0 && read(f, buffer, sizeof(buffer) - 1 ) > 0 )
|
||||
return;
|
||||
perror(errmsg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int getentry(const char *tag, const char *bufptr)
|
||||
{
|
||||
char *tail;
|
||||
int retval, len = strlen(tag);
|
||||
|
||||
while (bufptr)
|
||||
{
|
||||
if (*bufptr == '\n') bufptr++;
|
||||
if (!strncmp(tag, bufptr, len))
|
||||
{
|
||||
retval = strtol(bufptr + len, &tail, 10);
|
||||
if (tail == bufptr + len) return -1;
|
||||
else return retval;
|
||||
}
|
||||
bufptr = strchr( bufptr, '\n');
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void get_mem_info(struct meminfo *result)
|
||||
{
|
||||
// int i, res; char *bufptr;
|
||||
|
||||
reread(meminfo_fd, "get_meminfo:");
|
||||
result[0].total = getentry("MemTotal:", buffer);
|
||||
result[0].free = getentry("MemFree:", buffer);
|
||||
result[0].shared = getentry("MemShared:", buffer);
|
||||
result[0].buffers = getentry("Buffers:", buffer);
|
||||
result[0].cache = getentry("Cached:", buffer);
|
||||
result[1].total = getentry("SwapTotal:", buffer);
|
||||
result[1].free = getentry("SwapFree:", buffer);
|
||||
}
|
||||
|
||||
static double get_loadavg(void)
|
||||
{
|
||||
double load;
|
||||
|
||||
reread(loadavg_fd, "get_load:");
|
||||
sscanf(buffer, "%lf", &load);
|
||||
return load;
|
||||
}
|
||||
|
||||
static double get_uptime(void)
|
||||
{
|
||||
double uptime;
|
||||
|
||||
reread(uptime_fd, "get_uptime:");
|
||||
sscanf(buffer, "%lf", &uptime);
|
||||
return uptime;
|
||||
}
|
||||
|
||||
static void get_load(struct load * result)
|
||||
{
|
||||
static struct load last_load = { 0, 0, 0, 0, 0 }; struct load curr_load;
|
||||
|
||||
reread(load_fd, "get_load:");
|
||||
sscanf(buffer, "%*s %lu %lu %lu %lu\n",
|
||||
&curr_load.user, &curr_load.nice, &curr_load.system, &curr_load.idle);
|
||||
curr_load.total = curr_load.user + curr_load.nice
|
||||
+ curr_load.system + curr_load.idle;
|
||||
result->total = curr_load.total - last_load.total;
|
||||
result->user = curr_load.user - last_load.user;
|
||||
result->nice = curr_load.nice - last_load.nice;
|
||||
result->system = curr_load.system - last_load.system;
|
||||
result->idle = curr_load.idle - last_load.idle;
|
||||
last_load.total = curr_load.total;
|
||||
last_load.user = curr_load.user;
|
||||
last_load.nice = curr_load.nice;
|
||||
last_load.system = curr_load.system;
|
||||
last_load.idle = curr_load.idle;
|
||||
}
|
||||
|
||||
|
||||
static char tmp[256];
|
||||
|
||||
// A couple of tables for later use...
|
||||
static char *days[] = {
|
||||
"Sunday, ",
|
||||
"Monday, ",
|
||||
"Tuesday, ",
|
||||
"Wednesday,",
|
||||
"Thursday, ",
|
||||
"Friday, ",
|
||||
"Saturday, ",
|
||||
};
|
||||
|
||||
static char *months[] = {
|
||||
" January",
|
||||
" February",
|
||||
" March",
|
||||
" April",
|
||||
" May",
|
||||
" June",
|
||||
" July",
|
||||
" August",
|
||||
"September",
|
||||
" October",
|
||||
" November",
|
||||
" December",
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CPU screen shows info about percentage of the CPU being used
|
||||
//
|
||||
int cpu_screen(int rep)
|
||||
{
|
||||
#undef CPU_BUF_SIZE
|
||||
#define CPU_BUF_SIZE 4
|
||||
int i, j, n;
|
||||
float value;
|
||||
static float cpu[CPU_BUF_SIZE + 1][5];// last buffer is scratch
|
||||
struct load load;
|
||||
|
||||
|
||||
|
||||
get_load(&load);
|
||||
|
||||
// Shift values over by one
|
||||
for(i=0; i<(CPU_BUF_SIZE-1); i++)
|
||||
for(j=0; j<5; j++)
|
||||
cpu[i][j] = cpu[i+1][j];
|
||||
|
||||
// Read new data
|
||||
cpu[CPU_BUF_SIZE-1][0] = ((float)load.user / (float)load.total) * 100.0;
|
||||
cpu[CPU_BUF_SIZE-1][1] = ((float)load.system / (float)load.total) * 100.0;
|
||||
cpu[CPU_BUF_SIZE-1][2] = ((float)load.nice / (float)load.total) * 100.0;
|
||||
cpu[CPU_BUF_SIZE-1][3] = ((float)load.idle / (float)load.total) * 100.0;
|
||||
cpu[CPU_BUF_SIZE-1][4] = (((float)load.user + (float)load.system +
|
||||
(float)load.nice) / (float)load.total) * 100.0;
|
||||
|
||||
// Only clear on first display...
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
lcd.init_hbar();
|
||||
|
||||
sprintf(tmp, "%c%c CPU LOAD %c%c", PAD, PAD, PAD, PAD);
|
||||
|
||||
lcd.string(1, 1, tmp);
|
||||
lcd.string(1, 2, "Usr 0.0% Nice 0.0%");
|
||||
lcd.string(1, 3, "Sys 0.0% Idle 0.0%");
|
||||
lcd.string(1, 4, "0% 100%");
|
||||
|
||||
// Make all the same, if this is the first time...
|
||||
for(i=0; i<CPU_BUF_SIZE-1; i++)
|
||||
for(j=0; j<5; j++)
|
||||
cpu[i][j] = cpu[CPU_BUF_SIZE-1][j];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Average values for final result
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j][i];
|
||||
}
|
||||
value /= CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE][i] = value;
|
||||
}
|
||||
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][4];
|
||||
n = (int)(value * 70.0);
|
||||
if (value >= 99.9) { lcd.string(13, 1, " 100%"); }
|
||||
else { sprintf(tmp, "%4.1f%%", value); lcd.string(13, 1, tmp); }
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][0];
|
||||
if (value >= 99.9) { lcd.string(5, 2, " 100%"); }
|
||||
else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 2, tmp); }
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][1];
|
||||
if (value >= 99.9) { lcd.string(5, 3, " 100%"); }
|
||||
else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 3, tmp); }
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][2];
|
||||
if (value >= 99.9) { lcd.string(16, 2, " 100%"); }
|
||||
else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 2, tmp); }
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][3];
|
||||
if (value >= 99.9) { lcd.string(16, 3, " 100%"); }
|
||||
else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 3, tmp); }
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][4];
|
||||
n = (int)(value * 70.0 / 100.0);
|
||||
lcd.string(1, 4, "0% 100%");
|
||||
lcd.hbar(3, 4, n);
|
||||
|
||||
return 0;
|
||||
} // End cpu_screen()
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Cpu Graph Screen shows a quick-moving histogram of CPU use.
|
||||
//
|
||||
int cpu_graph_screen(int rep)
|
||||
{
|
||||
int i, j, n;
|
||||
float value, maxload;
|
||||
#undef CPU_BUF_SIZE
|
||||
#define CPU_BUF_SIZE 2
|
||||
static float cpu[CPU_BUF_SIZE + 1];// last buffer is scratch
|
||||
static float cpu_past[LCD_MAX_WIDTH];
|
||||
struct load load;
|
||||
int status=0;
|
||||
char out[LCD_MAX_WIDTH];
|
||||
|
||||
|
||||
|
||||
get_load(&load);
|
||||
|
||||
// Shift values over by one
|
||||
for(i=0; i<(CPU_BUF_SIZE-1); i++)
|
||||
cpu[i] = cpu[i+1];
|
||||
|
||||
// Read new data
|
||||
cpu[CPU_BUF_SIZE-1] = ((float)load.user + (float)load.system
|
||||
+ (float)load.nice) / (float)load.total;
|
||||
|
||||
|
||||
// Only clear on first display...
|
||||
if(!rep)
|
||||
{
|
||||
lcd.init_vbar();
|
||||
|
||||
// Make all the same, if this is the first time...
|
||||
for(i=0; i<CPU_BUF_SIZE-1; i++)
|
||||
cpu[i] = cpu[CPU_BUF_SIZE-1];
|
||||
|
||||
}
|
||||
|
||||
//lcd.clear();
|
||||
for(i=2; i<=lcd.hgt; i++)
|
||||
lcd.string(1,i," ");
|
||||
|
||||
|
||||
// Average values for final result
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j];
|
||||
}
|
||||
value /= (float)CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE] = value;
|
||||
|
||||
|
||||
maxload=0;
|
||||
for(i=0; i<lcd.wid-1; i++)
|
||||
{
|
||||
cpu_past[i] = cpu_past[i+1];
|
||||
lcd.vbar(i+1, cpu_past[i]);
|
||||
if(cpu_past[i] > maxload) maxload = cpu_past[i];
|
||||
}
|
||||
|
||||
value = cpu[CPU_BUF_SIZE];
|
||||
n = (int)(value * 8.0 * (float)(lcd.hgt-1));
|
||||
|
||||
cpu_past[lcd.wid-1] = n;
|
||||
lcd.vbar(lcd.wid, cpu_past[lcd.wid-1]);
|
||||
|
||||
sprintf(out, "%c%c CPU GRAPH %c%c%c%c%c%c", PAD,PAD,
|
||||
PAD,PAD,PAD,PAD,PAD,PAD);
|
||||
lcd.string(1,1,out);
|
||||
|
||||
|
||||
|
||||
if(n > maxload) maxload = n;
|
||||
|
||||
if(cpu_past[lcd.wid-1] > 0 ) status = BACKLIGHT_ON;
|
||||
if(maxload < 1) status = BACKLIGHT_OFF;
|
||||
|
||||
// return status;
|
||||
return 0;
|
||||
} // End cpu_graph_screen()
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Clock Screen displays current time and date...
|
||||
//
|
||||
// TODO: 24-hour time, if desired.
|
||||
int clock_screen(int rep)
|
||||
{
|
||||
char hr[8], min[8], sec[8], ampm[8];
|
||||
char day[16], month[16];
|
||||
time_t thetime;
|
||||
struct tm *rtime;
|
||||
int i;
|
||||
|
||||
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
sprintf(tmp, "%c%c DATE & TIME %c%c%c%c%c", PAD, PAD, PAD, PAD, PAD, PAD, PAD);
|
||||
lcd.string(1, 1, tmp);
|
||||
}
|
||||
|
||||
time(&thetime);
|
||||
rtime = localtime(&thetime);
|
||||
|
||||
strcpy(day, days[rtime->tm_wday]);
|
||||
|
||||
if (rtime->tm_hour > 12) { i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); }
|
||||
else { i = 0; sprintf(hr, "%02d", rtime->tm_hour); }
|
||||
if(rtime->tm_hour == 12) i=1;
|
||||
sprintf(min, "%02d", rtime->tm_min);
|
||||
sprintf(sec, "%02d", rtime->tm_sec);
|
||||
if (i == 1) { sprintf(ampm, "%s", "P"); }
|
||||
else { sprintf(ampm, "%s", "A"); }
|
||||
if (rep & 1) { sprintf(tmp, "%s:%s:%s%s %s", hr, min, sec, ampm, day); }
|
||||
else { sprintf(tmp, "%s %s %s%s %s", hr, min, sec, ampm, day); }
|
||||
|
||||
strcpy(month, months[rtime->tm_mon]);
|
||||
|
||||
lcd.string(1, 3, tmp);
|
||||
|
||||
sprintf(tmp, "%s %d, %d", month, rtime->tm_mday, (rtime->tm_year + 1900));
|
||||
lcd.string(2, 4, tmp);
|
||||
|
||||
return 0;
|
||||
} // End clock_screen()
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Mem Screen displays info about memory and swap usage...
|
||||
//
|
||||
int mem_screen(int rep)
|
||||
{
|
||||
int n;
|
||||
struct meminfo mem[2];
|
||||
|
||||
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
lcd.init_hbar();
|
||||
sprintf(tmp, "%c%c%c MEM %c%c%c%c SWAP %c%c",
|
||||
PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD);
|
||||
lcd.string(1, 1, tmp);
|
||||
lcd.string(9, 2, "Totl");
|
||||
lcd.string(9, 3, "Free");
|
||||
lcd.string(1, 4, "E F E F");
|
||||
}
|
||||
|
||||
get_mem_info(mem);
|
||||
sprintf(tmp, "%6dk", mem[0].total);
|
||||
lcd.string(1, 2, tmp);
|
||||
sprintf(tmp, "%6dk", mem[0].free);
|
||||
lcd.string(1, 3, tmp);
|
||||
sprintf(tmp, "%6dk", mem[1].total);
|
||||
lcd.string(14, 2, tmp);
|
||||
sprintf(tmp, "%6dk", mem[1].free);
|
||||
lcd.string(14, 3, tmp);
|
||||
|
||||
// This gives just main memory usage
|
||||
// n = (int)(50.0 - (float)mem[0].free / (float)mem[0].total * 50.0);
|
||||
// This uses main + swap usage...
|
||||
|
||||
lcd.string(1, 4, "E F E F");
|
||||
|
||||
n = (int)(35.0 -
|
||||
(float)mem[0].free / (float)mem[0].total
|
||||
* 35.0);
|
||||
lcd.hbar(2, 4, n);
|
||||
|
||||
n = (int)(35.0 -
|
||||
(float)mem[1].free / (float)mem[1].total
|
||||
* 35.0);
|
||||
lcd.hbar(13, 4, n);
|
||||
|
||||
|
||||
/*
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<100; i++)
|
||||
{
|
||||
lcd.hbar(1,1,i);
|
||||
lcd.hbar(1,2,i);
|
||||
lcd.hbar(1,3,i);
|
||||
lcd.hbar(1,4,i);
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
} // End mem_screen()
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Uptime Screen shows info about system uptime and OS version
|
||||
//
|
||||
int uptime_screen(int rep)
|
||||
{
|
||||
int i;
|
||||
char date[16], hour[8], min[8], sec[8];
|
||||
double uptime;
|
||||
|
||||
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
sprintf(tmp, "%c%c SYSTEM UPTIME %c%c%c", PAD, PAD, PAD, PAD, PAD);
|
||||
lcd.string(1, 1, tmp);
|
||||
|
||||
sprintf(tmp, "%s %s", sysname, kver);
|
||||
lcd.string(5, 4, tmp);
|
||||
}
|
||||
|
||||
uptime = get_uptime();
|
||||
i = (int)uptime / 86400;
|
||||
sprintf(date, "%d day%s,", i, (i != 1 ? "s" : ""));
|
||||
i = ((int)uptime % 86400) / 60 / 60;
|
||||
sprintf(hour, "%02i",i);
|
||||
i = (((int)uptime % 86400) % 3600) / 60;
|
||||
sprintf(min, "%02i",i);
|
||||
i = ((int)uptime % 60);
|
||||
sprintf(sec, "%02i",i);
|
||||
if (rep & 1)
|
||||
sprintf(tmp, "%s %s:%s:%s", date, hour, min, sec);
|
||||
else
|
||||
sprintf(tmp, "%s %s %s %s", date, hour, min, sec);
|
||||
i = ((20 - strlen(tmp)) / 2) + 1;
|
||||
lcd.string(i, 3, tmp);
|
||||
|
||||
|
||||
return 0;
|
||||
} // End uptime_screen()
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Shows a display very similar to "xload"'s histogram.
|
||||
//
|
||||
|
||||
int xload_screen(int rep)
|
||||
{
|
||||
static float loads[LCD_MAX_WIDTH];
|
||||
static int first_time=1;
|
||||
int n;
|
||||
float loadmax=0, factor, x;
|
||||
int status = 0;
|
||||
|
||||
|
||||
if(first_time) // Only the first time this is ever called...
|
||||
{
|
||||
memset(loads, 0, sizeof(float)*LCD_MAX_WIDTH);
|
||||
first_time = 0;
|
||||
}
|
||||
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
}
|
||||
|
||||
|
||||
for(n=0; n<(lcd.wid-2); n++) loads[n] = loads[n+1];
|
||||
loads[lcd.wid-2] = get_loadavg();
|
||||
|
||||
for(n=0; n<lcd.wid-1; n++)
|
||||
if(loads[n] > loadmax) loadmax = loads[n];
|
||||
|
||||
lcd.string(20, 4, "0");
|
||||
n = (int)loadmax;
|
||||
if ((float)n < loadmax) { n++; }
|
||||
sprintf(tmp, "%i", n); lcd.string(20, 2, tmp);
|
||||
|
||||
if (loadmax < 1.0) factor = 24.0;
|
||||
else factor = 24 / (float)n;
|
||||
|
||||
for(n=0; n<lcd.wid-1; n++)
|
||||
{
|
||||
x = (loads[n] * factor);
|
||||
lcd.vbar(n+1, (int)x);
|
||||
}
|
||||
|
||||
if(loadmax < 0.05) status = BACKLIGHT_OFF;
|
||||
if(loadmax > 0.05) status = BACKLIGHT_ON;
|
||||
if(loads[lcd.wid-2] > LOAD_THRESHOLD) status = BLINK_ON;
|
||||
|
||||
// This must be drawn *after* the vertical bars... (?)
|
||||
sprintf(tmp, "%c%c LOAD AVG %2.2f %c%c", PAD, PAD, loads[lcd.wid-2], PAD, PAD);
|
||||
lcd.string(1, 1, tmp);
|
||||
|
||||
if(!rep)
|
||||
lcd.init_vbar();
|
||||
|
||||
|
||||
return status;
|
||||
} // End xload_screen()
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Credit Screen shows who wrote this...
|
||||
//
|
||||
int credit_screen(int rep)
|
||||
{
|
||||
|
||||
if(!rep)
|
||||
{
|
||||
lcd.clear();
|
||||
sprintf(tmp, "%c%c LCDPROC %s %c%c%c%c",
|
||||
PAD, PAD, version, PAD, PAD, PAD, PAD);
|
||||
lcd.string(1, 1, tmp);
|
||||
lcd.string(1, 2, " for Linux ");
|
||||
lcd.string(1, 3, " by William Ferrell ");
|
||||
lcd.string(1, 4, " and Scott Scriven ");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // End credit_screen()
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This is mostly for debugging. It should never show up.
|
||||
//
|
||||
int dumbass_screen(int rep)
|
||||
{
|
||||
|
||||
lcd.string(1,1, "---=== Haha... ==---");
|
||||
lcd.string(1,2, " You specified an ");
|
||||
lcd.string(1,3, " INVALID MODE!!! ");
|
||||
lcd.string(1,4, "---== Ya LOSER! ==--");
|
||||
/*
|
||||
lcd.string(1,1, "--===GO AWAY!!!===--");
|
||||
lcd.string(1,2, " You're a slimy, ");
|
||||
lcd.string(1,3, " mold-ridden ");
|
||||
lcd.string(1,4, " pop-tart! ");
|
||||
*/
|
||||
|
||||
return BLINK_ON;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// This gets called upon program exit, to say "goodbye"
|
||||
//
|
||||
int goodbye_screen(int rep)
|
||||
{
|
||||
|
||||
lcd.clear();
|
||||
/*
|
||||
lcd.string(1,1, "---===SHUTDOWN===---");
|
||||
lcd.string(1,2, " DANGER, WILL ");
|
||||
lcd.string(1,3, " ROBINSON! ");
|
||||
lcd.string(1,4, "---===EJECT!!!===---");
|
||||
usleep(250000);
|
||||
*/
|
||||
|
||||
lcd.string(1,1, " ");
|
||||
lcd.string(1,2, " Thanks for using ");
|
||||
lcd.string(1,3, " LCDproc and Linux! ");
|
||||
lcd.string(1,4, " ");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#ifndef MODE_H
|
||||
#define MODE_H
|
||||
|
||||
/*
|
||||
Don't use this yet! It's barely even started!
|
||||
*/
|
||||
|
||||
int stat_init();
|
||||
void stat_close();
|
||||
|
||||
typedef struct status
|
||||
{
|
||||
// should hold persistent data somehow...
|
||||
// data_type data;
|
||||
|
||||
// Takes position onscreen (x,y), and
|
||||
// format (i=int, f=float, h=horz bar, v=vert bar, 2=24-hour, 1=12-hour,
|
||||
// x=xload-style, etc...)
|
||||
// Each stat will only draw valid formats...
|
||||
// size is max size (graphs) or num digits, etc... (0 is "max" size)
|
||||
// reread specifies to re-grab the value first.
|
||||
void (*draw)(int x, int y, int size, char format, int reread);
|
||||
void (*read)(int reread);
|
||||
|
||||
// Should also maybe be able to return the data?
|
||||
// return_type (*get)();
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern status cpu;
|
||||
extern status cpu_nice;
|
||||
extern status cpu_idle;
|
||||
extern status cpu_sys;
|
||||
extern status cpu_usr;
|
||||
|
||||
extern status mem_free;
|
||||
extern status mem_total;
|
||||
extern status swap_free;
|
||||
extern status swap_total;
|
||||
|
||||
extern status load;
|
||||
|
||||
extern status date;
|
||||
extern status uptime;
|
||||
|
||||
extern status os_ver;
|
||||
|
||||
extern status disk_activity;
|
||||
extern status disk_free;
|
||||
extern status disk_total;
|
||||
|
||||
extern status net_sent;
|
||||
extern status net_recv;
|
||||
extern status net_rate;
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user