/*
 * setr8n  v0.1 2005-08-31
 *
 * The original  location of this source is
 * http://www.economicoutlook.net/src/setr8n.c
 *
 * Copyright (C) 2005 by Adrian Butterworth
 * adrian@economicoutlook.net
 * ( This is a quick first hack - please send me any bugs / improvements etc. )
 *
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU Library 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 
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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
 */

/* setr8n provides a simple command line interface to a Rain8Net serial
 * communications watering control system.
 * 
 * See http://www.wgldesigns.com/
 * for H/W & protocol details.
 *
 * It sends a short command string out a serial port pauses briefly
 * then returns any characters received. See usage message in code below
 * 
 * TODO/BUGS
 * - needs locking code (till then avoid overlapping invocations)
 * - validation incomplete
 * - tidy usage
 * 
 * For a more generic serial IO utility see querySerial
 * from www.embeddedlinuxinterfacing.com by Craig Hollabaugh
 * which was hacked to form the base of this program. 
 */

/* build instructions ;)
 *  gcc -o /usr/bin/setr8n  setr8n.c
 */

#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <stdlib.h>

struct termios tio;

void usage () {
  printf("Usage: setr8n SERIALDEVICE COMMAND [ZONE]\n");
  printf("Example: setr8n /dev/tts/0 on 1\n\n");
  printf("commands: on, off\n");
  printf("zone: 1-8     (controller 1 zone\n");
  printf("      11-2548 (controllernumber*10 + zone\n");
  exit( 1 );
}

int controller (int z ) {
  if (z >=10 ) {
    return z/10;     // use high order digits for zone
  } else {
    return 1;        // default zone is 1 not 0
  }
}

int main(int argc, char *argv[])
{
  int fd, status, commandlength, result, zone;
  long baud;
  char buffer[255], command[40];
  baud = B4800;
  commandlength = 3;

  if (argc < 3 ) {
    usage();
  }

  if (strcmp (argv[2] , "on" ) == 0  ) { 
    if (argc != 4 || sscanf(argv[3], "%d", &zone) != 1 ) {
      usage();
    }
    command[0] = '@';
    command[1] = controller(zone); // controller specified as byte value
    command[2] = zone % 10 + 48 ;  // convert low order integer 1-8 to ascii 1-8
  } else if ( strcmp (argv[2] , "off" ) == 0 ) {
    if (argc != 4 || sscanf(argv[3], "%d", &zone) != 1 ) {
      // default to all zones all controllers
      command[0] = ' ';
      command[1] = 'U';
      command[2] = 'U';
    } else {
      command[0] = '@';
      command[1] = controller(zone);
      command[2] = zone % 10 + 64 ;  // convert low order integer 1-8 to ascii A-H
    }
  } else {
    usage();
  }
    
/* open the serial port device file
 * O_NDELAY - tells port to operate and ignore the DCD line
 * O_NOCTTY - this process is not to become the controlling 
 *            process for the port. The driver will not send
 *            this process signals due to keyboard aborts, etc.
 */
  if ((fd = open(argv[1],O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
  {
    printf("Couldn't open %s\n",argv[1]);
    exit(1);
  }

/* we are not concerned about preserving the old serial port configuration
 * CS8, 8 data bits
 * CREAD, receiver enabled
 * CLOCAL, don't change the port's owner 
 */
  tio.c_cflag = baud | CS8 | CREAD | CLOCAL;
  tio.c_cflag &= ~HUPCL; /* clear the HUPCL bit, close doesn't change DTR */ 
  tio.c_lflag = 0;       /* set input flag non-canonical, no processing */
  tio.c_iflag = IGNPAR;  /* ignore parity errors */
  tio.c_oflag = 0;       /* set output flag non-canonical, no processing */
  tio.c_cc[VTIME] = 0;   /* no time delay */
  tio.c_cc[VMIN]  = 0;   /* no char delay */
  tcflush(fd, TCIFLUSH); /* flush the buffer */
  tcsetattr(fd, TCSANOW, &tio); /* set the attributes */
  
/* Set up for no delay, ie non-blocking reads will occur. 
   When we read, we'll get what's in the input buffer or nothing */
  fcntl(fd, F_SETFL, FNDELAY);

/* write the formatted command out the serial port */
  result = write(fd, command, commandlength);
  if (result < 0) {
    fputs("write failed\n", stderr);
    close(fd);
    exit(1);
  }

/* wait for awhile, 500 ms*/
  usleep(500000);

/* read the input buffer and print it */
  result = read(fd,buffer,255);
  buffer[result] = 0; // zero terminate so printf works
  printf("%s",buffer);

/* close the device file */
  close(fd);
}
