Recent

Author Topic: Error on using hardware Raspberry Pi Inno-Maker RS485&CAN Module with TLAZserial  (Read 7641 times)

alpine

  • Hero Member
  • *****
  • Posts: 1032
Okay, let's go through ...

lazsynaser.pas:929

Code: Pascal  [Select][+][-]
  1. procedure TBlockSerial.Connect(comport: string); // comport:='\\.\COM12'
  2.   ...
  3.   FBuffer := '';
  4.   FDevice := comport; // FDevice:='\\.\COM12'
  5.   GetComNr(comport); // FComNr:=PortIsClosed (because both pos('COM', uppercase(Value)) <> 1 and pos('/DEV/TTYS', uppercase(Value)) <> 1
  6.   ...
  7.   if FComNr <> PortIsClosed then // False!
  8.     FDevice := '\\.\COM' + IntToStr(FComNr + 1); // Skipped
  9.   FHandle := THandle(CreateFile(PChar(FDevice), GENERIC_READ or GENERIC_WRITE,
  10.     0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0));
  11. // CreateFile() uses the same string as given in comport argument
  12.   ...
  13.  

My question is: What is the purpose of FComNr variable and GetComNr() method? (At least in Windows)

A little bit of clarification - my previous remark was based purely on the code snippet I saw in the discussion. I do not use the LazSerial component and I am not familiar with it.

Regards,
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

ThomasK

  • New Member
  • *
  • Posts: 48
Well this is not my problem. :D

It is cured by a small modification Jurassic Pork proposed (Reply #21). Now I can select and use the  /dev/TTYSC0 and  /dev/TTYSC1.

I want to get a dual RS485 HAT to work. Basically I use the sample application of TLAZSerial for testing to avoid problems between chair and keyboard and a Windows computer with an USB to RS422/485 adapter which works reliably. As terminal software for monitoring and sending I use cleverterm-2.4.4 which also supports ModBus RTU by generating the CRCs on its own.

But since this is based for handling the serial devices functionally to the features of Synaser it is also limited to it.
Synaser does not know about RS485 devices.

For the problem not finding the correct device names a solution was shown in 2017 in the german Lazarus forum but there was never a reply to it. I have to check if it can be found in the Synapse trunk.

Code: Pascal  [Select][+][-]
  1. uses BaseUnix;
  2. function GetSerialPortNames: string;
  3. type
  4. TSerialStruct = packed record
  5.   typ: Integer;
  6.   line: Integer;
  7.   port: Cardinal;
  8.   irq: Integer;
  9.   flags: Integer;
  10.   xmit_fifo_size: Integer;
  11.   custom_divisor: Integer;
  12.   baud_base: Integer;
  13.   close_delay: Word;
  14.   io_type: Char;
  15.   reserved_char: Char;
  16.   hub6: Integer;
  17.   closing_wait: Word; // time to wait before closing
  18.   closing_wait2: Word; // no longer used...
  19.   iomem_base: ^Char;
  20.   iomem_reg_shift: Word;
  21.   port_high: Cardinal;
  22.   iomap_base: LongWord; // cookie passed into ioremap
  23. end;
  24. var
  25.   i: Integer;
  26.   sr : TSearchRec;
  27.   sl: TStringList;
  28.   st: stat;
  29.   s: String;
  30.   fd: PtrInt;
  31.   Ser : TSerialStruct;
  32. const TIOCGSERIAL = $541E;
  33.   PORT_UNKNOWN = 0;
  34. begin
  35.   Result := '';
  36.   sl := TStringList.Create;
  37.   try
  38.     // 1. Alle möglichen Ports finden - find all possible ports
  39.     if FindFirst('/sys/class/tty/*', LongInt($FFFFFFFF), sr) = 0 then
  40.     begin
  41.       repeat
  42.         if (sr.Name <> '.') and (sr.Name <> '..') Then
  43.           if (sr.Attr and LongInt($FFFFFFFF)) = Sr.Attr then
  44.             sl.Add(sr.Name);
  45.       until FindNext(sr) <> 0;
  46.     end;
  47.     FindClose(sr);
  48.     // 2. heraussuchen ob ./device/driver vorhanden ist  - checking if ./device/driver exists
  49.     for i := sl.Count - 1 Downto 0 Do
  50.     Begin
  51.       If Not DirectoryExists('/sys/class/tty/' + sl[i] + '/device/driver') Then
  52.         sl.Delete(i); // Nicht vorhanden >> Port existiert nicht
  53.     end;
  54.     // 3. Herausfinden welcher Treiber  - checking which driver
  55.     st.st_mode := 0;
  56.     for i := sl.Count - 1 Downto 0 Do
  57.     Begin
  58.       IF fpLstat('/sys/class/tty/' + sl[i] + '/device', st) = 0 Then
  59.       Begin
  60.         if fpS_ISLNK(st.st_mode) Then
  61.         Begin
  62.           s := fpReadLink('/sys/class/tty/' + sl[i] + '/device/driver');
  63.           s := ExtractFileName(s);
  64.           // 4. Bei serial8250 Treiber muss der Port geprüft werden - with a serial8250 driver the port must be checked
  65.           If s = 'serial8250' Then
  66.           Begin
  67.             sl.Objects[i] := TObject(PtrInt(1));
  68.             fd := FpOpen('/dev/' + sl[i], O_RDWR Or O_NONBLOCK Or O_NOCTTY);
  69.             If fd > 0 Then
  70.             Begin
  71.               If FpIOCtl(fd, TIOCGSERIAL, @Ser) = 0 Then
  72.               Begin
  73.                 If Ser.typ = PORT_UNKNOWN Then // PORT_UNKNOWN
  74.                   sl.Delete(i);
  75.               end;
  76.               FpClose(fd);
  77.             end else sl.Delete(i); // Port kann nicht geöffnet werden - Port can't be opened
  78.           end;
  79.         End;
  80.       end;
  81.     end;
  82.     // 5. Dev anhängen - attach the device
  83.     for i := 0 To sl.Count - 1 Do
  84.       sl[i] := '/dev/' + sl[i];
  85.    Result := sl.CommaText;
  86.   finally
  87.     sl.Free;
  88.   end;
  89. end;

For developping the application I use a RS422/485 HAT for which uses a NE555 in a monoflop configuration to create the RTS_after_write by hardware very efficiently to handle the switching of the driver from *RE to DI. For the real use I need more RS485 ports.

With the new hardware I manipulate the RTS signal by the from application form to evaluate the behavoir of the board, but this should really be done by the OS.
After searching for the string "TIOCGRS485" I found that this missing in the TERMIOS definitions for ARM.

I will uses some functions in Synaser to modify them to set the TERMIOS record with the required flags and see if it does switch from transmit to receive on its own.
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
After searching for the string "TIOCGRS485" I found that this missing in the TERMIOS definitions for ARM.

Specifically, it's in aarch64 but not in the 32-bit section. If it works, report the omission as a bug on Mantis.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
Okay, let's go through ...

lazsynaser.pas:929

Code: Pascal  [Select][+][-]
  1. procedure TBlockSerial.Connect(comport: string); // comport:='\\.\COM12'
  2.   ...
  3.   FBuffer := '';
  4.   FDevice := comport; // FDevice:='\\.\COM12'
  5.   GetComNr(comport); // FComNr:=PortIsClosed (because both pos('COM', uppercase(Value)) <> 1 and pos('/DEV/TTYS', uppercase(Value)) <> 1
  6.   ...
  7.   if FComNr <> PortIsClosed then // False!
  8.     FDevice := '\\.\COM' + IntToStr(FComNr + 1); // Skipped
  9.   FHandle := THandle(CreateFile(PChar(FDevice), GENERIC_READ or GENERIC_WRITE,
  10.     0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0));
  11. // CreateFile() uses the same string as given in comport argument
  12.   ...
  13.  

My question is: What is the purpose of FComNr variable and GetComNr() method? (At least in Windows)

A little bit of clarification - my previous remark was based purely on the code snippet I saw in the discussion. I do not use the LazSerial component and I am not familiar with it.

Regards,

At least in Windows its only purpose is to use 'COM12' or '/dev/ttyS11' instead of '\\.\COM12'  ;)
As it is said in synaser.pas:
Code: Pascal  [Select][+][-]
  1.     {:Connects to the port indicated by comport. Comport can be used in Windows
  2.      style (COM2), or in Linux style (/dev/ttyS1). When you use windows style
  3.      in Linux, then it will be converted to Linux name. And vice versa! However
  4.      you can specify any device name! (other device names then standart is not
  5.      converted!)
  6.      .
  7.      .
  8.      .
  9.     }
  10.     procedure Connect(comport: string); virtual;
  11.  


alpine

  • Hero Member
  • *****
  • Posts: 1032
@tetrastes
Now I see it, as long you specify 'COMx', x < 10, it will do the work. Thanks!
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
x may be any.

alpine

  • Hero Member
  • *****
  • Posts: 1032
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

ThomasK

  • New Member
  • *
  • Posts: 48
After searching for the string "TIOCGRS485" I found that this missing in the TERMIOS definitions for ARM.

Specifically, it's in aarch64 but not in the 32-bit section. If it works, report the omission as a bug on Mantis.

MarkMLl

I got it to work. I will post later the code snippets. How can I report this as a bug? Do you have a link?
Rgds.
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
I got it to work. I will post later the code snippets. How can I report this as a bug? Do you have a link?

Well done. Please report via https://bugs.freepascal.org/ since that will mean it's "in the system" as far as the library maintainers go: the important thing is that the need to know that RS485 actually exists on that architecture from the kernel's POV.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

ThomasK

  • New Member
  • *
  • Posts: 48
I added the required definitions, functions and procedures in the LazSynaSer and LazSerial Units.
Code: Pascal  [Select][+][-]
  1. //|============================================================================|
  2. // copied into Unit LazSynaSer after line 172
  3. {$IFDEF UNIX}
  4. type
  5.   Tserial_RS485 = record
  6.                     flags                      : cardinal;
  7.                     delay_rts_before_send      : cardinal;
  8.                     delay_rts_after_send       : cardinal;
  9.                     padding    : array [0..4] of cardinal;
  10.   end;
  11.  
  12. const
  13.   TIOCGRS485 = $542E;                          //Read Flags
  14.   TIOCSRS485 = $542F;                          //Set Flags
  15.   SER_RS485_ENABLED         = $0001;
  16.   SER_RS485_RTS_ON_SEND     = $0002;
  17.   SER_RS485_RTS_AFTER_SEND  = $0004;
  18.   SER_RS485_RX_DURING_TX    = $0010;
  19.  
  20. var
  21.   RS485conf :  Tserial_rs485;
  22. {$ENDIF}
  23. //
  24. //|============================================================================|
  25.  

also

Code: Pascal  [Select][+][-]
  1. //*****************************************************************************
  2. // copied into Unit LazSynaSer after line 566
  3. {$IFDEF UNIX}
  4.  
  5.     function StatusRS485 : cardinal; virtual;
  6.  
  7.     procedure EnableRS485 (value : boolean); virtual;
  8.  
  9. {$ENDIF}
  10. //
  11. //*****************************************************************************
  12.  

and finally

Code: Pascal  [Select][+][-]
  1. //******************************************************************************
  2. //copied into Unit LazSynaSer after implementation
  3. {$IFDEF UNIX}
  4. procedure TBlockSerial.EnableRS485 (value:boolean);
  5. begin
  6.   if value then with RS485conf do
  7.     begin
  8.       flags := SER_RS485_ENABLED or SER_RS485_RTS_AFTER_SEND;
  9.       delay_rts_before_send  := 0;
  10.       delay_rts_after_send   := 0;
  11.     end else
  12.       RS485conf.flags :=  0;
  13.   fpioctl(FHandle, TIOCSRS485, @RS485conf);
  14. end;
  15.  
  16. function TBlockSerial.StatusRS485 : cardinal;
  17. begin
  18.     fpioctl(FHandle, TIOCGRS485, @RS485conf);
  19.     result:= RS485conf.flags;
  20. end;
  21. {$ENDIF}
  22. //
  23. //******************************************************************************
  24.  

In LazSerial the calls for the application:

Code: Pascal  [Select][+][-]
  1. //******************************************************************************
  2. //copied into Unit LazSerial after line 203
  3. {$IFDEF UNIX}
  4.  
  5.     function GetRS485Status : Cardinal;
  6.     procedure EnableRS485Port(OnOff : boolean);
  7.  
  8. {$ENDIF}
  9. //
  10. //******************************************************************************
  11.  

and also

Code: Pascal  [Select][+][-]
  1. //******************************************************************************
  2. //copied into Unit LazSerial after implementation
  3. {IFDEF UNIX}
  4.  
  5. function TLazSerial.GetRS485Status : Cardinal;
  6. begin
  7.   result:=FSynSer.StatusRS485;
  8. end;
  9.  
  10. procedure TLazSerial.EnableRS485Port(OnOff : boolean);
  11. begin
  12.   FSynSer.EnableRS485(OnOff);
  13. end;
  14. {ENDIF}
  15. //
  16. //******************************************************************************
  17.  

I am quite sure that there is potential for improvements, but this works for me.
Since the baudrate is 9600, the switch over time is not critical, it works like a charm.
Test was done with a 4B and the Raspberry Pi RS485&CAN Module from Inno-Maker.
fpc 3.0.4, Lazarus 2.0.12, LazSerial v0.3, LazSynaSer 007.005.002.

It is entered in Mantis.

CAN tests still to come.
« Last Edit: April 16, 2021, 02:08:26 pm by ThomasK »
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
@ThomasK If they don't go into the bugtracking system they will get lost. It's your responsibility to do that.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

ThomasK

  • New Member
  • *
  • Posts: 48
@ThomasK If they don't go into the bugtracking system they will get lost. It's your responsibility to do that.

MarkMLl

Just done 0038763, I had to register first - now I go walk the dog.
« Last Edit: April 16, 2021, 02:11:30 pm by ThomasK »
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Just done 0038763, I had to register first - now I go walk the dog.

Well done. Keep an eye on it in case somebody does a "Don't understand your banter old chap" :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018