#include<stdio.h>		// printf()

#include<stropts.h>		// ioctl()

#include<termios.h>		// struct termios

#include<unistd.h>		// read(), write()

#include<string.h>		// strlen()

#include<fcntl.h>		// O_RDWR, O_NDELAY, etc

#include <sys/ioctl.h>		// TIOCMGET, TIOCM_RTS, etc.

#include <assert.h>		// assert()


// "ISO485-HD_sample.c"
// JW -- Technologic Systems -- 11/09
//
// Sample code for the TS-ISO485 Half-Duplex mode
//
// TS-ISO485 jumper configuration:
//	ADD2, A_HD, B_HD, Share, IRQ2 & IRQ4
//
// Test board: TS-7260
//
// NOTE:
//	the following condition NEEDs to be met,
//	connect terminal-1, COM-A to terminal-1, COM-B
//	connect terminal-2, COM-A to terminal-2, COM-B
//
// NOTE:
//	the following shell command allows IRQ sharing, which
//	speeds up test:
//	'setserial /dev/tts/4 irq 33'
//	(this makes BOTH ports' IRQ's the same --33)


//***********************************************
//***********************************************
//* The idea:
//*	open both portA & portB (/dev/tts/4 & /dev/tts/5)
//*	set the port attributes for both ports (mainly 9600 BAUD)
//*	IMPORTANT: CLEAR the RTS bit on portB (/dev/tts/5),
//*     (the receiving port)
//*	send data to portA, receive on portB
//***********************************************


//***********************************************
// setRTS()
//
// IN:	'com': port to set
//	'state': (0)= CLEAR, (1)= SET
//
// OUT:	return the value given to us
//
// Set/clear the RTS bit
//***********************************************
int setRTS(int com, int state)
{
	// Get the current flag (bit status)
	// the value of 'flag' determines which flags are set
	// (bit == 1), RTS, DTR, etc.
	int flag;
	ioctl(com, TIOCMGET, &flag);

	// Do we SET or CLEAR this bit (flag)?
	if(state == 1)	
		// OR 'flag' with TCIOCM_RTS, to set the bit
		flag|= TIOCM_RTS;
	else
		// AND 'flag' with the inverse of TCIOCM_RTS, to clear the bit
		flag&= ~TIOCM_RTS;

	// Set the new flag value
	ioctl(com, TIOCMSET, &flag);

	return(state);
}//setRTS()


//***********************************************
// setCom()
//
// IN:	'com'= port to set
//
// OUT:	success
//
// Set the COM port attributes
// (9600, BAUD, 8N1)
// Flush this port
//***********************************************	
int setCom(int com)
{
	// This struct holds the port attributes
	struct termios attr;

        // Make sure this struct is zeroed out (all bits clear)
        bzero(&attr, sizeof(attr));

	// To the 'c_cflag' value, we OR the following flags (bits)
        attr.c_cflag= (B9600 | CS8 | CLOCAL | CREAD);
	
	// Flush all char's from this port's FIFO
        tcflush(com, TCIOFLUSH);

	// Set the new attributes
        tcsetattr(com, TCSANOW, &attr);

	return(0);
}//setCom()



//*****************************************************************************
// MAIN
int main()
{
	// These are COM-A & COM-B on the TS-ISO485
	int comA;
	int comB;
	char *portA="/dev/tts/4";
	char *portB="/dev/tts/5";

	// Open both ports; exit if error
	comA= open(portA, O_RDWR | O_NOCTTY | O_NDELAY);
	assert(comA > 0);

	comB= open(portB, O_RDWR | O_NOCTTY | O_NDELAY);
	assert(comB > 0);

	// Get, save the attributes for both ports (good programming practice)
	struct termios attrA;
	struct termios attrB;
	tcgetattr(comA, &attrA);
	tcgetattr(comB, &attrB);

	// Set the (new) attributes for both ports
	setCom(comA);
	setCom(comB);

	// Throw away all data in FIFO before writing
	tcflush(comB, TCIOFLUSH);
	
	// IMPORTANT: CLEAR RTS on the receiving port
	// else Half-Duplex is disabled by default
	setRTS(comB, 0);

/********************************************************************/
	// Write 12 char's, one-at-a-time
	// NOTE: no error checking!
	printf("Write 12 char's, read back 12 char's\n");
	unsigned char tx, rx, i;

	// Write 12 char's to portA
	tx= 0x31;
	for(i= 0; i < 12; i++)
	{
		printf("writing val 0x%x\n", tx);
		write(comA, &tx, 1);
		tx++;
	}

	// Block until all data is written
	tcdrain(comA);

	// Read back the 12 char's (from portB)
	for(i= 0, tx= 0x31; i < 12; i++, tx++)
	{
		printf("reading byte ...");

		// May need a slight delay between reads
		while(read(comB, &rx, 1) != 1)
		{
			printf("Data not ready...\n");
			usleep(10);
		}

		// Data read == data written?
		if(rx == tx)
			printf("[0x%x] - ok\n", rx);
		else
			printf("FAIL, expected 0x%x\n", tx);
	}
	printf("\n");


/********************************************************************/
	// Write/read one char at a time
	// NOTE: no error checking!
	printf("Write/read one char at a time\n");
	char *outStr= "TS-Test";	// String to write out
	char inStr[8];			// String to put data in
	inStr[7]= '\0';			// String terminator, just in case...

	// The 7 char's in 'outStr' [TS-test]
	for(i= 0; i < 7; i++)
	{
		// Write the next char
		printf("Write: [%c]", outStr[i]);
		write(comA, &outStr[i], 1);

		// Block until data is written
		tcdrain(comA);

		// Read the next char
		read(comB, &inStr[i], 1);
		printf("\tRead: [%c]\n", inStr[i]);
	}


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


	// Restore the port attributes (good prog. practice)
	tcsetattr(comA, TCSANOW, &attrA);
	tcsetattr(comB, TCSANOW, &attrB);

	// Close the ports (yes, good prog. practice)
	close(comA);
	close(comB);
	
	return(0);
}//main()



syntax highlighted by Code2HTML, v. 0.9.1