/* sio.c
 *   Serial I/O Emulation routines
 *   by Frank Barrus
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "memtype.h"
#include "6502.h"
#include "atari.h"
#include "device.h"
#include "sio.h"


extern char errmsg[];

static byte ibuf[280];
static byte obuf[280];

static int cmd;
static int opos;
static int ipos, ibufsize;
static int done;


static int bps = 19200;
static int bit = CPUHZ/19200;



void sio_read(int p)
{
	sys.serin = ibuf[ipos];
	/* printf("recv: %02x\n", sys.serin); */
	if(++ipos < ibufsize) {
		if(ipos == 1)
			cpu_schedule(SCHED_SERIN, MSEC(12), sio_read, 0);
		else
			cpu_schedule(SCHED_SERIN, 9*bit, sio_read, 0);
	}
	SET_IRQ(0x20);
}



void sio_cmd_start(void)
{
	opos = 0;
	cmd = True;
}

void sio_cmd_end(void)
{
	ipos = ibufsize = 0;
	if(!opos)
		return;
	if(!dev_send_cmd(obuf, opos)) 
		fprintf(stderr, "%s\n", errmsg);
	else {
		ibuf[0] = obuf[0];
		if(obuf[1])
			ibufsize = dev_recv_frame(&ibuf[1]);
		ibufsize++;
		cpu_schedule(SCHED_SERIN, MSEC(9), sio_read, 0);
	}
	cmd = False;
	opos = 0;
}


void sio_serdone(int p)
{
	SET_IRQ(0x08);
	if(done && !cmd) {
		opos = 0;
	}
}

void sio_serout(int p)
{
	cpu_schedule(SCHED_SERDONE, 2*bit, sio_serdone, 0);
	SET_IRQ(0x10);
	done = True;
}

void sio_write(byte data)
{
	cpu_schedule(SCHED_SEROUT, 8*bit, sio_serout, 0);
	obuf[opos++] = data;
	if(opos >= sizeof(obuf)) 
		opos = 0;
	done = False;
}



int sio_init(int argc, char **argv)
{
static int init = True;
int narg = 0;
char **argp = argv;
int dev;
	if(init) { 
		for(dev=0; dev<8; dev++) {
			if(dev < 2) {
				interface_device_param('P',dev,"","n/a");
				interface_device_param('R',dev,"","n/a");
			}
			interface_device_param('D',dev,"","n/a");
		}
	}
	while(argc--) {
		if(!strcmp(*argv, "-bps") && argc) {
			bps = atoi(*(++argv)); argc--;
			bit = CPUHZ/bps;
		} else {
			*argp++ = *argv; narg++;
		}
		if(!strcmp(*argv++,"-h")) {
			printf("SIO interface options:\n");
			printf("\t-bps <speed>\t\tset simulated transfer rate\n");
		} 
	}
	init = False;
	return narg;
}

