/* Martin Koch and Jesper H. Olsen 15/01/1997 16:19. mk.*/ /* Version 0.99 : Introduced version numbers. This update now generates the status file, a html-page, and a .plan in /home/coke. Also introduced a select call that sleeps for 100 usec before each probe() Version 1.0 : Introduced automatic refresh each 15 secs in html code. Introduced white background color. Introduced link to home page. Fixed bug so a coke is no longer 'sold' from each full column each time coke is started. Version 1.1 : Added a "back to mainpage" on the HTML page and changed location of the log files Version 1.2 : Changed the text in the current status files to reflect the actual contents of the respective column. Version 1.3 : Fixed bug in init() - when current_status is read, the timer must not be set to 0 when the column is empty 16/02/1997 15:46. mk. Version 1.4 : Had to change some stuff because localtime has been changed in redhat 4 26/03/1997 mk. */ #define VERSION "1.4" /* string for the version */ #include #include #include /* gettimeofday */ #include "/usr/include/asm/io.h" #include #include #include #define DEBUG 1 #define EMPTY 0 #define FULL 1 #define SELL 2 #define INDECISIVE 3 #define MAXTIME 10 /* number of seconds diode must be lit for*/ /* the column to be considered empty*/ #define UPDATE 5 /* number of seconds between updates of */ /* status file */ typedef struct { int state; long time; /* no see :-) */ } statetype; typedef struct { int machine; int * probe; long * timer; /* times how long a diode has been lit */ statetype * state; int * counter; int max; /*maximum number of columns, including use correct change */ int mintime; } machinetype; typedef struct { int days; int hours; int minutes; } my_time_type; machinetype cola,mars,witten,faxe; /* reserved for future expansions */ int probecount=0; int P (int i) { if (i>0) return 1; else return 0; } void probe() { char s,c; int i; probecount++; s=inb(0x279); c=inb(0x27a); cola.probe[0]=P(c&1); cola.probe[1]=!(P(s&64)); cola.probe[2]=(P(s&128)); cola.probe[3]=!(P(s&32)); cola.probe[4]=!(P(s&16)); cola.probe[5]=!(P(s&8)); cola.probe[6]=P(c&8); /* cola.probe[0]=0; SLET DETTE NAAR ELEKTRONIKKEN BLIVER LAVET! */ /* for (i=0;i<=6;i++) printf("%3d ",cola.probe[i]); printf("\n"); */ } void log(machinetype * m, int col, int event) { /* struct timeval tv; struct timezone tz; */ struct tm *tmp; time_t t; FILE* fp; char res[50]; /* gettimeofday(&tv,&tz); */ t=time(NULL); tmp=localtime(&t); sprintf(res,"/home/httpd/html/log/%d_%d_%d.log", m->machine,tmp->tm_mon,tmp->tm_year); fp = fopen(res,"a"); /* fprintf(fp, "1 "); */ fprintf(fp, "%d ",col); switch (event) { case EMPTY : { fprintf(fp, "E "); break; } case FULL : { fprintf(fp, "F "); break; } case SELL : { fprintf(fp, "V "); break; } case INDECISIVE : { fprintf(fp, "I "); break; } } fprintf(fp, "%ld\n",t); /*ld is format for long int */ fclose(fp); } void init() { struct timeval tv; struct timezone tz; int i; int b; char dummyx; char tmpchar; FILE *fp; long duration; gettimeofday(&tv,&tz); if (ioperm(0x278,3,1)<0) { perror("ioperm aaben gik galt"); exit(-1); } cola.machine = 1; cola.timer = (long*) malloc(sizeof(long)*7); /* use correct change diode*/ cola.probe = (int*) malloc(sizeof(int)*7); /* the coke machine has 6 */ /* columns and 1 diode */ cola.state = (statetype*) malloc(sizeof(statetype)*7); cola.counter = (int*) malloc(sizeof(int)*7); /* the number of sold items*/ /* from each column */ cola.max = 6; cola.mintime = 1; printf("This Cokeserver-interface(tm) is connected with cable from BN-elektronik.Good.\n"); /* joke */ printf("Version: %s\n",VERSION); /* This reads the old current_status file in case of a reboot */ fp = fopen("/home/httpd/html/current_status","r"); if (fp != NULL) /* if file exists */ { for (i=0;i<7;i++) {b = fgetc(fp);} /* ignore magic cookie */ probe(); for (i=0;i<=cola.max;i++) { if(i==0) { fscanf(fp,"%c%1s%ld",&dummyx,&tmpchar,&duration); cola.counter[0]=0; /* not used */ } else fscanf(fp,"%1s%d%ld",&tmpchar,&cola.counter[i],&duration); cola.state[i].time = tv.tv_sec-duration; if (cola.probe[i]==0) { cola.state[i].state=FULL; cola.timer[i]=0; if(tmpchar=='E') /* column has been filled during downtime */ { cola.counter[i]=0; cola.state[i].time=tv.tv_sec; log(&cola,i,FULL); } } else { cola.timer[i]=tv.tv_sec; /* light is lit; assume it lit now */ if(tmpchar=='E') cola.state[i].state=EMPTY; else cola.state[i].state=FULL; } } fclose(fp); } else /* just initialize with sensible values */ { for (i=0;i<=cola.max;i++) { cola.probe[i]=0; /* state of the diode */ cola.timer[i]=0; /* event timer */ cola.state[i].state=FULL; /* state of the column */ cola.state[i].time=tv.tv_sec; /* init time */ cola.counter[i]=0; /* amount of items sold */ } } } void update (machinetype * m) { struct timeval tv; struct timezone tz; int i; gettimeofday(&tv,&tz); for (i=0;i<= m->max; i++) { if ((m->timer[i]==0) && (m->probe[i]==0)) { /*m->state[i].state=0*/; } else { gettimeofday(&tv,&tz); if (m->probe[i]==0) /* diode is not lit */ { if (((tv.tv_sec - m->timer[i]) > MAXTIME) && (m->state[i].state == EMPTY)) /* column has been filled */ { /* printf("%d %d\n",m->state[i].state,m->probe[i]);*/ m->state[i].state=FULL; m->state[i].time=tv.tv_sec; m->counter[i]=0; m->timer[i]=0; log(m,i,FULL); } else { if ((tv.tv_sec - m->timer[i]) > m->mintime) /* vend */ { if (DEBUG && (m->state[i].state==EMPTY)) printf ("strange\n"); m->counter[i]++; m->timer[i]=0; log(m,i,SELL); } else /* indecisive press */ { m->timer[i]=0; log(m,i,INDECISIVE); } } } else /* diode is lit */ { if ((m->timer[i]==0) && (m->state[i].state==FULL)) /* diode has lit. Start timer */ { m->timer[i]=tv.tv_sec; } else { if (((tv.tv_sec - m->timer[i]) > MAXTIME) && (m->state[i].state==FULL))/* column has gone empty */ { m->state[i].state=EMPTY; m->state[i].time=tv.tv_sec; m->counter[i]++; log(m,i,EMPTY); } } } } } } void status_file() { int i; FILE *fp; struct timeval tv; struct timezone tz; gettimeofday(&tv,&tz); fp = fopen ("/home/httpd/html/current_status","w"); fprintf(fp,"MK&JHO\n"); fprintf(fp,"1 "); if (cola.state[0].state==FULL) /* Use Correct Change diode is not lit. */ fprintf(fp,"- "); /* It is represented using the same */ else /* datatypes as columns, for simplicity */ fprintf(fp,"+ "); fprintf(fp,"%ld ",tv.tv_sec-cola.state[0].time); for (i=1;i<=6;i++) { if (cola.state[i].state==FULL) fprintf (fp,"F "); else fprintf (fp,"E "); fprintf(fp,"%d %ld ",cola.counter[i],tv.tv_sec-cola.state[i].time); } fprintf(fp,"\n"); fclose(fp); fp = fopen ("/home/httpd/html/probe_status","w"); for (i=0;i<=6;i++) { fprintf (fp,"%d ",cola.probe[i]); } fprintf(fp,"\n"); fclose(fp); } void write_time(char * t, long time) { int days,hours,mins; mins = (time / 60) % 60; hours = (time / (60*60)) % 24; days = (time / (60*60*24)); if (days > 0) sprintf(t,"%d days, %d hours, and %d minutes",days,hours,mins); else if (hours > 0) sprintf(t,"%d hours and %d minutes",hours,mins); else sprintf(t,"%d minutes",mins); } void html_status_file() { int i; FILE *fp; struct timeval tv; struct timezone tz; my_time_type t; char text[100]; /* for writing durations in */ gettimeofday(&tv,&tz); fp = fopen ("/home/httpd/html/current_status.html","w"); fprintf(fp,""); fprintf(fp,"Current state of the coke machine at DIKU\n"); fprintf(fp,"

The current state of the coke machine at DIKU


\n"); fprintf(fp,"

This file is updated every 5 seconds


\n"); if (cola.state[0].state==FULL) /*diode*/ fprintf(fp,"At the moment, it's not necessary to use correct change.\n"); else fprintf(fp,"At the moment, it's necessary to use correct change. \n"); write_time(text,tv.tv_sec-cola.state[0].time); fprintf(fp,"This has been the case the last %s\n

",text); fprintf(fp,"

    \n"); for (i=1;i<=5;i++) { fprintf(fp, "
  • Column %d ",i); if (cola.state[i].state==FULL) { fprintf(fp,"contains some cokes.
  • \n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp,"
    • It's been %s since it was filled.
    • \n",text); fprintf(fp,"
    • Meanwhile, %d items have been sold from this column
    \n",cola.counter[i]); } else { fprintf (fp,"is currently empty.\n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp,"
    • It's been %s since it became empty.
    • \n",text); fprintf(fp,"
    • %d items were sold from this column before it became empty.
    \n",cola.counter[i]); } } fprintf(fp, "
  • Column %d ",i); if (cola.state[i].state==FULL) { fprintf(fp,"contains some coke-lights.
  • \n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp,"
    • It's been %s since it was filled.
    • \n",text); fprintf(fp,"
    • Meanwhile, %d items have been sold from this column
    \n",cola.counter[i]); } else { fprintf (fp,"is currently empty.\n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp,"
    • It's been %s since it became empty.
    • \n",text); fprintf(fp,"
    • %d items were sold from this column before it became empty.
    \n",cola.counter[i]); } fprintf(fp,"
    Back to the main page.\n"); fprintf(fp,"
\n"); fclose(fp); } void finger_status_file() { int i; FILE *fp; struct timeval tv; struct timezone tz; my_time_type t; char text[100]; /* for writing durations in */ gettimeofday(&tv,&tz); fp = fopen ("/home/cola/.plan","w"); fprintf(fp,"\n\nCurrent state of the coke machine at DIKU\n"); fprintf(fp,"This file is updated every 5 seconds\n"); if (cola.state[0].state==FULL) /*diode*/ fprintf(fp,"At the moment, it's *not* necessary to use correct change.\n"); else fprintf(fp,"At the moment, it's necessary to use correct change. \n"); write_time(text,tv.tv_sec-cola.state[0].time); fprintf(fp,"This has been the case the last %s\n\n",text); for (i=1;i<=6;i++) { fprintf(fp, "Column %d ",i); if (cola.state[i].state==FULL) { if (i==6) fprintf(fp,"contains some coke-lights.\n"); else fprintf(fp,"contains some cokes.\n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp," It's been %s since it was filled.\n",text); fprintf(fp," Meanwhile, %d items have been sold from this column.\n",cola.counter[i]); } else { fprintf (fp,"is currently *empty*.\n"); write_time(text,tv.tv_sec-cola.state[i].time); fprintf(fp," It's been %s since it became empty.\n",text); fprintf(fp," %d items were sold from this column before it became empty.\n",cola.counter[i]); } } fprintf(fp,"\n"); fclose(fp); } void update_current_status() { status_file(); html_status_file(); finger_status_file(); } void loop() { struct timeval tv; struct timezone tz; long ring=0,start; gettimeofday(&tv,&tz); start=ring=tv.tv_sec; while(1) { probe(); gettimeofday(&tv,&tz); if ((tv.tv_sec - ring) >= UPDATE) { /* printf("probecount=%d\n",probecount);*/ probecount=0; update_current_status(); ring=tv.tv_sec; } update(&cola); /* wait a while. A delay of 100 usec gives 50 probes/sec */ tv.tv_sec=0; tv.tv_usec=400; select(0,0,0,0,&tv); } } void main () { init(); loop(); }