Discussion:
"Gateway" /dev/ttySx <-> /dev/ttySy?
(zu alt für eine Antwort)
Nico Hoffmann
2020-12-09 22:13:43 UTC
Permalink
Hallo,

ich brauche eine Art Gateway zwischen zwei seriellen Schnittstellen,
konkret zwischen /dev/ttyS0 (das ist die RS232) und /dev/ttyUSB0
(dahinter hängt ein spezieller USB-Seriell-Adapter mit FTDI-Chip).

Es sollen kurze (ca 5 - 20 Byte) Datentelegramme bidirektional
übertragen werden.

Ich habe nun versucht, mir was in C zu basteln. Mein Ansatz ist im
groben, die beiden Devices RW zu öffnen und dann zwei Threads zu
starten, an die ich die "File"handles für die Schnittstellen
weitergebe. Der eine Thread liest RS232 und schreibt USB, der zweite
Thread liest USB und schreibt RS232.
Für die beiden Threads starte ich einunddieselbe Funktion zweimal, nur
mit Quell/Ziel-Handle vertauscht.

Mein Programm läßt sich fehlerfrei kompilieren und starten, aber es
funktioniert nur in einer Richtung. D.h. ich kann per RS232 etwas
einfüllen, was über USB rausgeschrieben wird, aber wenn auf USB etwas
ankommt, wird es nicht nach RS232 durchgereicht, bzw. es wird vom
Programm offenbar gar nicht eingelesen.
Ich weiß aber sicher, dass auch über USB etwas ankommt.

Für mich ist das alles neu, ich habe mir den Code aus dem Internet
zusammenkopiert.

Vielleicht zunächst eine grundsätzliche Frage, bevor ich Code wälze:
Ist meine Herangehensweise überhaupt sinnvoll, oder geht das
geschickter, einfacher, etc?

N.
--
Mephisto war kein Sachse.
Bonita Montero
2020-12-10 05:52:11 UTC
Permalink
Dann kopier den Code doch hier rein.
Bei so einer minimalistischen Aufgabe kann das ja nicht viel sein.
Nico Hoffmann
2020-12-10 07:46:23 UTC
Permalink
Post by Bonita Montero
Dann kopier den Code doch hier rein.
Bei so einer minimalistischen Aufgabe kann das ja nicht viel sein.
Bitte sehr :-)




#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <pthread.h>
#include <stdlib.h>




#define SERIAL "/dev/ttyS0"
#define SERIALUSB "/dev/ttyUSB0"

pthread_t tid[2];
struct data {int src; int dst;};

/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/

int open_port(char * portname)
{
int fd; /* File descriptor for the port */


fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/*
* Could not open the port.
*/
perror(portname);
perror("open_port: Unable to open port");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("open_port successfull on %s\n", portname);
}

return (fd);
}

int set_options(int fd)
{

struct termios options;

/*
* Get the current options for the port...
*/

tcgetattr(fd, &options);

/*
* Set the baud rates to 9600...
*/

cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);

/*
* Enable the receiver and set local mode...
*/

options.c_cflag |= (CLOCAL | CREAD);

/*
* Set the new options for the port...
*/

tcsetattr(fd, TCSANOW, &options);

/* data size */
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */

/* parity */
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;

/* disable hardware flow control */
options.c_cflag &= ~CRTSCTS;

/* also disable software flow control */
options.c_iflag &= ~(IXON | IXOFF | IXANY);

/* raw input (not line oriented) */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

/* choosing raw output */
options.c_oflag &= ~OPOST;

return 0; // show always success, never fail.
}

void *serial_channel(void *arg)
/* int serial_channel(struct data f) */
{
struct data *f = (struct data *)arg;

unsigned char buf[1000];
ssize_t s=0;
int wr_ret = 0;


printf("thread-ID: %ld\n", pthread_self());
printf("file handle src: %i\n", f->src);
printf("file handle dst: %i\n", f->dst);


while(1)
{
/* write(fd, &c,1); */

if((s=read(f->src, &buf, 1000)) != -1)
{
/* printf("0x %s ", buf); */

if( s > 0)
{

wr_ret = write(f->dst, buf, s);
if(wr_ret == -1)
{
printf("writing to %i failed with %i\n", f->dst, errno);
}
else
{
printf("%li bytes from \"%i\" ->", s, f->src);
for (int i = 0; i < s; i++)
{
printf("0x%x ", buf[i]);
}
printf("<- to \"%i\"\n", f->dst);
fflush(stdout);
}
}
}
else
{
perror("read");
}
}

/* return 0; */
}



int main(void)
{

/* unsigned char d; */

struct data *f;
struct data *h;

int fd_ser, fd_usb; /* File descriptor for the port */

if((fd_ser = open_port(SERIAL)) < 0)
{
return fd_ser;
}

if((fd_usb = open_port(SERIALUSB)) < 0)
{
return fd_usb;
}


set_options(fd_ser);
set_options(fd_usb);

/* Speicher fuer Daten anfordern u. m. Werten belegen*/
f = (struct data *)malloc(sizeof(struct data));
if(f == NULL) {
printf("Konnte keinen Speicher reservieren ...!\n");
exit(EXIT_FAILURE);
}

h = (struct data *)malloc(sizeof(struct data));
if(h == NULL) {
printf("Konnte keinen Speicher reservieren ...!\n");
exit(EXIT_FAILURE);
}

f->src = fd_ser;
f->dst = fd_usb;
h->src = fd_usb;
h->dst = fd_ser;


/* serial_channel(&f); */

int i = 0;
int err;
/* while(i < 1) */
/* { */
err = pthread_create(&(tid[i]), NULL, &serial_channel, h);
if (err != 0)
{
printf("\ncan't create thread :[%s]", strerror(err));
}
else
{
printf("\n Thread created successfully\n");
}
i++;
/* } */

err = pthread_create(&(tid[i]), NULL, &serial_channel, f);
if (err != 0)
{
printf("\ncan't create thread :[%s]", strerror(err));
}
else
{
printf("\n Thread created successfully\n");
}



char c;

/* forever loop to keep the treads running */
while((c=getchar()) != 'q')
{
}

close(fd_ser);
close(fd_usb);

return 0;
}
--
Mephisto war kein Sachse.
Enrik Berkhan
2020-12-10 11:39:39 UTC
Permalink
Post by Nico Hoffmann
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
/*
* Set the new options for the port...
*/
tcsetattr(fd, TCSANOW, &options);
/* data size */
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
Ich habe da jetzt nur ganz flüchtig drüber geschaut, aber ist das
tcsetattr() nicht etwas zu früh?

Gruß,
Enrik
Nico Hoffmann
2020-12-13 21:03:15 UTC
Permalink
Post by Enrik Berkhan
Post by Nico Hoffmann
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
/*
* Set the new options for the port...
*/
tcsetattr(fd, TCSANOW, &options);
/* data size */
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
Ich habe da jetzt nur ganz flüchtig drüber geschaut, aber ist das
tcsetattr() nicht etwas zu früh?
In der Tat...!

Ich hab' es korrigiert. Jetzt funktioniert es offenbar :-)

N.
--
Mephisto war kein Sachse.
Rainer Weikusat
2020-12-13 21:44:49 UTC
Permalink
Post by Nico Hoffmann
int main(void)
{
/* unsigned char d; */
struct data *f;
struct data *h;
[...]
Post by Nico Hoffmann
/* Speicher fuer Daten anfordern u. m. Werten belegen*/
f = (struct data *)malloc(sizeof(struct data));
if(f == NULL) {
printf("Konnte keinen Speicher reservieren ...!\n");
exit(EXIT_FAILURE);
}
h = (struct data *)malloc(sizeof(struct data));
if(h == NULL) {
printf("Konnte keinen Speicher reservieren ...!\n");
exit(EXIT_FAILURE);
}
Diese beiden Datenstrukturen kann man auch auf dem Stack anlegen, dh als

struct data f,h;

deklarieren. Dann muß man sich den dafür benötigen Speicher nicht mit
malloc anfordern und dafür eine Fehlerbehandlung machen.

[...]
Post by Nico Hoffmann
err = pthread_create(&(tid[i]), NULL, &serial_channel, h);
if (err != 0)
{
printf("\ncan't create thread :[%s]", strerror(err));
}
else
{
printf("\n Thread created successfully\n");
}
i++;
/* } */
err = pthread_create(&(tid[i]), NULL, &serial_channel, f);
if (err != 0)
{
printf("\ncan't create thread :[%s]", strerror(err));
}
else
{
printf("\n Thread created successfully\n");
}
char c;
/* forever loop to keep the treads running */
while((c=getchar()) != 'q')
{
}
Es gibt einen Systemaufruf pause (=> pause(2)), der den Thread, der ihn
ausführt, solange im Kernel blockiert, bis der Prozess ein Signal
empfangen hat. Den könnte man hier verwenden und das Programm mit Ctrl-C
abbrechen, wenn man das möchte.

Bessere Idee: Wozu eine Thread haben, der nichts tut außer warten?
Anstatt zwei zusätzliche Threads zu erzeugen, könnte man bloß einen
starten und die Arbeitsfunktion danach aus main direkt aus main heraus
aufrufen.

Loading...