#include <unistd.h>
#include <fcntl.h>

#include "serial.h"

int ser_init(const char *device)
{
	struct termios attr;
	int handle;

	/* Mac OS X: O_NONBLOCK is required because (in some cases?) the open
	 * will block until the hardware flow control lines are set correctly,
	 * and if this never happens the program hangs and becomes unkillable.
	 */
	handle = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
	if (handle < 0)
		return 0;

	tcgetattr(handle, &attr);
	cfsetispeed(&attr, B19200);
	cfsetospeed(&attr, B19200);
	cfmakeraw(&attr);
	attr.c_cflag |= CLOCAL | CREAD;
	attr.c_iflag &= ~IXOFF & ~IXANY;
	tcsetattr(handle, TCSANOW, &attr);

	/* It's safe to block now that flow control has been turned off */
	fcntl(handle, F_SETFL, 0);

	return handle;
}

void ser_shutdown(int handle)
{
	close(handle);
}

void ser_send_buf(int handle, void *buf, int len)
{
	write(handle, buf, len);
	fsync(handle);
}

unsigned char ser_recv(int handle)
{
	unsigned char byte;

	read(handle, &byte, 1);

	return byte;
}

void ser_recv_buf(int handle, void *buf, int len)
{
	while (len)
	{
		int n = read(handle, buf, len);
		if (n < 0)
		{
			memset(buf, 0, len);
			return;
		}

		len -= n;
		buf += n;
	}
}

