Monky Python has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I try to communicate with a serial device which should return 17 bytes if I send the command 0x11 0x00.
But this works only if I put a sleep between the write and read command.
Without sleep the read function return zero bytes. I also tried lookfor instead of read, but this did also not work.
How can I block during read/lookfor until I received all bytes?
#!/usr/local/bin/perl -w use Device::SerialPort; use strict; $|=1; my %ergoCommands; ## initialize serial port my $portname="/dev/ttyS0"; my $port = new Device::SerialPort ($portname); $port->user_msg("ON"); $port->databits(8); $port->baudrate(4800); $port->parity("none"); $port->stopbits(1); $port->handshake("xoff"); $port->write_settings() || undef $port; my $count_out = $port->write("\x40\x0"); warn "command failed:$_[0]\n" unless ($count_out eq length($cmddata)); ## I don't want to go asleep :( ##sleep(1); ## hmm.. does not block ($real_in, $data_in) = $port->read(17);

MP

Replies are listed 'Best First'.
Re: read does not block
by tachyon (Chancellor) on Sep 01, 2001 at 17:54 UTC

    Presumably there is a delay before the data response to write() is available from read(). Here is how to wait and also time out after a certain delay so you don't go infinite. The read_data() sub will return a value 3 seconds after the program starts. This simulates a delay. It will time out as shown as we only try to get data for 2 seconds. Uncomment the $wait = 5; line to see it succeed. You can see that it tries a lot (several hundred times) - this is very resource intensive so a short sleep is often a good idea before retries. You can trial the sleep 1 to see it cut the retries. There is a Time::HiRes module available to let you sleep a few millisconds which would generally be better as a full second is a bit over the top as you note.

    $wait = 2; # wait up to this many seconds for data # $wait = 5; $start = time(); # zero our vars and then enter the do until loop $timeout = $wait + time(); $data = ''; $count = 0; do { $count++; $data = read_data(); # sleep 1 unless $data; } until $data or time() > $timeout; if ($data) { print "Tried $count times\nGot data '$data'\n"; } else { print "Tried to read_data() but failed after $wait seconds and $co +unt tries!\n"; } # a short sub that only returns data after 3 seconds from # program start time sub read_data { return (time() > ( $start + 3) ) ? "You have waited long enough!" : +''; }

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print