Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.os.linux.development.apps > #159
| 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> |
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 | Next — Previous in thread | Next in thread | Find similar
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