/* 
 * prs.c - Control Pow-R-Switch from BlackBox
 *
 * Copyright (C) 2000, 2001 Martin K. Petersen <mkp@mkp.net>
 *
 * 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 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

static char const rcsid[] = "$Id: prs.c,v 1.2 2001/11/19 02:03:36 mkp Exp $";

void usage (void)
{
    fprintf (stderr, "Usage:\n\n");
    fprintf (stderr, "prs [-p <device>] [-u|-d|-t|-s] <socket>|all\n\n");
    fprintf (stderr, "\t-p <dev>\tSerial port to send commands to\n");
    fprintf (stderr, "\t-u\tPower Up\n");
    fprintf (stderr, "\t-d\tPower Down\n");
    fprintf (stderr, "\t-t\tPower Toggle\n");
    fprintf (stderr, "\t-s\tPower Status\n\n");
    fprintf (stderr, "Where <socket> is a number from 0-9 or `all' for all sockets\n\n");
    fprintf (stderr, "If PRSPORT is not set, -p must be specified\n\n");

    exit (EXIT_FAILURE);
}


int main (int argc, char *argv[])
{
    char opt, action = 0, *sockstr, cmdbuf[16], buf[1024], *port = NULL;
    int fd, socket;
    struct termios tios;
    FILE *file;

    if (argc < 2)
	usage();

    /* Grab default port from environment */
    port = getenv ("PRSPORT");

    /* Option parsing */
    while ((opt = getopt (argc, argv, "udtshp:")) != EOF) {

	switch (opt) {

	case 'p':
	    port = optarg;
	    if (port == NULL)
		usage();
	    break;
	    
	case 'u':
	    action = '1';
	    break;
	    
	case 'd':
	    action = '0';
	    break;
	    
	case 't':
	    action = 'T';
	    break;
	    
	case 's':
	    action = '?';
	    break;
	    
	case 'h':
	default:
	    usage();
	}

    }

    /* No environtment variable, and no -p */
    if (port == NULL)
	usage();

    /* I friggin' HATE user input validation */
    if (action == 0)
	action = '?';
    
    sockstr = argv[optind];

    /* If nothing or "all" is specified, use that */
    if (sockstr == NULL || !strcmp (sockstr, "all"))
	socket = '*';
    /* Else find socket number */
    else {
	if (*sockstr < '0' || *sockstr > '9')
	    usage();

	socket = *sockstr;
    }

    /* Don't allow powering off, nor toggling all sockets */
    if (socket == '*' && (action == '0' || action == 'T')) {
	fprintf (stderr, "Can't power down/toggle all sockets in one go\n");
	exit (EXIT_FAILURE);
    }

    /* Do the serial dance */
    fd = open (port, O_RDWR|O_SYNC, 0);

    if (fd < 0) {
	fprintf (stderr, "Could not open %s for reading and writing\n", port);
	exit (EXIT_FAILURE);
    }

    if (tcgetattr (fd, &tios) < 0) {
	fprintf (stderr, "Could not get I/O settings for %s\n", port);
	exit (EXIT_FAILURE);
    }

    /* 9600n8 */
    tios.c_iflag = IGNBRK;
    tios.c_oflag = 0;
    tios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | CRTSCTS;
    tios.c_lflag = 0;
    memset ((char *) tios.c_cc, 0, NCCS);

    if (tcsetattr (fd, TCSANOW, &tios) < 0) {
	fprintf (stderr, "Could not apply tcsettings for %s\n", port);
	exit (EXIT_FAILURE);
    }

    if (! (file = fdopen (fd, "r+"))) {
	fprintf (stderr, "Could not open file for %s\n", port);
	exit (EXIT_FAILURE);
    }

    /* Assemble command string */
    sprintf (cmdbuf, "\r\n%c%c%c%c%c%c%c%c\r\n", '', '', '', 
	     '', '', '', socket, action);
    
    /* Kick the PRS into action */
    if (write (fd, cmdbuf, 12) < 12)
	fprintf (stderr, "Error writing command to %s\n", port);

    /* Can't use select() because we don't know the actual number of
     * lines the PRS will output. And in the toggle case, we'll have a
     * huge time gap between Off and On.  Sucks!
     */
    sleep (1);

    /* Read status */
    while (fgets (buf, sizeof (buf), file))
	if (!strncmp (buf, "Plug", 4))
	    printf ("%s", buf);

    if (action == 'T') {
	sleep (10);

	while (fgets (buf, sizeof (buf), file))
	    if (!strncmp (buf, "Plug", 4))
		printf ("%s", buf);
    }

    exit (EXIT_SUCCESS);
}
 
/* EOF */
