Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
07-30-2010, 12:36 AM
|
#1
|
|
LQ Newbie
Registered: Jul 2010
Distribution: Ubuntu
Posts: 4
Rep:
|
Serial Programming, Write-Read Issue
Hi,
I am still new to serial programming in linux. So to communicate with an A to D device I found some code online and modified it for my purpose. The problem is I can never perform "Write then Read".
Whereas when I perform "just Read" and "Read then Write and then Read", the code works with no issues. But if I write a command to the port first and then try to read the response, the program just waits for the response indefinitely.
Another interesting thing I noticed is while the program is waiting for the response, if I open a connection to the port using "CuteCom" then the program starts reading the response.
Also if I perform the write operation using a different binary, then I can read the responses with no issues.
I really don't understand why this is happening. Any form of help on this regard would really be appreciated. My system details and code are below.
Thanks and Regards,
Aravind
System Details:
Ubuntu 10.04 & Connected the RS-232 cable to my laptop by using RS-232 to USB converter.
Code:
Code:
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#define BAUDRATE B115200
#define PORT "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
void signal_handler_IO ( int status ); // definition of signal handler
volatile int STOP = FALSE;
int wait_flag = TRUE; // TRUE while no signal received
int main()
{
int fd, res, sen;
int i;
struct termios oldtio, newtio;
struct sigaction saio; /* definition of signal action */
char comm[7], resp[10];
for ( i = 0; i < 10; i++ ) { resp[i] = 0x00; }
/* open the device to be non-blocking (read will return immediatly) */
fd = open( PORT, O_RDWR | O_NOCTTY | O_NONBLOCK );
if (fd < 0) { perror(PORT); return 1; }
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
//saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction( SIGIO, &saio, NULL );
/* allow the process to receive SIGIO */
fcntl( fd, F_SETOWN, getpid() );
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
fcntl( fd, F_SETFL, FASYNC );
//tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
//newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
//newtio.c_lflag = 0;
newtio.c_cc[VMIN] = 0;
newtio.c_cc[VTIME] = 0;
tcflush(fd, TCIFLUSH);
tcsetattr( fd, TCSANOW, &newtio );
comm[0] = 'V'; comm[1] = '\r';
printf("Write start...\n");
sen = write( fd, comm, 2 );
printf("Write stop...\nsen = %d\n", sen);
printf("Read start...\n");
res = read( fd, resp, 4 );
printf("Read stop...\n");
resp[res] = '\0';
printf("Response = %s\n", resp );
/* restore old port settings */
tcsetattr( fd, TCSANOW, &oldtio );
return 0;
}
/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
***************************************************************************/
void signal_handler_IO (int status)
{
printf("received SIGIO signal.\n");
wait_flag = FALSE;
}
|
|
|
|
07-30-2010, 09:38 PM
|
#2
|
|
Senior Member
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,388
|
I do not know if I will be able to help you too much, but I would suggest that you examine the return value from read(); that is check the value of res.
Code:
res = read( fd, resp, 4 );
Since you have the port set up to be non-blocking, it is possible that 'res' is equal to -1 (and errno is equal to EAGAIN). If the read() is interrupted by a signal, it may return less than the desired 4-bytes that you seek.
|
|
|
|
07-30-2010, 09:50 PM
|
#3
|
|
Senior Member
Registered: Sep 2003
Posts: 3,171
Rep: 
|
Given your symptoms, I would be looking hard at the device that is on the other end of the serial connection. I'm guessing that you are not initializing it correctly and as a consequence when you write to it, it does not expect that and therefore does not know to respond. Perhaps it is expecting to be read first.
When you start by reading it, it is happy - which suggests that it is starting expecting to be read.
Perhaps it has some communications handshaking that is only initialized when you read from it; perhaps this is how it knows something is connected to it. Could be some kind of DTR/DCR problem also.
Last edited by jiml8; 07-30-2010 at 09:51 PM.
|
|
|
|
08-09-2010, 10:49 AM
|
#4
|
|
LQ Newbie
Registered: Jul 2010
Distribution: Ubuntu
Posts: 4
Original Poster
Rep:
|
Hi, The following code solved the issue for me.
Note: The code is used to convert the reading from DAQ as well. And hence for serial communication please refer to the relevant portions.
Code:
/*
writeread.cpp
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/time.h>
#include "serial.h"
#define DAQ_BAUDRATE B9600
#define DAQ_PORT "/dev/ttyUSB0"
#define FILE_DATALOG "datalog.txt"
#define FILE_ERRLOG "errlog.txt"
#define SIZE 10
#define R_OHM 250
using namespace std;
int daq_fd;
int num = 0;
fstream datalog, errlog;
void getHex( char read[], char hexval[] )
{
hexval[3] = '\0';
hexval[0] = read[2];
hexval[1] = read[3];
hexval[2] = read[4];
}
int hex2dec( char hexval[] )
{
long int temp = strtol( hexval, NULL, 16 );
return (int)temp;
}
double getVolt_V( int ADCsample )
{
return ADCsample * 5.0 / 4096;
}
double getAvg( double data[] )
{
double total = 0;
for ( int i = 0; i < num; i++ ) { total += data[i]; }
return total / num;
}
double getCurr_mA( double volt )
{
return volt * 1000 / R_OHM;
}
double getKlux( double curr_mA )
{
return ( 9.375 * curr_mA ) - 37.5;
}
double getLux( double Klux )
{
return Klux * 1000;
}
int main( int argc, char **argv )
{
if( argc != 3 ) { cout << "Please enter the PORT name and number of readings.\n"; return 1; }
char *daqport;
char sResp[10];
char hexval[4];
int ADCsample = 0;
double volt_V[num], curr_mA[num], Klux[num], lux[num];
double volt = 0, volt_avg = 0, curr_avg = 0, Klux_avg = 0, lux_avg = 0;
struct timeval time;
int i = 0;
// Get the PORT name
daqport = argv[1];
// Get the number of readings
num = atoi( argv[2] );
// Open and Initialise port
daq_fd = open( daqport, O_RDWR | O_NOCTTY | O_NONBLOCK );
if ( daq_fd < 0 ) { perror(daqport); return 1; }
initport( daq_fd, DAQ_BAUDRATE );
// Open the file to store info
datalog.open( FILE_DATALOG, ios::out );
errlog.open( FILE_ERRLOG, ios::out );
if ( !datalog.is_open() || !errlog.is_open() ) { cout << "Unable to open files.\n"; return 1; }
char sCmd[10];
char command[] = "U8";
for ( i = 0; i < strlen(command); i++ )
sCmd[i] = command[i];
sCmd[i] = '\r'; sCmd[i+1] = '\n'; sCmd[i+2] = 0x00;
i = 0;
while ( i < num )
{
if ( !writeport( daq_fd, sCmd ) ) { cout << "write failed\n"; /*close( daq_fd ); return 1;*/ }
printf( "written:%s\n", sCmd );
while ( wait_flag == TRUE );
if ( readport( daq_fd, sResp, 10 ) )
{
if ( (strlen(sResp) == 5) && (sResp[0] == 'U') )
{
getHex( sResp, hexval ); // Get the HEX data
ADCsample = hex2dec( hexval ); // Convert to 12bit decimal value
volt = getVolt_V( ADCsample ); // Convert to unipolar voltage
//if ( volt >= 1 && volt <= 5 )
//{
volt_V[i] = volt;
curr_mA[i] = getCurr_mA( volt_V[i] ); // Compute current in mA
Klux[i] = getKlux( curr_mA[i] ); // Compute Kilo Lux
lux[i] = getLux( Klux[i] ); // Convert to Lux
gettimeofday( &time, NULL );
printf( "%s \t0x%s \t%4d \t%lf;\r",
sResp, hexval, ADCsample, volt_V[i] );
datalog << sResp << "\t"
<< "0x" << hexval << "\t"
<< setw(4) << ADCsample << "\t"
<< setw(8) << volt_V[i] << "\t"
<< setw(8) << curr_mA[i] << "\t"
<< Klux[i] << "\t" << lux[i] << "; "
<< time.tv_sec << " " << time.tv_usec << ";" << endl;
i++;
//}
}
else
{
errlog << "InVAL: " << sResp << endl; cout << "...\t";
}
}
wait_flag == TRUE;
usleep(50000);
}
volt_avg = getAvg( volt_V );
curr_avg = getAvg( curr_mA );
Klux_avg = getAvg( Klux );
lux_avg = getAvg( lux );
datalog << "* " << volt_avg << "\t" << curr_avg << "\t"
<< Klux_avg << "\t" << lux_avg << ";" << endl;
// Close the open port
close( daq_fd );
// Close the open files
datalog.close();
errlog.close();
return 0;
}
/* serial.h
(C) 2004-5 Captain http://www.captain.at
Helper functions for "ser"
Used for testing the PIC-MMC test-board
http://www.captain.at/electronic-index.php
*/
#include <iostream>
#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 */
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#define TRUE 1
#define FALSE 0
using namespace std;
int wait_flag = TRUE; // TRUE while no signal received
// Definition of Signal Handler
void DAQ_signal_handler_IO ( int status )
{
cout << "received SIGIO signal." << endl;
wait_flag = FALSE;
}
int writeport( int fd, char *comm )
{
int len = strlen( comm );
int n = write( fd, comm, len );
if ( n < 0 )
{
cout << "write failed!" << endl;
return 0;
}
return n;
}
int readport( int fd, char *resp, size_t nbyte )
{
int iIn = read( fd, resp, nbyte );
if ( iIn < 0 )
{
if ( errno == EAGAIN )
{
cout << "SERIAL EAGAIN ERROR" << endl;
return 0;
}
else
{
cout << "SERIAL read error: " << errno << "=" << strerror(errno) << endl;
return 0;
}
}
if ( resp[iIn-1] == '\r' )
resp[iIn-1] = '\0';
else
resp[iIn] = '\0';
return 1;
}
int getbaud( int fd )
{
struct termios termAttr;
int inputSpeed = -1;
speed_t baudRate;
tcgetattr( fd, &termAttr );
// Get the input speed
baudRate = cfgetispeed( &termAttr );
switch ( baudRate )
{
case B0: inputSpeed = 0; break;
case B50: inputSpeed = 50; break;
case B110: inputSpeed = 110; break;
case B134: inputSpeed = 134; break;
case B150: inputSpeed = 150; break;
case B200: inputSpeed = 200; break;
case B300: inputSpeed = 300; break;
case B600: inputSpeed = 600; break;
case B1200: inputSpeed = 1200; break;
case B1800: inputSpeed = 1800; break;
case B2400: inputSpeed = 2400; break;
case B4800: inputSpeed = 4800; break;
case B9600: inputSpeed = 9600; break;
case B19200: inputSpeed = 19200; break;
case B38400: inputSpeed = 38400; break;
case B115200: inputSpeed = 115200; break;
}
return inputSpeed;
}
/* ser.c
(C) 2004-5 Captain http://www.captain.at
Sends 3 characters (ABC) via the serial port (/dev/ttyS0) and reads
them back if they are returned from the PIC.
Used for testing the PIC-MMC test-board
http://www.captain.at/electronic-index.php
*/
int initport( int fd, speed_t baudRate )
{
struct termios options;
struct sigaction saio; // Definition of Signal action
// Install the signal handler before making the device asynchronous
saio.sa_handler = DAQ_signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction( SIGIO, &saio, NULL );
// Allow the process to receive SIGIO
fcntl( fd, F_SETOWN, getpid() );
// Make the file descriptor asynchronous (the manual page says only
// O_APPEND and O_NONBLOCK, will work with F_SETFL...)
fcntl( fd, F_SETFL, FASYNC );
// Get the current options for the port...
tcgetattr( fd, &options );
/*
// Set port settings for canonical input processing
options.c_cflag = BAUDRATE | CRTSCTS | CLOCAL | CREAD;
options.c_iflag = IGNPAR | ICRNL;
//options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = ICANON;
//options.c_lflag = 0;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;
*/
// Set the baud rates to...
cfsetispeed( &options, baudRate );
cfsetospeed( &options, baudRate );
// Enable the receiver and set local mode...
options.c_cflag |= ( CLOCAL | CREAD );
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Flush the input & output...
tcflush( fd, TCIOFLUSH );
// Set the new options for the port...
tcsetattr( fd, TCSANOW, &options );
return 1;
}
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 01:29 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|