Lazarus

Free Pascal => General => Topic started by: dogriz on September 25, 2020, 11:15:30 am

Title: Reading from /dev/usb/lp0 device on Linux
Post by: dogriz on September 25, 2020, 11:15:30 am
I can send commands and print data to a USB barcode printer (Sanei SK1-21) using code like this:
Code: Pascal  [Select][+][-]
  1. fs := TFileStream.Create('/dev/usb/lp0', fmCreate);
  2. fs.WriteBuffer(something[1], Length(something));
  3. fs.Free;
and it works without a problem.

When I want to check printer status (waiting, error, near end, paper empty...) I send matching command using the code above, then free the FileStream, open it for reading like this:
Code: Pascal  [Select][+][-]
  1. fs := TFilestream.Create('/dev/usb/lp0', fmOpenRead, fmShareDenyNone);
  2. fs.ReadBuffer(buf, SizeOf(buf));
  3. fs.Free;
and get a response (for example: R000) and use it as wanted.

But, from time to time, it happens that there is nothing to be read in '/dev/usb/lp0' (same happens if I don't send request for status first, before trying to read it) and that's also OK. The only thing that troubles me is - when there is nothing to be read in '/dev/usb/lp0', this line: fs.ReadBuffer(buf, SizeOf(buf)); hangs forever and I can't do anything anymore with '/dev/usb/lp0' because it's locked. I don't even get any error message, it's just stuck.

Is there some kind of TimeOut setting or something for TFileStream.ReadBuffer or other way to deal with this issue?
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: Kays on September 25, 2020, 02:53:29 pm
[…] Is there some kind of TimeOut setting or something for TFileStream.ReadBuffer or other way to deal with this issue?
Well, select (https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)? Or its FP wrapper fpSelect (https://freepascal.org/docs-html/current/rtl/baseunix/fpselect.html)? But I’m not familiar with tFileStream, so I can’t tell you nothing about that.
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: MarkMLl on September 25, 2020, 03:44:09 pm
I am not at all an expert on stream access, and I don't even know whether it supports polling for available data (which is more of a "keyboard-like" operation). You've obviously got to allow for the fact that the device name might change (or the device disappear) depending on hotplug events, but I think there are two possibilities:

Either have a separate thread which spends most of its time waiting for input from that device and when it knows it's got an entire message writes it to a shared variable,

Or replace your existing code with direct access to lower-level calls (fpRead() etc.), since that will allow you to use fpSelect() with a zero or nil timeout, or an fpIoctl() call, to determine whether the next read will block.

MarkMLl

 
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: dogriz on September 28, 2020, 08:08:38 am
I solved the problem externaly, using bash script. I'm not familiar with fpSelect but I'll look into it.
Thanks
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: Thaddy on September 28, 2020, 08:38:33 am
Note the example for fpselect handles time out  :D
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: MarkMLl on September 28, 2020, 08:55:19 am
I solved the problem externaly, using bash script. I'm not familiar with fpSelect but I'll look into it.
Thanks

fpSelect() is effectively a unix kernel system call. You pass it bitmaps representing handles, and a timeout. You get back which of those handles has shown a sign of activity within the timeout. I don't know how well it integrates with streams.

MarkMLl
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: Thaddy on September 28, 2020, 09:33:59 am
Yes, you can use fpselect together with the much higher level TFileStream, as well as with Assign/Assignfile Reset/Rewrite to check if a read/write operation will block.
"Bitmaps" is a bit unlucky, although correct: here it is not an image, but a set of bits.  :D
Title: Re: Reading from /dev/usb/lp0 device on Linux
Post by: Alextp on September 29, 2020, 11:27:59 pm
Maybe related?
Code: Pascal  [Select][+][-]
  1. procedure TATStrings.LoadFromFile(const AFilename: string);
  2. var
  3.   fs: TFileStream;
  4.   ms: TMemoryStream;
  5. begin
  6.   fs:= TFileStream.Create(AFilename, fmOpenRead or fmShareDenyNone);
  7.   try
  8.     if fs.Size>=0 then
  9.       LoadFromStream(fs)
  10.     else
  11.     begin
  12.       ms:= TMemoryStream.Create;
  13.       try
  14.         _ReadFileToStream(ms, AFilename);
  15.         LoadFromStream(ms);
  16.       finally
  17.         FreeAndNil(ms);
  18.       end;
  19.     end;
  20.   finally
  21.     FreeAndNil(fs);
  22.   end;
  23. end;
  24.  
  25. procedure _ReadFileToStream(AStream: TStream;
  26.   const AFileName: string;
  27.   AMaxSize: integer=20*1024*1024);
  28. const
  29.   BufSize = 4096;
  30. var
  31.   Buf: array[0..BufSize-1] of char;
  32.   fs: TFileStream;
  33.   NSize, NTotalSize: integer;
  34. begin
  35.   fs:= TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
  36.   try
  37.     AStream.Position:= 0;
  38.     NTotalSize:= 0;
  39.     repeat
  40.       NSize:= fs.Read(Buf, BufSize);
  41.       if NSize>0 then
  42.       begin
  43.         AStream.Write(Buf, NSize);
  44.         Inc(NTotalSize, NSize);
  45.         if NTotalSize>=AMaxSize then
  46.           Break;
  47.       end;
  48.     until NSize<BufSize;
  49.   finally
  50.     FreeAndNil(fs);
  51.   end;
  52. end;
  53.  
  54.  
TinyPortal © 2005-2018