Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

problem with read from file descriptor

Status
Not open for further replies.

DCO_81

Member level 1
Joined
Mar 10, 2005
Messages
39
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,288
Location
Germany, south
Activity points
1,657
Hi all,

I´ve some trouble with this code. Got this from "serial programming guide for posix operating systems". But this doesn´t work - the buffer is always empty. Where is my mistake? I don´t have a cure.

Code:
int response()
{
  int nbytes;
  char *bufptr;
  char buffer[255];

  write(fd, "AT\r", 3);

  sleep(1);

  bufptr = buffer;

  while ((nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0)
  {
	  bufptr += nbytes;
	  if (bufptr[-1] == '\n' || bufptr[-1] = '\r')
		  break;
  }

  *bufptr = '\0';

  cout << buffer << endl; // buffer is empty !! - WHY ?!?

  if (strncmp(buffer, "OK", 2))
	  return 0;
  
  return -1;
}
 

When you read from the serial port, you get all bytes in the input buffer. But Since PC's are fast, there might be no bytes there ;-).

I guess your systems sends something over a serial port, and tries to receive the answer. But since your PC is so fast, there is no information available at the time of checking ;-).

Perhaps you should do some settings to make the read operation blocking?
fcntl(fd, F_SETFL, 0);
(but this should be the default setting unless you opened the serial port with the unblocking option)

But then there is another problem that keeps your program halted untill a byte is received ;-). So you should jump out of the while loop when you get the data or set a timeout.

Perhaps you should read the part about The SELECT System Call!
http://www.easysw.com/~mike/serial/serial.html#5_2_1

Antharax
 

Thanks Antharax,

quick answer like always.

When I initialize the modem I use fcntl(fd, F_SETFL, 0); explicit. So this shouldn´t be the problem.
Since my program was never in the while-loop, I haven´t problems yet to get out of it ;)
The read-operation takes 2-3 seconds, so I think it´s a blocking one. Unfortunatley my problem isn´t solved yet. Any other suggestions?
 

ok, I see.
Then there are 2 possibilities:
Possibility 1:
You wait for data but there is no data comming!
and the read is blocking with a timeout:
Code:
options.c_cc[VTIME] = 10; // Meaning 1 second
So it waits for a second or so to receive data. When it hasn't received any, it returns.

What modem device are you talking with? And what baudrate are you using?
Perhaps you should set the baudrate to 9600 (most of the GSM modems i use work with that baudrate)

The best way to debug your program is using a crossed serial cable to another serial port (on the same or another PC). Open Hyperterminal on the other end with the baudrate specified in your program. Try do disable all Hardware flow control on both sides. Also increase the VTIME timeout from above (unless you can switch very fast between the programs) Now you should be able to send some characters back.

Possiblility 2 (I have a hunch it's this one):
And how can you be sure you never got in the loop? The first characters received from a modem are 0x0D 0x0A which are equal to '\n'. So you break out of the loop before even receiving the OK and everything printed out would just be carriage return line feed.
(actually the modem answers with <0x0D><0x0A>OK<0x0D><0x0A>) bytes marked with <> are the hex values of the bytes received.

And one remark: I don't like the pointer twiggling done in the code. Something like this:
Code:
bufptr[-1]
just is something i don't like to see in my code (although it is efficient ;-), an error is easily made )

hope this helps
Antharax
 

Hi,

I think I can be sure that the program is never running in the loop. I put several "cout"s in the loop-body and nothing is printed (I used "endl", so the buffer should be flushed). The baud is already set to 9600 using B9600. I use an option fusion card which is a combo card (gsm, gps, umts). I connected 2 pc´s via a gsm data connection. It still won´t work.
To your remark: Any suggestions what I should write instead of bufptr[-1] ?

Thanks in advance.
 

Any suggestions what I should write instead of bufptr[-1] ?
In this code: nothing, just rewrite the entire loop thingy ;-)

Have you tried connecting 2 PC's with a Nulmodem cable? (A nulmodem cable is a serial cable with 2 female plugs and crossed tx/rx wires (tx of one side is connected to rx of other side and vice versa))

also try to put a
Code:
cout << hex << (int)buffer;
in the loop
then you see the hex code of the receive characters. Then you can be sure that nothing has been received.

or print out the length of the received data every time you get in the loop
Code:
cout < nbytes << " received" << endl;

or print out something when you get in the loop
Code:
cout < "Houston we received data" << endl;
when this ain't displayed, nothing is received and the problem is not this code. It's the other side (other side = modem!) which ain't responding. This can be tested with the nulmodem cable. (meaning you can verify with the nulmodem cable that your code works)

But perhaps you already tried those
 

When I run my program, I can see the responses of the AT-commands in minicom (terminal-program). When I send AT the answer OK is receiving. I´ve printed out the length of nbytes before and this is definitely 0. But I can also try it with the nulmodem cable now.

Added after 49 minutes:

This

Code:
cout << hex << (int) buffer << endl;
cout << buffer << endl;

makes this printed out:

bfffef60
-- a empty line --
ffffffff

Does this help you?
 

sorry, made a mistake, you should write

cout << hex << (int)(*buffer) << endl;
(I'm not interested in the adress of buffer, only in the value ;-) )

And yes, it helps!

This means that you receive a cariage return ('\n') and break out of the while loop.

After lunch i will write you a quick routine that helps you


Antharax
 

Enjoy your meal.

Now the response looks like this:

0
-- empty line --
ffffffff
 

could you try this please?

Code:
#define BUFFERSIZE 256

int response()
{
  int          i;
  int          nbytes;
  unsigned int writePos = 0;
  char         response[BUFFERSIZE];

  write(fd, "AT\x0D\x0A", 4);

  sleep(1);

  while ((nbytes = read(fd, &response[writePos], BUFFERSIZE - readPos)) > 0)
    {
      for (i=writePos ; i<writePos+nbytes; i++)
        cout << "Byte received: " << hex << (int)response[i] << endl;

      writePos += nbytes;
      if (writePos >= BUFFERSIZE)
        break;
      // Probably you receive "\x0D\x0AOK\x0D\x0A"
      if ( (writePos > 2) && (response[writePos-1] == 0x0A) )
        break;
    }

  cout << response << endl;

  if (strncmp(response, "\x0D\x0AOK\x0D\x0A", 6))
     return 0;

  return -1;
}
 

    DCO_81

    Points: 2
    Helpful Answer Positive Rating
You haven´t defined readPos before use in function read(fd,..., readPos). Is it initialised with 0?

Added after 9 minutes:

I have no cure what you did, but this code does work! Where´s the trick? Thanks a lot!
 

If i am not wrong OK response must be preceeded and followed by <CR><LF> you check in your loop for those and get out due to first occurence of CR LF rraither than last . Therefore Antharax wrote
writePos > 2 to prevent things to be triggered from first occurence .
 

Hello again,

I think I was a little bit to rashly with my pleasure.

The return of your function is 0 - excellent!
But the program runs never in the loop-body.
cout << response << endl; printed out this:
h_@@u@
but the strncmp does work.
 

indeed
and the BUFFERSIZE - readPos
must be BUFFERSIZE - writePos
(sorry, didn't compile the thing ;-) )

I also forgot to null terminate the response after comming out the while loop!
response[writePos] = 0;

I hope it helps a bit.
Perhaps you could use a debugger and set a breakpoint on the line printing out the buffer?
Or you could use
Code:
printf(response)
have a nice weekend!

Antharax
 

Hi,

add your changes now, but the program still doesn´t run in the loop. So when the strncmp is on his turn, it will compare an empty char-field.

This statement should be a ok?

for ((nbytes = read(fd, &response[writePos], BUFFERSIZE - writePos)) > 0 )
 

when you replace the
Code:
for
by
Code:
while
it should be ok!

And you never see
Byte received: 0D
or similar printed out?
then there are no bytes received. Perhaps the problem isn't this routine but the initialisation of the uart. Can you post the initialisation code?
 

The replace while/for doesn´t help. It´s very strange, but once I get "Byte receiced" :
41, 54, d, d, a, 4f, 4b, d, a (HEX)
-> A,T,<CR>,<CR>,<LF>,O,K,<CR>,<LF>

Here is the code for UART (it´s in a constructor):

Code:
Serial::Serial (char *device_name)
{
  fd = open(device_name, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd < 0)
  {
     exit(1);
  }

  fcntl(fd, F_SETFL, 0);

  tcgetattr(fd, &old_settings); 

  bzero(&new_settings, sizeof(new_settings);

  new_settings.c_cflag |= ( CLOCAL | CREAD );
  new_settings.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG );
  new_settings.c_oflag &= ~OPOST;
  new_settings.c_cc[VMIN] = 0;
  new_settings.c_cc[VTIME] = 50;

  cfsetspeed(&new_settings, B9600);

  tcflush(fd, TCIFLUSH);

  tcsetattr(fd, TCSANOW, &new_settings);
}

Added after 5 minutes:

Don´t worry about this function no more. I found the problem - it was not my program. Another program was running and was reading from the fd. So there were race conditions. When I terminate the other program, it runs fine.

Thanks for your support!
 

Hello again,

the program runs fine with my option fusion gsm-pcmcia card. But when I try use it with siemens MC 45T on ttyS0 it won´t work. The init is well done and I can send commands. But when it comes to

Code:
while ((nbytes = read(fd, &response[writePos], BUFFERSIZE - readPos)) > 0)

it reads garbage. I can see in nbytes several canceled characters in my debugger, but when using the old-modem there are proper values.

Is this some kind of wrong settings in my init - funcition? (see code posted before)
 

I´ll try to explain the strange behaviour of the program.

It´s able to write and read from the ttyS0, so everything is fine. But when I start it the next time, it writes proper values, but it doesn´t read anything. A further re-start and it works again, the next re-start causes the read-failure again and so on and on.
How occures this behaviour?
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top