LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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

Reply
 
Search this Thread
Old 07-30-2010, 12:36 AM   #1
a5k3r
LQ Newbie
 
Registered: Jul 2010
Distribution: Ubuntu
Posts: 4

Rep: Reputation: 0
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;

}
 
Old 07-30-2010, 09:38 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,507

Rep: Reputation: 331Reputation: 331Reputation: 331Reputation: 331
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.
 
Old 07-30-2010, 09:50 PM   #3
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Rep: Reputation: 114Reputation: 114
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.
 
Old 08-09-2010, 10:49 AM   #4
a5k3r
LQ Newbie
 
Registered: Jul 2010
Distribution: Ubuntu
Posts: 4

Original Poster
Rep: Reputation: 0
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;
}
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[bash] synchronizing write/read to serial t00c00l Programming 3 08-01-2009 08:44 AM
Serial programming - binary data using open() and read() neutron001 Programming 5 04-07-2008 03:04 PM
is there any shell command to read and write data from parallel and serial port? baosheng Linux - Hardware 2 01-13-2007 08:35 PM
Should be dead simple - read/write serial port from bash ericcarlson Linux - Software 3 10-21-2006 08:35 PM
Serial port Read Write SeanatIL Programming 2 07-14-2004 03:42 PM


All times are GMT -5. The time now is 12:09 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration