
/*
 *  SERNET.C
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  NetWork device interface.
 */

#include "dnet.h"

IOSER *NetAbortRead();
void NetWaitWrite();
void SaveState();
void RestoreState();
void NetSerialOff();
void NetSerialOn();



static IOSER Iosw;
static ubyte IoswIP;
static ubyte LastWasWrite;

static ubyte IosrIP;
static ubyte RBuf[MAXPACKET*2];     /*	Recv Buf.		    */

static IOSER *CNet;		    /*	control-req (synchro)       */
static IOSER *RNet;		    /*	read-request		    */
static ubyte SerialIsOpen;	    /*	serial device is open	     */
static ubyte RecvEnabled = 1;
static char *DevName;
static long UnitNum;

void
NetOpen(iosink, devname, unitnum, pbaud)
PORT *iosink;
char *devname;
long *pbaud;
{
    IOSER ios;
    long baud = *pbaud;

    DevName = devname;
    UnitNum = unitnum;

    printf("netopen %s %d\n", devname, unitnum);

    BZero(&ios, sizeof(ios));
    ios.io_CtlChar = 0x11130102;
    ios.io_SerFlags = SERF_SHARED|SERF_XDISABLED|SERF_RAD_BOOGIE;
    if (OpenDevice(devname, unitnum, (IOR *)&ios, 0))
	dneterror(devname);
    ios.IOSer.io_Message.mn_ReplyPort = iosink;
    SerialIsOpen = 1;

    RNet = (IOSER *)AllocMem(sizeof(IOSER), MEMF_PUBLIC);
    CNet = (IOSER *)AllocMem(sizeof(IOSER), MEMF_PUBLIC);
    *RNet = ios;
    *CNet = ios;

    {
	IOSER *ioc = CNet;

	ioc->IOSer.io_Command = SDCMD_QUERY;
	DoIO((IOR *)ioc);

	if (Getty == 0) {
	    ioc->IOSer.io_Command = SDCMD_SETPARAMS;
	    ioc->io_SerFlags = SERF_SHARED|SERF_XDISABLED|SERF_RAD_BOOGIE;
	    ioc->io_ExtFlags = 0;
	    ioc->io_ReadLen = ioc->io_WriteLen = 8;
	    ioc->io_CtlChar = 0x01020304;

	    if (baud)
		ioc->io_Baud = baud;

	    switch(Protocol) {
	    case 0:
		break;
	    case 1:	/*  xon-xoff	*/
		Mode7 = 1;
		ioc->io_SerFlags &= ~SERF_XDISABLED;
		break;
	    case 2:
		ioc->io_SerFlags |= SERF_7WIRE;
		break;
	    }

	    *pbaud = Baud = ioc->io_Baud;
	    if (DoIO((IOR *)ioc) != 0)
		dneterror("Unable to set serial parameters");
	}
    }

    RNet->IOSer.io_Command = CMD_READ;
    RNet->IOSer.io_Message.mn_Node.ln_Name = (char *)RNET_REQ;

    CNet->IOSer.io_Command = CMD_WRITE;
    CNet->IOSer.io_Message.mn_Node.ln_Name = (char *)WNET_REQ;

    Iosw = *CNet;

    CNet->IOSer.io_Message.mn_Node.ln_Name = (char *)CNET_REQ;

    puts("net open");
}

/*
 *  Closedown the network.
 */

void
NetClose()
{
    NetAbortRead();
    NetWaitWrite();
    if (SerialIsOpen)
	CloseDevice((IOR *)RNet);
    if (RNet)
	FreeMem(RNet, sizeof(IOSER));
    if (CNet)
	FreeMem(CNet, sizeof(IOSER));
    SerialIsOpen = 0;
    RNet = CNet = NULL;
}

/*
 *  NETCLWRITE()
 *
 *  Clear write request which was GetMsg()'d in DNET.C instead of
 *  WaitIO()'d here.
 */

void
NetClWrite(ior)
IOSER *ior;
{
    if (ior == &Iosw)
	IoswIP = 0;
}

void
NetWrite(buf, bytes)
ubyte *buf;
int bytes;
{
    if (PDebug) {
	short i;

	LastWasWrite = 1;
	printf("WRITE %03x Bytes:", bytes);
	for (i = 0; i < bytes; ++i)
	    printf(" %02x", buf[i]);
	printf("\n");
    }

    if (!SerialIsOpen)
	return;

    if (IoswIP) {
	WaitIO((IOR *)&Iosw);
	IoswIP = 0;
    }

    if (bytes) {
	Iosw.IOSer.io_Message.mn_Node.ln_Name = (char *)WNET_REQ;
	Iosw.IOSer.io_Data = (APTR)buf;
	Iosw.IOSer.io_Length = bytes;
	SendIO((IOR *)&Iosw);
	IoswIP = 1;
    }
    fixsignal(Iosw.IOSer.io_Message.mn_ReplyPort);
}

void
NetBreak()
{
    if (SerialIsOpen) {
	CNet->IOSer.io_Command = SDCMD_BREAK;
	DoIO((IOR *)CNet);
	fixsignal(Iosw.IOSer.io_Message.mn_ReplyPort);
    }
}

/*
 *  NETREADY()
 *
 *  Using the specified inactive request, return the # bytes ready and
 *  the carrier status.
 */

NetReady()
{
    long n = 0;

    if (SerialIsOpen && RecvEnabled) {
	CNet->IOSer.io_Command = SDCMD_QUERY;
	if (DoIO((IOR *)CNet) == 0)
	    n = CNet->IOSer.io_Actual;
	Cd = !(CNet->io_Status & (1 << 5));
    }
    return(n);
}

/*
 *  SetBaudRate()
 */

SetBaudRate(baud)
long baud;
{
    long result;

    if (Getty)
	return(0);
    if (TOBaud == 0)
	SetTimeouts(baud);
    if (CNet)
	CNet->io_Baud = baud;
    if (!SerialIsOpen)
	return(1);
    SaveState();
    CNet->IOSer.io_Command = SDCMD_SETPARAMS;
    result = DoIO((IOR *)CNet);
    RestoreState();

    if (result)
	printf("Unable to set baud rate to %d\n", baud);

    if (!result && PDebug)
	printf("Baud rate set to %d\n", baud);

    return(0);  /*  don't abort whether we can or not   */
}

/*
 *  Assumes CNet holds current settings
 */

void
DropDTR()
{
    if (SerialIsOpen) {     /*  only if serial.device currently open    */
	NetSerialOff();
	Delay(50*4);
	NetSerialOn();
    }
}

IOSER *
NetAbortRead()
{
    if (IosrIP) {
	if (SerialIsOpen && RecvEnabled) {
	    AbortIO((IOR *)RNet);
	    WaitIO((IOR *)RNet);
	}
	IosrIP = 0;
    }
    return(RNet);
}

/*
 *  NetStartRead(bytes)
 */

static long  SaveLen;

void
NetStartRead(len)
long len;
{
    if (len > sizeof(RBuf))
	len = sizeof(RBuf);

    if (SerialIsOpen && RecvEnabled) {
	if (IosrIP)
	    NetAbortRead();
	RNet->IOSer.io_Data = (APTR)RBuf;
	SaveLen = RNet->IOSer.io_Length = len;
	SendIO((IOR *)RNet);
    } else {
	SaveLen = len;
	RNet->IOSer.io_Actual = 0;
    }
    IosrIP = 1;
}

IOSER *
NetReadReady()
{
    return((IOSER *)CheckIO((IOR *)RNet));
}

NetReadReturned(pptr)
ubyte **pptr;
{
    long bytes = 0;

    IosrIP = 0;

    bytes = RNet->IOSer.io_Actual;
    *pptr = RBuf;

    if (PDebug) {
	short i = 0;
	if (LastWasWrite) {
	    LastWasWrite = 0;
	    printf("READ: ");
	}
	for (i = 0; i < bytes; ++i)
	    printf("%02x ", RBuf[i]);
	fflush(stdout);
    }
    return(bytes);
}

void
NetWaitWrite()
{
    if (IoswIP) {
	WaitIO((IOR *)&Iosw);
	IoswIP = 0;
	fixsignal(Iosw.IOSer.io_Message.mn_ReplyPort);
    }
}

static char SaveIosrIP;

void
SaveState()
{
    if (SaveIosrIP = IosrIP)
	NetAbortRead();
    NetWaitWrite();
}

void
RestoreState()
{
    if (SaveIosrIP)
	NetStartRead(SaveLen);
}

void
NetRecvOff()
{
    if (RecvEnabled) {
	SaveState();
	RecvEnabled = 0;
    }
}

void
NetRecvOn()
{
    if (!RecvEnabled) {
	RecvEnabled = 1;
	RestoreState();
    }
}

void
NetSerialOff()
{
    if (SerialIsOpen) {
	SaveState();            /*  make sure no requests pending   */
	CloseDevice((IOR *)RNet);   /*  close the device                */
	SerialIsOpen = 0;
    }
}

void
NetSerialOn()
{
    if (!SerialIsOpen) {
	if (OpenDevice(DevName, UnitNum, (IOR *)RNet, 0))      /* OH HELL! */
	    return;

	/*
	 *  Fix the Device / Unit fields and restore the previous
	 *  modes.
	 */

	SerialIsOpen = 1;
	Iosw.IOSer.io_Device = RNet->IOSer.io_Device;
	Iosw.IOSer.io_Unit   = RNet->IOSer.io_Unit;

	CNet->IOSer.io_Device = RNet->IOSer.io_Device;
	CNet->IOSer.io_Unit   = RNet->IOSer.io_Unit;

	RNet->IOSer.io_Command = CMD_READ;
				/*  restore params		    */
	CNet->IOSer.io_Command = SDCMD_SETPARAMS;
	CNet->io_SerFlags = SERF_SHARED|SERF_XDISABLED|SERF_RAD_BOOGIE;
	DoIO((IOR *)CNet);
	RestoreState();         /*  restore pending read req.       */
    }
    return;
}

