Project Home
Project Home
Trackers
Trackers
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - Reading from serial port: (8 Items)
   
Reading from serial port  
Hey all!

I am having difficulty reading from the serial port, it is being controlled by interrupts when the data comes in, it is 
supposed to be roughly 1Hz (depends on GPS signal and stuff)
I am encountering 2 problems:

1: Is that when i read using Interrupts so the serial port interrupts when the data is ready to be read, that happens 
roughly 1Hz, then after that i for some reason get like  roughly 20(give or take)  interrupts one after another which 
also reads the data (its not supposed to do this, because the program on the IMU that i am using outputs data roughly 
every 1Hz).

2: After i perform the read I noticed that the data in the serial port doesn;t get updated for some reason, and the data
 that is in the serial port is only maxed at 2048 bytes(anyone know why this is?), it only gets updated when i perform 
an InterruptWait() and corresponding InterruptUnmask() when this happens I found out that the data in the serial port 
gets refreshed 8 bytes at a time, so eventually after say 2048 - 167 *(amount of reads), the data in the serial port 
runs out and ruins my whole output.
To counteract that problem i put in a while loop (which is in the code below).
To make sure I only read when there is more then 167 bytes.

CODE: FOR READING FROM SERIAL PORT

while(1){

         InterruptWait( 0, NULL );
   //THE LOOP BELOW IS WHAT I USE TO MAKE SURE THERE IS MORE THEN 167 BYTES BEFORE I READ     
   while (tcischars(fd)<(167))
          {
             InterruptUnmask( IRQ, intr_id );
             InterruptWait(0,NULL);
          }
      numRead = read(fd, buffer, SIZE_BUFFER);
      printf("\n numREAD %d\n",numRead);
      /*WRITE*/
      printf("%s",buffer);
      write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104

      /* Reenable this interrupt since writing is finished */
     InterruptUnmask( IRQ, intr_id );

      }


CODE FOR SETTING UP SERIAL PORT
The IMU has to be read at 9600baud No flow contorl no parity and read 8 Bits at a time (ASCII)

int open_port(void)
{
int fd; /* File descriptor for the port */
      struct termios termios_p; /*termios structure*/
      fd = open("/dev/ser1", O_RDONLY | O_NOCTTY );
  if (fd == -1)

      {
            perror("open_port: Unable to open /dev/ser1 - ");
            return 0;
      }
      else
            printf ("port opened\n");
      tcgetattr(fd, &termios_p);                /*read in the current settings*/
      cfsetispeed(&termios_p, BAUD_RATE);       //set input baud
      cfsetospeed(&termios_p, BAUD_RATE);       //set output baud
      termios_p.c_cflag &= ~PARENB;       //no parity bit (error checking bit)
      termios_p.c_cflag &= ~CSIZE;
      termios_p.c_cflag |= CS8;           //set number of bits to 8
      termios_p.c_cflag &=~ IHFLOW ;      //disable input h/w flow control
      termios_p.c_cflag &= ~OHFLOW ;      //disable output h/w flow control
      tcsetattr(fd, TCSANOW, &termios_p);
      return (fd);

}


Can anyone please help me?
I am going crazy :(

Thanks.
RE: Reading from serial port  
You CANNOT mix using hardware interrupts  and going through a the serial port driver. It`s either one or the other.  You
 are disabling interrupt while writing to disk and to the screen, this is real bad because these operation can take a 
long time, and you lucking the disc controller is not using the same interrupt as the serial port ;-)

Basically your approach is all wrong.  Either you totally take control of the hardware and kill devc-8250 or you rely 
totally on the driver.  

You code should look something like

 open_port();
ssize_t rssize;
#define SIZE_BUFFER 167
char buffer[SIZE_BUFFER];
while (1 )
{
  rssize = read(fd, buffer, SIZE_BUFFER);  // this will block until SIZE_BUFFER bytes has been received, no need to use 
interrupt
  if ( rrsize != SIZE_BUFFER )
  {
	// handle error or the fact that not all data has bee received
  }
 else
 {
     printf("\n numREAD %d\n",numRead);
      /*WRITE*/
      printf("%s",buffer);
      write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104
 }

-----Message d'origine-----
De : Avantha Jayawickreme [mailto:community-noreply@qnx.com] 
Envoyé : 17 août 2010 23:22
À : momenticsgs-community
Objet : Reading from serial port

Hey all!

I am having difficulty reading from the serial port, it is being controlled by interrupts when the data comes in, it is 
supposed to be roughly 1Hz (depends on GPS signal and stuff) I am encountering 2 problems:

1: Is that when i read using Interrupts so the serial port interrupts when the data is ready to be read, that happens 
roughly 1Hz, then after that i for some reason get like  roughly 20(give or take)  interrupts one after another which 
also reads the data (its not supposed to do this, because the program on the IMU that i am using outputs data roughly 
every 1Hz).

2: After i perform the read I noticed that the data in the serial port doesn;t get updated for some reason, and the data
 that is in the serial port is only maxed at 2048 bytes(anyone know why this is?), it only gets updated when i perform 
an InterruptWait() and corresponding InterruptUnmask() when this happens I found out that the data in the serial port 
gets refreshed 8 bytes at a time, so eventually after say 2048 - 167 *(amount of reads), the data in the serial port 
runs out and ruins my whole output.
To counteract that problem i put in a while loop (which is in the code below).
To make sure I only read when there is more then 167 bytes.

CODE: FOR READING FROM SERIAL PORT

while(1){

         InterruptWait( 0, NULL );
   //THE LOOP BELOW IS WHAT I USE TO MAKE SURE THERE IS MORE THEN 167 BYTES BEFORE I READ     
   while (tcischars(fd)<(167))
          {
             InterruptUnmask( IRQ, intr_id );
             InterruptWait(0,NULL);
          }
      numRead = read(fd, buffer, SIZE_BUFFER);
      printf("\n numREAD %d\n",numRead);
      /*WRITE*/
      printf("%s",buffer);
      write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104

      /* Reenable this interrupt since writing is finished */
     InterruptUnmask( IRQ, intr_id );

      }


CODE FOR SETTING UP SERIAL PORT
The IMU has to be read at 9600baud No flow contorl no parity and read 8 Bits at a time (ASCII)

int open_port(void)
{
int fd; /* File descriptor for the port */
      struct termios termios_p; /*termios structure*/
      fd = open("/dev/ser1", O_RDONLY | O_NOCTTY );
  if (fd == -1)

      {
            perror("open_port: Unable to open /dev/ser1 - ");
            return 0;
      }
      else
            printf ("port opened\n");
      tcgetattr(fd, &termios_p);                /*read in the current settings*/
      cfsetispeed(&termios_p, BAUD_RATE);       //set input baud
      cfsetospeed(&termios_p, BAUD_RATE);       //set output baud
      termios_p.c_cflag &= ~PARENB;       //no parity bit (error checking bit)
      termios_p.c_cflag &= ~CSIZE;
      termios_p.c_cflag |= CS8;           //set number of...
View Full Message
Re: RE: Reading from serial port  
> You CANNOT mix using hardware interrupts  and going through a the serial port 
> driver. It`s either one or the other.  You are disabling interrupt while 
> writing to disk and to the screen, this is real bad because these operation 
> can take a long time, and you lucking the disc controller is not using the 
> same interrupt as the serial port ;-)
> 
> Basically your approach is all wrong.  Either you totally take control of the 
> hardware and kill devc-8250 or you rely totally on the driver.  
> 
> You code should look something like
> 
>  open_port();
> ssize_t rssize;
> #define SIZE_BUFFER 167
> char buffer[SIZE_BUFFER];
> while (1 )
> {
>   rssize = read(fd, buffer, SIZE_BUFFER);  // this will block until 
> SIZE_BUFFER bytes has been received, no need to use interrupt
>   if ( rrsize != SIZE_BUFFER )
>   {
> 	// handle error or the fact that not all data has bee received
>   }
>  else
>  {
>      printf("\n numREAD %d\n",numRead);
>       /*WRITE*/
>       printf("%s",buffer);
>       write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104
>  }
> 

Hey Mario, thanks heaps for that! Cleared up the interrupt thingy,

But still having a problem with the read, it reads it a couple of times

then it goes into the else and prints -1 as read failed,

here is the code i implemented from your suggestion, 
CODE:: I declared ssize_t rssize; locally in the function that is performing the read
ALSO BTW: I am giving the thread permission to access hardware with the following:

/* Give this thread root permissions to access the hardware */
 privity_err = ThreadCtl( _NTO_TCTL_IO, NULL );
if ( privity_err == -1 ) { printf( "Can't get root permissions\n" );
 return -1;
 }


 while(1){
    rssize = read(fd, buffer, SIZE_BUFFER);  // this will block until SIZE_BUFFER bytes has been received, no need to 
use

    if ( rssize != SIZE_BUFFER )
    {
          // handle error or the fact that not all data has bee received
      printf("\n numREAD %d\n",rssize); //IT GOES INTO HERE AFTER A COUPLE OF READS LIKE 20 TIME  OR SO
    }
   else
   {
       printf("\n numREAD %d\n",rssize);
        /*WRITE*/
        printf("%s",buffer);
        write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104
   }
 }


So was my termios structure right for setting up the serial port,

Also here is the .build file set up of the serial port using devc-8250

   #######################################################################
   ## serial driver

	display_msg Starting Serial Com...
    devc-ser8250 0x3F8,4 0x2F8,3 -t 8 -b 9600 & 
	# Start a debug server for debugging programs
    waitfor /dev/ser1
    waitfor /dev/ser2
    stty par=none -ihflow -ohflow +cs8 stopb=1  

Thanks so much for you help Mario, really appreciate it!
Please let me know if you require any more information from me 


Attachment: Text pico_1.c 2.98 KB
Re: RE: Reading from serial port  
Sorry disregard the attached file the proper file is here
Attachment: Text pico_1.c 2.75 KB
RE: RE: Reading from serial port  
If it`s -1 it`s an error condition, print errno to get more information about the error.  No need to call 
InterruptAttachEvent(), I might be why it`s not working.

Also note that since your buffer is 2048 bytes, read() will not return until it has read the 2048 bytes.  This means 
that if the message that the GPS send is 167 bytes, it will take a bunch of "packet" before read() returns.  You might 
want to use readcond instead of read, to handle timeout and stuff.

-----Message d'origine-----
De : Avantha Jayawickreme [mailto:community-noreply@qnx.com] 
Envoyé : 18 août 2010 09:22
À : momenticsgs-community
Objet : Re: RE: Reading from serial port

> You CANNOT mix using hardware interrupts  and going through a the 
> serial port driver. It`s either one or the other.  You are disabling 
> interrupt while writing to disk and to the screen, this is real bad 
> because these operation can take a long time, and you lucking the disc 
> controller is not using the same interrupt as the serial port ;-)
> 
> Basically your approach is all wrong.  Either you totally take control 
> of the hardware and kill devc-8250 or you rely totally on the driver.
> 
> You code should look something like
> 
>  open_port();
> ssize_t rssize;
> #define SIZE_BUFFER 167
> char buffer[SIZE_BUFFER];
> while (1 )
> {
>   rssize = read(fd, buffer, SIZE_BUFFER);  // this will block until 
> SIZE_BUFFER bytes has been received, no need to use interrupt
>   if ( rrsize != SIZE_BUFFER )
>   {
> 	// handle error or the fact that not all data has bee received
>   }
>  else
>  {
>      printf("\n numREAD %d\n",numRead);
>       /*WRITE*/
>       printf("%s",buffer);
>       write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104
>  }
> 

Hey Mario, thanks heaps for that! Cleared up the interrupt thingy,

But still having a problem with the read, it reads it a couple of times

then it goes into the else and prints -1 as read failed,

here is the code i implemented from your suggestion,
CODE:: I declared ssize_t rssize; locally in the function that is performing the read ALSO BTW: I am giving the thread 
permission to access hardware with the following:

/* Give this thread root permissions to access the hardware */  privity_err = ThreadCtl( _NTO_TCTL_IO, NULL ); if ( 
privity_err == -1 ) { printf( "Can't get root permissions\n" );  return -1;  }


 while(1){
    rssize = read(fd, buffer, SIZE_BUFFER);  // this will block until SIZE_BUFFER bytes has been received, no need to 
use

    if ( rssize != SIZE_BUFFER )
    {
          // handle error or the fact that not all data has bee received
      printf("\n numREAD %d\n",rssize); //IT GOES INTO HERE AFTER A COUPLE OF READS LIKE 20 TIME  OR SO
    }
   else
   {
       printf("\n numREAD %d\n",rssize);
        /*WRITE*/
        printf("%s",buffer);
        write(outfd,buffer,SIZE_BUFFER);     //writing to file on PC/104
   }
 }


So was my termios structure right for setting up the serial port,

Also here is the .build file set up of the serial port using devc-8250

   #######################################################################
   ## serial driver

	display_msg Starting Serial Com...
    devc-ser8250 0x3F8,4 0x2F8,3 -t 8 -b 9600 & 
	# Start a debug server for debugging programs
    waitfor /dev/ser1
    waitfor /dev/ser2
    stty par=none -ihflow -ohflow +cs8 stopb=1  

Thanks so much for you help Mario, really appreciate it!
Please let me know if you require any more information from me 






_______________________________________________

QNX Momentics Getting Started
http://community.qnx.com/sf/go/post63383
Re: RE: RE: Reading from serial port  
Ok, cool thanks Mario, yeah i forgot to remove that InterruptAttach,

I will try it tomorrow morning, yeh the 2048 bytes i am not sure why its that, but ill give it a go tomorrow and fingers
 crossed it works.
PS, thanks heaps!!! Was very helpful!!
Re: RE: RE: Reading from serial port  
Hey Mario got it working 100% now
Here is the code im using

 while(1){

   rssize = readcond(fd,buffer,SIZE_BUFFER,SIZE_BUFFER,0,0); //blocked here until SIZE_BUFFER bytes


    if ( errno ==0 )
    {
       write(outfd,buffer,SIZE_BUFFER);
    }
   else
   {
     errvalue = errno;
     // handle error or the fact that not all data has bee received
          printf( "The error generated was %d\n That means: %s\n ", errvalue,strerror( errvalue ) );

   }
 }

This gets me what i need perfectly, only problem is the numbers are stored in a string, they are seperated by spaces 
need to now get the data to perform calculations, any thoughts on the best way to do that ?
I have a character '*' to indicate the start of each new line of the data
*  0508  0528  0479  0522  0531  0524  0228  0000  0335  0796   0000.00000   0000.00000   0000.00000   00 
I was using strchr(buffer,'*') to find the first instance of the that then using sscanf and stuff but is there a better 
way to do that?

Thanks heaps for getting me on the right track!
RE: RE: RE: Reading from serial port  
I wouldn`t use readconf the way you do, the GPS string is probably say 128 bytes long, but readconf is waiting for 
SIZE_BUFFER ( which is 2048 I believe), that means readconfig will only return after receving 16 data packets.  

As for parsing the content of buffer, there are so many ways to do that ;-)  Don`t see anything wrong with how you do it
.  However I personnaly would use strtok to split each field and handle them separately. That gives me finer control and
 better error handling then one big scanf.


-----Message d'origine-----
De : Avantha Jayawickreme [mailto:community-noreply@qnx.com] 
Envoyé : 19 août 2010 12:56
À : momenticsgs-community
Objet : Re: RE: RE: Reading from serial port

Hey Mario got it working 100% now
Here is the code im using

 while(1){

   rssize = readcond(fd,buffer,SIZE_BUFFER,SIZE_BUFFER,0,0); //blocked here until SIZE_BUFFER bytes


    if ( errno ==0 )
    {
       write(outfd,buffer,SIZE_BUFFER);
    }
   else
   {
     errvalue = errno;
     // handle error or the fact that not all data has bee received
          printf( "The error generated was %d\n That means: %s\n ", errvalue,strerror( errvalue ) );

   }
 }

This gets me what i need perfectly, only problem is the numbers are stored in a string, they are seperated by spaces 
need to now get the data to perform calculations, any thoughts on the best way to do that ?
I have a character '*' to indicate the start of each new line of the data
*  0508  0528  0479  0522  0531  0524  0228  0000  0335  0796   0000.00000   0000.00000   0000.00000   00 
I was using strchr(buffer,'*') to find the first instance of the that then using sscanf and stuff but is there a better 
way to do that?

Thanks heaps for getting me on the right track!



_______________________________________________

QNX Momentics Getting Started
http://community.qnx.com/sf/go/post63582