/* $Id: tsl.c,v 1.4 2001/01/29 09:23:29 root Exp $ tsl, temperature sensor data logger Copyright (C) 2000 James Cameron (quozl@us.netrek.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* to do set audio alarm on long duration increase over threshold */ #ifndef lint static char vcid[] = "$Id: tsl.c,v 1.4 2001/01/29 09:23:29 root Exp $"; #endif /* lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXSENSOR 4 #define MAX_NONE -50.0 #define MIN_NONE 100.0 /* line number where matrix starts */ #define MATRIX 7 #define COLUMN_WIDTH 12 #define COLUMN (80-(COLUMN_WIDTH*MAXSENSOR)) #define PLACE(number) (COLUMN+(COLUMN_WIDTH*number)) int woken; int lines[8] = { 0, 2, 3, 4, 6, 7, 9, 11 }; float datum[MAXSENSOR], max[MAXSENSOR], min[MAXSENSOR]; float lo[MAXSENSOR], hi[MAXSENSOR], acc[MAXSENSOR], sam[MAXSENSOR]; int loset[MAXSENSOR], hiset[MAXSENSOR], seen[MAXSENSOR]; int x, y; char old[256] = { 0 }; /* port access functions borrowed from prog84 */ int dev_port_fd = -1; #ifdef __alpha int port = 0x3bc; #else int port = 0x378; /* lpt1 /dev/lp0 */ #endif void open_io() { dev_port_fd = open("/dev/port", O_RDWR); if(dev_port_fd < 0) { perror("/dev/port"); exit(errno); } } void close_io() { close(dev_port_fd); dev_port_fd = -1; } void out_byte(int port, unsigned char byte) { off_t s; int r; s = lseek(dev_port_fd, port, 0); if (s < 0) perror("lseek"); else if (s != port) fprintf(stderr, "hmmm: seeking to %d, went to %ld.\n", port, (long)s); r = write(dev_port_fd, &byte, 1); if (r != 1) { fprintf(stderr, "hmmm: write returned %d\n", r); if (r < 0) perror("write"); } } unsigned char in_byte(int port) { off_t s; int r; unsigned char ch = 0; s = lseek(dev_port_fd, port, 0); if (s < 0) perror("lseek"); else if (s != port) fprintf(stderr, "hmmm: seeking to %d, went to %ld.\n", port, (long)s); r = read(dev_port_fd, &ch, 1); if (r != 1) { fprintf(stderr, "hmmm: read returned %d\n", r); if (r < 0) perror("read"); } return ch; } void reaper() { wait(NULL); } void graph() { if (strlen(old) == 0) return; signal(SIGCHLD, reaper); if (fork() != 0) return; execl("graph.sh", "graph.sh", old, NULL); execlp("graph.sh", "graph.sh", old, NULL); exit(0); } void beeper_on() { out_byte(port,0xff); } void beeper_off() { out_byte(port,0x00); } void wake(int x) { signal(SIGALRM, wake); woken++; } void cursor(int x, int y) { mvprintw(lines[y]+MATRIX, COLUMN+COLUMN_WIDTH*x-1, " "); mvprintw(lines[y]+MATRIX, COLUMN+COLUMN_WIDTH*x+COLUMN_WIDTH-3, " "); } void cursor_on(int x, int y) { standout(); cursor(x, y); standend(); } void cursor_off(int x, int y) { cursor(x, y); } void background() { int i; mvprintw(0, 0, "Temperature Sensor Logger, 0.4-macanbar"); mvprintw(1, 0, "Copyright (C) 2001 James Cameron (quozl@us.netrek.org)"); mvhline(2, 0, 0, 80); mvhline(MATRIX-3, COLUMN+COLUMN_WIDTH*0-2, 0, COLUMN_WIDTH*MAXSENSOR); mvprintw(MATRIX-2, COLUMN+COLUMN_WIDTH*0, "Truck"); mvprintw(MATRIX-2, COLUMN+COLUMN_WIDTH*1, "Big"); mvprintw(MATRIX-2, COLUMN+COLUMN_WIDTH*2, "Little"); mvprintw(MATRIX-2, COLUMN+COLUMN_WIDTH*3, "Shed"); mvhline(MATRIX-1, 0, 0, 78); mvprintw(MATRIX+0, 0, "Current Temperature"); mvhline(MATRIX+1, 0, 0, 78); mvprintw(MATRIX+2, 0, "Minimum Temperature"); mvprintw(MATRIX+3, 0, "Maximum Temperature"); mvprintw(MATRIX+4, 0, "Average Temperature"); mvhline(MATRIX+5, 0, 0, 78); mvprintw(MATRIX+6, 0, "Alarm if hotter than"); mvprintw(MATRIX+7, 0, "Alarm if colder than"); mvhline(MATRIX+8, 0, 0, 78); mvprintw(MATRIX+9, 0, "Alarm status"); mvhline(MATRIX+10, 0, 0, 78); /* vertical bars */ for(i=0;i<(MAXSENSOR+1);i++) { chtype ttee = (i == MAXSENSOR) ? ACS_URCORNER : ((i == 0) ? ACS_ULCORNER : ACS_TTEE); chtype plus = (i == MAXSENSOR) ? ACS_RTEE : ACS_PLUS; chtype btee = (i == MAXSENSOR) ? ACS_LRCORNER : ACS_BTEE; mvvline(MATRIX-3, COLUMN+COLUMN_WIDTH*i-2, ttee, 1); mvvline(MATRIX-2, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX-1, COLUMN+COLUMN_WIDTH*i-2, plus, 1); mvvline(MATRIX+0, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+1, COLUMN+COLUMN_WIDTH*i-2, plus, 1); mvvline(MATRIX+2, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+3, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+4, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+5, COLUMN+COLUMN_WIDTH*i-2, plus, 1); mvvline(MATRIX+6, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+7, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+8, COLUMN+COLUMN_WIDTH*i-2, plus, 1); mvvline(MATRIX+9, COLUMN+COLUMN_WIDTH*i-2, 0, 1); mvvline(MATRIX+10, COLUMN+COLUMN_WIDTH*i-2, btee, 1); } } void redo(int x, int y, float z) { mvprintw(MATRIX+lines[y], PLACE(x), "%5.2f ", z); } void text(int x, int y, char *z) { mvprintw(lines[y]+MATRIX, PLACE(x), z); } void wipe(int x, int y) { text(x, y, " "); } /* if keyboard used, process it */ void keyboard() { static char value[COLUMN_WIDTH+1] = { 0 }; int z, c; alarm(6); c = getch ( ); while ( c != ERR ) { switch ( c ) { case ' ': beeper_off(); mvprintw(22, 0, " "); clrtoeol(); break; case 'g': graph(); break; case '\f': clear(); background(); for (z=0;z 0) redo(z, 3, (float)(acc[z]/sam[z])); if (hiset[z]) redo(z, 4, hi[z]); if (loset[z]) redo(z, 5, lo[z]); } } cursor_on(x, y); refresh(); break; case KEY_LEFT: if (x>0) { cursor_off(x, y); x--; cursor_on(x, y); } break; case KEY_RIGHT: if (x<(MAXSENSOR-1)) { cursor_off(x, y); x++; cursor_on(x, y); } break; case KEY_UP: if (y>0) { cursor_off(x, y); y--; cursor_on(x, y); } break; case KEY_DOWN: if (y<(7-1)) { cursor_off(x, y); y++; cursor_on(x, y); } break; case KEY_NPAGE: if (y == 4) { hi[x]++; hiset[x] = 1; redo(x, y, hi[x]); } else if (y == 5) { lo[x]++; loset[x] = 1; redo(x, y, lo[x]); } break; case KEY_PPAGE: if (y == 4) { hi[x]--; hiset[x] = 1; redo(x, y, hi[x]); } else if (y == 5) { lo[x]--; loset[x] = 1; redo(x, y, lo[x]); } break; case KEY_END: if (y == 4) { hi[x] = datum[x]; hiset[x] = 1; redo(x, y, hi[x]); } else if (y == 5) { lo[x] = datum[x]; loset[x] = 1; redo(x, y, lo[x]); } break; case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (y == 4 || y == 5) { int len = strlen(value); if (len < (COLUMN_WIDTH - 2)) { value[len++] = c; value[len++] = 0; text(x, 7, value); } } break; case KEY_BACKSPACE: if (y == 4 || y == 5) { int len = strlen(value); if (len > 0) { value[len-1] = 0; wipe(x, 7); text(x, 7, value); } } break; case KEY_IC: case '\n': case '\r': case 0x09: if (y == 4 || y == 5) { int len = strlen(value); if (len > 0) { if (y == 4) { hi[x] = atof(value); hiset[x] = 1; redo(x, y, hi[x]); } else if (y == 5) { lo[x] = atof(value); loset[x] = 1; redo(x, y, lo[x]); } value[0] = 0; wipe(x, 7); } } break; case KEY_DC: case 0xff: case 0x7f: switch (y) { case 0: break; case 1: min[x] = MIN_NONE; break; case 2: max[x] = MAX_NONE; break; case 3: acc[x] = 0.0; sam[x] = 0.0; break; case 4: hiset[x] = 0; break; case 5: loset[x] = 0; break; } wipe(x, y); break; default: break; } c = getch ( ); } alarm(0); } int main ( int argc, char *argv[] ) { char *device; FILE *input, *output = NULL, *current; int fd, sample = 60, was, number, cursor = 0; time_t now; struct tm *tm; int i; struct termios termios; char *p, buffer[128]; /* buffer for data from sensor */ open_io(); /* reset sensor result array */ for (i=0; i 1) device = argv[1]; /* initialise curses screen handling */ initscr(); cbreak(); noecho(); nonl(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); /* leaveok(stdscr, TRUE); */ background(); /* position cursor */ x = 0; y = 0; cursor_on(x, y); /* open the serial port, causing DTR to be raised and the sensor to run */ input = fopen(device, "r" ); if (input == NULL) { perror("fopen"); } /* set the serial port characteristics */ fd = fileno(input); if (tcgetattr(fd, &termios) < 0) { perror("tcgetattr"); exit(1); } /* useful at remote end to see echo'd data */ termios.c_lflag |= ECHO; if (cfsetospeed(&termios, B2400) < 0) { perror("cfsetospeed"); exit(1); } if (cfsetispeed(&termios, B2400) < 0) { perror("cfsetispeed"); exit(1); } if (tcsetattr(fd, TCSANOW, &termios) < 0) { perror("tcsetattr"); exit(1); } woken = 0; signal(SIGALRM, wake); /* infinite loop */ for(;;) { /* refresh the screen */ refresh(); /* wait for data */ { struct timeval tv; fd_set in; int status; tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO(&in); FD_SET(fileno(input), &in); FD_SET(fileno(stdin), &in); status = select(fileno(input)+1, &in, NULL, NULL, &tv); if (status == 0) { standout(); mvprintw(22, 0, "Communication breakdown, check power and cables."); standend(); beep(); beeper_on(); continue; } if (FD_ISSET(fileno(stdin), &in)) { keyboard(); continue; } mvprintw(23, 0, "Receiving okay."); clrtoeol(); if (status < 0) { perror("select"); exit(1); } } alarm(2); /* get a line of data from the sensor */ p = fgets(buffer, 128, input); if (p == NULL) { perror("fgets"); exit(1); } alarm(0); /* remove the terminating new-line */ buffer[strlen(buffer)-1] = '\0'; /* remove preceeding carriage return */ p = buffer; while (*p == '\r' || *p == '\n') p++; /* establish timestamp for this sample */ now = time(NULL); tm = localtime(&now); /* check packet header for reset detection */ if (*p == 'R') { mvprintw(MATRIX-2, 0, "%s", p); continue; } /* ignore any other packet header other than sensor reports */ if (!isdigit(*p)) continue; /* decode the sensor number */ sscanf(p, "%d", &number); number--; if (number < 0 || number > MAXSENSOR-1) continue; /* check for missing blank */ p++; if (!isblank(*p)) continue; /* check for verbose mode additional data */ if (strlen(p) > 9) { #ifdef PRINT_VERBOSE mvprintw(22, 0, p); #endif p += 10; } /* read and decode the data */ sscanf(p, "%f", &datum[number]); redo(number, 0, datum[number]); if (datum[number] < min[number]) { min[number] = datum[number]; redo(number, 1, min[number]); } if (datum[number] > max[number]) { max[number] = datum[number]; redo(number, 2, max[number]); } acc[number] += datum[number]; sam[number]++; redo(number, 3, (float)(acc[number]/sam[number])); /* check for limit */ if (hiset[number] && (datum[number] > hi[number])) { standout(); text(number, 6, "TOO HOT"); standend(); beep(); mvprintw(22, 0, "Overtemperature alarm for sensor %d", number+1); clrtoeol(); beeper_on(); } else if (loset[number] && (datum[number] < lo[number])) { standout(); text(number, 6, "TOO COLD"); standend(); beep(); mvprintw(22, 0, "Undertemperature alarm for sensor %d", number+1); clrtoeol(); beeper_on(); } else { text(number, 6, "Okay "); } seen[number] = 5; for(i=0;itm_yday ); if ( output == NULL ) { output = fopen ( new, "a" ); if (output == NULL) { perror("fopen"); exit(1); } strcpy ( old, new ); } else { if ( strcmp ( old, new ) ) { fclose ( output ); output = fopen ( new, "a" ); if (output == NULL) { perror("fopen"); exit(1); } strcpy ( old, new ); } } fprintf(output, "%7.4f", (float) tm->tm_hour + (float) tm->tm_min / 60.0 + (float) tm->tm_sec / 3600.0); for(i=0;i