LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
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 11-29-2010, 04:04 PM   #1
rados
LQ Newbie
 
Registered: Oct 2010
Posts: 10

Rep: Reputation: 0
Exclamation RS232 Configuration is not doing do wanted operation


I am writing a program to send data over serial port but the sending and reading operation is not occurring as desired to be... Below you can see the read and write parts. Could you please help me to find where I am doing wrong...

Reading Part:
Code:
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>




#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyS0"
#define TRUE 1
#define FALSE 0

//Threads
pthread_t ReadThread; 

//Global Variables
volatile int STOP = FALSE;
char read_buf[13] = "\0";


//file descriptor
int fd_r;

//place for old and new port settings for serial port
struct termios oldtio;


//Called Functions
void portconfig(int *);//serial port configuration settings
void listenport(int );//waiting serial port for input

//Thread Functions//////////////////////////////////////

void *ReadThreadFunc(void *);

///////////////////////////////////////////////////////


main()
{

	int code;

	
	fd_r = open(MODEMDEVICE,O_RDWR | O_NOCTTY | O_NDELAY);
	if(fd_r < 0)
	{
		perror(MODEMDEVICE);
		exit(-1);	
	}

	code = tcgetattr(fd_r,&oldtio); //Save the current port settings
	if(code < 0)
		{
		 perror("Getting attributes failed!");
		 exit(-1);	
		}


	//serial port configuration settings for file descriptor
	portconfig(&fd_r);

	
	//Threads Calling//////////
	if(pthread_create(&ReadThread, NULL, ReadThreadFunc, NULL) != 0)
	{
		perror("Read Thread Creation FAILURE!!!\n");
		return -11;
	}

	

	//Wait Called Threads//////
	pthread_join(ReadThread, NULL);

	

	tcsetattr(fd_r,TCSANOW,&oldtio);	//restore old port settings.
	close(fd_r);
	

	return 0;
}



/* New port settings for canonical input processing */
void portconfig(int *fdf)
{
	struct termios newtio;
	int kod;
	
	newtio.c_cflag = 0; 
	
	newtio.c_iflag = 0 ; 	
	
	newtio.c_oflag = 0;			
	
	newtio.c_lflag = 0;

	kod=tcsetattr(*fdf,TCSANOW,&newtio);	//changes occurs immediately.
	if(kod < 0)
	{
		perror("Setting attributes failed!");
		exit(-1);	
	}

	

	
	newtio.c_cflag = BAUDRATE | CS8  | CREAD | CLOCAL | PARENB | PARODD | CRTSCTS ;
	
	newtio.c_iflag = INPCK; 	
	
	newtio.c_oflag = 0;			
	
	newtio.c_lflag = NOFLSH;

	newtio.c_cc[VMIN] = 13;

	newtio.c_cc[VTIME] = 0;

	tcflush(*fdf,TCIFLUSH);		//flushed data received but not read.
	
	kod=tcsetattr(*fdf,TCSANOW,&newtio);	//changes occurs immediately.
	
	if(kod < 0)
	{
		perror("Setting attributes failed!");
		exit(-1);	
	}
}





void *ReadThreadFunc(void *ptr)
{
	int numbytes = 0, i = 0;
	strcpy(read_buf, "\0");	
	
	while(STOP==FALSE)
	{		
						
		numbytes = read(fd_r, read_buf, 13);
	
		if(numbytes > 0)
		{			
			printf(":%s:%d\n",read_buf,numbytes);
		
		}		
	}


}

Writing Part:
Code:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<termios.h>
#include<unistd.h>
#include<string.h>
#include <aio.h>
#include <errno.h>


#define BAUDRATE B9600
#define SERIALDEVICE "/dev/ttyS1"
#define TRUE 1
#define FALSE 0

void portconfig(int *);


main()

{

int fd_w, code;
int n = 13;
int i = 0;

struct termios oldtio;

char data[13] = "13.2 21.3\0";


fd_w = open(SERIALDEVICE,O_RDWR | O_NOCTTY |  O_NDELAY);	//opening serial port device for write action
if(fd_w < 0)
	{
	 perror(SERIALDEVICE);
	 exit(-1);	
	}

code = tcgetattr(fd_w,&oldtio);

if(code < 0)
	{
	 perror("Getting attributes failed!");
	 exit(-1);	
	}

portconfig(&fd_w);



for(i = 0; i < 10; i++)
	{ 
		write(fd_w,data,n);  
		puts(data);
		
	}

tcsetattr(fd_w,TCSANOW,&oldtio);	//restore old port settings.
close(fd_w);


}



/* Port configuration function */
void portconfig(int *device)
{
struct termios newtio;
int cod = 0;


newtio.c_cflag = 0; 
	
newtio.c_iflag = 0 ; 	
	
newtio.c_oflag = 0;			

newtio.c_lflag = 0;

cod=tcsetattr(*device,TCSANOW,&newtio);	
if(cod<0)
	{
	 perror("Setting attributes failed!");
	 exit(-1);	
	}



newtio.c_cflag = BAUDRATE | CS8 | CLOCAL |  PARENB | PARODD | CRTSCTS;

newtio.c_lflag = NOFLSH;

newtio.c_iflag = 0;

newtio.c_oflag = 0;


tcflush(*device,TCOFLUSH);//flushes untransmitted output
cod=tcsetattr(*device,TCSANOW,&newtio);	//changes occurs immediately.

if(cod<0)
	{
	 perror("Setting attributes failed!");
	 exit(-1);	
	}

}

When I compile and run the above programs Reading part does not read the 13 bytes once it first reads 8 byte then 8 again then 2 and so on. It always divides the sent data... I could not find where the problem is... Any help will be appreciated very much. Thanks in advance.
 
Old 11-29-2010, 07:41 PM   #2
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
In the name of the Flying Spaghetti Monster,

Serial data is a series of bytes, pure and simple. There is nothing to guarantee that when you write 13 bytes at a time, you'll get 13 bytes at a time on the other end for each read.

If you want 13 bytes, put the read into a loop that keeps going until it gets those 13 bytes. It would be advisable, each time through the loop, to read only the number of bytes remaining in the request. Otherwise, you'll end up with later data that you don't want yet, and you'll have to figure out what to do with it.
 
Old 11-30-2010, 12:08 AM   #3
rados
LQ Newbie
 
Registered: Oct 2010
Posts: 10

Original Poster
Rep: Reputation: 0
You mean read into a char array until the number of bytes read is 13 then retun the read char array. Is it what you are telling me?
I can do it but in the configurations of serial port, I am giving the below configuration in order to guarantee that read does not return until 13 bytes of data is read... I think with this termios configuration it should behave as I mention and it is written to do so everywhere.

newtio.c_cc[VMIN] = 13;//I am trying to tell serial port to return when 13 bytes of data is read.

newtio.c_cc[VTIME] = 0;

Every source mentioning the termios says that this configuration works for what I am telling. Do I consider something wrong?

Another issue is that I am also telling the read operation to read 13 bytes of data by the command:
numbytes = read(fd_r, read_buf, 13);

Could you please help me with my doubts?

Another question in my mind is that if there is a way to configure serila port buffer in linux...

I urgently need your answers...
 
Old 11-30-2010, 07:28 AM   #4
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
In the name of the Flying Spaghetti Monster,

When you code c_cc[VTIME] to be zero and c_cc[VMIN] to be 13, that's nice, but don't expect it to be a guarantee.

Always check the result of the read call to see how many characters you got. In particular, always check for -1, which means error. Error can mean "received a signal". And for purposes of defensive coding, always check for zero, which means "end of file" (sort of). In canonical environments (and I realize you're almost certainly not working in a canonical environment), receiving ^D can mean end of file. Check for it anyway. The check is inexpensive. And, of course, always check to see that you got all 13 bytes.

Usually (meaning always unless you have a good reason not to) put this whole thing in a loop, changing c_cc[VMIN] to be the number of characters remaining, the third argument to read() to be that same value, and the second argument to read() to point to the first (remaining) byte in the buffer.

If you find 0 or (more likely) -1 as a return value, you've learned something. If, instead, you get a return value less than 13, you know that neither you nor I have read the documents carefully enough. Signals might be involved here. Perhaps a lurker can step forward and explain. But if not, just do it. I know this is a very sloppy answer, but it will get you on your way.

If you're still interested in why this is necessary in your case (and I know I would be, and would invest the time to find out if I were you), consider the possible presence of signals. I wish I had the time to be more helpful.
 
Old 12-01-2010, 01:02 AM   #5
rados
LQ Newbie
 
Registered: Oct 2010
Posts: 10

Original Poster
Rep: Reputation: 0
Thank you very much you have already helped me very much. I want to ask you my final questions : )

Is there any way to configure serial port buffer in linux as there is in windows? If there is a way could you please explain or give me a source link to read and learn.

Another question in my mind is that if I do this data sending using TCP/IP will I encounter the same issue? I mean in TCP/IP if I send a message with a 13 byte data do I get the 13 byte in once or is it possible to get it 8 bytes first, then 3bytes and lastly 2 bytes?
 
Old 12-01-2010, 04:33 AM   #6
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
In the name of the Flying Spaghetti Monster,

Quote:
Originally Posted by rados View Post
Is there any way to configure serial port buffer in linux as there is in windows?
I have no experience with Microsoft Windows. You'd have to be more specific. Sorry.
Quote:
Originally Posted by rados View Post
if I do this data sending using TCP/IP will I encounter the same issue?
You betcha.
 
Old 12-01-2010, 07:52 AM   #7
rados
LQ Newbie
 
Registered: Oct 2010
Posts: 10

Original Poster
Rep: Reputation: 0
Quote:
I have no experience with Microsoft Windows. You'd have to be more specific. Sorry.
I mean when doing serial port configuration in windows(in some APIs) there is an option for both input and output. By this option you determine the size of buffer(i.e. FIFO) for serial port. For example if you say 200 for the FIFO size of serial port for input, your configured serial port stores 200 bytes of data in a FIFO and after this fills(if you do not read the FIFO it will surely fill up) it then overwrites that... By the use of this buffer configuration option you have the ability to determine size of your serial port data storage for unread bytes.

Do you know anyway to configure this buffer size in linux also?

If there is not a way to configure what is the default size for FIFO in linux?
 
Old 12-01-2010, 11:19 AM   #8
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
In the name of the Flying Spaghetti Monster,

Quote:
Originally Posted by rados View Post
Do you know anyway to configure this buffer size in linux also?
Nnnnnope. According to this, there is none. Sixteen bytes is what you get. See that document for many other interesting things about serial ports.
 
Old 12-01-2010, 11:48 PM   #9
rados
LQ Newbie
 
Registered: Oct 2010
Posts: 10

Original Poster
Rep: Reputation: 0
Thank you very much you really helped me a lot...
 
  


Reply



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
Wanted: software configuration change tracker wanderingpenguin Linux - Newbie 1 01-19-2009 09:10 PM
Connecting to an RS232 without an RS232 timnp Linux - General 6 06-06-2008 03:53 PM
Wanted: Info about GRUB configuration for Slackware fc6_user Linux - General 8 06-06-2007 05:41 AM
USB>RS232 versus PCMCIA>RS232 jayhel Linux - Laptop and Netbook 2 08-04-2005 06:09 PM
MAC based DHCP configuration ! Help wanted aronnok Linux - Networking 5 10-30-2004 06:37 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:39 AM.

Main Menu
Advertisement
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
Open Source Consulting | Domain Registration