I have an application where I am sending data via serial port from PC1 (Java App) and reading that data in PC2 (C++ App). The problem that I am facing is that my PC2 (C++ App) is not able to read complete data sent by PC1 i.e. from my PC1 I am sending 190 bytes but PC2 is able to read close to 140 bytes though I am trying to read in a loop.
Below is code snippet of my C++ App
/**Open the connection to serial port**/
serialfd = open( serialPortName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (serialfd == -1)
{
/*
* Could not open the port.
*/
TRACE << "Unable to open port: " << serialPortName << endl;
}
else
{
TRACE << "Connected to serial port: " << serialPortName << endl;
fcntl(serialfd, F_SETFL, 0);
}
/**Configure the Serial Port parameters**/
struct termios options;
/*
* Get the current options for the port...
*/
tcgetattr(serialfd, &options);
/*
* Set the baud rates to 9600...
*/
cfsetispeed(&options, B38400);
cfsetospeed(&options, B38400);
/*
* 8N1
* Data bits - 8
* Parity - None
* Stop bits - 1
*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
/*
* Enable hardware flow control
*/
options.c_cflag |= CRTSCTS;
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
// Flush the earlier data
tcflush(serialfd, TCIFLUSH);
/*
* Set the new options for the port...
*/
tcsetattr(serialfd, TCSANOW, &options);
**Now I am reading data**
const int MAXDATASIZE = 512;
std::vector<char> m_vRequestBuf;
char buffer[MAXDATASIZE];
int totalBytes = 0;
fcntl(serialfd, F_SETFL, FNDELAY);
while(1) {
bytesRead = read(serialfd, &buffer, MAXDATASIZE);
if(bytesRead == -1)
{
//Sleep for some time and read again
usleep(900000);
}
else
{
totalBytes += bytesRead;
//Add data read to vector
for(int i =0; i < bytesRead; i++)
{
m_vRequestBuf.push_back(buffer[i]);
}
int newBytesRead = 0;
//Now keep trying to read more data
while(newBytesRead != -1)
{
//clear contents of buffer
memset((void*)&buffer, 0, sizeof(char) * MAXDATASIZE);
newBytesRead = read(serialfd, &buffer, MAXDATASIZE);
totalBytes += newBytesRead;
for(int j = 0; j < newBytesRead; j++)
{
m_vRequestBuf.push_back(buffer[j]);
}
}//inner while
break;
} //while
Lateee response, but if you are reading in non-canonical mode, consider setting VMIN to the number of bytes you want to read.
Related
I'm trying to communicate with a motor device via serial communication(RS485) by Ubuntu18 & C++.
I wrote this C++ code below.
#include <iostream>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <cstring>
int main(){
char *dev = "/dev/ttyUSB0";
int fd = 0;
char message[3];
char reply[1024];
struct termios oldtio, newtio;
memset(&oldtio, 0, sizeof(oldtio));
memset(&newtio, 0, sizeof(newtio));
//Open COM Port;
fd = open(dev, O_RDWR | O_NOCTTY);
if(fd < 0){
std::cout << "COM Port Error" << std::endl;
return -1;
}
tcgetattr(fd, &oldtio);
//Serial Settings
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
newtio.c_iflag = IGNPAR;
newtio.c_cflag |= CS8;
newtio.c_cflag |= CREAD;
newtio.c_cflag &= ~CSTOPB;
newtio.c_lflag = ICANON;
tcsetattr(fd, TCSANOW, &newtio);
//Set Message(This is not real one because it will be too long)
messages[0] = char(0x02);
messages[1] = char(0x32);
messages[2] = char(0x03);
//Send Message
write(fd, message, 3);
//Receive Message
unsigned int length = 0;
length = read(fd, reply, 1024);
std::cout << reply << std::endl;
//Close Serial Port
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
}
・I added tcgetattr and tcsetattr (24/09/2021)
・modified strlen(message) to just 3
(This serial communication is done by ASCII and it starts with STX(0x02), ends with ETX(0x03).)
I could send a message correctly. I verified this by checking a motor working.
But I couldn't receive the message from the device that automatically replys message.
In detail, the process stops at length = read(fd, reply, 1024) and won't move on next line.
I verified the TxD and RxD lamp blinks correctly so the reply message must be send. And I could received reply message by pySerial in Python.
Is there any mistakes in this code for serial communication ?
I have success writing code in Windows and performing serial port communication. But not in Linux so far.
Here is the code I wrote:
I have used Picocom to verify that I can communicate over the serial ports via my (USB to NULL Modem to USB) cable.
Setting the code to None blocking yields "errno: 11 Resource temporarily unavailable" on both client and server."
When I set to Blocking, it hangs in code at the Read File method. If I comment that line out it runs... but not getting data.
Server sends packets continuous.
Client receives packets continuous.
Problem seems to be bytes aren't received at the client. They are sent, however at the server.
CLIENT:
RECV(1611912): NumChars: 0 String:
RECV(1611913): NumChars: 0 String:
RECV(1611918): NumChars: 0 String:
RECV(1611919): NumChars: 0 String:
RECV(1611920): NumChars: 0 String:
SERVER:
SENT(106775): NumChars: 10 String: 0123456789
SENT(106776): NumChars: 10 String: 0123456789
SENT(106777): NumChars: 10 String: 0123456789
SENT(106778): NumChars: 10 String: 0123456789
SENT(106779): NumChars: 10 String: 0123456789
to run:
g++ -o sp serialport.cpp
client: ./sp /dev/ttyS0 c
server: ./sp /dev/ttyS4 s
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
class C_SerialPort
{
private:
int giFD;
char gpcDevice[100] = {0};
public:
//------------------------------------------------
//
//------------------------------------------------
int GetError(char* pcMessage = (char*)"")
{
char pcError[100] = {0};
sprintf(pcError, " (%s): errno: %d %s\n", pcMessage, errno, strerror(errno));
if(errno > 0)
{
printf("%s", pcError);
}
return errno;
}
//------------------------------------------------
//
//------------------------------------------------
int Connect()
{
return Connect((char*)"/dev/ttyS0");
//return Connect((char*)"/dev/ttyUSB0");
}
//------------------------------------------------
//
//------------------------------------------------
int Connect(char *pcDevice)
{
strcpy(gpcDevice, pcDevice);
struct termios s_TA;
// Open the serial port
giFD = open(gpcDevice, O_RDWR | O_NOCTTY | O_NDELAY | O_FSYNC );
if(giFD < 0)
{
printf("open_port: Unable to open %s\n%s", gpcDevice, strerror(errno));
printf("EXITING...\n");
return 1;
}
else
{
printf("Connect Device: %s\n", gpcDevice);
}
// get attributes
if(tcgetattr(giFD, &s_TA) != 0)
{
GetError((char*)"tcgetattr");
printf("EXITING...\n");
return 1;
}
// clear terminalAttributes data
//memset(&s_TA, 0, sizeof(struct termios));
if(0)
{
// 57600 bauds; 8 bits per word; Ignore modem control lines; Enable receiver.
s_TA.c_cflag = B57600 | CS8 | CLOCAL | CREAD;
// Ignore framing errors and parity errors.
s_TA.c_iflag = IGNPAR | ONLCR;
//Enable implementation-defined output processing.
s_TA.c_oflag = OPOST;
// min time; min bytes to read
s_TA.c_cc[VTIME] = 1;
s_TA.c_cc[VMIN] = 1;// none zero blocks
}
else
{
cfsetospeed(&s_TA, B9600);
cfsetispeed(&s_TA, B9600);
s_TA.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
s_TA.c_cflag &= ~CSIZE;
s_TA.c_cflag |= CS8; /* 8-bit characters */
s_TA.c_cflag &= ~PARENB; /* no parity bit */
s_TA.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
s_TA.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
s_TA.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
s_TA.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
s_TA.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
s_TA.c_cc[VMIN] = 1; // 0 1
s_TA.c_cc[VTIME] = 1; // 0 1
}
//int iVal = fcntl(giFD, F_SETFL, 0); // set blocking?
//printf("file status = 0x%x\n", iVal);
//GetError((char*)"fcntl");
// Set the port to our state
if (tcsetattr(giFD, TCSANOW, &s_TA) != 0)
{
GetError((char*)"tcsetattr");
printf("EXITING...\n");
return 1;
}
// flushes data written but not transmitted.
// flushes data received but not read.
tcflush(giFD, TCOFLUSH);
tcflush(giFD, TCIFLUSH);
printf("CONNECTION OK\n");
//return giFD;
return 0;
}
//------------------------------------------------
//
//------------------------------------------------
void Disconnect(void)
{
close(giFD);
printf("nPort 1 has been CLOSED and %d is the file descriptionn", giFD);
GetError((char*)"Disconnect");
}
//------------------------------------------------
//
//------------------------------------------------
int SendArray(unsigned char *buffer, int len)
{
int n = write(giFD, buffer, len);
// error catch
if(n < 0)
GetError((char*)"write");
return n;
}
//------------------------------------------------
//
//------------------------------------------------
int GetArray (unsigned char *buffer, int len)
{
int n = 0;
int len2 = BytesToRead();
n = read(giFD, buffer, len2); // this line is an issue? with settings?
// error catch
//if(n < 0)
// GetError((char*)"read");
return n;
}
//------------------------------------------------
//
//------------------------------------------------
void Clear()
{
tcflush(giFD, TCIFLUSH);
tcflush(giFD, TCOFLUSH);
}
//------------------------------------------------
//
//------------------------------------------------
int BytesToRead()
{
int iBytes = 0;
ioctl(giFD, FIONREAD, &iBytes);
//printf("Byte2Read: %d\n", iBytes);
// error catch
GetError((char*)"BytesToRead");
return iBytes;
}
};
//------------------------------------------------
//
//------------------------------------------------
int main(int argc, char const *argv[])
{
// device
char *pcDevice = (char*)argv[1];
printf("init:device:%s\n", pcDevice);
// connection type
char cConnType = argv[2][0];
printf("ConnectionType:%c\n", cConnType);
// instantiate SerialPort
C_SerialPort c_SP;
// connect
int iReturn = c_SP.Connect(pcDevice);
if(iReturn != 0)
{
printf("EXITING...\n");
return 1;
}
// clear buffer
c_SP.Clear();
printf("clear\n");
printf("prior...\n");
// main loop
while(1)
{
int iSleep_ms = 200;
usleep(iSleep_ms);
char pcArray[100] = {0};
int iNumChars = 0;
if(cConnType == 's')
{
static long lCount = 0;
// Send
strcpy(pcArray, "0123456789");
iNumChars = c_SP.SendArray((unsigned char*)pcArray, 10);
if(iNumChars > 0)
{
printf("SENT(%ld): NumChars: %d String: %s\n", lCount, iNumChars, pcArray);
}
lCount++;
}
if(cConnType == 'c')
{
static long lCount = 0;
// Receive
iNumChars = c_SP.GetArray((unsigned char*)pcArray, sizeof(pcArray));
if(iNumChars > 0)
{
printf("RECV(%ld): NumChars: %d String: %s\n", lCount, iNumChars, pcArray);
}
else
{
//printf("RECV: NumChars: %d String: %s\n", iNumChars, pcArray);
}
lCount++;
}
}
c_SP.Disconnect();
return 0;
}
You have four major bugs:
Your GetArray function ignores the return value of BytesToRead. It should read the lesser of the buffer size or the number of bytes available.
Your code has no ability to sanely handle the case where BytesToRead returns zero.
You ignore the return value of GetArray. When you print pcArray, you do not tell printf how many characters to output. So how is it supposed to know what to print?
You overwrite the returned values from tcgetattr by calling memset.
The issue is the serial port to communicate through.
The /dev/ttyS0 and /dev/ttyS4 are the serial ports after the USB in the NULL modem cable hook up. But to communicate I had to use /dev/ttyUSB0 and /dev/ttyUSB1
I have written a small and simple serial port read/write application to connect to my modem and to run commands. There is a problem. The program works perfectly for the most part but when the command takes a bit of time to execute and respond, the program acts strangely. Here is my code:
void write (char cmd[256]) {
int n_written = 0;
char atcmd [259];
sprintf (atcmd, "%s\r\n", cmd);
n_written = write( fd, &atcmd, strlen(atcmd) );
printf ("WROTE: %d\n", n_written);
}
void read (char * cmdresp) {
int n = 0;
char response[1024];
memset(response, 0 , sizeof response);
n = read( fd, &response, sizeof (response) );
if (n < 0) {
printf ("ERROR=%d - %s\n", errno, strerror(errno));
} else if (n == 0) {
printf ("Read nothing!\n");
} else {
printf ("READ: %s\n", response);
strcpy (cmdresp, response);
}
}
void manage_transaction (char * message, char * response) {
tv.tv_sec = 5;
tv.tv_usec = 0;
write (message);
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
int retval = select(fd+1, &rfds, NULL, NULL, &tv);
if (retval == -1) {
perror("select()");
} else if (retval) {
if (FD_ISSET(fd, &rfds) ) {
usleep(200000);
read(response);
}
} else {
printf("No data within five seconds.\n");
}
}
Here is two successive runs, one successful one unsuccessful:
Successful:
AT> AT+CGSN
Client ConnectedHere is the message: AT+CGSN
WROTE: 11
READ: AT+CGSN
123456789012345
OK
AT+CGSN
123456789012345
OK
FAILED:
AT> ATD11234567890;
Here is the message: ATD11234567890;
WROTE: 19
READ: ATD11234567890;
AT> 1234567890;
<<-- If I press an enter key or send another message the rest of the message comes through:
Here is the message:
WROTE: 4
READ:
OK
OK
AT>
Am I missing something? How can I fix this problem?
Any ideas is greatly appreciated.
*********** EDIT ***************
Here are the open and config codes:
int open_port(void)
{
fd = open("/dev/ttyUSB2", O_RDWR | O_NOCTTY);
if(fd == -1) {
perror("open_port: Unable to open /dev/ttyUSB2");
}
else {
fcntl(fd, F_SETFL, 0);
printf("port is open.\n");
}
tcflush(fd, TCIFLUSH);
tcflush(fd, TCOFLUSH);
return fd;
}
void config () {
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
if ( tcgetattr ( fd, &tty ) != 0 ) {
printf ("ERROR=%d - %s\n", errno, strerror(errno));
}
tty_old = tty;
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B115200);
cfsetispeed (&tty, (speed_t)B115200);
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_iflag &= ~INPCK;
tty.c_iflag |= (IGNBRK | BRKINT);
tty.c_iflag |= IGNPAR;
tty.c_iflag &= ~ICRNL;
tty.c_iflag &= ~IXON;
tty.c_iflag &= ~ISTRIP;
tty.c_iflag &= ~INLCR;
tty.c_iflag &= ~IGNCR;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 0; // 5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
tty.c_iflag &= ~(IXON |IXOFF|IXANY); /* no XON/XOFF flow control */
tty.c_oflag &= ~(IXON |IXOFF|IXANY); /* no XON/XOFF flow control */
tty.c_oflag &= ~(OPOST | ONLCR );
/* Make raw */
cfmakeraw(&tty);
/* Flush Port, then applies attributes */
tcflush(fd, TCIFLUSH );
tcflush(fd, TCIOFLUSH );
int reuse = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
if ( (tcsetattr(fd,TCSANOW,&tty) < 0) ) {
printf ("ERROR=%d - %s\n", errno, strerror(errno));
}
}
This code is reading data from RFID module(EM-18) .I have a big problem here. When my application was running and I was passing RFID card from em module, It was reading data in 2 part. First read 8 byte's card ID then send 4 bytes. Like this:
[root#FriendlyARM /fgit]# ./RFIDMonitor -qws
enter the port name:
ttySAC3
open_port: succesfully open port
open_port: succesfully open port
RFID MONITORING => '010B7528'
RFID MONITORING => '297E'
RFID MONITORING => '010B7528'
RFID MONITORING => '297E'
I changed VMIN and VTime but the result did not change.
This is my code:
if(!fork())
{
while(1)
{
memset(buf2,'\0',MAXDATASIZE);
//------------------------------------------------
if ((numbytes = read(fd,buf2, MAXDATASIZE-1)) != -1)
{
buf2[numbytes] = '\0';
printf("RFID MONITORING => '%s'\n",buf2);
}
}
}
This is my config :
int openport(void)
{
cout<<"enter the port name:\n";
string portname="";
cin>>portname;
portname="/dev/"+portname;
fd=open(portname.c_str(),O_RDWR|O_NOCTTY|O_NDELAY);
if (fd==-1)
{
//printf("open_port: unable to open port \n");
return -1;
}
else
{
//printf("open_port: succesfully open port \n");
fcntl(fd,F_SETFL,0);
return 1;
}
}
//-------------------------------------
void closeport(void)
{
close(fd);
}
//-------------------------------------
void configport(void)
{
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( fd, &tty ) != 0 ) {
std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
}
/* Save old tty parameters */
tty_old = tty;
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] =1;// change to 0 and 5
tty.c_cc[VTIME] = 10;// change to 0 and 5
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
/* Make raw */
cfmakeraw(&tty);
/* Flush Port, then applies attributes */
tcflush( fd, TCIFLUSH );
if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) {
std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}
}
I want to show like this (all data in one part)
RFID MONITORING => '010B7528297E
read only reads what is available to be read. If you have to read the whole the whole thing, keep reading until you have the whole thing.
while(1)
{
memset(buf2,'\0',MAXDATASIZE);
int bytesread = 0;
//------------------------------------------------
//Keep going until the whole message has been read
while (bytesread != MAXDATASIZE-1)
{
//read less on successive reads, but write further into buffer
if ((numbytes = read(fd,buf2[bytesread], MAXDATASIZE-1-bytesread)) == -1)
{
printf("Error in reading data");
// handle error. Probably reopen port and resynch with RFID
}
else
{
// keep track of where we are in accumulating
bytesread += numbytes;
}
}
buf2[bytesread] = '\0';
printf("RFID MONITORING => '%s'\n",buf2);
}
I solve the problem ( just append that with sleep 1 second)
int numbytes;
char buf2[MAXDATASIZE];
//*****************************
// SerialCodes
//*****************************]
fd=-1;
while(fd==-1)
{
int a=openport();
if(a==1)
{
pid_t pid;
if((pid=fork()))
{
qDebug()<<("%d",pid);
while(1)
{
//------------------------------------------------
if ((numbytes = read(fd,buf2, MAXDATASIZE-1)) == -1)
{
//qDebug()<<("Error in reading data");
}
else
{
buf2[numbytes] = '\0';
usleep(10000);
QString s1(buf2);
memset(buf2,'\0',MAXDATASIZE);
read(fd,buf2, MAXDATASIZE-1) ;
QString s2(buf2);
memset(buf2,'\0',MAXDATASIZE);
qDebug()<<("RFID MONITORING => '%s'\n",s1+s2);
kill(pid,SIGTERM);
break;
}
}
}
}
}
I just connected my raspberry Pi with a SM5100b GSM. I would like to test it sending a simple message in my mobile. I can do it with emulators like cutecom and minicom (because I have raspbian linux version). But Is there any code in C++ which does this job? I do not use Arduino, only a SM5100B. I wrote this code until now and of course it does not work yet
#include <stdio.h> // standard input / output functions
#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 definitionss
#include <time.h> // time calls
int open_port(void)
{
int fd; // file description for the serial port
fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) // if open is unsucessful
{
//perror("open_port: Unable to open /dev/ttyAMA0 - ");
printf("open_port: Unable to open /dev/ttyAMA0. \n");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("port is open.\n");
}
return(fd);
} //open_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);
} //configure_port
int query_modem(int fd) // query modem with an AT command
{
char n;
fd_set rdfs;
struct timeval timeout;
// initialise the timeout structure
timeout.tv_sec = 10; // ten second timeout
timeout.tv_usec = 0;
unsigned char send_bytes[] = "AT+CMGF=1";
unsigned char send_bytes1[] = "AT+CMGS=\"603*****\"";
unsigned char send_bytes3[] = "TEST";
// puts(send_bytes);
write(fd, send_bytes, 13); //Send data
write(fd, send_bytes1, 13);
write(fd, send_bytes3, 13);
//printf("Wrote the bytes. \n");
// do the select
n = select(fd + 1, &rdfs, NULL, NULL, &timeout);
// check if an error has occured
if(n < 0)
{
perror("select failed\n");
}
else if (n == 0)
{
puts("Timeout!");
}
else
{
printf("\nBytes detected on the port!\n");
}
return 0;
} //query_modem
int main(void)
{
int fd = open_port();
configure_port(fd);
query_modem(fd);
return(0);
} //main
Open the relevant serial port (/dev/ttySx, where x is most likely a number), use write or fwrite to write to the port, close the port, exit program.