serial port rs-232 full duplex connectme NET+OS6.3 example

my application being a ethernet to serial bridge I would need to use the serial port in full duplex if possible.

I found examples in NET+OS6.3 to connect the 2 com ports on the board but they are half-duplex (one example on ftp1.digi.com is DMA but it’s still only half-duplex): i.e. either read OR write simultaneously, since RS-232 is full-duplex, i.e. there are 2 separate FIFO for rx/tx on each port, is it possible to both read AND write to a serial port and where to find an example ?
should I set flow control to enable full duplex ?
I tried to set up simultaneous read/write threads but the act of writing appears to empty the read buffer.

I would like to port (for example) this miniterm.c with full duplex serial rs232 to NET+OS 6.3, is it possible with DIGI serial UART driver of connectme board :

/*

  • AUTHOR: Sven Goldt (goldt@math.tu-berlin.de)
  • This program is free software; you can redistribute it and/or
  • modify it under the terms of the GNU General Public License
  • as published by the Free Software Foundation; either version 2
  • of the License, or (at your option) any later version.
  • This program is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.

/
/

This is like all programs in the Linux Programmer’s Guide meant
as a simple practical demonstration.
It can be used as a base for a real terminal program.
*/

#include
#include
#include
#include
#include

#define BAUDRATE B38400
#define MODEMDEVICE “/dev/modem”
#define ENDMINITERM 2 /* ctrl-b to quit miniterm */

#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

void child_handler(int s)
{
STOP=TRUE;
}

main()
{
int fd,c;
struct termios oldtio,newtio,oldstdtio,newstdtio;
struct sigaction sa;

/*
Open modem device for reading and writing and not as controlling tty
because we don’t want to get killed if linenoise sends CTRL-C.
*/
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (fd <0) {perror(MODEMDEVICE); exit(-1); }

tcgetattr(fd,&oldtio); /* save current modem settings */

/*
Set bps rate and hardware flow control and 8n1 (8bit,no parity,1 stopbit).
Also don’t hangup automatically and ignore modem status.
Finally enable receiving characters.
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

/*
Ignore bytes with parity errors and make terminal raw and dumb.
*/
newtio.c_iflag = IGNPAR;

/*
Raw output.
*/
newtio.c_oflag = 0;

/*
Don’t echo characters because if you connect to a host it or your
modem will echo characters for you. Don’t generate signals.
*/
newtio.c_lflag = 0;

/* blocking read until 1 char arrives */
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;

/* now clean the modem line and activate the settings for modem */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

/*
Strange, but if you uncomment this command miniterm will not work
even if you stop canonical mode for stdout. This is a linux bug.
/
tcsetattr(1,TCSANOW,&newtio); /
stdout settings like modem settings */

/* next stop echo and buffering for stdin /
tcgetattr(0,&oldstdtio);
tcgetattr(0,&newstdtio); /
get working stdtio */
newstdtio.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0,TCSANOW,&newstdtio);

/* terminal settings done, now handle in/ouput /
switch (fork())
{
case 0: /
child /
/
user input /
close(1); /
stdout not needed /
for (c=getchar(); c!= ENDMINITERM ; c=getchar()) write(fd,&c,1);
tcsetattr(fd,TCSANOW,&oldtio); /
restore old modem setings /
tcsetattr(0,TCSANOW,&oldstdtio); /
restore old tty setings /
close(fd);
exit(0); /
will send a SIGCHLD to the parent /
break;
case -1:
perror(“fork”);
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
exit(-1);
default: /
parent /
close(0); /
stdin not needed /
sa.sa_handler = child_handler;
sa.sa_flags = 0;
sigaction(SIGCHLD,&sa,NULL); /
handle dying child /
while (STOP==FALSE) /
modem input handler /
{
read(fd,&c,1); /
modem /
write(1,&c,1); /
stdout /
}
wait(NULL); /
wait for child to die or it will become a zombie */
break;
}
}

Use the tc functions. Do NOT use getchar(). I will post an example when I get back to my computer.

-Erik

I will also post my code that OS6.3 I think does not have fork() so it’s with threads, but I suspect I have serial receiver buffering off because writes clear the receive buffer.

the read thread :

/* SerialRead
*

  • Description: This function does the setup of the Serial port 0 and then uses it to
  • receive data which were sent into the serial port 0.
  • Called by: root

*/
void SerialRead(ULONG thread_input)
{
int zeroFd, result, status, baudrate;
int bytetorecv = 0;
int numBytesRcvd= 0;
int numBytesSent= 0;

#ifdef LOOP_FOREVER_IN_THIS_TEST
unsigned int iteration = 0;
#endif

#ifdef OLD_SERIAL_API
int iOptions;
#else
static int first_open = 1;
struct ioflags_t iOptions;
struct termios tios;
struct serial_cntr_t prev_counters;
struct serial_cntr_t curr_counters;
memset( &prev_counters, 0, sizeof(prev_counters));
#endif

printf ("serial recv thread created.

");

// char sendBuffer=setSendBuffer(BufferSizeForSendAndReceive);
while (1/SWserlTests[currentop].szData/)
{
/
Check status. /
// status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
if (status != TX_SUCCESS)
{
printf("Unable to get semaphore for com 0.
");
goto err;
}
else
{
zeroready = 0; /
com zero not ready */

        zeroFd = open (TEST_COM0, SWserlTests[currentop].mode);   /* because hardware handshake is needed */
        if (zeroFd &lt;0)
        {
            printf ("Can't open %s [%d].

", TEST_COM0, getErrno());
goto err;
}
else
{
#if IS_DTR_DSR_PRESENT == TRUE
#ifdef OLD_SERIAL_API
do
{
/* get the DCD state */
result = ioctl(zeroFd, SIO_GET_STATUS_DCD, &iOptions);
if (result < 0)
{
printf ("ioctl(SIO_GET_STATUS_DCD) errno[%d]
", getErrno());
goto err;
}

                /*  get the DSR state   */
                result = ioctl(zeroFd, SIO_GET_STATUS_DSR, &amp;status);
                if (result &lt; 0)
                {
                    printf ("ioctl(SIO_GET_STATUS_DSR) errno[%d]

", getErrno());
goto err;
}

                if ((status == 0) &amp;&amp; (iOptions == 0))
                {
                    printf ("Connect Serial cable!

" );
// tx_thread_sleep(100);
}
}
while((status == 0) && (iOptions == 0));
#else
do
{
tcgetstats( zeroFd, &ser_status );
if ( (ser_status.mstat & (MS_DCD | MS_DSR)) == 0 )
{
printf ("Connect Serial cable!
");
// tx_thread_sleep(100);
}
}
while( (ser_status.mstat & (MS_DCD | MS_DSR)) == 0 );
#endif /* OLD_SERIAL_API /
#endif /
IS_DTR_DSR_PRESENT */

            /*  set the baud rate   */
            baudrate = SWserlTests[currentop].baudrate;

#ifdef OLD_SERIAL_API
result = ioctl(zeroFd, SIO_BAUD_SET, &baudrate);
if (result < 0)
{
printf ("ioctl(Baud set) errno[%d]
", getErrno());
goto err;
}
#else
tcgetattr(zeroFd, &tios);
cfsetospeed(&tios, baudrate);
#endif

            /*  set other parameters    */
            iOptions = SWserlTests[currentop].ioflags;

#ifdef OLD_SERIAL_API
result = ioctl(zeroFd, SIO_HW_OPTS_SET, &iOptions);
if (result < 0)
{
printf ("ioctl(Line options) failure: errno[%d]
", getErrno());
goto err;
}
#else
tios.c_cflag = iOptions.cflags;
tios.c_iflag = iOptions.iflags;

	result = tcsetattr( zeroFd, TCSANOW, &amp;tios );
	if (result &lt; 0) {
                printf ("ioctl(Set attributes) failure: errno[%d]

", getErrno());
goto err;
}
if ( cfgetospeed(&tios) != baudrate ) {
printf ("ioctl(Baud set) errno[%d]
", getErrno());
return;
}
if ( (tios.c_cflag != iOptions.cflags) ||
(tios.c_iflag != iOptions.iflags) )
{
printf ("ioctl(Flag settings) failure errno[%d]
", getErrno());
goto err;
}
#endif

    bytetorecv = BufferSizeForSendAndReceive;

// bytetorecv = SWserlTests[currentop].szData;

#ifdef OLD_SERIAL_API
result = ioctl(zeroFd, SIO_GET_STATUS_ERROR, &iOptions);
if (iOptions != 0)
{
printf ("Error condition [0x%x].
", iOptions);
ioctl(zeroFd, SIO_CLEAR_STATUS_ERROR, &iOptions);
}
#else
tcgetcounters(zeroFd, &curr_counters);

	if (first_open) {
	    prev_counters = curr_counters;
	    first_open = 0;
	} 
	if (prev_counters.norun != curr_counters.norun)
	{
            printf ("Error condition [Overrun].

");
}
if (prev_counters.noflow != curr_counters.noflow)
{
printf ("Error condition [Overflow].
");
}
if (prev_counters.nframe != curr_counters.nframe)
{
printf ("Error condition [Framing Error].
");
}
if (prev_counters.nparity != curr_counters.nparity)
{
printf ("Error condition [Parity Error].
");
}
if (prev_counters.nbreak != curr_counters.nbreak)
{
printf ("Error condition [Break].
");
}
prev_counters = curr_counters;
#endif

            zeroready = 1;

// status = tx_semaphore_put(&semaphore_0);
numBytesRcvd = 0;
// com0NotFinish = 1;
do
{
if (numBytesRcvd < bytetorecv)
{
bufstat("R1 ",zeroFd);
result = read(zeroFd, (rcvBuffer0 + numBytesRcvd), (bytetorecv - numBytesRcvd));
bufstat("R2 ",zeroFd);

					if (result &lt; 0)
                    {
                        printf ("read failed [%d].

", getErrno() );
}
else
{
numBytesRcvd += result;
printf ("serial num bytes recvd [%d]=%c.
", numBytesRcvd, (char )(rcvBuffer0 + numBytesRcvd - result) );
}

					INT32 var_yellow,var_green;
					char cmd[100];
					char rc=(char *)*(rcvBuffer0 + numBytesRcvd - result);
					manGetINT32(EXAMPLE_greenLedOn, &amp;var_green, NULL, MAN_TIMEOUT_FOREVER);
					manGetINT32(EXAMPLE_yellowLedOn, &amp;var_yellow, NULL, MAN_TIMEOUT_FOREVER);

					switch (rc)
					{
					case 'D':// tasto down
						if(var_green==2)
							sendTrap();
						manSetINT32(EXAMPLE_greenLedOn, 1, NULL, MAN_TIMEOUT_FOREVER);
						break;
					case 'U':// tasto up
						if(var_green==1)
							sendTrap();
						manSetINT32(EXAMPLE_greenLedOn, 2, NULL, MAN_TIMEOUT_FOREVER);
						break;
					case 'O':// led on
					    manSetINT32(EXAMPLE_yellowLedOn, 1, NULL, MAN_TIMEOUT_FOREVER);
						break;
					case 'o':// led off
					    manSetINT32(EXAMPLE_yellowLedOn, 2, NULL, MAN_TIMEOUT_FOREVER);
						break;
					case 'Q':// richiesta comandi
					if(g_delta)
					{

// while (bytetosend) // attendo invio ;
sendBuffer[0]=g_delta;// ultimo set da snmp manager
bytetosend=1;
// tx_thread_sleep(1); /* wait for send to finish completely */
SerialWrite1(zeroFd,sendBuffer,1);
// while (bytetosend) // attendo invio ;

						g_delta=0;
						break;
					}

					default:

/*
if (result > 0)
{
while (bytetosend) // attendo invio
;
sendBuffer[0]=rc;// ultimo set da snmp manager
bytetosend=1;
}
*/
break;
}
// SerialWrite(zeroFd,&rc,1);
}
}
while (numBytesRcvd < bytetorecv);
numBytesRcvd = 0;
numBytesSent = 0;
result = close (zeroFd);
if (result<0)
{
printf ("Close failed [%d].
", getErrno() );
}

            currentop++;

#ifdef LOOP_FOREVER_IN_THIS_TEST
if (SWserlTests[currentop].szData == 0)
{
currentop = 0;
printf("
Iteration %d
", ++iteration);
}
#endif
}
} /* end if /
} /
end while /
// tx_thread_sleep(1000); /
wait for send to finish completely */
printf ("Thread Serial One complete.
");
return;

err:
return;
}

the write thread will write in this way but it seems to me it is flushing the input buffer, and also getting serial port stats seems to flush it

void SerialWrite1(int oneFd, char *psendBuffer, int pbytetosend)
{
int result;

bufstat("W1 ",oneFd);
result = write (oneFd, psendBuffer, pbytetosend);
bufstat("W2 ",oneFd);
if (result &lt; 0)
{
    printf ("write failed [%d].

", getErrno());
}
else
{
if (result)
printf("serial char sent ‘%c’
",psendBuffer[0]);
}
}

I sent some files from pc hypeterminal of known content with a alphabet like pattern and checked the contents received by the digi while the digi was also sending a known pattern which was wrapping periodically well on the terminal on the pc, also with another little test program on the pc I did not need any 10 ms delay on the pc to wait for the “turn around” of the digi from write to read (which I checked with my colleague it is not obviously full duplex, since only one end is transmitting at any one time, but the problem is half duplex with some sort of problem in quickly transitioning to read from the digi’s end) so I suspect it’s a problem of the microchip pic’s uart I observed this initially and I have yet to find out what is lacking on the pic. I did set to 0 this #define NEED_ECHO 0 from netos_serl.c which might have been a problem but I am unsure.Thanks for any information.