
/*************************************************************************
**
** pr_Protocol.c
** Copyright (c) 1995,1996 Daniel Kahlin <tlr@stacken.kth.se>
**
** Handle Highlevelprotocol
**
** NOT MACHINE DEPENDENT
**
******/

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>


#include "Main_rev.h"

#include "Protocol.h"
#include "Block.h"
#include "Main.h"
#include "o5protocol.h"


#define BSIZE 256


/*************************************************************************
**
** skriv till c64 minne
**
******/
void bl_sendmem(UBYTE *buffer,ULONG addr, ULONG len)
{
	struct wm_header wmhd;
	ULONG	endaddr;


/*** calculate relevant info ***/
	endaddr=addr+len;

/*** send COMMAND on channel 15 ***/
	wmhd.wmhd_type=TYPE_MEMTRANSFER;
	wmhd.wmhd_subtype=SUB_MT_WRITEMEM;
	wmhd.wmhd_start_l=addr&0xff;
	wmhd.wmhd_start_h=(addr>>8)&0xff;
	wmhd.wmhd_end_l=endaddr&0xff;
	wmhd.wmhd_end_h=(endaddr>>8)&0xff;
	writeblock_err((UBYTE *)&wmhd,sizeof(struct wm_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** send body on channel 1 ***/
	sendbody_err(buffer,len);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

}

/*************************************************************************
**
** Ta emot minne från c64
**
**
******/
void bl_recvmem(UBYTE *buffer,ULONG addr, ULONG len)
{
	struct rm_header rmhd;
	ULONG	endaddr;

/*** calculate relevant info ***/
	endaddr=addr+len;

/*** send COMMAND on channel 15 ***/
	rmhd.rmhd_type=TYPE_MEMTRANSFER;
	rmhd.rmhd_subtype=SUB_MT_READMEM;
	rmhd.rmhd_start_l=addr&0xff;
	rmhd.rmhd_start_h=(addr>>8)&0xff;
	rmhd.rmhd_end_l=endaddr&0xff;
	rmhd.rmhd_end_h=(endaddr>>8)&0xff;
	writeblock_err((UBYTE *)&rmhd,sizeof(struct rm_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** receive body on channel 1 ***/
	receivebody_err(buffer,len);

/*** send ok! ***/
	respond_err(RESP_OK);

}

/*************************************************************************
**
**
******/
void bl_sys(ULONG pc, UBYTE memory, UBYTE sr, UBYTE ac, UBYTE xr, UBYTE yr, UBYTE sp)
{
	struct sy_header syhd;

/*** send COMMAND on channel 15 ***/
	syhd.syhd_type=TYPE_MEMTRANSFER;
	syhd.syhd_subtype=SUB_MT_SYS;
	syhd.syhd_pc_l=pc&0xff;
	syhd.syhd_pc_h=(pc>>8)&0xff;
	syhd.syhd_memory=memory;
	syhd.syhd_sr=sr;
	syhd.syhd_ac=ac;
	syhd.syhd_xr=xr;
	syhd.syhd_yr=yr;
	syhd.syhd_sp=sp;
	writeblock_err((UBYTE *)&syhd,sizeof(struct sy_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);
}

/*************************************************************************
**
**
******/
void bl_run(ULONG lowmem, ULONG himem)
{
	struct ru_header ruhd;

/*** send COMMAND on channel 15 ***/
	ruhd.ruhd_type=TYPE_MEMTRANSFER;
	ruhd.ruhd_subtype=SUB_MT_RUN;
	ruhd.ruhd_lowmem_l=lowmem&0xff;
	ruhd.ruhd_lowmem_h=(lowmem>>8)&0xff;
	ruhd.ruhd_himem_l=himem&0xff;
	ruhd.ruhd_himem_h=(himem>>8)&0xff;
	writeblock_err((UBYTE *)&ruhd,sizeof(struct ru_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);
}



/*************************************************************************
**
** Skicka fil med block
**
******/
void bl_sendfile(char *filename,UBYTE *buffer,ULONG len,int device)
{
	UBYTE *dataptr;
	ULONG datalen;
	struct wf_header wfhd;
	ULONG blocks;


/*** calculate relevant info ***/
	dataptr=buffer;
	datalen=len;
	blocks=((len+253)/254);
	printf("Sending (%d bytes, %d blocks)...\n",len,blocks);


/*** send COMMAND on channel 15 ***/
	wfhd.wfhd_type=TYPE_FILETRANSFER;
	wfhd.wfhd_subtype=SUB_FT_WRITEFILE;
	wfhd.wfhd_len_l=datalen&0xff;
	wfhd.wfhd_len_h=(datalen>>8)&0xff;
	wfhd.wfhd_device=device;
	stccpy(&(wfhd.wfhd_filename[0]),filename,HEADER_FILENAMELEN);
	writeblock_err((UBYTE *)&wfhd,sizeof(struct wf_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** send body on channel 1 ***/
	sendbody_err(dataptr,datalen);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** check status again on channel 15 ***/
	checkresponse_err(0,0,TIMEOUT_FILEWAIT);

}

/*************************************************************************
**
** Ta emot fil!
**
**
******/
void bl_recvfile(char *filename,UBYTE **buffer_st, ULONG *len_st, int device)
{
	UBYTE *dataptr;
	ULONG datalen;
	struct rf_header rfhd;
	struct rf_response rfrs;
	ULONG blocks;


/*** send COMMAND on channel 15 ***/
	rfhd.rfhd_type=TYPE_FILETRANSFER;
	rfhd.rfhd_subtype=SUB_FT_READFILE;
	rfhd.rfhd_device=device;
	stccpy(&(rfhd.rfhd_filename[0]),filename,HEADER_FILENAMELEN);
	writeblock_err((UBYTE *)&rfhd,sizeof(struct rf_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** check status again on channel 15 ***/
	checkresponse_err((UBYTE *)&rfrs,sizeof(struct rf_response),TIMEOUT_FILEWAIT);

	datalen=rfrs.rfrs_len_l+rfrs.rfrs_len_h*256;
	blocks=((datalen+253)/254);
	printf("Receiving (%d bytes, %d blocks)...\n",datalen,blocks);
/*** malloc+ safety ***/
	if (!(dataptr=jalloc(datalen+256)))
		panic("couldn't malloc");


/*** send ok! ***/
	respond_err(RESP_OK);

/*** receive body on channel 1 ***/
	receivebody_err(dataptr,datalen);

/*** send ok! ***/
	respond_err(RESP_OK);

	*buffer_st=dataptr;
	*len_st=datalen;

}



/*************************************************************************
**
** Ta emot Directory!
**
**
******/
void bl_recvdir(char *filename,UBYTE **buffer_st, ULONG *len_st,int device)
{
	UBYTE *dataptr;
	ULONG datalen;
	struct dr_header drhd;
	struct dr_response drrs;


/*** send COMMAND on channel 15 ***/
	drhd.drhd_type=TYPE_DISKCOMMAND;
	drhd.drhd_subtype=SUB_DC_DIRECTORY;
	drhd.drhd_device=device;
	stccpy(&(drhd.drhd_filename[0]),filename,HEADER_FILENAMELEN);
	writeblock_err((UBYTE *)&drhd,sizeof(struct dr_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** check status again on channel 15 ***/
	checkresponse_err((UBYTE *)&drrs,sizeof(struct dr_response),TIMEOUT_FILEWAIT);

	datalen=drrs.drrs_len_l+drrs.drrs_len_h*256;

/*** malloc+ safety ***/
	if (!(dataptr=jalloc(datalen+256)))
		panic("couldn't malloc");


/*** send ok! ***/
	respond_err(RESP_OK);

/*** receive body on channel 1 ***/
	receivebody_err(dataptr,datalen);

/*** send ok! ***/
	respond_err(RESP_OK);

	*buffer_st=dataptr;
	*len_st=datalen;

}

/*************************************************************************
**
** Ta emot Status!
**
**
******/
void bl_recvstatus(UBYTE **buffer_st, ULONG *len_st,int device)
{
	UBYTE *dataptr;
	ULONG datalen;
	struct st_header sthd;
	int	channel;


/*** malloc ***/
	if (!(dataptr=jalloc(256)))
		panic("couldn't malloc");

/*** send COMMAND on channel 15 ***/
	sthd.sthd_type=TYPE_DISKCOMMAND;
	sthd.sthd_subtype=SUB_DC_STATUS;
	sthd.sthd_device=device;
	writeblock_err((UBYTE *)&sthd,sizeof(struct st_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** receive body on channel 1 ***/
	readblock_err(dataptr,&datalen,&channel,0);
	if (channel!=1)
		panic("unexpected packet");

/*** send ok! ***/
	respond_err(RESP_OK);

	*buffer_st=dataptr;
	*len_st=datalen;

}

/*************************************************************************
**
** Skicka DISK COMMAND
**
******/
void bl_sendcommand(UBYTE *buffer,ULONG len,int device)
{
	struct cm_header cmhd;

/*** send COMMAND on channel 15 ***/
	cmhd.cmhd_type=TYPE_DISKCOMMAND;
	cmhd.cmhd_subtype=SUB_DC_COMMAND;
	cmhd.cmhd_device=device;
	writeblock_err((UBYTE *)&cmhd,sizeof(struct cm_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** send body on channel 1 ***/
	writeblock_err(buffer,len,1);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

}


/*************************************************************************
**
** Do transfer diagnostics! BLOCK
**
******/
void bl_blocktest()
{
	int	i,j;
	int	channel,recvchannel;
	ULONG datalen,recvlen;
	UBYTE buffer[2048];
	UBYTE buffer2[2048];
	struct bt_header bthd;

/*** send BLOCKTEST COMMAND on channel 15 ***/
	puts("Requesting blocktest...");
	bthd.bthd_type=TYPE_TESTCOMMAND;
	bthd.bthd_subtype=SUB_TC_BLOCKTEST;
	writeblock_err((UBYTE *)&bthd,sizeof(struct bt_header),15);
/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);


/*** build testdata ***/
	for (i=0; i<2048; i++)
		buffer[i]=i*7;

/*** DO BLOCKTEST ***/
	puts("***testing block level...");
	for (j=0; j<16; j++) {
		channel=j;
		datalen=256-j;
		printf("sending %d bytes on channel %d...\n",datalen,channel);
		writeblock_err(&buffer[0],datalen,channel);

		recvlen=0;
		recvchannel=0;
		readblock_err(&buffer2[0],&recvlen,&recvchannel,0);
		if (recvlen!=datalen) 
			panic("wrong length");
		if (recvchannel!=channel) 
			panic("wrong channel");
		puts("Bounced OK!");

/*** compare blocks ***/
		for (i=0; i<256; i++) {
			if (buffer[i]!=buffer2[i])
				panic("error in block");
		}
	}
	puts("all was ok...");
}


/*************************************************************************
**
** Do transfer diagnostics! FILE
**
******/
#define FILETESTLEN	40960
void bl_filetest()
{
	int	i;
	ULONG datalen,recvlen;
	UBYTE *buffer;
	UBYTE *buffer2;
	UBYTE out,in;
	struct ft_header fthd;
	struct ft_response ftrs;


/*** malloc ***/
	if (!(buffer=jalloc(FILETESTLEN)))
		panic("couldn't malloc");
	if (!(buffer2=jalloc(FILETESTLEN)))
		panic("couldn't malloc");

/*** build testdata ***/
	for (i=0; i<FILETESTLEN; i++)
		*(buffer+i)=i*7;


/*** DO FILETEST ***/
	puts("Requesting filetest...");
	datalen=FILETESTLEN;

/*** send FILETEST COMMAND on channel 15 ***/
	fthd.fthd_type=TYPE_TESTCOMMAND;
	fthd.fthd_subtype=SUB_TC_FILETEST;
	fthd.fthd_len_l=datalen&255;
	fthd.fthd_len_h=datalen>>8;
	writeblock_err((UBYTE *)&fthd,sizeof(struct ft_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);
	puts("sending body...");

/*** send body on channel 1 ***/
	sendbody_err(buffer,datalen);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);


	puts("Waiting for bounce...");

/*** GET THE BOUNCE ***/
	checkresponse_err((UBYTE *)&ftrs,sizeof(struct ft_response),60);

	recvlen=ftrs.ftrs_len_l+ftrs.ftrs_len_h*256;
	if (recvlen!=datalen)
		panic("wrong length");

/*** send ok! ***/
	respond_err(RESP_OK);

	puts("receiving body...");
/*** receive body on channel 1 ***/
	receivebody_err(buffer2,recvlen);

/*** send ok! ***/
	respond_err(RESP_OK);

/*** compare files ***/
	for (i=0; i<datalen; i++) {
		out=*(buffer+i);
		in=*(buffer2+i);
		if (out!=in) {
			printf("error @ %d   sent $%02x   got $%02x\n",i,out,in);
			panic("error in data");
		}
	}

	puts("all was ok...");
}


int sectors[]={
  0,
	21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
	19,19,19,19,19,19,19,
	18,18,18,18,18,18,
	17,17,17,17,17
};

/*************************************************************************
**
** Skicka Track
**
******/
UBYTE *bl_sendtrack(int track,int numtracks,UBYTE *buffer,int device)
{
	int	i;
	struct	wt_header	wthd;
	LONG	size=0;

/*** calculate size ***/
	for (i=0; i<numtracks; i++) {
		size+=256*sectors[track+i];	
	}

/*** send COMMAND on channel 15 ***/
	wthd.wthd_type=TYPE_RAWDISKTRANSFER;
	wthd.wthd_subtype=SUB_RT_WRITETRACK;
	wthd.wthd_track=track;
	wthd.wthd_numtracks=numtracks;
	wthd.wthd_device=device;
	writeblock_err((UBYTE *)&wthd,sizeof(struct wt_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** send body on channel 1 ***/
	sendbody_err(buffer,size);

/*** check status again on channel 15 ***/
	checkresponse_err(0,0,TIMEOUT_FILEWAIT);


	return(buffer+size);
}



/*************************************************************************
**
** Receive Track
**
******/
UBYTE *bl_recvtrack(int track,int numtracks,UBYTE *buffer,int device)
{
	int	i;
	struct	rt_header	rthd;
	LONG	size=0;

/*** calculate size ***/
	for (i=0; i<numtracks; i++) {
		size+=256*sectors[track+i];	
	}

/*** send COMMAND on channel 15 ***/
	rthd.rthd_type=TYPE_RAWDISKTRANSFER;
	rthd.rthd_subtype=SUB_RT_READTRACK;
	rthd.rthd_track=track;
	rthd.rthd_numtracks=numtracks;
	rthd.rthd_device=device;
	writeblock_err((UBYTE *)&rthd,sizeof(struct rt_header),15);

/*** check status on channel 15 ***/
	checkresponse_err(0,0,0);

/*** check status again on channel 15 ***/
	checkresponse_err(0,0,TIMEOUT_FILEWAIT);

/*** send ok! ***/
	respond_err(RESP_OK);

/*** receive body on channel 1 ***/
	receivebody_err(buffer,size);

/*** send ok! ***/
	respond_err(RESP_OK);


	return(buffer+size);
}
