/** PARSTUFF.H */


/** THE STANDARD MESSAGE WHICH IS PASSED AROUND */
struct StdMsg {
	struct	Message msg;
	struct	Remember *mem;
	short	type;					/* what this message represents */
	long	result;					/* the result of this message */
	void	*user1;					/* for exclusive use by the original sender */
	void	*user2;
};

/** StdMsg->type DEFINES FOR THIS PROGRAM */
#define PM_PKT_RECEIVED		0	/* indicates new packet from remote (generated)
								 * do not touch if you do a ReplyMsg - see examples
								 * you don't have to replymsg packets received
								 * but you have to do a FreeRemember pktmsg->mem
								 * to free memory alloc'd to the system */

#define PM_PKT_RETURN		1	/* message returned after send (with result) (ie you post us this message, we send it off & return it with this) */
#define PM_PKT_SENDDMA		2	/* request this as a write DMA to another machine (you are asking us to DMA) */
#define PM_PKT_RECVDMA		3	/* request this to be put into the read DMA list (you are asking us that this be DMA'able) */
#define PM_PKT_SEND			4	/* ordinary send out (you are asking us to send) and reply as soon as the message is sent */
#define PM_PKT_REMRECVDMA	5	/* request this message to be removed from the read DMA list (you are asking us that this be DMA'able) */




/** return code from all of the asm routines */
#define PAR_OK 0

/** return codes from the "setup" asm routines */
#define PAR_ERROR_TIMEOUT 1
#define PAR_ERROR_BUSY 2

/** extra return codes from the C-code packet handlers */
#define PAR_ERROR_CHKSUM 3
#define PAR_ERROR_REJECT 4
#define PAR_ERROR_NOMEM 5

#define PAR_ERROR_QUIT 6

/** ACTUAL DATA STRUCTURES WHICH ARE SENT/RECEIVED */
struct PktHead
{
	short	phchk;				/* check sum of the header (internal) */
	short	bodychk;			/* check sum of the body (internal) */

	/* user should fill the following in */
	short	length;				/* body length */
	char	pad0;				/* ignore */
	unsigned char sender;		/* sender machine ID (filled by handler) */
	short	serv;				/* at the moment only handles LOWER 256 values (filled by us) - this is the destination port server */
	short	fromserv;			/* which client this packet came from (ie opposite of type) - user filled */
	long	arg1;				/* if DMA this is the dest address to go to */
	long	arg2;				/* some kind of argument (for your own use) */
	long	arg3;				/* do not use */
};


/** SENT BACK IF THE PACKET IS ACCEPTABLE */
struct PacketAccept
{
	long	majic;
};


/** SENT BACK AFTER THE BODY AND EVERYTHING ELSE */
struct PacketResult
{
	long	majic;
};

/** MAJIC ACCEPT AND ERROR CODES */
#define MAJIC_ACCEPT 0x5350614B
#define MAJIC_REJECT 0x68456144
#define MAJIC_NOMEM  0x7E4D656D
#define MAJIC_NOSERVER 0x4E734572
/** ACTUALLY ANYTHING ELSE CAN BE CONSIDERED A CHKSUM ERROR */
#define MAJIC_CHKSUMERR 0x64414D6E



/** PACKET TYPES (PktHead->type) (This is who the packets are headed for) */
/* currently only the first 256 are supported */
#define PKT_DMARECV	0					/* an internal packet type */
/** ALL OTHER PACKET types are user definable */
/** Filesystem uses: */
#define PKT_FILESER 'F'					/* the file server */


/******************************************************************************/

/** BELOW ARE THE DIFFERENT MESSAGES PASSED AROUND WITH THIS PROGRAM */

/** PACKET WHICH IS SENT TO A SERVER FOR RECEIVED DATA (AUTO ALLOC'D) */
struct PktMsgRecv {
	struct	StdMsg smsg;
	struct	PktHead pkthead;			/* this is UNTOUCHED! */
	void	*body;						/* memory alloc'd by us (use freeremember on smsg.mem to free) */
	struct	MsgPort *sendport;			/* message port you can "putmsg" to send off a packet */
};

/** FORMAT OF MESSAGE TO REQUEST A SEND (OTHER MACHINE AUTOALLOC'S) */
struct PktMsgSend {
	struct	StdMsg smsg;
	struct	PktHead pkthead;			/* fill this in as commented for pkthead */
	void	*body;						/* buffer to send off */
	unsigned char dest;					/* machine ID to send this to */
	char	pad0;
	short	retries;					/* number of times to try and send */
};

/** WHEN YOU WANT TO AUTO-DMA SEND OUT SOME STUFF */
struct PktMsgSendDMA {
	struct PktMsgSend pmsgs;			/* pkt size comes from here, arg1 contains dest mem - see supplied macros */
	long	totallength;				/* individual pktlength in pmsgs.pkthead.length */
	short	originalretries;
};
/** USE THIS MACRO to get to the PktMsgSendDMA from PktMsg */
#define PKT_DMA(a,b) (((struct PktMsgSendDMA *)(a))->b)


/** DMA NOTIFICATION MESSAGE (SAYS THAT IT IS OK TO DMA INTO XXX)
    NOTE: YOU SEND THIS TO US BEFORE THE OTHER MACHINE BEGINS TO "DMA"
    the actual messages are kept as queues within a hash table */

struct PktMsgRecvDMA {
	struct	StdMsg smsg;
	struct	PktMsgRecvDMA *next;		/* these are used by us
										 * (do not muck with this when in use) */
	void	*stuff;						/* used internally as a marker in the hash table */
						/* you MUST fill these in when calling */
	void	*body;						/* where to DMA to (updated) */
	long	totallength;				/* this is also used as a counter (down to 0) */
	short	pktsize;					/* size to split DMA packets into */
	char	sender;						/* which machine will send this to us */
	char	pad0;						/* ignore - just to make even */
};

#define HASH_TABLE_SIZE 128					/* must be power of 2, mem used = *2*4 */
#define HASH_FIRST		0
#define HASH_LAST		1
#define HASH_FUNC(a)	(((long)(a)>>6)&(HASH_TABLE_SIZE-1))


/******************************************************************************/


/** STRUCT COMMAND */
struct RegisterMsg {
	struct	StdMsg smsg;					/* look at smsg.return for the return value */
	long	command;						/* command to perform, see below */
	long	arg1;							/* depending on the command */
	long	arg2;
	long	arg3;
	void	*stuff;							/* usually a pointer to extra stuff (if needed) */
};



/** registermsg->command types */
#define RM_ADD_SERVER	1			/* add "arg1" as the port serviced by message port "arg2", "arg1" returned with the address of the "comport" or NULL if error */
#define RM_REMOVE_SERVER 2			/* "arg1" is the port server to remove (return is what it used to be) */



/**
 **
 ** MACROS TO INIT THE ABOVE STRUCTURES
 **
 ** Use the "PREPS" if the structure has been "INIT'd" at least once
 ** otherwise, when building a structure from scratch use the "INIT"s to write all
 ** the needed values in
 **
 ** Note that the "mem" field in StdMsg is left to your own manipulation (it is not
 ** touched)
 **
 **/




/** WRITE DEF VALUES INTO A MESSAGE STRUCTURE */
#define INIT_MSG(a,b,c) \
	\
	((a)->mn_Node.ln_Type = NT_MESSAGE, \
	 (a)->mn_Node.ln_Name = NULL, \
	 (a)->mn_ReplyPort = b, \
	 (a)->mn_Length = c)


#define PREP_PKTMSGSEND_(pms_o, destmach_o, body_o, \
			length_o, retries_o, destserver_o, fromserver_o) \
	\
	((pms_o)->dest = destmach_o, \
	(pms_o)->pkthead.length = length_o,\
	(pms_o)->retries = retries_o,\
	(pms_o)->pkthead.serv = destserver_o,\
	(pms_o)->pkthead.fromserv = fromserver_o,\
	(pms_o)->body = body_o )				/* body is returned */


#define PREP_PKTMSGSEND(pms_o, destmach_o, body_o, \
			length_o, retries_o, destserver_o, fromserver_o) \
	\
   ((pms_o)->smsg.type = PM_PKT_SEND, \
	PREP_PKTMSGSEND_(pms_o, destmach_o, body_o, \
		length_o, retries_o, destserver_o, fromserver_o))


#define INIT_PKTMSGSEND(pms_o, replyport_o, destmach_o, body_o, \
							length_o, retries_o, destserver_o, fromserver_o) \
	\
	(INIT_MSG(&((pms_o)->smsg.msg), replyport_o, sizeof(struct PktMsgSend)), \
	(pms_o)->pkthead.arg1 = 0, \
	(pms_o)->pkthead.arg2 = 0, \
	(pms_o)->pkthead.arg3 = 0, \
	PREP_PKTMSGSEND(pms_o,destmach_o,body_o,length_o,retries_o,destserver_o,fromserver_o))



#define PREP_PKTMSGSENDDMA( pmsd_o, destmach_o, bodymem_o, \
		destmemaddr_o, totallength_o, pktlength_o, retries_o, fromserver_o) \
	\
	(PREP_PKTMSGSEND_(&((pmsd_o)->pmsgs),destmach_o,bodymem_o, \
					pktlength_o,retries_o,PKT_DMARECV,fromserver_o), \
	(pmsd_o)->pmsgs.smsg.type = PM_PKT_SENDDMA, \
	(pmsd_o)->totallength = totallength_o, \
	(pmsd_o)->originalretries = retries_o, \
	(pmsd_o)->pmsgs.pkthead.arg1 = (long)destmemaddr_o)


#define INIT_PKTMSGSENDDMA( pmsd_o, replyport_o, destmach_o, bodymem_o, \
		destmemaddr_o, totallength_o, pktlength_o, retries_o, fromserver_o) \
	\
	(INIT_MSG(&((pmsd_o)->pmsgs.smsg.msg), replyport_o, sizeof(struct PktMsgSendDMA)), \
	(pmsd_o)->pmsgs.pkthead.arg2 = 0, \
	(pmsd_o)->pmsgs.pkthead.arg3 = 0, \
	PREP_PKTMSGSENDDMA( pmsd_o, destmach_o, bodymem_o, \
		destmemaddr_o, totallength_o, pktlength_o, retries_o, fromserver_o) )



#define PREP_PKTMSGRECVDMA(pmrd_o, sendermach_o, destmem_o, totallength_o, pktlength_o) \ 
	\
	((pmrd_o)->sender = sendermach_o, \
	(pmrd_o)->smsg.type = PM_PKT_RECVDMA, \
	(pmrd_o)->totallength = totallength_o, \
	(pmrd_o)->pktsize = pktlength_o, \
	(pmrd_o)->body = destmem_o)


#define INIT_PKTMSGRECVDMA(pmrd_o, replyport_o, \
				sendermach_o, destmem_o, totallength_o, pktlength_o) \ 
	\
	(INIT_MSG(&((pmrd_o)->smsg.msg), replyport_o, sizeof(struct PktMsgRecvDMA)), \
	PREP_PKTMSGRECVDMA(pmrd_o, sendermach_o, destmem_o, totallength_o, pktlength_o))


#define INIT_REGISTERMSG(rm_o, replyport_o, com_o, a1_o, a2_o, a3_o) \
	\
	(INIT_MSG(&((rm_o)->smsg.msg), replyport_o, sizeof(struct RegisterMsg)), \
	(rm_o)->arg1 = (long)a1_o, \
	(rm_o)->arg2 = (long)a2_o, \
	(rm_o)->arg3 = (long)a3_o, \ 
	(rm_o)->command = com_o )

