
/*
 *  TASK.C
 *
 *  -Accept packets to send to network
 *  -Receive data from network
 *
 *	    ParWrite(destaddr, buf, bytes)
 */

#include "defs.h"

/* par.asm */
extern int ParDataReady(void);
extern int ParReadV();
extern int ParWriteV();

typedef struct {
    uword   Port;   /*	destination port    */
    uword   ChkSum; /*	data checksum	    */
    ulong   Bytes;  /*	# of bytes	    */
} Header;

char	DataBuf[MAXPKTSIZE];
Header	Hdr;
long	TLock[2] = { 0, 0 };
static	short Cnt = 0;

/* prototyping */
void CParNetTask(void);
int OutputPacket(Packet *);

void
CParNetTask(void)
{
    long mask;
    Unit *unit;
    Packet *packet;
    long n;

    for (;;) {
	mask = Wait(SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
	LockAddr(TLock);
	if (mask & SIGBREAKF_CTRL_F) {      /*  packet pending  */
data:
	    if (ParDataReady() > 0) {
		n = ParReadV(&Hdr, sizeof(Hdr), DataBuf, MAXPKTSIZE, NULL, NULL);

		sprintf(StickyPort->DebugBuf, "%03d READ %6ld bytes port %d", Cnt++,n, Hdr.Port);

		if (n >= sizeof(Hdr) && n >= sizeof(Hdr) + Hdr.Bytes) {
		    if (unit = FindUnitForPort(Hdr.Port)) {
			packet = AllocParPacket(NULL, unit, DataBuf, Hdr.Bytes, NULL, 0);
			LockAddr(unit->UnitLock);
			(*packet->io_Unit->DataFunc)('r', packet, n - sizeof(Hdr));
			UnlockAddr(unit->UnitLock);
		    }
		}
	    }
	}
	if (mask & SIGBREAKF_CTRL_E) {      /*  port            */
	    while (packet = (Packet *)GetMsg(&DevBase->Port)) {
		n = OutputPacket(packet);
		if (n == -2) {
		    Forbid();
		    AddHead(&DevBase->Port.mp_MsgList, (struct Node *)packet);
		    Permit();
		    goto data;
		}
	    }
	}
	UnlockAddr(TLock);
    }
}

int
OutputPacket(packet)
Packet *packet;
{
    long n;
    Unit *unit = packet->io_Unit;

    Hdr.Port  = packet->DestPort;
    Hdr.ChkSum= 0;
    Hdr.Bytes = packet->DLen1 + packet->DLen2;

    n = ParWriteV(packet->DestAddr, &Hdr, sizeof(Hdr), packet->Data1, packet->DLen1, packet->Data2, packet->DLen2, NULL, NULL);

    sprintf(StickyPort->DebugBuf, "%03d WRITE %6ld to %d port %d", Cnt++,
	    n,packet->DestAddr,packet->DestPort);

    if (n == -2)                /*  can't write, pending rcv    */
	return(n);
    LockAddr(unit->UnitLock);
    if (n == sizeof(Hdr) + packet->DLen1 + packet->DLen2)
	(*unit->DataFunc)('w', packet, n - sizeof(Hdr));
    else
	(*unit->DataFunc)('W', packet, n - sizeof(Hdr));
    UnlockAddr(unit->UnitLock);
    return(n);
}


/*
 *  Queue packet for write.  If QUICKIO is requested and the packet can be
 *  sent manually it is, else it is queued to the task.
 */

void
QueuePacketForWrite(packet)
Packet *packet;
{
    Iob *iob = packet->iob;

    if ((iob->io_Flags & IOF_QUICK) && TryLockAddr(TLock) > 0) {
	if (OutputPacket(packet) != -2) {
	    UnlockAddr(TLock);
	    return;
	}
	/*
	 *  Can't write packet, rcv packet pending.
	 */
	UnlockAddr(TLock);
    }
    iob->io_Flags &= ~IOF_QUICK;
    iob->io_Flags |= IOF_QUEUED;
    PutMsg(&DevBase->Port, &packet->Msg);
}

