/*
	BL17SCCE.C

	Example program for SCC communications using BL17xx channel A or B.

	This program simply echoes text typed at an ascii terminal back to a
	terminal program such as MS-Windows Terminal.

	Connect an rs232 10-pin cable to SCC port A at Header H14 and the other
	end of the cable to a PC or dumb terminal. Simply type characters into the
	terminal and they will be echoed back from the BL17xx. (Note that SCC port B
	is located at header H15. Change the macro SCC_A to SCC_B to use port B.)

	The macro BLOCK determines the type of data transfer accomplished.
	For BLOCK=0 the characters are echoed back as they are typed in. BLOCK=1 will
	echo more than one character at a time depending upon the rate of character
	transfer. BLOCK=2 will echo characters only in blocks of BLKSIZE as defined
	by the user. If BLKSIZE is 10, characters will not be echoed back until 10
	characters have been entered. At this point all 10 characters will be echoed
	to the terminal.

	This "blocking" mechanism is useful for accurate character transfer in cases
	where more than one task is operating. Thus fast character transfer is
	possible even when serial transfers are operating "in the background".

	If using a PC, MS-Windows terminal.exe can be used in "ANSI Terminal
	Emulation" with "Local Echo" disabled and "Flow Control" set to "None".
	If RTS/CTS handshaking is enabled by setting the macro SHAKE to non-zero,
	enable "Flow Control" within terminal.exe to "Hardware".

	This example program defaults to settings of "No Parity", "One Stop Bit" and
	"Eight Data Bits". Set your terminal accordingly.
	
	Break processing is illustrated by the function aascBreak(), which simply
	increments a counter each time a break is detected. Note that a C version
	and an assembly version of the function are included here. Note also the
	use of the "interrupt" keyword with the C version. This ensures that
	registers are saved upon entry and restored upon exit of the function.

	See further notes in the library file aascscc.lib.
*/

#use aasc.lib
#use aascscc.lib

#define BUFSIZE 684	// Circular buffer size
#define BLOCK 0		// Transfer type: 0-characterwise, 1-block, 2-block (all or none)
#define BLKSIZE 10	// Size of blocks to be transferred
#define BAUDMULT 8	// x 1200 bits per second ( eg: 8 x 1200 = 9600 baud )
#define SHAKE 0		// Set to 1 for RTS/CTS handshaking

extern long sccError;

void aascBreak(void);
void showError(char);

char readBuffer[BUFSIZE],writeBuffer[BUFSIZE],workBuffer[BUFSIZE],*pworkBuffer;
char block,breakCounter;
long sccErrors,bytesRead;
unsigned bytesWritten;
struct _Channel *aascChannel;

main()
{
	_GLOBAL_INIT(); // This must be the first action performed in main().

	breakCounter=0;
	block=BLOCK;
	sccErrors=0;

	// Open channel A of the SCC at 8N1
	
	aascChannel = aascOpen( DEV_SCC, SHAKE,
                 SCC_A | // change to SCC_B to use port B
                 SCC_1STOP |
                 SCC_NOPARITY |
                 SCC_8DATA |
                 SCC_1200*BAUDMULT,
                 aascBreak);

	if(aascChannel==NULL) {
		printf("SCC channel A not available.");
	}
	
   // Setup the circular buffers.
   
	aascSetReadBuf( aascChannel, readBuffer, sizeof( readBuffer));
	aascSetWriteBuf( aascChannel, writeBuffer, sizeof( writeBuffer));

	// Process the data transfer.
	
	while(1) {

		hitwd();

		// Display the number of breaks received.
		
		if(breakCounter!=0) printf("%d\r",breakCounter);

		// Display the current AASC error state, if there is one.
		
		if(sccError!=0) {
			sccErrors|=sccError;		
			showError((char)sccErrors);
			sccClrErr(aascChannel);
		}

		// Perform data transfer.
		
		switch(block) {
		
		   case 0: // Characterwise
				if( aascReadChar( aascChannel, workBuffer) ) {
					while( !aascWriteChar( aascChannel, workBuffer[0]) ) {
						hitwd();
					}
				}
		   break;

		   case 1: // Blockwise "any characters"
				if( bytesRead = aascReadBlk( aascChannel, workBuffer, BLKSIZE, 0) ) {
					pworkBuffer=workBuffer;
					while( bytesRead ) {
						bytesWritten=aascWriteBlk( aascChannel, pworkBuffer, (unsigned)bytesRead, 1);
						pworkBuffer+=bytesWritten;
						bytesRead-=bytesWritten;
						hitwd();
					}
				}
		   break;

		   case 2: // Blockwise "all or nothing"
				if( aascReadBlk( aascChannel, workBuffer, BLKSIZE, 1) ) {
					while( !aascWriteBlk( aascChannel, workBuffer, BLKSIZE, 1) ) {
						hitwd();
					}
				}
		   break;

		   default: // do nothing 
		   break;
		}
	}
}

interrupt void aascBreak()
{
	++breakCounter;
}

// Assembly break processing preferred for speed.
/*
#asm
aascBreak::
	ld		hl,(breakCounter)
	inc	hl
	ld		(breakCounter),hl
	ret
#endasm
*/

void showError(char error)
{
	printf("%d\r",error);
}
