/* dmx.c */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <termios.h>
#include <strings.h>
#include <assert.h>
#include "dmx.h"

#define PORT "/dev/ttyU0"
#define DMX_PACKETSIZE (DMX_UNIVERSESIZE + 6)

int dmxfd;

char dmxpacket[DMX_UNIVERSESIZE + DMX_PACKETSIZE];
char *dmxuniverse;

void dmx_open(void)
{
	struct termios t;
	int flags;

	dmxfd = open(PORT, O_NONBLOCK | O_RDWR, 0);
	if (dmxfd == -1) {
		err(1, "failed to open DMX port");
	}

	flags = fcntl(dmxfd, F_GETFL);
	fcntl(dmxfd, F_SETFL, flags & ~O_NONBLOCK);

	tcgetattr(dmxfd, &t);
	cfmakeraw(&t);
	t.c_cflag = CLOCAL | CREAD | CS8;
	tcsetattr(dmxfd, TCSANOW, &t);
}


void dmx_close(void)
{
	close(dmxfd);
}

void dmx_dumpparams(void)
{
	char buf[1024];
	int more;
	char *ptr;
	int bytes;
	int len;

	buf[0] = 0x7e;
	buf[1] = 3;
	buf[2] = 2;
	buf[3] = 0;
	buf[4] = 0;
	buf[5] = 0;
	buf[6] = 0xe7;
	if (write(dmxfd, buf, 7) != 7)
		printf("didn't write 7 bytes\n");

	more = 1;
	ptr = buf;
	bytes = 0;
	len = 0;
	while (more) {
		if (read(dmxfd, ptr, 1) != 1)
			goto out;
		bytes++;
		ptr++;
		if (buf[0] != 0x7e) {
			printf("Invalid packet received\n");
			goto out;
		}
		if (bytes == 4)
			len = buf[2] | (buf[3] << 8);
		if (bytes == len + 5) {
			if (buf[bytes-1] != (char)0xe7) {
				printf("Invalid packet end\n");
				goto out;
			}
			more = 0;
		}
	}

	printf("Received packet:\n");
	printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);

out:
	printf("buffer contents:\n");
	printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
}

int dmx_init(void)
{
	dmx_open();
	dmxpacket[0] = 0x7e;
	dmxpacket[1] = 6;
	dmxpacket[2] = (DMX_UNIVERSESIZE+1) & 0xff;
	dmxpacket[3] = ((DMX_UNIVERSESIZE+1) >> 8) & 0xff;
	dmxpacket[4] = 0; /* start code */
	bzero(dmxpacket+5, DMX_UNIVERSESIZE);
	dmxpacket[DMX_UNIVERSESIZE+5] = 0xe7;
	dmxuniverse = dmxpacket+5;
//	dmx_dumpparams();
	return 1;
}

void dmx_setchannel(int channel, int value)
{
	assert(channel < DMX_UNIVERSESIZE);
	dmxuniverse[channel] = (char)value;
}

void dmx_output(void)
{
	int off = 0;
//	char *buf = dmxpacket;
//	printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
	while (off < DMX_PACKETSIZE) {
		int r;
		r = write(dmxfd, dmxpacket + off, DMX_PACKETSIZE - off);
//		printf("write returned %d\n", r);
		if (r == -1)
			err(1, "error writing packet");
		off += r;
	}
}

