RS232 Redirector Program in C using Linux
- From: Steffen <steffen.kuehn@xxxxxxxxx>
- Date: Sun, 20 Jan 2008 21:42:27 -0800 (PST)
Hello to Everybody
I need some help with a c program I am writing. (ubuntu 7-10,
SlickEdit IDE). By the way, please don't discuss about if it would by
better to use/do this with xyz etc.. it must be in c, and it must be a
sw, no hw - i know a python script is maybe more easy for that :-)
What should my program do?
I should develop a program being a "RS232 Redirector". Means a program
that is collecting incoming data on one serial port and forward this
input, like it is (no processing), to another port... both directions.
Example: The program listens if there is incoming data on ttyS0... if
so, it forwards this data to ttyS1. At the same time it should listen
on port ttyS1 and forward this data to ttyS0.
So what is my problem exactly? I am new to all of this (means
developing linux aps as well as in the serial port), but i tried hard
to get these things running. Currently my status is that my program
does the job, to 99%. But > if i am transferring a file (raw, using
GTKTerm - e. g. a JPEG), some bytes get corrupted and i am receiving a
corrupted file - means my program must have an error :-(
So currently I am trying hard to figure out the bug... cos I am new to
all of this i can not base on any experiences... so the only thing I
can use is google - and the news groups. Hopefully there is somebody
how can help me.
I am posting the main - I think important parts/functions - of my
program: maybe somebody sees an mistake?
int open_serial_port(const char* devname, struct SPDCS* spdcs, struct
termios* tio, struct termios* tio_bak)
{
int fd = 0;
struct sigaction saio;
//open serial device for reading and writing, don't wait
(O_NONBLOCK)
fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
//no error
if (fd >= 0)
{
//fill the new termios structure with the current serial port
values and do a backup of the current settings
if (tcgetattr (fd, tio) != 0)
{
perror("error: tcgetattr() failed to get current settings
from device\n");
}
else
{
//backup the current tty settings
*tio_bak = *tio;
//set the baudrate (input and output rate)
cfsetispeed(tio, resolve_baud_rate (spdcs));
cfsetospeed(tio, resolve_baud_rate (spdcs));
//CLOCAL: local connection, no modem contol
//CREAD: enable receiving characters
tio->c_cflag |= (CLOCAL | CREAD);
//stopbits (choose between 2 or 1 stopbits)
if (spdcs->stopbits == s_2)
{
tio->c_cflag |= CSTOPB;
}
else
{
tio->c_cflag &= ~CSTOPB;
}
//hardware flow control
if (spdcs->rtscts == hw_on)
{
tio->c_cflag |= CRTSCTS;
}
else
{
tio->c_cflag &= ~CRTSCTS;
}
//read always returns immediately with as many characters
as are available in the queue
//if no input is immediately available, read returns a
value of zero.
tio->c_cc[VMIN] = 0;
tio->c_cc[VTIME] = 0;
//set the tty to raw mode
cfmakeraw(tio);
/* cfmakeraw does this:
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|
IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
*/
//flush the buffers in case there is old data in
tcflush(fd, TCIFLUSH);
//apply the new settings
if (tcsetattr (fd, TCSANOW, tio) != 0)
{
perror("error: tcsetattr() failed to set new settings
to device\n");
}
//init the serial interrupt
saio.sa_handler = (__sighandler_t)serial_handler; //assign
the int handler
saio.sa_flags = 0; //clear the interrupt
flag
saio.sa_restorer = NULL; //no restorer
sigemptyset(&saio.sa_mask); //clear existing
settings
sigaction(SIGIO, &saio, NULL); //apply the new
settings
//enable our process to to receive serial interrupts
fcntl(fd, F_SETOWN, getpid()); //allow the process to
receive SIGIO
//a SIGIO signal is sent whenever input on becomes
possible on that file descriptor
fcntl(fd, F_SETFL, O_ASYNC);
}
}
else
{
//making the device file readonly and put out an error message
fcntl(fd, F_SETFL, 0);
perror("error: can't open device\n");
}
return fd;
}
int write_to_port(int fd, char* buf, unsigned int bufsize)
{
int nbytes = 0;
nbytes = write(fd, buf, bufsize);
//if ((nbytes < 0) && (errno == EAGAIN))
{
return 0;
}
return nbytes;
}
int read_from_port(int fd, char* buf, unsigned int bufsize)
{
int nbytes = 0;
//return zero if there is nothing to read in the buffer
fcntl (fd, F_SETFL, O_NONBLOCK);
nbytes = read (fd, buf, bufsize);
if ((nbytes < 0) && (errno == EAGAIN))
{
return 0;
}
return nbytes;
}
void serial_handler(void)
{
char serialbuf_one[REDIRECTION_BUFLEN] = {0},
serialbuf_two[REDIRECTION_BUFLEN] = {0};
int n_readbytes_one = 0, n_readbytes_two = 0;
n_readbytes_one = read_from_port(fdsp_one, serialbuf_one,
sizeof(serialbuf_one));
write_to_port(fdsp_two, serialbuf_one, n_readbytes_one);
n_readbytes_two = read_from_port(fdsp_two, serialbuf_two,
sizeof(serialbuf_two));
write_to_port(fdsp_one, serialbuf_two, n_readbytes_two);
//a SIGIO signal is sent whenever input on becomes possible on
that file descriptor (re-enable the interrupt)
fcntl(fdsp_one, F_SETFL, O_ASYNC);
fcntl(fdsp_two, F_SETFL, O_ASYNC);
}
int main(void)
{
//these are the configuration structures for the serial ports
(baudrate, parity, stopbits...)
struct termios tio_one = {0}, tio_two = {0}, tio_one_bak = {0},
tio_two_bak = {0};
//try to init the pdcs (programm data control structure) with the
values from the config file
if (EXIT_FAILURE == evaluate_config_file(CONFIG_FILE, &pdcs))
{
perror("error: config file is missing or incorrect\n");
return EXIT_FAILURE;
};
//open the two serial ports and setup them (setup also includes
the serial interrupt)
fdsp_one = open_serial_port(resolve_dev_name_one(&pdcs),
&(pdcs.spdcs), &tio_one, &tio_one_bak);
fdsp_two = open_serial_port(resolve_dev_name_two(&pdcs),
&(pdcs.spdcs), &tio_two, &tio_two_bak);
printf("RS232Redirector is running\nRedirecting pair: %s <--> %s
\nStop the Programm by pressing ESC\n", resolve_dev_name_one(&pdcs),
resolve_dev_name_two(&pdcs));
//do an endles loop until the ECC button is pressed
while (1)
{
if (ESC == getch())
{
break;
}
}
//close the two serial ports
close_serial_port(fdsp_one, &tio_one_bak);
close_serial_port(fdsp_two, &tio_two_bak);
return EXIT_SUCCESS;
}
- is my serial port initialization correct - or is there something
missing/or to much? I want to transfer raw data - no processing - i
want to collect the data like they comes in and put them out exactly
like that (do i need to setup party, stopbit, rtccts, xoxoff in that
case?)
- is my interrupt handler setup correct?? Or is there a possibility to
create two interrupts? One for receiving on ttyS0 and one for ttyS1?
Thanks so much for any help!!!!!
Steffen
.
- Follow-Ups:
- Re: RS232 Redirector Program in C using Linux
- From: William Pursell
- Re: RS232 Redirector Program in C using Linux
- Prev by Date: Re: gtk in cygwin
- Next by Date: Re: setting enviroment variable before deamon starts
- Previous by thread: gtk in cygwin
- Next by thread: Re: RS232 Redirector Program in C using Linux
- Index(es):