Recent

Author Topic: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]  (Read 2602 times)

BobT

  • New Member
  • *
  • Posts: 19
LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« on: January 13, 2021, 03:47:47 pm »
I'm developing a small application using LazSerial component for Modbus-RTU master. Serial hardware is an FTDI based USB to RS485 convertor. Read operations use the LazSerial.SynSer.ReadBufferEx function and require a timeout up to 250ms to allow for slave device response delays.

This is working well on Linux (MX Linux, 64bit) but is failing on Windows 7 (SP1, same dual boot 64 bit platform) where the ReadBufferEx function seems to return immediately whatever the 'Timeout' parameter value. I get the same result whether exe is cross-complied or built in W7.

The serial port is opened and closed in the main thread and the Modbus message write-read sequence is carried out in a seperate thread launched for each bus transaction; but using 'synchronize' to call the read and write actions from the main thread apparently makes no difference.

A rough workaround using my own timeout loop to call 'Waitingdata' before attempting a read seems to work, but I'd much prefer to understand what is causing the problem with ReadBuffEx or the way I am using it, and if possible fix it.
« Last Edit: January 14, 2021, 11:41:50 pm by BobT »

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: LazSynaser ReadBufferEx timeout in W7 64
« Reply #1 on: January 14, 2021, 12:51:19 am »
hello,
 :o readbufferex doesn't exist for synser element (TBlockSerial) of TLazserial component. It is recvBufferEx !
for timeout recvBufferEx use canRead(Timeout) and canRead method isn't the same for linux and windows :
Code: Pascal  [Select][+][-]
  1. {$IFNDEF MSWINDOWS}
  2. function TBlockSerial.CanRead(Timeout: integer): boolean;
  3. var
  4.   FDSet: TFDSet;
  5.   TimeVal: PTimeVal;
  6.   TimeV: TTimeVal;
  7.   x: Integer;
  8. begin
  9.   TimeV.tv_usec := (Timeout mod 1000) * 1000;
  10.   TimeV.tv_sec := Timeout div 1000;
  11.   TimeVal := @TimeV;
  12.   if Timeout = -1 then
  13.     TimeVal := nil;
  14.   {$IFNDEF FPC}
  15.   FD_ZERO(FDSet);
  16.   FD_SET(FHandle, FDSet);
  17.   x := Select(FHandle + 1, @FDSet, nil, nil, TimeVal);
  18.   {$ELSE}
  19.   fpFD_ZERO(FDSet);
  20.   fpFD_SET(FHandle, FDSet);
  21.   x := fpSelect(FHandle + 1, @FDSet, nil, nil, TimeVal);
  22.   {$ENDIF}
  23.   SerialCheck(x);
  24.   if FLastError <> sOK then
  25.     x := 0;
  26.   Result := x > 0;
  27.   ExceptCheck;
  28.   if Result then
  29.     DoStatus(HR_CanRead, '');
  30. end;
  31. {$ELSE}
  32. function TBlockSerial.CanRead(Timeout: integer): boolean;
  33. begin
  34.   Result := WaitingData > 0;
  35.   if not Result then
  36.     Result := CanEvent(EV_RXCHAR, Timeout) or (WaitingData > 0);
  37.     //check WaitingData again due some broken virtual ports
  38.   if Result then
  39.     DoStatus(HR_CanRead, '');
  40. end;
  41. {$ENDIF}

Note this comment in the windows part of canread :
Quote
  //check WaitingData again due some broken virtual ports

FTDI  use virtual port.
and in the advanced settings of the windows ftdi driver you have  read and write timeouts.

Quote
6.6.1 Timeouts
The read and write timeout values may be set through the FTDIPORT.INF file.
[FtdiPort.NT.HW.AddReg]
HKR,,"MinReadTimeout",0x00010001,0
HKR,,"MinWriteTimeout",0x00010001,0
This INF file fragment shows the minimum read and minimum write timeout values set to 0ms.
These values are held in the registry under this key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\{Device VID, PID and serial
number}\0000\Device Parameters

Friendly, J.P

Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: LazSynaser ReadBufferEx timeout in W7 64
« Reply #2 on: January 14, 2021, 02:04:03 am »
On top of all that, why not use the Threaded model that is provided ?

when you CONNECT, you then call EXECUTE.

That will call the OnRXdata event if there is any..

make things stream line..
The only true wisdom is knowing you know nothing

BobT

  • New Member
  • *
  • Posts: 19
Re: LazSynaser ReadBufferEx timeout in W7 64
« Reply #3 on: January 14, 2021, 01:34:17 pm »
Thanks JP, that's very helpful. That Windows FDTI driver overriding the SynSer timeout setting explains the behaviour. It's useful to know where that driver might be adjusted, but in practice if I can work around asking my eventual users to do anything "advanced" (especially anything o/s specific) that would keep life much simpler.

(Apologies for the typo btw, it is indeed revcBufferEx that I am using)

At the moment this is a quick lashup mainly to check out the hardware and UI so, no, the code is pobably far from streamlined! Each master-slave transaction runs in its own thread, returning the result to the main thread which may then respond by launching another bus query, depending on the message data it received previously. But the time overhead of the port 'open' and 'close' operations is (on Linux, not measured on Windows) around 100ms, much longer than most of the bus exchanges, so it seems to make sense to keep the port open until the current sequence of bus exchanges has completed.






jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #4 on: January 15, 2021, 12:28:53 am »
actually I think it's because in windows it's most likely not using a Blocking method..
so even if you were to continue with how you are doing it now you should be able to simply loop there until it returns something valid..
there should be a count on the return but I would need to look a that one.
The only true wisdom is knowing you know nothing

BobT

  • New Member
  • *
  • Posts: 19
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #5 on: January 15, 2021, 07:23:51 pm »
Quote
in windows it's most likely not using a Blocking method.

Hi jamie, yes, that looks to be the case. I see the same behaviour using the PC's 'real' serial port (16550) with RecvBufferEx , RecvBufferStr or Recvstring called directly from the main thread.

sstvmaster

  • Sr. Member
  • ****
  • Posts: 299
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #6 on: January 15, 2021, 08:52:17 pm »
In Windows you can change this parameters direct in device manager, see attachment.
« Last Edit: January 15, 2021, 09:47:32 pm by sstvmaster »
greetings Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

tetrastes

  • Sr. Member
  • ****
  • Posts: 473
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #7 on: January 15, 2021, 11:55:46 pm »
Quote
in windows it's most likely not using a Blocking method.

Hi jamie, yes, that looks to be the case. I see the same behaviour using the PC's 'real' serial port (16550) with RecvBufferEx , RecvBufferStr or Recvstring called directly from the main thread.

I use synaser at windows for many years (though always directly, without LazSerial wrapper), and these functions work as they should both with real and virtual serial ports. I don't remember whether there were FTDI devices among those, but it's strange to me that "FDTI driver overriding the SynSer timeout setting", AFAIK applications override driver setting, but not vise versa. You can easily see it, for example, working with 16550 port. May be the driver does not let to override its settings, but then there is something wrong with it...

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #8 on: January 16, 2021, 02:17:40 am »
hello,
I'm developing a small application using LazSerial component for Modbus-RTU master. Serial hardware is an FTDI based USB to RS485 convertor. Read operations use the LazSerial.SynSer.ReadBufferEx function and require a timeout up to 250ms to allow for slave device response delays.
i think that i have found why you have problems with  Lazserial and RecvBufferEx   timeout on windows. It isn't the ftdi driver. It is because Lazserial use a thread for reading serial port (event driven) with a 100ms timeout. 
Code: Pascal  [Select][+][-]
  1. procedure TComPortReadThread.Execute;
  2. begin
  3.   try
  4.     while not MustDie do begin
  5.       if Owner.FSynSer.CanReadEx(100) then
  6.         Synchronize(@CallEvent);
  7.     end;
  8.   finally
  9.     Terminate;
  10.   end;
  11. end;
So if you want to use a recvBufferEx with timeout don't use TLazserial , use synaser or lazsynaser.

This code generate a timeout  error after 10 seconds on windows 10 with FTDI  usb serial port :
Code: Pascal  [Select][+][-]
  1. program serialrecvtest;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5.  uses
  6.   lazsynaser,
  7.   sysutils;
  8.  
  9. var
  10.    ser:TBlockSerial;
  11.    buf : array [0..128] of Byte;
  12. begin
  13.    ser:=TBlockserial.Create;
  14.    try
  15.      ser.RaiseExcept:=true;
  16.      ser.Connect('COM4');
  17.      ser.Config(9600,8,'N',0,false,false);
  18.      ser.RecvBufferex(@buf[0], 128 ,10000);
  19.    finally
  20.      ser.Free;
  21.    end;
  22.  end.                              

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

BobT

  • New Member
  • *
  • Posts: 19
Re: LazSynaser ReadBufferEx timeout in W7 64 [SOLVED]
« Reply #9 on: January 16, 2021, 04:20:10 pm »
Quote
So if you want to use a recvBufferEx with timeout don't use TLazserial , use synaser or lazsynaser.
That's it. Timeout works as expected using lazsynaser.

 

TinyPortal © 2005-2018