Markdown source

<!--  READY FOR REVIEW -->
#Seriali reali e simulate  su Linux

<abstract>
Su linux è possibile simulare coppie di porte seriali interconnesse tra di loro
</abstract>

Installare il package socat

<code>
sudo apt-get install socat
</code>

Il comando seguente crea due porte seriali interconnesse tra di loro con un link virtuale:
<pre class="terminal">
sudo socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
</pre>

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à:

<pre class="terminal">
sudo screen /dev/ttyS10
sudo screen /dev/ttyS11
</pre>



##Come accedere ad una seriale da un programma scritto in C

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.


##Programma di esempio

<pre class="prettyprint" "lang-c">

/**
 * Serial port example.
 * Compile with: g++ serialtest.cpp -lpthread -o serialtest
 *
 * taken from Cymait http://cymait.com
 **/

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;errno.h&gt;

#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;pthread.h&gt;
#include &lt;termios.h&gt;

#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;
}
</pre>



##Link interessanti sull'argomento

* [Virtual Serial Port for Linux](https://stackoverflow.com/questions/52187/virtual-serial-port-for-linux)
* [HowTo: Virtual Serial Ports on Linux using socat, and more](https://justcheckingonall.wordpress.com/2009/06/09/howto-vsp-socat/)
* [Some useful socat commands](http://technostuff.blogspot.com/2008/10/some-useful-socat-commands.html)
* [Socat examples](https://github.com/craSH/socat/blob/master/EXAMPLES)
* [Socat explained](http://lorgor.blogspot.com/2009/11/socat.html) 
* [Serial sockets](http://www.drdobbs.com/embedded-systems/serial-sockets/240149514)
* [Serial port redirection from Windows to Linux with socat](https://lb9mg.no/2015/07/09/serial-port-redirection-from-windows-to-linux-with-socat/)
* [SOCAT - The most comprehensive networking utility](http://aplawrence.com/Girish/socat.html)


@include='bio_andrea_montefusco'