/*
 * serial.c - Send data to a Modela MDX-15/20
 *
 * Written 2009 by Werner Almesberger
 * Copyright 2009 Werner Almesberger
 *
 * 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.
 */


#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>

#include "serial.h"


static int tty;
static struct termios old;


static void reset_tty(void)
{
	if (tty >= 0)
		if (tcsetattr(tty, TCSADRAIN, &old) < 0)
			perror("tcsetattr");
}


void serial_open(const char *name)
{
	struct termios new;


	tty = open(name, O_WRONLY | O_NOCTTY);
	if (tty < 0) {
		perror(name);
		exit(1);
	}

	if (tcgetattr(tty, &old) < 0) {
		perror("tcgetattr");
		exit(1);
	}
	atexit(reset_tty);

	new = old;
	cfmakeraw(&new);
	cfsetospeed(&new, B9600);
	new.c_iflag |= IXON;
	new.c_cflag |= CLOCAL | CRTSCTS;
	new.c_lflag &= ~ECHO;
	if (tcsetattr(tty, TCSAFLUSH, &new) < 0) {
		perror("tcsetattr");
		exit(1);
	}
}


void serial_close(void)
{
	reset_tty();
	(void) close(tty);
	tty = -1;
}


void serial_printf(const char *fmt, ...)
{
	char buf[10000]; /* more than enough :) */
	va_list ap;
	int len;
	ssize_t wrote;

	va_start(ap, fmt);
	len = vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);
	if (len >= sizeof(buf)-1) {
		fprintf(stderr, "buffer too small\n");
		exit(1);
	}
	wrote = write(tty, buf, strlen(buf));
	if (wrote < 0) {
		perror("write");
		exit(1);
	}
	if (wrote != len) {
		fprintf(stderr, "short write: %d < %d\n",
		    (int) wrote, (int) len);
		exit(1);
	}
}