I am writing a linux application in the userspace to communicate to an FPGA via uart. I am using non-canonical blocking read operation with vmin and vtime specified. FPGA responds to a command sent by me on uart with fixed no of bytes. I can successfully read them for a long time, but after executing for a while, the code simply gets stuck up in the read function. For a blocking read, I would assume it to exit the routine after the vtime period specified even if it does not see any data on the uart buffer.But, it simply hangs the whole application.
Does anyone have an idea what must be causing this?
following are the properties i set for my uart port:
struct termios oldtio;
int fd;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
/* get old settings */
if (tcgetattr(fd, &oldtio) == -1) {
perror("tcgetattr");
}
/* no parity, CR=>NL */
oldtio.c_iflag |= IGNPAR | ICRNL;
/* XON/XOFF flow control off */
oldtio.c_iflag &= ~IXON;
oldtio.c_oflag = 0;
/* zero the character size bits */
oldtio.c_cflag &= ~CSIZE;
/* 8 data bits */
oldtio.c_cflag |= CS8 | CLOCAL | CREAD;
/* no hw flow control, no parity and 1 stop bit */
oldtio.c_cflag &= ~CRTSCTS & ~PARENB & ~CSTOPB;
if (cfsetispeed(&oldtio, B115200) == -1) {
perror("cfsetispeed");
exit(1);
}
if (cfsetospeed(&oldtio, B115200) == -1) {
perror("cfsetospeed");
exit(1);
}
/* raw mode */
//oldtio.c_lflag &= ~(ICANON | ISIG);
oldtio.c_lflag &= ~(ECHO | ICANON | ISIG);
oldtio.c_cc[VTIME] = vtime_value;
oldtio.c_cc[VMIN] = vmin_value;
if (tcflush(fd, TCIFLUSH) == -1) {
perror("tcflush");
exit(1);
}
if (tcsetattr(fd,TCSANOW,&oldtio) == -1) {
perror("tcsetattr");
exit(1);
}
baud_rate = 115200;
vmin = 0;
vtime=255;
Related
I am reading the data from the serial/UART, with 9600 baud rate (my 115200 baud rate is working fine)
I wrote the below code, but the select API every time gives time out, it requires timeout more than 2 seconds, that is not desirable. As I have 2048 bytes of data so within 100 ms I should able to get some data, but I think select API is not receiving interrupts, even though Rx buffer of serial has some data to process.
NOTE: the same piece of code working fine on beaglebone black, while not on intel atom-3900 / Kernel used is Linux-intel 4.9.
Thanks for the anticipation
code:
int main(void)
{
int ret;
char buf[1280];
fd_set m_Inputs; // fd_set for the select call for com input
int m_maxFD; // max FD for select() call.
struct timeval tv;
/*Open Serial port in non blocking mode*/
int fd1;
fd1 = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);
/* get the termios structure */
struct termios options;
tcgetattr(fd1, &options); // Get the current options for the port...
// Set the baud rates...
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD | CS8);
options.c_cflag &= ~PARENB; // ignore parity
options.c_cflag &= ~CSTOPB; // 1 stop bit (2 if set)
options.c_cflag &= ~CSIZE; // clear the size bits
options.c_cflag &= ~CRTSCTS; //No hard flow control
options.c_cflag &= ~HUPCL; //Hang Up on last Close
options.c_cflag |= CS8; // reset the size to 8 bits / char
options.c_cc[VMIN]=1;
options.c_cc[VTIME] = 1;
options.c_oflag = 0;
options.c_lflag = 0; //ICANON;
// Set the new options for the port...
tcsetattr(fd1, TCSANOW, &options);
cout << endl << "FD1 = " << fd1 << endl;
while (1)
{
fd_set rfds; // fd_set for the select call for com input
FD_ZERO(&rfds);
FD_SET(fd1, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 100000;
ret = select(fd1 + 1, &rfds, NULL, NULL, &tv);
if (ret > 0)
{
ret = read(fd1, buf, 127);
buf[ret] = '\0';
cout << buf;
}else{
cout << "Time OUT" << endl;
break;
}
}
return 0;
}
Good afternoon,
I have a peripheral device which communicates over usb over virtual serial port. Everything works well under Windows with generic ACM serial driver, for example with: https://www.kernel.org/doc/Documentation/usb/linux-cdc-acm.inf
Under Linux, it uses CDC ACM drivers. Everything in sys logs seems to work ok, but communication is behaving strangely. When I connect the device, about 10 bytes at the begining of communication are lost. Next, just each second command is received ok.
My questions are:
1) Communication protocol of this device doesn't use ASCII, it is binary (it can randomly contain control characters etc...). Should I use stty for configuring just speed, data bits, stop bits and parity, or something more is necessary to be set up for binary communication? (To ignore control bits in kernel and transmit every byte - raw data.)
2) Any idea, how to test if linux ACM drivers works properly, or which another drivers should i try for my CDC ACM device?
Thanks for any idea!
Linux will often mangle things like line-ending characters (0x0A and 0x0D) when you try to send them over a serial port, which can cause issues if they are actually binary data and not intended as line-ending characters.
Here is a snippet from Pololu that shows how to configure your serial port correctly and then send and receive a few bytes. Pay attention to the part that calls tcsetattr in particular.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#ifdef _WIN32
#define O_NOCTTY 0
#else
#include <termios.h>
#endif
// Gets the position of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
int maestroGetPosition(int fd, unsigned char channel)
{
unsigned char command[] = {0x90, channel};
if(write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
unsigned char response[2];
if(read(fd,response,2) != 2)
{
perror("error reading");
return -1;
}
return response[0] + 256*response[1];
}
// Sets the target of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
// The units of 'target' are quarter-microseconds.
int maestroSetTarget(int fd, unsigned char channel, unsigned short target)
{
unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F};
if (write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
return 0;
}
int main()
{
const char * device = "/dev/ttyACM0"; // Linux
int fd = open(device, O_RDWR | O_NOCTTY);
if (fd == -1)
{
perror(device);
return 1;
}
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#else
struct termios options;
tcgetattr(fd, &options);
options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tcsetattr(fd, TCSANOW, &options);
#endif
int position = maestroGetPosition(fd, 0);
printf("Current position is %d.\n", position);
int target = (position < 6000) ? 7000 : 5000;
printf("Setting target to %d (%d us).\n", target, target/4);
maestroSetTarget(fd, 0, target);
close(fd);
return 0;
}
You might be able to do the same thing with the stty command line utility.
My Linux C application cannot receive bytes from Arduino
Hi all, I intend to use Arduino Mega 2560 as a programmer for AT89S52 (a family of 8051 microprocessor). The Arduino board connects to PC via USB Serial cable.
At first I need to write a program in my Ubuntu to communicate with Arduino board. My program can open connection and write bytes to Arduino properly (I tested by turning led on/off), but the problem is that the Linux program cannot receive data from Arduino.
I already searched through many tutorials and forums but still cannot resolve the problem, so I post question here and hope that someone can help me.
Below is my functon used to open connection to device
AT89S_EID usbserial_open ( char* dev_name,
UsbSerialDevice* dev_ptr,
int baudrate,
int config ) {
speed_t io_baudrate = B9600;
if (dev_name == NULL || dev_ptr == NULL)
{
return AT89S_EID_ARG_NULL;
}
if (baudrate != US_BAUDRATE_9600
&& baudrate != US_BAUDRATE_19200
&& baudrate != US_BAUDRATE_115200)
{
return AT89S_EID_SERIAL_BAUDRATE_INVALID;
}
if (config != US_CONFIG_8N1
&& config != US_CONFIG_7E1
&& config != US_CONFIG_7O1)
{
return AT89S_EID_SERIAL_CONFIG_INVALID;
}
// store device name
strcpy(dev_ptr->name, dev_name);
// open device
dev_ptr->fd = open (dev_ptr->name,
O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (dev_ptr->fd < 0)
{
return AT89S_EID_SERIAL_OPEN;
}
// get current termios settings
if (tcgetattr(dev_ptr->fd, &dev_ptr->tios) < 0)
{
return AT89S_EID_SERIAL_GET_ATTR;
}
// set input/output baudrdate
if (baudrate == US_BAUDRATE_9600)
io_baudrate = B9600;
else if (baudrate == US_BAUDRATE_19200)
io_baudrate = B19200;
else if (baudrate == US_BAUDRATE_115200)
io_baudrate = B115200;
if (cfsetispeed(&dev_ptr->tios, io_baudrate) != 0
|| cfsetospeed(&dev_ptr->tios, io_baudrate) != 0)
{
return AT89S_EID_SERIAL_SET_IOSPEED;
}
// enable receiver, ignore status line
dev_ptr->tios.c_cflag |= (CREAD | CLOCAL);
// set config
if (config == US_CONFIG_8N1)
{
dev_ptr->tios.c_cflag &= ~PARENB;
dev_ptr->tios.c_cflag &= ~CSTOPB;
dev_ptr->tios.c_cflag &= ~CSIZE;
dev_ptr->tios.c_cflag |= CS8;
}
else if (config == US_CONFIG_7E1)
{
dev_ptr->tios.c_cflag |= PARENB;
dev_ptr->tios.c_cflag &= ~PARODD;
dev_ptr->tios.c_cflag &= ~CSTOPB;
dev_ptr->tios.c_cflag &= ~CSIZE;
dev_ptr->tios.c_cflag |= CS7;
}
else if (config == US_CONFIG_7O1)
{
dev_ptr->tios.c_cflag |= PARENB;
dev_ptr->tios.c_cflag |= PARODD;
dev_ptr->tios.c_cflag &= ~CSTOPB;
dev_ptr->tios.c_cflag &= ~CSIZE;
dev_ptr->tios.c_cflag |= CS7;
}
// no HW flow control
dev_ptr->tios.c_cflag &= ~CRTSCTS;
// no input processing (raw input)
dev_ptr->tios.c_iflag &= ~(IXON | IXOFF | IXANY);
// other input settings
dev_ptr->tios.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// no output processing (raw output)
dev_ptr->tios.c_oflag &= ~OPOST;
// control character settings
dev_ptr->tios.c_cc[VMIN] = 1; // wait for 1 minimum chacacter received
dev_ptr->tios.c_cc[VTIME] = 0; // no timeout when waiting for charater
// commit new settings
if (tcsetattr(dev_ptr->fd, TCSANOW, &dev_ptr->tios) < 0)
{
return AT89S_EID_SERIAL_SET_ATTR;
}
// wait for device reset & sync up
usleep(1500 * 1000);
return AT89S_EID_OK;
} /* usbserial_open */
And this is the receiving function:
AT89S_EID usbserial_recv ( UsbSerialDevice* dev_ptr,
unsigned char* data_ptr,
int data_len ) {
int read_byte = 0;
char b[1];
if (dev_ptr == NULL
|| data_ptr == NULL)
{
return AT89S_EID_ARG_NULL;
}
// block reading
fcntl(dev_ptr->fd, F_SETFL, 0);
// start receiving data
while (read_byte < data_len)
{
if (read(dev_ptr->fd, b, 1) > 0)
{
data_ptr[read_byte++] = *b;
}
else
{
if (errno == EAGAIN)
continue;
else if (errno == ETIMEDOUT)
break;
else
return AT89S_EID_SERIAL_RECV;
}
}
return AT89S_EID_OK;
} /* usbserial_recv */
So sorry for posting a long code :)
I already searched through many tutorials and forums but still cannot resolve the problem. I believe that the Arduino code is working fine because I used some other tools to test it (e.g.: minicom)
I resolved my problem. Just add flush function when open the connection to device, everything can be working fine.
tcflush(fd, TCIOFLUSH);
I have created a bluetooth input device (stylus) and would like to connect it to both a Mac and Windows (and preferably Linux in the future).
Is there an ideal software / language to use to create a cross-platform application? I have considered writing native applications for each, but I don't feel the application will be so complex that this is absolutely necessary.
The application will take the input data of the BT device and use it to move the cursor around the screen and provide click and pressure functionality.
Thank you in advance.
I don't know how you device is set up.
However, if you managed to put on it a PIC (Such as the Arduino ATMega328) with at least one serial interface, you could be able to connect it to your PC via Universal Serial Bus (USB).
After that you will be able to open a pipe to your device in many languages.
C is always a good choice both for Linux and OS X, using POSIX libraries will make it even easier.
This snippet I wrote taking some tips online may help to get started
int init_port (const char * port_name, int baud) {
/* Main vars */
struct termios toptions;
int stream;
/* Port data */
speed_t brate = baud;
if ((stream = apri_porta(port_name)) < 1)
return 0;
if (tcgetattr(stream, &toptions) < 0) {
printf("Error");
return 0;
}
/* INITIALIZING BAUD RATE */
cfsetispeed(&toptions, brate);
cfsetospeed(&toptions, brate);
// IMPORTANT BLOCK OF OPTIONS TO MAKE TX AND RX WORKING
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
toptions.c_cflag &= ~CRTSCTS;
toptions.c_cflag |= CREAD | CLOCAL;
toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
toptions.c_oflag &= ~OPOST;
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 0;
tcsetattr(stream, TCSANOW, &toptions);
if (tcsetattr(stream, TCSAFLUSH, &toptions) < 0) {
printf("Error");
return 0;
}
return stream;
}
int open_port (const char * port_name) {
int stream;
stream = open(port_name, O_RDWR | O_NONBLOCK );
if (stream == -1) {
printf("apri_porta: Impossibile aprire stream verso '%s'\n", port_name);
return -1;
}
return stream;
}
int close_port (int stream) {
return (close(stream));
}
int write_to_port(int stream, char * str) {
int len = (int)strlen(str);
int n = (int)write(stream, str, len);
if (n != len)
return 0;
return 1;
}
int read_from_port(int fd, char * buf, int buf_max, char until) {
int timeout = 5000;
char b[1];
int i=0;
do {
int n = (int)read(fd, b, 1);
if( n==-1) return -1;
if( n==0 ) {
usleep( 1 * 1000 );
timeout--;
continue;
}
buf[i] = b[0];
i++;
} while( b[0] != until && i < buf_max && timeout > 0 );
buf[i] = 0; // null terminate the string
return 0;
}
Objective-C (OS X) has got a good library which works like a charm (ORSSerialPort)
However, if you would like to have a cross-platform solution, Java is the best choice either for Windows, OS X and Linux.
I hope this helped you and others to get started.
Feel free to PM me if you need further help.
Best regards.
I'm trying to write a program to interpret traffic received from a serial interface under Cygwin. I copied some demo code from another project to open the serial port. Then I set up the serial port speed to the baudrate used by the serial port (921600).
static int serial_open(char *portname)
{
int FD_com; // file descriptor for the serial port
struct termios term;
FD_com = open(portname, O_RDONLY | O_NOCTTY | O_NDELAY);
if (FD_com == -1) // if open is unsuccessful
{
printf("serial_open: Unable to open %s.\n", portname);
}
else
{
// set speed of port
cfsetspeed(&term, BAUDRATE);
// set to 8-bits, no parity, 1 stop bit
term.c_cflag &= ~PARENB;
term.c_cflag &= ~CSTOPB;
term.c_cflag &= ~CSIZE;
term.c_cflag |= CS8;
term.c_cflag |= (CLOCAL | CREAD);
tcsetattr(FD_com, TCSANOW, &term);
}
return(FD_com);
}
Then I tried to capture the traffic in a file
if (FD_ISSET(FD_com, &fds))
{
// wait for data to come in on the serial port
if ((nbytes = read(FD_com, port_buf, PORTBUFSIZE)) > 0)
{
for (i=0; i<nbytes; i++)
{
fwrite(&port_buf[i], 1, sizeof(uint8_t), fout);
The problem is, the traffic recorded in the file lost some bytes. The longest consecutive string it can record is over 48 bytes, but most other strings, it wraps around with 48 bytes. I assume that this because of buffer overflow. But how to configure the serial port rx buffer? The port_buf defined in the application is 512 (PORTBUFSIZE)bytes, which should be big enough.