/*
    $Id: tsl.c,v 1.12 2004/01/26 06:58:50 james Exp james $

    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
*/

#ifndef lint
static char vcid[] = "$Id: tsl.c,v 1.12 2004/01/26 06:58:50 james Exp james $";
#endif /* lint */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>

#define MAXSENSOR 4
#define MAXFILENAME 256

#include <termios.h>
#include <unistd.h>

static int sfd;
static int cancel;
static char *device;

static void serial_open()
{
  struct termios termios;

  sfd = open(device, O_RDONLY);
  if (sfd < 0) {
    char buffer[1024];

    snprintf(buffer, 1024, "open: %s", device);
    perror(buffer);
    exit(1);
  }

  /* set the serial port characteristics */
  if (tcgetattr(sfd, &termios) < 0) {
    perror("tcgetattr");
    exit(1);
  }

  if (cfsetospeed(&termios, B2400) < 0) {
    perror("cfsetospeed");
    exit(1);
  }

  if (cfsetispeed(&termios, B2400) < 0) {
    perror("cfsetispeed");
    exit(1);
  }

  if (tcsetattr(sfd, TCSANOW, &termios) < 0) {
    perror("tcsetattr");
    exit(1);
  }
}

static void serial_close()
{
  close(sfd);
}

static char *serial_read(char *buffer, int size)
{
  char *p;
  int s;

  cancel = 0;
  alarm(5);
  p = buffer;
  s = size;
  while (1) {
    int n = read(sfd, p, 1);
    if (cancel) {
      serial_close();
      sleep(10);
      serial_open();
      break;
    }
    if (n == 0) {
      sleep(1);
      continue;
    }
    if (n < 0) {
      perror("read");
      break;
    }
    if (*p == '\r' || *p == '\n') break;
    p++;
    s--;
    if (s == 1) break;
  }
  *p = '\0';
  alarm(0);

  return buffer;
}

static void sigalrm(int signal)
{
  fprintf(stderr, "timeout cancel\n");
  cancel = 1;
}

int main ( int argc, char *argv[] )
{
  char *p, buffer[128];
  char *name = "%Y-%j.log";
  FILE *output = NULL;
  int i, number, sample, seen[MAXSENSOR];
  time_t now;
  struct tm *tm;
  float datum[MAXSENSOR];
  int breaker = 0;

  /* handle SIGALRM */
  {
    struct sigaction *sa = calloc(1, sizeof(struct sigaction));
    sa->sa_handler = sigalrm;
    sigaction(SIGALRM, sa, NULL);
    free(sa);
  }

  /* reset sensor result array */
  for (i=0; i<MAXSENSOR; i++) {
    seen[i] = 0;
    datum[i] = 0.0;
  }

  /* say g'day */
  fprintf(stderr, "Temperature Sensor Logger (Minimal), 1.5\n"
	 "Copyright (C) 2008  James Cameron (quozl@us.netrek.org)\n"
	 "%s\n\n"
"This program comes with ABSOLUTELY NO WARRANTY; for details see source.\n"
"This is free software, and you are welcome to redistribute it under certain\n"
"conditions; see source for details.\n\n", vcid);

  /* allow user to specify alternate serial port as first argument */
  device = "/dev/ttyS0";
  if (argc > 1) {
    device = argv[1];
  }

  /* allow user to specify sample recording rate */
  sample = 30;
  if (argc > 2) {
    sample = atoi(argv[2]);
  }

  /* allow user to specify recording file name */
  if (argc > 3) {
    name = argv[3];
  }

  /* open the serial port, causing DTR to be raised and the sensor to run */
  serial_open();

  /* infinite loop */
  for(;;) {
    p = serial_read(buffer, 128);
    p = buffer + strlen(buffer) - 1;
    while (*p == '\r' || *p == '\n') {
      *p-- = '\0';
      if (p < buffer) break;
    }
    p = buffer;
    while (*p == '\r' || *p == '\n') p++;
    if (*p == 'R') {
      continue;
    }
    if (!isdigit(*p)) continue;
    number = atoi(p)-1;
    if (number < 0 || number > MAXSENSOR-1) continue;
    p++;
    if (*p != ' ') continue;
    if (strlen(p) > 9) p += 11;
    now = time(NULL);
    tm = localtime(&now);
    p++;
    sscanf(p, "%f", &datum[number]);
    seen[number]++;
    if (number != 0) {
      /* is not first sensor, so go back for more */
      continue;
    }
    if (seen[number] < 2) {
      /* is first sensor, but it is first time we saw it, try more */
      continue;
    }

    char new[MAXFILENAME];
    char old[MAXFILENAME];

    /* create a file name */
    strftime(new, MAXFILENAME-1, name, tm);
    if (output == NULL) {
      output = fopen(new, "a");
      if (output == NULL) { perror(new); exit(1); }
      strcpy(old, new);
    } else {
      if (strcmp(old, new)) {
	fprintf(stderr, "\n\nnew file, new=%s, old=%s\n\n", new, old);
	fclose(output);
	output = fopen(new, "a");
	if (output == NULL) { perror(new); exit(1); }
	strcpy(old, new);
      }
    }

    /* gnuplot deserves a blank line for a new sample range, aka run */
    if (!breaker) {
      fprintf(output, "\n");
      breaker++;
    }

    char ts[80];
    strftime(ts, 79, "%s", tm);
    fprintf(output, "%s", ts);

    for (i=0; i<MAXSENSOR; i++) {
      if (seen[i]) {
        fprintf(output, "\t%.2f", datum[i]);
      } else {
        fprintf(output, "\t");
      }
    }
    fprintf(output, "\n");
    fflush(output);
    serial_close();
    now = time(NULL);
    sleep(sample);
    /* did we sleep for an apparently unreasonable time period due suspend? */
    if ((time(NULL) - now) > (sample * 2)) breaker = 0;
    serial_open(device);
    for (i=0; i<MAXSENSOR; i++) {
      seen[i] = 0;
      datum[i] = 0.0;
    }
  }
}
