Reading and writing from/to ttyS0 - c

I have a RPI Zero W connected to my virtual machine through USB, which can be found under /dev/ttyS0 on both PC and the RPI. Currently I am trying to send something from the RPI through the USB cable to the virtual machine (PC).
I am trying to read on the port with the following code:
#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 */
/* * 'open_port()' − Open serial port 1. *
* Returns the file descriptor on success or −1 on error. */
int fd; /* File descriptor for the port */
int open_port(void)
{
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
/* * Could not open the port. */
perror("open_port: Unable to open /dev/ttyS0 − ");
}
else
fcntl(fd, F_SETFL, FNDELAY);
return (fd);
}
int close_port(void)
{
close(fd);
return (fd);
}
int main()
{
printf("Serial reader has started...\n\n");
while(1)
{
open_port();
close_port();
}
return 0;
}
and on the RPI side, I have made a little bash script, which sends the character 1:
while :
do
echo "sending character 1 to /dev/ttyS0"
echo "1" > /dev/ttyS0
done
However, even though the bash script and the c program are both running in continuous loops, I am not receiving anything on the PC side.
What could be the reason?

Related

Bytes are not sent to the serial driver buffer

I have this program:
// C headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
// POSIX headers
#include <unistd.h>
#include <sys/ioctl.h>
// Other headers
#include "ZL_sleep.h"
#include "ZL_utf8.h"
#include "ZL_serial.h"
#define BS 4 // Buffer size
int main(int argc, char * argv[]){
int32_t p; // Port
int32_t r; // Read finished
uint8_t b[BS]; // Buffer
uint32_t n; // Number of bytes to be read from driver buffer
if(argc != 2){
printf("ERROR: Supply a \"serial port\" device file.");
exit(EXIT_FAILURE);
}
p = ZL_open_tty(argv[1]);
if(p < 0){
perror("ERROR: open()");
exit(EXIT_FAILURE);
}
while(1){
memset(b, '\0', BS);
r = read(p, b, BS);
if(r < 0){
if(errno == EAGAIN){
}
else{
perror("ERROR: read()");
close(p);
exit(EXIT_FAILURE);
}
}
ZL_utf8_print_bytes(b, BS);
putchar('\n');
}
close(p);
return EXIT_SUCCESS;
}
that uses function ZL_utf8_print_bytes() that prints the buffer bytes (one by one in a for loop). It also calls function ZL_open_tty() and passes the argv[1] (/dev/pts/1) to it as an argument.
Function ZL_open_tty() function sets O_NONBLOCK flag with open() in order for open() to return immediately i.e. "nonblocking" with whatever status. Then before any other I/O function is used, function clears O_NONBLOCK flag and switches back to "blocking". It then sets VMIN and VTIME so that read():
blocks until VMIN or more bytes is received/exists in driver
buffer. (It may block indefinitely)
uint32_t ZL_open_tty(const char * terminal){
uint32_t fd; // File's descriptor
uint32_t fl; // File's flags
struct termios fo; // File's options
fd = open(terminal, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd < 0){
return -1;
}
fl = fcntl(fd, F_GETFL, 0);
if(fl < 0){
perror("ERROR: fcntl():");
return -1;
}
fcntl(fd, F_SETFL, fl & ~(O_NONBLOCK | O_APPEND | O_DSYNC | O_RSYNC | O_SYNC));
tcgetattr(fd, &fo);
fo.c_cc[VMIN] = 1;
fo.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &fo);
fputs("─────────────────────────────────────────────────── terminal settings\n", stdout);
printf("VMIN = %d\n", fo.c_cc[VMIN]);
printf("VTIME = %d\n", fo.c_cc[VTIME]);
putchar('\n');
return(fd);
Afterwards my program enters an endless while loop where read() blocks until I enter any key when keyboard focus is in /dev/pts/1.
The problem that I am facing is that sometimes I press a key in /dev/pts/1 and bytes registered with this key aren't transmitted to the driver buffer?! Bytes just stays in the /dev/pts/1. This happens with ASCII (1-byte) characters and UTF8 (multi-byte) bytes...
I know that read() tries to read requested amount of bytes (BS) from the driver buffer. But it reads less bytes if there aren't BS bytes available in the driver buffer. So... if some bytes would arrive later it could read them later. But these bytes never arrive to the driver buffer for some reason...
What could be causing bytes not to arrive in the driver buffer and remain forever in the /dev/pts/1?
The pts was created when a virtual terminal was attached to the system (usually ssh). The pts was connected as stdin/stdout for a shell which was started for the connection, therefore you already have a process attached to the pts and reading from it.
Once you attach your application, you effectively start a race between both processes (your application and the shell), so whoever is faster will receive the content of the buffer. The character had not remained in the buffer of the pts, rather it was read by the shell attached to the pts.
To be able to read without interruption from the attached process, you need to intercept the buffer of the pts by informing the master multiplexer ptmx, see more in ptmx(4). You can study how it's done in the interceptty

what is the api for redirecting i/o of serial device to standard i/o in linux

I am trying to port Vxworks application to Linux. For redirecting i/o of one of the serial device to standard i/o they are using ioTaskStdSet(); in vxworks.
But I am not able to find the api in linux like as. Only duplicating device is available in linux that is also not working in my application.
Can anyone help me out in this?
As #Ignacio mentioned dup2 is used exactly for this purpose. For example this program redirect stdout to "echo" file:
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd = open("echo", O_RDWR | O_CREAT, 00644);
if(fd == -1)
return 1;
if(dup2(fd, 1) == -1)
return 1;
close(fd);
system("echo Hi!");
return 0;
}
int main()
{
for(i=0;i<4;i++)
{
sprintf(dev_name,"tsports%d",i);
fd[i] = open(dev,O_RDWR | O_SYNC);
pthread_create(tid[i],NULL,&thread_fun,(void *)fd[i]);
}
pthread_exit(NULL);
}
int thread_fun(void *chan)
{
int new_fd,old_fd;
old_fd = (int)chan;
new_fd = dup2(old_fd,0);
new_fd = dup2(old_fd,1);
ts_fd = old_fd;
tn();
pthread_exit(NULL);
}
void tn()
{
printf("hello on terminal");
while(1)
{
read(ts_fd,&ch,1);
/* command line */
........
........
........
/* starts telnet client application on terminal port*/
.......
......
......
.......
sleep(1);
}
}
In the above code while taking input from terminal 1 it is again redirecting stdi/o to terminal 2 in second thread.
So i want thread specific stdi/o even though redirected on each terminal. That is available in Vxworks as IoTaskStdSet API.
Is it possible to implement in linux.

Unable to read data from serial port in C on Ubuntu

I have two C Programs 1. To Write Data to Serial Port and 2. To Read Data from Serial Port. I have connected a USB-Serial converter to my laptop and shorted Tx & Rx to test the program.
Program 1 is getting executed successfully.
Program 2 blocks at read.
Can anyone please suggest a solution for this.
Thanks in advance.
Program to Write to Serial Port:
#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 */
/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int write_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/* Could not open the port. */
perror("open_port: Unable to open /dev/ttyUSB0 - ");
}
else
fcntl(fd, F_SETFL, 0);
int n = write(fd, "ATZ\r", 4);
if (n < 0)
fputs("write() of 4 bytes failed!\n", stderr);
return (fd);
}
void main(){
printf("\nAccessing Serial Port to Write\n");
int fd=write_port();
if(fd<0){
printf("\nSerial Port Access Failed\n");
return;
}
printf("\n%d\tSuccess\n",fd);
}
Program to Read from Serial Port:
#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 */
/*
* 'read_port()' - Reads serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int read_port(void)
{
int fd = open("/dev/ttyUSB0", O_RDONLY | O_NOCTTY);
if (fd == -1)
{
/* Could not open the port. */
perror("open_port: Unable to open /dev/ttyUSB0 - ");
}
char buffer[32];
int n = read(fd, buffer, sizeof(buffer));
if (n < 0)
fputs("read failed!\n", stderr);
return (fd);
}
void main(){
printf("\nAccessing Serial Port to Read\n");
int fd=read_port();
if(fd<0){
printf("\nSerial Port Access Failed\n");
return;
}
printf("\n%d\tSuccess\n",fd);
}

Linux Serial Port in C [duplicate]

This question already has answers here:
Reading from a serial port after writing on it
(5 answers)
Closed 8 years ago.
I have written a program in c for reading and writing serial port.But the problem is I am using while loop and it is continuously sending the command over the serial port.
I want to write some command on serial port
wait for answer
write another command
wait for some answer and so on
My code goes like this:-
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <errno.h>
#include <time.h>
int main()
{
printf("\n");
printf("Please wait till serial Port is being Initialized .... \n");
sleep(2);
printf("\n................. Initializing ................\n");
sleep(2);
printf("\n");
printf("\n\n");
static int fd = 0;
int len;
char res[100];
char s[100] = " Hellow World";
struct termios options;
//==================================================================
// hard coaded port ttyO3
//==================================================================
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
fcntl(fd, F_SETFL, O_NONBLOCK);
//==================================================================
// Error Handling
//==================================================================
if (fd < 0)
{
printf("Serial open error %d %s\n", errno, strerror(errno));
}
printf("\n");
printf("\n==================================================\n");
//==================================================================
// Get the current options for the port...
//==================================================================
tcgetattr(fd, &options);
//==================================================================
// Set the baud rates to 115200...
//==================================================================
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
//=================================================================
// Enable the receiver and set local mode..
//==================================================================
options.c_cflag |= (CLOCAL | CREAD);
//==================================================================
// Set the new options for the port...
//==================================================================
tcsetattr(fd, TCSANOW,&options);
while(1)
{
write(fd,s,strlen((char*)s));
sleep(1);
len = read(fd,res,100);
if (len < 0)
{
if (errno == EAGAIN)
{
continue;
}
else
{
printf("read error %d %s\n", errno, strerror(errno));
}
}
else
{
res[len < 100 ? len:100] ='\0';
printf("read %d chars: %s\n",len, res);
}
}
close(fd);
}
where am I getting wrong.
Thanks and Regards
It looks like the file descriptor is opened as non-blocking (fcntl(fd, F_SETFL, O_NONBLOCK);). You must have some blocking operation if you want to wait for data to be read.
You can make the file descriptor blocking, or use some asynchronous manager like select.
Since you make your file descriptor non-blocking (twice), you have to as the system to wait between the steps. A common way to do this is the select system call, which you can use to wait until there is something to read from the file descriptor.
Can be done something like this:
write(...);
fd_set poll_set;
FD_ZERO(&poll_set);
FD_SET(fd, &poll_set);
/* Wait, with no timeout, for something to be readable */
int rc = select(fd + 1, &poll_set, NULL, NULL, NULL);
if (rc == -1)
{
perror("select");
}
else
{
/* Continue to next step, where you read */
}
Also note that the read-calls may actually not receive the complete messages in the first attempt. You may have to read multiple times to get the complete message. If your messages are of a fixed size, then read in a loop while decreasing the amount of bytes to read until you have received the complete message. If your message have a end-of-message marker, then read byte by byte until you receive it. If your messages contain a header with the message size, then use the first fixed-size read method twice, once to get the header and once to get the data.

howto check a network devices status in C?

I would like to check a network devices status e.g. promiscous mode. Basically like shown with ip a command.
Maybe someone could push me in the right direction?
I want to do this in C for linux so linux specific headers are available.
You need to use the SIOCGIFFLAGS ioctl to retrieve the flags associated with an interface. You can then check if the IFF_PROMISC flag is set:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h> /* ioctl() */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>
#include <unistd.h> /* close() */
#include <linux/if.h> /* struct ifreq */
int main(int argc, char* argv[])
{
/* this socket doesn't really matter, we just need a descriptor
* to perform the ioctl on */
int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct ifreq ethreq;
memset(&ethreq, 0, sizeof(ethreq));
/* set the name of the interface we wish to check */
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
/* grab flags associated with this interface */
ioctl(fd, SIOCGIFFLAGS, &ethreq);
if (ethreq.ifr_flags & IFF_PROMISC) {
printf("%s is in promiscuous mode\n",
ethreq.ifr_name);
} else {
printf("%s is NOT in promiscuous mode\n",
ethreq.ifr_name);
}
close(fd);
return 0;
}
If you want to set the interface to promiscuous mode, you will need root privileges, but you can simply set the field in ifr_flags and use the SIOCSIFFLAGS ioctl:
/* ... */
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(fd, SIOCSIFFLAGS, &ethreq);

Resources