/*
 *
 *	DISCLAIMER:
 *
 *	This program is provided as a service to the programmer
 *	community to demonstrate one or more features of the Amiga
 *	personal computer.  These code samples may be freely used
 *	for commercial or noncommercial purposes.
 * 
 * 	Commodore Electronics, Ltd ("Commodore") makes no
 *	warranties, either expressed or implied, with respect
 *	to the program described herein, its quality, performance,
 *	merchantability, or fitness for any particular purpose.
 *	This program is provided "as is" and the entire risk
 *	as to its quality and performance is with the user.
 *	Should the program prove defective following its
 *	purchase, the user (and not the creator of the program,
 *	Commodore, their distributors or their retailers)
 *	assumes the entire cost of all necessary damages.  In 
 *	no event will Commodore be liable for direct, indirect,
 *	incidental or consequential damages resulting from any
 *	defect in the program even if it has been advised of the 
 *	possibility of such damages.  Some laws do not allow
 *	the exclusion or limitation of implied warranties or
 *	liabilities for incidental or consequential damages,
 *	so the above limitation or exclusion may not apply.
 *
 */

#include        "exec/types.h"
#include        "exec/nodes.h"
#include        "exec/lists.h"
#include        "exec/ports.h"
#include        "exec/libraries.h"
#include        "exec/devices.h"
#include        "exec/io.h"
#include        "devices/serial.h"

struct IOExtSer *IORser;
struct MsgPort *port;
char   buffer[200];
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();

/* note:  to run this program, you must have an external terminal, set
 * at 9600 baud, attached to the Amiga serial port.  Additionally the
 * serial.device file must be located in the directory currently 
 * assigned to DEVS:  (to check this, in AmigaDOS, type:  ASSIGN 
 * then check the directory (usually the boot CLI disk volume, devs directory.
 */

main()
{
	int     error;
	int     actual;
	unsigned long rbl;
	unsigned long brk;
	unsigned long baud;
	unsigned char rwl;
	unsigned char wwl;
	unsigned char sf;
	unsigned long t0;
	unsigned long t1;

	/* SET UP the message port in the I/O request */
	port = CreatePort (SERIALNAME,0);
	if (port == NULL) {
		printf("\nProblems during CreatePort");
		exit(100);
	}

	/* Create the request block for passing info to and from the serial device. */
	IORser = (struct IOExtSer *)CreateExtIO(port,sizeof(struct IOExtSer));
	if (IORser == NULL) 
	{ 
		printf("\nProblems during CreateExtIO"); 
		goto cleanup1; 
	}

open:
	/* OPEN the serial.device */
	if ((error = OpenDevice (SERIALNAME, 0, IORser, 0)) != 0) {
		printf ("Serial device did not open, error = %ld",error);
		goto cleanup1;
	}

	/*    SET PARAMS for the serial.device */
	rbl = 4096;
	rwl = 0x08;
	wwl = 0x08;
	brk = 750000;
	baud= 9600;
	sf  = 0x00;
	t0  = 0x51040303;
	t1  = 0x03030303;

	if ((error = SetParams (IORser,rbl,rwl,wwl,brk,baud,sf,t0,t1)) != 0) {
		printf ("Set parameters command returned an error: %ld",error);
		goto cleanup2;
	} 

	printf("\nSerial Device opened and accepted parameters");
	WriteSer (IORser,"\n\015Device opened ok\n\015", -1);

	printf("\nTesting character exact-count output thru SendWaitWrite");
	SendWaitWrite (IORser,
		"User counts characters in string to send\n\015", 42);

	printf("\nTest string length of -1 (make system find end of string)");
	SendWaitWrite (IORser,
		"or if null terminated string, say '-1'\n\015", -1);

	printf("\nType 16 characters to send to amiga...");
	printf("\nIf no external terminal is attached, waits forever!!");
	WriteSer (IORser,
		"\n\015Type 16 characters to send to amiga\n\015", -1);
	actual = ReadSer (IORser,buffer,16);
	WriteSer (IORser,
		"\n\015You typed these printable characters:\n\015", -1); 
	WriteSer (IORser,buffer, actual); 
	WriteSer (IORser,"\n\015End of test\n\015", -1); 
	WriteSer (IORser,"54321.....exit\n\015", 16); 
	printf("\nTest completed!\n");

	/* CLOSE the serial.device */
cleanup2:
	CloseDevice (IORser);
cleanup1:
	DeletePort (port);
	exit (0);
}

/* SERIAL I/O functions */

SetParams(io,rbuf_len,rlen,wlen,brk,baud,sf,ta0,ta1)

struct IOExtSer *io;
unsigned long rbuf_len;
unsigned char rlen;
unsigned char wlen;
unsigned long brk;
unsigned long baud;
unsigned char sf;
unsigned long ta0;
unsigned long ta1;

{
	int error;

	io->io_ReadLen       = rlen;
	io->io_BrkTime       = brk;
	io->io_Baud          = baud;
	io->io_WriteLen      = wlen;
	io->io_StopBits      = 0x01;
	io->io_RBufLen       = rbuf_len;
	io->io_SerFlags      = sf;
	io->IOSer.io_Command = SDCMD_SETPARAMS;
	io->io_TermArray.TermArray0 = ta0;
	io->io_TermArray.TermArray1 = ta1;

	if ((error = DoIO (io)) != 0) {
		printf ("serial.device setparams error %ld \n", error);
	}
	return (error);
}

ReadSer(io,data,length)
struct IOExtSer *io;
char *data;
int length;
{
	int error;

	io->IOSer.io_Data = (APTR)data;
	io->IOSer.io_Length = (ULONG)length;
	io->IOSer.io_Command = CMD_READ;

	if ((error = DoIO (io)) != 0) {
		printf ("serial.device read error %ld \n", error);
	}
	return ((int)io->IOSer.io_Actual);
}


WriteSer(io,data,length)
struct IOExtSer *io;
char *data;
int length;
{
	int     error;

	io->IOSer.io_Data = (APTR)data;
	io->IOSer.io_Length = length;
	io->IOSer.io_Command = CMD_WRITE;

	if ((error = DoIO (io)) != 0) {
		printf ("serial.device write error %ld \n", error);
	}
	return (error);
}

SendWaitWrite(io,data,length)
struct IOExtSer *io;
char *data;
int length;
{
	int     error;

	io->IOSer.io_Data = (APTR)data;
	io->IOSer.io_Length = length;
	io->IOSer.io_Command = CMD_WRITE;

	SendIO (io);

	if ((error = WaitIO (io)) != 0) {
		printf ("serial.device waitio error %ld \n", error);
	}
	return ((int)io->IOSer.io_Actual);
}


/***********************************************************************
*
*	Exec Support Function -- Extended IO Request
*
***********************************************************************/

#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"

extern APTR AllocMem();

/****** exec_support/CreateExtIO **************************************
*
*   NAME	
*	CreateExtIO() -- create an Extended IO request
*
*   SYNOPSIS
*	ioReq = CreateExtIO(ioReplyPort,size);   
*
*   FUNCTION
*	Allocates memory for and initializes a new IO request block
*	of a user-specified number of bytes.
*
*   INPUTS
*	ioReplyPort - a pointer to an already initialized
*		message port to be used for this IO request's reply port.
*
*   RESULT
*	Returns a pointer to the new block.  Pointer is of the type
*	struct IORequest.
*
*	0 indicates inability to allocate enough memory for the request block
*	or not enough signals available.
*
*   EXAMPLE
*	struct IORequest *myBlock;
*	if( (myBlock = CreateExtIO(myPort,sizeof(struct IOExtTD)) == NULL)
*		exit(NO_MEM_OR_SIGNALS);
*
*	example used to allocate space for IOExtTD (trackdisk driver
*	IO Request block for extended IO operations).
*
*   SEE ALSO
*	DeleteExtIO
*
***********************************************************************/

struct IORequest *CreateExtIO(ioReplyPort,size)
    struct MsgPort *ioReplyPort;
    LONG size;
{
    struct IORequest *ioReq;

    if (ioReplyPort == 0)
	return ((struct IORequest   *) 0);

    ioReq = (struct IORequest *)AllocMem (size, MEMF_CLEAR | MEMF_PUBLIC);

    if (ioReq == 0)
	return ((struct IORequest   *) 0);

    ioReq -> io_Message.mn_Node.ln_Type = NT_MESSAGE;
    ioReq -> io_Message.mn_Node.ln_Pri = 0;

    ioReq -> io_Message.mn_ReplyPort = ioReplyPort;

    return (ioReq);
}

/****** exec_support/DeleteExtIO **************************************
*
*   NAME
*	DeleteExtIO() - return memory allocated for extended IO request
*
*   SYNOPSIS
*	DeleteExtIO(ioReq,size);
*
*   FUNCTION
*	See summary line at NAME.  Also frees the signal bit which
*	had been allocated by the call to CreateExtIO.
*
*   INPUTS
*	A pointer to the IORequest block whose resources are to be freed.
*
*   RESULT
*	Frees the memory.  Returns (no error conditions shown)
*
*   EXAMPLE
*	struct IORequest *myBlock;
*	DeleteExtIO(myBlock,(sizeof(struct IOExtTD)));
*		
*	example shows that CreateExtIO had been used to create a trackdisk
*	(extended) IO Request block.
*
*   SEE ALSO
*	CreateExtIO
*
**************************************************************************/

DeleteExtIO(ioExt,size)
    struct IORequest *ioExt;
    LONG size;
{
    ioExt -> io_Message.mn_Node.ln_Type = 0xff;
    ioExt -> io_Device = (struct Device *) -1;
    ioExt -> io_Unit = (struct Unit *) -1;

    FreeMem (ioExt, size);
}
