/****************************************************************************
 *FILE: test10p.c
 *
 *DESCRIPTION:
 *	Demonstration of how a DOS application can load and execute a program
 *	into the ARM,  then communicate with it using both the synchronous and
 *	asynchronous block transfer routines.
 *
 *COMPILER:  Mark Williams MWC86 Version 3.0.6
 *
 */
 


#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include "armintc.h"



/* Define TRUE and FALSE here.  Didn't want to include hfiles\stds.h */
typedef int		BOOL;
#define TRUE	(BOOL)1
#define FALSE	(BOOL)0



/* Declare types of the routines in this file. */

extern int				main(	/* int  argc, char  *argv[] */  );
extern BOOL				chkrrsig(	/* void */  );
extern unsigned int		asy_read_int(	/* unsigned long int	arm_addr */ );
extern void				asy_write_int(  /* unsigned long int	arm_addr, 
										 * unsigned int			val  */ );
extern void				asy_read_block(	/* unsigned long int	arm_addr,
										 * unsigned int			length;
										 * unsigned char		*char_buff_p;
										 */ );
extern void				asy_write_block(/* unsigned long int	arm_addr,
										 * unsigned int			length;
										 * unsigned char		*char_buff_p;
										 */ );



/*****************************************************************************
 */
int		main( argc, argv )
int		argc;
char	*argv[];
	{

#	define SEND_BUFF_LEN 	256
	char	  				send_buff[ SEND_BUFF_LEN ];
#	define RECEIVE_BUFF_LEN 256
	char	  				receive_buff[ RECEIVE_BUFF_LEN ];
	unsigned long int		long_int_buff[1];
	unsigned long int		arm_addr;
	unsigned long int		num_recieved;
	struct reg				sreg,	rreg;
	int		  				arg;
#	define ARMPROG 			"test10a"
	int						i;
#	define ARM_comms_area_data_available	0
#	define ARM_comms_area_work_done			2
#	define ARM_comms_area_string			4



	printf("test10p.c: Main of test10p.exe entered.\n");




	/* Clear send buffer. */
	for (i=0; i< SEND_BUFF_LEN; i++)	send_buff[i] = 0;




	/* Read command line into a string.
	 */
	strcpy( send_buff, "" );
	for( arg = 1; arg < argc; arg++ )
		{
		strcat( send_buff, argv[arg] );
		strcat( send_buff, " " );
		}
	send_buff[ strlen( send_buff ) - 1 ] = '\0';	/* Remove trailing ' ' */




	/* Check for the ram resident interface software being loaded. 
	 */
	if (!chkrrsig())
		{
		printf( "ARM interface sortware is not loaded.  Use arminit.\n" );
		return(1);
		}




	printf("test10p.c: Reset,  load and execute program '%s' in ARM\n",
				ARMPROG);

	sreg.r_ax = ARMEXEC;
	ptoreg(dsreg, sreg.r_dx, sreg.r_ds, ARMPROG);
	intcall(&sreg, &rreg, ARMINT);

	if (rreg.r_ax != FNOK)
		{
		printf("test10p.c: ARMEXEC failed:  error number = 0x%x\n", rreg.r_ax);
		printf("The program test10a.ax1 must be in the ARM's library path\n");
		return( 1 );
		}

    printf("test10p.c: ARMEXEC succeeded\n" );

	/* The program that has just been booted into the ARM is an ARM C one.
	 * So it is necessary to service the OSWORD 1 (read time) that the ARM C
	 * startup code generates.
	 */
	sreg.r_ax = ARMSERV;
	intcall(&sreg, &rreg, ARMINT);
	if (rreg.r_ax != FNOK)
		{
		printf("test10p.c: ARMSERV failed:  error number = 0x%x\n", rreg.r_ax);
		return( 1 );
		}

    printf("test10p.c: ARMSERV succeeded\n" );




	/* Do a block transfer read to get from the ARM the address of an area
	 * of memory to be used for communication.
	 */
	printf("test10p.c: Receiving address from ARM.\n");

	sreg.r_ax = ARMBKW;
	ptoreg(dsreg, sreg.r_dx, sreg.r_ds, long_int_buff);
	sreg.r_bx = 4;
	sreg.r_cx = 0;
	intcall(&sreg, &rreg, ARMINT);

	if (rreg.r_ax != 0)
		{	
		printf("test10p.c: Receive transfer failed,  error code 0x%x\n", 
					rreg.r_ax);
		return(1);
	 	}

	num_recieved = ((unsigned long)rreg.r_cx << 16) + rreg.r_bx;

	if (num_recieved != 4L)
		{
		printf("test10p.c: Receive transfer failed, number recieved = 0x%lx\n",
				num_recieved);
		return(1);
		}

	/* Following assumes byte ordering. */
	arm_addr = long_int_buff[0];

	printf("test10p.c: Receive succeeded. ARM address = 0x%lx\n", arm_addr);




	printf("test10p.c: Block is the string = '%s'\n", send_buff);
		sreg.r_ax = ARMBKGET;
	asy_write_block( arm_addr + ARM_comms_area_string, strlen( send_buff ) + 1, send_buff );
	printf("test10p.c: Send complete.\n");


	printf("test10p.c: Signal to ARM that the data is ready.\n");
	asy_write_int( arm_addr + ARM_comms_area_data_available, TRUE );


	/* Poll,  waiting until the ARM has done its work. */
	while ( asy_read_int( arm_addr + ARM_comms_area_work_done ) != TRUE )
		{
		printf("test10p.c: Waiting for ARM.\n");
		}


	printf("test10p.c: Receive string back from ARM\n");
	asy_read_block( arm_addr + ARM_comms_area_string, RECEIVE_BUFF_LEN, receive_buff );
	printf("test10p.c: Receive buffer contents = '%s'\n", receive_buff);


	printf("test10p.c: Signal to ARM that the data has been taken.\n");
	asy_write_int( arm_addr + ARM_comms_area_work_done, FALSE );


	printf("test10p.c: Exiting.\n");
	return(0);
	}



/*************************************************************************
 * Check that ram resident code signature is present.
 */
BOOL chkrrsig()
	{
	struct reg r;
	r.r_ax = GETVEC | ARMSINT;		/* Get old vector */
    intcall(&r, &r, DOSINT);
    if ((r.r_es == ARMSIG2) && (r.r_bx == ARMSIG1))
    	return( TRUE );
    else
    	return( FALSE );
	}


/*************************************************************************
 * Read an integer (2 bytes) from a specified location in the ARM.
 */
unsigned int		asy_read_int( arm_addr )
unsigned long int	arm_addr;
	{
	unsigned int		int_buff[1];

	/* Assumes byte ordering of ARM and PC is the same.  Asssumes integers
	 * on the ARM and on the PC are both 2 bytes. */
	asy_read_block( arm_addr, 2, int_buff );

	return( int_buff[0] );
	}


/*************************************************************************
 * Write an integer (2 bytes) to a specified location in the ARM.
 */
void				asy_write_int( arm_addr, val )
unsigned long int	arm_addr;
unsigned int		val;
	{
	/* Assumes byte ordering of ARM and PC is the same.  Asssumes ints
	 * on the ARM and on the PC are both 2 bytes. */
	asy_write_block( arm_addr, 2, (char *)(&val) );
	}



/*************************************************************************
 * Read a block of data asynchronously from the ARM.
 */
void				asy_read_block( arm_addr, length, char_buff_p )
unsigned long int	arm_addr;
unsigned int		length;
unsigned char		*char_buff_p;
	{
	struct reg				sreg,	rreg;

	sreg.r_ax = ARMBKPUT;
	ptoreg(dsreg, sreg.r_dx, sreg.r_ds, char_buff_p);
	sreg.r_bx = length;
	sreg.r_cx = 0;
	sreg.r_si = (unsigned int)arm_addr;
	sreg.r_es = (unsigned int)(arm_addr >> 16);
	intcall(&sreg, &rreg, ARMINT);

	if (rreg.r_ax != 0)
		{	
		printf("test10p.c: asy_read_block:  Receive transfer failed,  error \
code %d\n", rreg.r_ax);
		printf("aborting\n");
		return;
 		}
	}



/*************************************************************************
 * Write a block of data asynchronously to the ARM.
 */
void				asy_write_block( arm_addr, length, char_buff_p )
unsigned long int	arm_addr;
unsigned int		length;
unsigned char		*char_buff_p;
	{
	struct reg				sreg,	rreg;

	sreg.r_ax = ARMBKGET;
	ptoreg(dsreg, sreg.r_dx, sreg.r_ds, char_buff_p);
	sreg.r_bx = length;
	sreg.r_cx = 0;
	sreg.r_si = (unsigned int)arm_addr;
	sreg.r_es = (unsigned int)(arm_addr >> 16);
	intcall(&sreg, &rreg, ARMINT);

	if (rreg.r_ax != 0)
		{	
		printf("test10p.c: asy_write_block:  Send transfer failed,  error \
code %d\n", rreg.r_ax);
		printf("aborting\n");
		return;
 		}
	}

