I have a one line serial communication interface, and the problem is that I send in 01010101 and the echo that I receive is 8 out of 10 times 01010101 but 2 out of 10 I receive 01110101.
Code example:
void checkVersion(int fd) {
tcflush(fd, TCIFLUSH);
unsigned char checkVersion[] = {0x55, 0x02, 0x00, 0x02};
int n = write(fd, &checkVersion, 4); //Send data
if (n < 0) cout << "BM: WRITE FAILED" << endl;
char read_bytes[10] = {0};
char c;
int aantalBytes = 0;
bool foundU = false;
int res;
while (aantalBytes < 7) {
res = read(fd, &c, 200);
if (res != 0) {
cout << "Byte received: " << bitset < 8 > (c) << endl;
if (c == 'U')foundU = true;
if (foundU)
read_bytes[aantalBytes++] = c;
}
if (aantalBytes > 2 && !foundU) break;
}
if (!foundU) checkVersionSucceeded = false;
if (read_bytes[aantalBytes - 3] == 0x02 && read_bytes[aantalBytes - 2] == 0x04 && read_bytes[aantalBytes - 1] == 0x06)
cout << "BM Version 4" << endl;
}
How I configure my port:
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return (fd);
}
What is the problem? How is it possible that the echo is mixed up 2 out 10 times?
Perhaps you should try the function bzero() when you configure the connection.
bzero(&port_settings, sizeof (port_settings));
This clears the struct for new port settings, which might help to stop the irregular answers you receive over the serial port.
Related
I have a simple application that runs on an embedded device running Linux that sends and receives bytes over UART. I have a minicom session open in my host machine to which the RS-232 USB cable is connected.
So far, I am only able to send data from the app to the serial session but not the other way around. This should indicate my UART configs including the baud rate are fine since I can send the data at least, and the serial session is also running at the same baud rate.
select() returns 0 which indicates the call timed out. Is it implying the socket is busy at the moment and can't be used?
Opening a socket
#DEVICE_PORT "/dev/ttyHSL0"
static int buildFlowControl(Enum_FlowCtrl fc, struct termios* term)
{
if (NO_FLOW_CTRL == fc)
{
term->c_cflag |= CRTSCTS;
term->c_iflag &= ~(IXON | IXOFF);
}
else if (FC_RTSCTS == fc)
{
term->c_cflag &= ~CRTSCTS;
term->c_iflag |= (IXON | IXOFF);
}
else if (FC_XONXOFF == fc)
{
term->c_cflag &= ~CRTSCTS;
term->c_iflag &= ~(IXON | IXOFF);
}else{
return -1;
}
return 0;
}
int UART_Open(const char* port, unsigned int baudrate, Enum_FlowCtrl flowCtrl)
{
int fd;
struct termios term;
fd = open(port, O_RDWR);
bzero(&term, sizeof(term));
cfmakeraw(&term);
term.c_cflag |= CREAD;
tcgetattr(fd, &term);
buildBaudrate(baudrate, &term);
buildDataBit(8, &term);
buildStopBit(1, &term);
buildParity(PB_NONE, &term);
buildFlowControl(flowCtrl, &term);
term.c_iflag &= ~ICRNL;
term.c_iflag &= ~INLCR;
term.c_iflag |= IGNBRK;
term.c_oflag &= ~OCRNL;
term.c_oflag &= ~ONLCR;
term.c_oflag &= ~OPOST;
term.c_lflag &= ~ICANON;
term.c_lflag &= ~ISIG;
term.c_lflag &= ~IEXTEN;
term.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
term.c_cc[VMIN] = 5; // minimum received bytes before unblocking
term.c_cc[VTIME] = 100; // 10 SECONDS timeout
tcsetattr(fd, TCSANOW, &term);
tcflush(fd, TCIOFLUSH);
return fd;
}
Main
int socketFileDescriptor;
int main(void argc, char *argv[])
{
int baudRate = atoi(argv[1]);
socketFileDescriptor = UART_Open(DEVICE_PORT, baudRate, NO_FLOW_CTRL);
if (pthread_create(&threadUartRcv, NULL, UartRcv, NULL) != 0)
{
// error handling
}
while(true);
}
UART receive function:
static void* UartRcv(void* arg)
{
int ret;
fd_set fdset;
struct timeval timeout = {5, 0};
char buffer[100] = {0};
FD_ZERO(&fdset);
FD_SET(socketFileDescriptor, &fdset);
while(true)
{
ret = select(socketFileDescriptor + 1, &fdset, NULL, NULL, &timeout); // waits for 5 seconds for any activity on socket
// reset the time value back to the original since it's reset by select()
timeout.tv_sec = 5;
if (ret == -1)
{
printf("< failed to select >\n");
exit(-1);
}
else if (ret == 0)
{
printf("< no data >\n");
}
else
{
if (FD_ISSET(socketFileDescriptor, &fdset))
{
do {
memset(buffer, 0x0, sizeof(buffer));
ret = read(socketFileDescriptor, buffer, 100);
sleep(3);
} while (true);
}
}
}
}
I was able to send data from minicom by disabling the Hardware Flow Control. I'm not quite certain as to why would that solve given RTS/CTS is enabled
I have to read a data from Serial port using C program. I am sending Hex array data and the device will response the corresponding response for the request.
I have tried with the GTK+ Serial port Terminal, For Example, if i write data "FC 05 40 2B 15" the device will resturn the response as "FC 05 50 AA 05".
Someone please guide me to get this, i have been trying for so long.
I have attached my code here.
void main()
{
int fd;
struct termios SerialPortSettings;
char write_buffer[512];
int dispense_card[5] = { 0XFC,0X05,0x40,0x2B,0x15 };
//char dispense[7] = {0x02,0x31,0x35,0x44,0x43,0x03,0x02};
int bytes_read = 0;
FILE* lfp;
time_t now;
time(&now);
//lfp = fopen("carddispense.log","a+");
fd = open("/dev/ttyUSB1",O_RDWR | O_NOCTTY);
if(fd == -1)
{
//fprintf(lfp,"\nError! in Opening ttyUSB0 %s", ctime(&now));
printf("\nError in Opening in ttyUSB0\n");
exit(1);
}
else
{ printf("\nttyUSB0 Opened Successfully\n");
//fprintf(lfp,"Card reader has been used %s", ctime(&now));
tcgetattr(fd, &SerialPortSettings); /* save current serial port settings */
cfsetispeed(&SerialPortSettings,B9600); /* Baud rate for read */
cfsetospeed(&SerialPortSettings,B9600);
SerialPortSettings.c_cflag &= PARENB; // No Parity
SerialPortSettings.c_cflag &= ~CSTOPB; //Stop bits = 1
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the Mask */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /*Turn off hardware based flow control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Turn on the receiver of the serial port (CREAD) */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /*Turn off hardware based flow control */
SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* NON Cannonical mode for serial communication */
SerialPortSettings.c_cc[VMIN] = 100; /* Read 128 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinitely */
tcsetattr(fd,TCSANOW,&SerialPortSettings);
int pos =0,percent_count = 0;
int i;
for(i=0;i<5;i++)
{
printf("number = %x\t",dispense_card[i]);
sprintf(write_buffer+(i),"%c", dispense_card[i]);
}
printf("write_buffer%s\n",write_buffer);
//printf("write_buffer length: %d\n",strlen(write_buffer));
write(fd,write_buffer,strlen(write_buffer));
close(fd);
}
}
Try this
char tx_buf[5];
char rx_buf[5];
sprintf(tx_buf, "%c%c%c%c%c",0XFC,0X05,0x40,0x2B,0x15);
write(fd, tx_buf, 5);
while (1) {
int n = read (fd, rx_buf, 5);
if (n > 0) {
for(int i=0; i<n; i++) {
printf("data i: %02X ", rx_buf[i]); // "FC 05 50 AA 05"
}
}
}
close(fd);
I'm newbie in linux system programming, so be kind please.
I have to read data from serial port (/dev/ttyX) with baudrate 921600 in 8N1 mode with no parity via RS-422.
stty output signals that this baudrate is supported.
So I've decided to call epoll.
Problem is that epoll returns wrong bytes.
Since I have specified messages format I'm trying to debug by verifying incoming data by hands. So I've drawn this:
All messages have 2 bytes crc on the tail.
11 b5 means message start. Message should be 36 bytes in length.
72 b5 is another message start marker. 112 bytes len.
73 b5 is message marker too. 36 bytes.
Please find blue underline: this is good message.
Tiny red + fat red is a bad one.
It is 37 bytes len. I have one extra byte and crc mismatch.
Next good one goes (green).
And next bad one. It is 114 bytes instead of 112 bytes and crc mismatch of course.
Here is my code:
... All necessary includes
#define SERIAL_BAUD 921600
#define MAXEVENTS 1024
int openSerial()
{
struct termios options;
int fd;
if ((fd = open("/dev/ttyUSB0", O_RDWR)) == -1)
{
return -1;
}
if (tcgetattr(fd, &options) < 0)
{
printf("Unable to get options with tcgetattr\n");
return -1;
}
if (cfsetispeed(&options, SERIAL_BAUD) < 0)
{
printf("Unable to set input speed with cfsetispeed\n");
return -1;
}
if (cfsetospeed(&options, SERIAL_BAUD) < 0)
{
printf("Unable to set output speed with cfsetispeed\n");
return -1;
}
cfmakeraw(&options);
//options.c_cflag |= SERIAL_BAUD; // Set Baudrate first time
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
options.c_cflag &= ~ECHO; // Disable echoing of input characters
options.c_cflag &= ~ECHOE;
// set to 8N1
options.c_cflag &= ~PARENB; // no parity
options.c_cflag &= ~CSTOPB; // 1 stop bit
options.c_cflag &= ~CSIZE; // Mask the character size bits
options.c_cflag |= CS8; // 8 data bits
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
options.c_oflag = 0;
options.c_cc[VTIME] = 2; // inter-character timer
options.c_cc[VMIN] = 1; // blocking read until
if (tcflush(fd, TCIFLUSH) < 0)
{
printf("Unable to flush fd with tcflush\n");
return -1;
}
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
printf("Unable to set options with tcsetattr\n");
return -1;
}
return fd;
}
int main(void)
{
int fd;
int efd;
struct epoll_event event;
struct epoll_event* events;
int length;
unsigned char buff[512];
if ((fd = openSerial()) < 0)
{
printf("Exiting because of openSerial failure\n");
return 1;
}
efd = epoll_create1(0);
event.data.fd = fd;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) < 0)
{
printf("Epoll_ctl error occured\n");
return 1;
}
events = (epoll_event*) calloc(MAXEVENTS, sizeof(event));
for(;;)
{
int n = epoll_wait(efd, events, MAXEVENTS, 5000);
if (n < 0)
{
// No ready descriptors, so wait a bit longer
continue;
}
if(events[0].events & EPOLLIN)
{
length = read(events[0].data.fd, buff, sizeof(buff) / 2);
if(length > 0)
{
printf("\n------MESSAGE START-------\n");
for (int i = 0 ; i < length ; ++i)
{
if (i && i % 16 == 0)
{
printf("\n");
}
printf("%02x ", buff[i]);
}
printf("\n------MESSAGE FINISH-------\n");
}
}
else if(events[0].events & EPOLLOUT)
{
// TODO Write here to serial
}
else if(events[0].events & EPOLLHUP || events[0].events & EPOLLERR)
{
printf("Error occured on serial port\n");
}
else
{
printf("No data whthin 5 seconds.\n");
}
}
free(events);
close(fd);
return 0;
}
Your problem is that read() returns bytes that fail to meet your expectations. I see no reason to believe that epoll has anything to do with that.
I also see no reason to suppose that read() is delivering different bytes than the system received from device /dev/ttyUSB0. If these are different than you expected then I'm inclined to believe that either the device is malfunctioning or your expectations are incorrect (or at least incomplete).
I want to read data frames sent by a GPS XBee protocol. The USB XStick receives the following data:
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : ....
and so on ... I can read by typing in the terminal control :
$ screen /dev/ttyUSB0
I'd like to see these details in the same way, but with a program written in C. Here's what I do :
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "serial_port.h"
void read_Serial_Port(const char* DEVICE_PORT)
{
int file;
struct termios options;
char message[100];
unsigned int nCountMax = 60;
bool b;
file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);
if(file == -1){perror("Unable to open the serial port\n");}
printf("Serial port open successful\n");
tcgetattr(file, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB; //No parity
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; //8 bits
options.c_iflag |= (INPCK | ISTRIP);
tcsetattr(file, TCSANOW, &options);
fcntl(file, F_SETFL, FNDELAY);
printf("Reading serial port ...\n\n");
b = readMessage(file, message, nCountMax);
if (b == 0){printf("Error while reading serial port\n");}
else printf("Serial port read successful\n");
close(file);
printf("Serial port closed\n");
};
bool readMessage(int file, char *message, unsigned int nCountMax)
{
int nbCharToRead;
char data[100];
int i;
if (file != 0)
{
i = 0;
while (i<nCountMax && data != ".")
{
if (read(file,&data,1) == -1)
{
printf("reception error\n");
return false;
}
else
{
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
But it does not work, I get "reception error", corresponding to:
read(file,&data,1) == -1
Where am I going wrong?
My program is the following:
bool readMessage(int file, unsigned int nCountMax)
{
int i;
size_t nbytes;
ssize_t bytes_read;
if (file != -1)
{
i = 0;
char message[100];
char data[100];
while (i<nCountMax && data != ".")
{
if (read(file, data, 1) == -1)
{
printf("reception error\n");
printf("code errno = %d\n", errno);
return false;
}
else
{
nbytes = sizeof(data);
bytes_read = read(file, data, nbytes);
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
This time there are no more errors, but the characters shown are wrong:
$$$$QUC
U$C
$$$$JQMJ' J$Cz(HSQ'Q'y
UKUNiQUMJ
the dollar signs $$$$ represent numbers in groups of four... I repeat that what I would like to have is
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : .....
I have tried using %c, %d, %x in the format string, but obviously none of them worked properly ...
Thank you!
In my code, I only change c_cflag, as follows:
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
// Set 8-bit mode
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
I'll post more code tomorrow, but give that a shot (and don't modify c_iflag).
I want to connect to Cisco router from my c++ application.
Need it in order to get interface status.
My linux station (Ubuntu) and the router connected via serial interface.
connected from puty or minicom or Console Connections work.
for example:
root#test:/etc/minicom# cu -l /dev/ttyS0 -s 9600
Connected.
Router#show int summary
*: interface is up
IHQ: pkts in input hold queue IQD: pkts dropped from input queue
OHQ: pkts in output hold queue OQD: pkts dropped from output queue
RXBS: rx rate (bits/sec) RXPS: rx rate (pkts/sec)
TXBS: tx rate (bits/sec) TXPS: tx rate (pkts/sec)
TRTL: throttle count
Now i tried to do the same with C++ (or C) , but read hang.
My c code:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int fd1;
int fd2;
char *buff, *buffer, *bufptr;
int wr, rd, nbytes, tries;
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
bzero(&port_settings, sizeof(port_settings));
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return (fd);
}
int main() {
fd1 = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd1 == -1) {
perror("open_port: Unable to open /dev/ttyS0 – ");
} else {
fcntl(fd1, F_SETFL, 0);
}
printf("Port 1 has been sucessfully opened and %d is the file description\n",fd1);
configure_port(fd1);
wr = write(fd1, "\r", 1);
cout << " wr status " << wr << endl;
wr = write(fd1, "\r", 1);
cout << " wr status " << wr << endl;
wr = write(fd1, "ena\r", 4);
cout << " wr status " << wr << endl;
wr = write(fd1, "show int sum\r", 13);
cout << " wr status " << wr << endl;
rd = read(fd1, buff, 50);
cout << " rd status " << rd << endl;
cout << rd << endl;
return 0;
}
You aren't zeroing your port_settings struct first before modifying it. That's surely a bug, though it may not be the source of your problems. Have you tried building one of the dozens of "termios sample programs" available on the intnernet for comparison?
This work - probably sleep was missing.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int set_interface_attribs(int fd, int speed, int parity) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
printf("err");//error_message("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("err");//error_message("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void set_blocking(int fd, int should_block) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
printf("err");//error_message("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr(fd, TCSANOW, &tty) != 0)
printf("err");//error_message("error %d setting term attributes", errno);
}
int main(int argc, char **argv) {
char *portname = "/dev/ttyS0";
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("err");//error_message("error %d opening %s: %s", errno, portname,strerror(errno));
return -1;
}
set_interface_attribs(fd, B9600, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking(fd, 0); // set no blocking
write(fd, "\r", 1); // send 7 character greeting
write(fd, "\r", 1);
usleep(100000);
char buf[1000];
write(fd, "ena\r", 4);
memset(&buf, 0, sizeof buf);
usleep(100000);
write(fd, "show int sum\r", 15);
sleep(1);
memset(&buf, 0, sizeof buf);
int n = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
cout << " n " << n << endl;
cout << " buf " << buf << endl;
close(fd);
}
You should use SNMP to get interface status/statistics instead of connecting to serial console.
This is exact purpose what was SNMP designed for.