Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.os.linux.development.apps > #159

Re: termios

From Tauno Voipio <tauno.voipio@notused.fi.invalid>
Newsgroups comp.os.linux.development.apps
Subject Re: termios
Date 2011-06-18 22:44 +0300
Organization A noiseless patient Spider
Message-ID <itiv7i$9mj$1@dont-email.me> (permalink)
References <4dfb6e98$0$30769$ba4acef3@reader.news.orange.fr> <itgct7$a04$1@reader1.panix.com> <4dfcc0dd$0$14684$ba4acef3@reader.news.orange.fr> <itik9n$1bh$1@dont-email.me> <4dfce742$0$30775$ba4acef3@reader.news.orange.fr>

Show all headers | View raw


On 18.6.11 9:01 , michel simian wrote:
> Tauno Voipio écrivit de sa plume:
>> You have found the hard core of RS-485 communications.
>>
>> The problem is to control the transmiter enable so that
>> your last character is wholly transmitted, but the response
>> is not arriving yet, when the transmitter (RTS) is turned off.
>>
>> Most serial interface chips report ready well ahead in time
>> before the last character has even started to send. If the
>> chip can report 'transmitter idle', you can use it, else
>> you need to have a well-adjusted delay after sending.
>>
>
> OK. Thank you.
>
> So, the first hypothesis is that the chip do that,
> and the linux driver is correct. Then, when I return
> from write operation, (or from a select on the dedicated
> write fd_set file descriptor), I can read :
>
> - the bytes from the echo
> - and the device answer
>
> But it does not work as described.
>
> If I try to read the echoed bytes before, the analyzer does
> not show the bytes sent... and I think they are not sent.
>
> Then, 2nd hypothesis: the chip and the linux driver
> does not do the right job, and I must adjust some
> 'usleep' when I hope they are efficient ?
>
> Yep, may I hope succeeding without putting candles ?
>

Well, it seems that you have at least to do something to the
serial line driver. Even if the interface chip handles the
transmitter empty condition, it needs a driver able to
understand the condition.

Some interface chips have hardware support to the RTS control
which can be selected with an ioctl(), but evewn here we do
need a co-operating device driver.

Attached is a module running RS-485 packet traffic under
Linux on an Atmel AT91RM920 serial port with hardware control
of transmit enable.

-- 

Tauno Voipio


------ clip clip -----

/*   $Id: serio.c 566 2010-04-22 07:59:29Z tauno $   */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/*   Module data   */

#define BRATE B38400
#define TICKTIME 10
#define TMOTICKS 3

#define FLAG     0x7e    /* framing flag */

#define IF_UP    (IGNBRK | IGNPAR )
#define IF_DOWN  (INPCK | ISTRIP | BRKINT | ICRNL | INLCR | \
                   IUCLC | IXON | IXANY | IXOFF | IMAXBEL | IUTF8)

#define OF_UP    (0)
#define OF_DOWN  (OPOST)

#define CF_UP    (CS8 | CLOCAL | CREAD)
#define CF_DOWN  (CSIZE | CSTOPB | PARENB | CRTSCTS)

#define LF_UP    (ICANON)
#define LF_DOWN  (ISIG | XCASE | ECHO | ECHOE | ECHOK | ECHONL | \
                   ECHOCTL | ECHOPRT | ECHOKE | TOSTOP | PENDIN | IEXTEN)

#define TIOCM_RS485 0x2000     /* AT91 serial port ioctl: enable 
auto-RS485 */

static int handle;     /* serial I/O port file handle */
static uint8_t codebuf[2 * sizeof(struct packet)];


/*   Update a flag word   */

static void updflgs(tcflag_t *fp, tcflag_t up, tcflag_t down)
	{
	*fp &= ~down;
	*fp |= up;
	}


/*   Open and set up serial port   */

static int opensio(const char *path)
	{
	struct termios tio;
	unsigned int i;
	int fd, flgs;

	fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);

	if (fd < 0)
		fail("Open serial I/O");

	flgs = fcntl(fd, F_GETFL);

	if (flgs == -1)
		fail("Get serial channel flags");

	flgs &= ~O_NONBLOCK;

	if (fcntl(fd, F_SETFL, flgs) == -1)
		fail("Set serial channel flags");

	if (tcgetattr(fd, &tio) < 0)
		fail("Get serial I/O attributes");

	updflgs(&tio.c_iflag, IF_UP, IF_DOWN);
	updflgs(&tio.c_oflag, OF_UP, OF_DOWN);
	updflgs(&tio.c_cflag, CF_UP, CF_DOWN);
	updflgs(&tio.c_lflag, LF_UP, LF_DOWN);

	cfsetispeed(&tio, BRATE);
	cfsetospeed(&tio, BRATE);

	for (i = 0; i < NCCS; i++)
		tio.c_cc[i] = '\0';

	tio.c_cc[VEOL] = FLAG;

	if (tcsetattr(fd, TCSANOW, &tio) < 0)
		fail("Set serial I/O attributes");

#ifndef PCTEST
	/* Enable RS-485 mode */

	ioctl(fd, TIOCMGET, &flgs);
	flgs |= TIOCM_RS485;

	if (ioctl(fd, TIOCMSET, &flgs) < 0)
		fail("Set RS-485 auto mode");
#endif

	return fd;
	}


/*   Wait for serial data   */
/*   Waits in 10 ms ticks and checks that the output buffer is empty   */

static bool waitread(void)
	{
	int code, count, qlen;
	struct timeval tmo;
	fd_set input;

	for (count = TMOTICKS; count > 0; )
		{
		FD_ZERO(&input);
		FD_SET(handle, &input);

		tmo.tv_usec = 1000 * TICKTIME;
		tmo.tv_sec = 0;

		code = select(handle + 1, &input, NULL, NULL, &tmo);

		if (code > 0)
			return true;

		/* timeout - refresh the count if packet is not sent yet,
		   else deceŕement the count */

		if (ioctl(handle, TIOCOUTQ, &qlen) < 0)
			fail("Get output queue length");

		if (qlen != 0)
			count = TMOTICKS;
		else
			count--;
		}

	return false;
	}


/*   Serial data receive   */

static int siorec(uint8_t *recv, unsigned int maxlen)
	{
	unsigned int total;
	int count;

	memset(recv, 0, maxlen);
	total = 0;

	do
		{
		if (!waitread())
			break;

		count = read(handle, recv, maxlen);

		if (count <= 0)
			break;

		total += count;

		if (recv[count - 1] != FLAG)
			{
			recv += count;
			maxlen -= count;
			}
		else

		if (total == 1)
			total--;
		else
			return total;
		}
	while (maxlen > 0);

	return 0;
	}


/*   Exchange bus packets   */

int busxch(struct packet *pktp, unsigned int count)
	{
	unsigned int n;

	pktp -> snode = A_MASTER;

#if 0
	printlog("Sending %d bytes, rx %u, tx %u, tp %u, ch %u\n",
	          count, pktp -> rnode, pktp -> snode,
	          pktp -> type, pktp -> channel);
#endif
	trace(pktp, count);

	n = encode(pktp, codebuf, count);

	tcflush(handle, TCIFLUSH);
	write(handle, codebuf, n);

	do
		{
		n = siorec(codebuf, sizeof(codebuf));

		if (n == 0)
			return 0;      /* timeout */

		n = decode(pktp, codebuf, n);
		}
	while (n < HDRSZ || pktp -> snode == A_MASTER);

#if 0
	printlog("Received %d bytes, rx %u, tx %u, tp %u, ch %u\n",
	        n, pktp -> rnode, pktp -> snode, pktp -> type, pktp -> channel);
#endif
	trace(pktp, n);
	return n;
	}


/*   Initialize bus handling   */

void init_bus(void)
	{
#ifdef PCTEST
	handle = opensio("/dev/ttyUSB0");
#else
	handle = opensio("/dev/ttyS1");
#endif
	}

Back to comp.os.linux.development.apps | Previous | NextPrevious in thread | Next in thread | Find similar


Thread

termios michel simian <michel@simian.fr> - 2011-06-17 17:14 +0200
  Re: termios Jan Panteltje <pNaonStpealmtje@yahoo.com> - 2011-06-17 17:01 +0000
  Re: termios Grant Edwards <invalid@invalid.invalid> - 2011-06-17 20:19 +0000
    Re: termios michel simian <michel@simian.fr> - 2011-06-18 17:17 +0200
      Re: termios Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2011-06-18 19:38 +0300
        Re: termios michel simian <michel@simian.fr> - 2011-06-18 20:01 +0200
          Re: termios Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2011-06-18 22:44 +0300
            Re: termios michel simian <michel@simian.fr> - 2011-06-19 06:56 +0200
            Re: termios michel simian <michel@simian.fr> - 2011-06-24 19:28 +0200
              Re: termios Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2011-06-24 21:42 +0300
                Re: termios Grant Edwards <invalid@invalid.invalid> - 2011-06-26 02:27 +0000

csiph-web