Installare il package socat
sudo apt-get install socat
Il comando seguente crea due porte seriali interconnesse tra di loro con un link virtuale:
sudo socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
poichè i due devices si trovano sotto la directory /dev per poterli accedere occorre avere i privilegi di superutente. Tuttavia non vi' è nessun vincolo che imponga di usare la /dev (e anche i nomi sono in realtà liberi), quindi, per evitare il fastidio del sudo, basta creare i devices sotto /tmp. Oltretutto, essendo sotto /tmp, i nuovi devices non sopravviveranno al prossimo reboot.
Con un qualunque programma (screen minicom lanciati in due terminali virtuali separati) e' possibile effettuare un test di funzionalità:
sudo screen /dev/ttyS10 sudo screen /dev/ttyS11
Una porta seriale virtuale è vista come un semplice device a carattere, quindi non richiede speciali considerazioni quando è acceduta da un programma in C. Il programma va bene anche una porta seriale fisica, al netto del settaggio dei parametri di velocita', bit di start/stop e parità: come si vede il bit rate è comunque stabilito da un costante
#define BAUDRATE B9600
anche se per le porte virtuali questo valore è ininfluente.
/** * Serial port example. * Compile with: g++ serialtest.cpp -lpthread -o serialtest * * taken from Cymait http://cymait.com **/ #include <iostream> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <pthread.h> #include <termios.h> #define BUFFER_SIZE 128 #define BAUDRATE B9600 struct Td { int fd; char buf[128]; bool exit; }; void usage(char* cmd) { std::cerr << "usage: " << cmd << " slave|master [device, only in slave mode]" << std::endl; exit(1); } void* reader_thread(void* pointer) { Td *d = (Td *) pointer; long fd = d->fd; char inputbyte; unsigned n = 0; while (d->exit != true) { if (read(fd, &inputbyte, 1) == 1) { fprintf (stderr, "[%d]: %02x\n", n, inputbyte); n++; if (inputbyte == 'X') break; } else break; } std::cerr << "Terminating thread..." << std::endl; d->exit = true; close (0); return 0; } int main (int argc, char** argv) { if (argc < 2) usage(argv[0]); int fd = 0; fd = open(argv[1], O_RDWR); if (fd == -1) { perror ("error opening file"); return 1; } else std::cerr << argv[1] << " successfully opened." << std::endl; /* serial port parameters */ struct termios newtio = {0}; struct termios oldtio; tcgetattr(fd, &oldtio); // remove local echo newtio = oldtio; newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; newtio.c_iflag = 0; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VMIN] = 1; newtio.c_cc[VTIME] = 0; newtio.c_lflag &= ~(ICANON | ECHO); // disable local echo tcflush(fd, TCIFLUSH); cfsetispeed(&newtio, BAUDRATE); cfsetospeed(&newtio, BAUDRATE); tcsetattr(fd, TCSANOW, &newtio); Td data; data.fd = fd; data.exit = false; /* start reader thread */ pthread_t thread; pthread_create(&thread, 0, reader_thread, (void*) &data); /* read from stdin and send it to the serial port */ unsigned n = 0; while (data.exit != true) { //std::cin >> c; char x = getchar(); if (write(fd, &x, 1) != 1) { perror ("writing"); break; } else { fprintf (stderr, "[%d]: %02x\n", n, x); } n++; } close(fd); return 0; }
2018 Ⓒ TanzoLab