/********************************************************************
 ** PARALLEL PORT SUPPORT (PACKET DRIVER)
 **
 ** (c) Spak, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                    49-829-710
 ** (c) SST 1994
 **
 ** SEND PACKET SUPPORT
 **
 ** TABS to 4
 ********************************************************************/

#include "packets.h"
#include "globs_protos.h"
#include "wingdings_protos.h"

/********************************************************************/
void OriginateReply(struct PktMsg *pm)
/********************************************************************/
{
	MAJIC_REMOVE(pm);
	REPLY_STDMSG(&pm->smsg);
}

/********************************************************************/
void OriginateSendBody(struct PktMsg *pm)
/********************************************************************/
{
	INTERNAL_PREP_PKTMSG_DMA(pm,
		(pm->recv[SERV2INDEX(SERV_RETURN)].len ||
		pm->recv[SERV2INDEX(SERV_RESULT)].len)? EMEM_NOROUTINE : OriginateReply,
			SERV_SEND,
			pm->send_body, pm->send_len);
		PUT_STDMSG(&pm->smsg, comport, TYPE_INTERNAL_SEND);

}

/********************************************************************/
	short InitOriginalPkt(struct PktMsg *pm)
/********************************************************************
  These packets are always placed in to the majic DMA list also
 ********************************************************************/
{
struct StdReq *sr = pm->send.mem;

/** MAKE SURE THE PKTMSG IS VALID AS FAR AS WE CAN TELL */
	if(	pm == FIND_MAJIC((long)pm) ||
		pm->send.len < 0 ||
		pm->recv[1].len < 0 ||
		pm->recv[2].len < 0 ||
		pm->send_len < 0) 	{
			fpf(out,"PAR_SEND: Packet %lx is invalid\n", pm);
			return(0);
		}


	pm->smsg.type = TYPE_INTERNAL_SEND;

/** FILL IN THE STDREQ */
	sr->majic_code = MAJIC_PLACE(pm);
	sr->result_len = pm->recv[SERV2INDEX(SERV_RESULT)].len;
	sr->return_len = pm->recv[SERV2INDEX(SERV_RETURN)].len;

/** FILL IN EVERYTHING ELSE */
	pm->retriesleft = -1;
	pm->pkthead.totallength = pm->send.len + pm->send_len;

	pm->send.routine = EMEM_NOROUTINE;

	if(pm->recv[SERV2INDEX(SERV_RETURN)].len) {
		pm->recv[SERV2INDEX(SERV_RESULT)].routine = EMEM_NOROUTINE;
		pm->recv[SERV2INDEX(SERV_RETURN)].routine = OriginateReply;
	}
	else if(pm->recv[SERV2INDEX(SERV_RESULT)].len) {
		pm->recv[SERV2INDEX(SERV_RESULT)].routine = OriginateReply;
	}
	else if(!pm->send_len)
		pm->send.routine = OriginateReply;

	if(pm->send_len)
		INIT_EMEM(&pm->recv[SERV2INDEX(SERV_MAJIC)],
				&pm->remote_majic, 4, OriginateSendBody);
	return(1);
}


/********************************************************************/
short SendPacket(char machine, struct PktHead *ph,
					void *buffer1, short buf1len, char *aborty)
/********************************************************************
This keeps sending out memory from the address-length table until 'n'
       or the dest machine responds with an error or the
 ********************************************************************/
{
long	pktresult;
short	chksum, error = PAR_OK;

/** GET THE PORT FOR OURSELVES */
	switch(SetupSend(machine, aborty, cir.ciares)) {
		case PAR_OK: break;
		case PAR_ERROR_BUSY:
			fpf(out, "Network too busy\n");
			error = PAR_ERROR_BUSY;
			goto sendnomore;
		default:
			fpf(out, "Machine not responding\n");
			error = PAR_ERROR_TIMEOUT;
			goto sendnomore;
	}

/** SEND OUT THE PACKET HEAD */
	if(SendData(ph, sizeof(struct PktHead), aborty)) {
		fpf(out, "header timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto sendnomore;
	}

/** GET BACK THE RESULT */
	if(BackReceiveData(&pktresult, 4, aborty, &chksum)) {
		fpf(out, "accept timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto sendnomore;
	}
	switch(pktresult) {
		case MAJIC_ACCEPT: break;
		case MAJIC_REJECT: fpf(out, "Packet rejected\n");
			error = PAR_ERROR_REJECT;
			goto sendnomore;
		default: fpf(out, "check sum error\n");
			error = PAR_ERROR_CHKSUM;
			goto sendnomore;
	}
	if(buf1len < 1) goto sendnomore;

/** SEND OUT THE MAIN BODY */
	if(SendData(buffer1, buf1len, aborty)) {
		fpf(out,"body timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto sendnomore;
	}

/** GET BACK THE RESULT */
	if(BackReceiveData(&pktresult, 4, aborty, &chksum)) {
		fpf(out,"result timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto sendnomore;
	}
	switch(pktresult) {
		case MAJIC_ACCEPT:
			break;
		case MAJIC_REJECT:
			error = PAR_ERROR_REJECT;	/* should never really happen */
			break;
		default:
			error = PAR_ERROR_CHKSUM;
			break;
	}

sendnomore:

/** NAUGHTY PATCH */
	if(!error) SetICR(cir.ciares, (1<<CIAINTB));
	AbleICR(cir.ciares, (1<<7)+(1<<CIAINTB));

/** GIVE UP THE PORT */
	RelinquishPort();
	return(error);
}


/********************************************************************/
	short HandleSend(struct PktMsg *pm)
/********************************************************************/
{
short pktlen = MIN(maxpktlen, pm->send.len), result;
	cir.abort = 0;

	if(pm->smsg.type == TYPE_ORIGINALPKT) {
		if(!InitOriginalPkt(pm)) {
			pm->smsg.result = PAR_ERROR_CALLER;
			REPLY_STDMSG(&pm->smsg);
			return(PAR_ERROR_CALLER);
		}
	}

	INTERNAL_PREP_PKTHEAD(&pm->pkthead, pm->send.mem, pktlen);
	if(pm->retriesleft == -1) pm->retriesleft = maxretries;
	START_TIMER(timerintio, timeoutsecs, timeoutmicros);

	pm->smsg.result = result = 
			SendPacket( pm->dest,
						&pm->pkthead,
						pm->send.mem, pktlen,
						&cir.abort);

	AbortIO(timerintio);

/*	fpf(out, "PAR_SEND: pchk=%lx, bchk=%lx, maji=%lx, plen=%ld, serv=%ld\n"
			 "      send=%lc, rtry=%ld, res =%ld\n",
			pm->pkthead.phchk,
			pm->pkthead.bodychk,
			pm->pkthead.majic_code,
			pm->pkthead.pktlen,
			pm->pkthead.server,
			pm->pkthead.sender,
			pm->retriesleft,
			result); */


/** CHECK THE RESULT */
	if(result == PAR_OK) {
		*(long *)(&pm->send.mem) += pktlen;

	/** CALL THE ROUTINE IF WE ARE DONE */
		if( (pm->send.len -= pktlen ) <= 0) {
			switch((long)pm->send.routine) {
				case (long)EMEM_NOROUTINE: break;
				case (long)EMEM_RETURNMSG: REPLY_STDMSG(&pm->smsg); break;
				default: pm->send.routine(pm);
			}
			return(PAR_OK);
		}

	/** REQUEUE THE MESSAGE FOR MORE SENDING */
		else {
			if(pm->retriesleft < maxretries) pm->retriesleft = maxretries;
			PutMsg(comport, pm);
			return(PAR_OK);
		}
	}

/** DO A RETRY OF THE PACKET (REQUEUE) ?? */
	else if(/* result != PAR_ERROR_REJECT && */
								pm->retriesleft > 0) {
		fpf(out, "error: remaining=%ld\n", pm->retriesleft);
		pm->retriesleft--;
		PutMsg(comport, pm);
	}

/** ERROR: RETURN IF IT WAS AN EXTERNAL PKT WITH AN ERROR OF COURSE */
	else {
		fpf(out, "too many errors\n");
		if(pm == FIND_MAJIC((long)pm)) MAJIC_REMOVE(pm);

		if(pm->smsg.type == TYPE_INTERNAL_DOOFUSRECV)
			FREE_PKTMSGRECV((struct PktMsgRecv *)pm);
		else
			REPLY_STDMSG(&pm->smsg);
	}

	return(result);
}
