Recent

Author Topic: How to register a component  (Read 1662 times)

KoBraSoft

  • New Member
  • *
  • Posts: 20
How to register a component
« on: April 21, 2020, 09:40:42 am »
Hi,
I found a Modbus driver that meet my needs.  https://sourceforge.net/projects/pascal-modbus/ 
Now I would like create a Lazarus component and include this driver.
I modified pascal_modbus_rtu.pas, added published and a register porcedure.
I created a Lazarus component according https://wiki.freepascal.org/How_To_Write_Lazarus_Component/de
On compiling the new package I get this error message:
Code: Pascal  [Select][+][-]
  1. Pascal_Modbus_RTU.pas(225,51) Error: Incompatible type for arg no. 2: Got "{Array Of Const/Constant Open} Array of Class Of TPascal_Modbus_RTU", expected "{Open} Array Of TComponentClass"
Here is the header (including register procedure):
Code: Pascal  [Select][+][-]
  1. unit Pascal_Modbus_RTU;
  2.  
  3. { ENG: Comments on Russian! Translation will be in future versions.
  4.  At the moment, I suggest to use automatic translation.}
  5.  
  6. {$mode objfpc}{$H+}
  7. { TODO : Добавить отчеты об ошибках }
  8. { TODO : Добавить функции записи одиночных катушек и регистров, мб функции 20-23 }
  9. { TODO : отправка сообщения об ошибках в линию при ошибках }
  10. interface
  11.  
  12. uses
  13.     Classes, SysUtils, synaser, SynaUtil, crc16_stream;
  14.  
  15. type
  16.  
  17.     // тип - обработчик сообщений ответов от контроллера
  18.     TProcedureReadModbus = procedure(Station: byte; FunctionCode: byte;
  19.         StartAddress: word; CountSended: word; size_mb: cardinal; DataStream: TMemoryStream;
  20.         NotMatch: boolean = False) of object;
  21.     // тип - обработчик ошибок ответа контроллера
  22.     TResponceError = procedure(Station: byte; ErrorCode, ExceptionCode: byte) of object;
  23.     // тип - обработчик ошибок прослушки линии
  24.     TListenError = procedure(ErrorCode: byte; DataStream: TmemoryStream) of object;
  25.     // процедура для вывода диагностических сообщений
  26.     TDiagStr = procedure(DiagStr: string) of object;
  27.  
  28.  
  29.     { TSendThread }
  30.  
  31.     // класс для функции фоновой отправки данных в линию
  32.     TSendThread = class(TThread)
  33.     private
  34.     protected
  35.         procedure Execute; override;
  36.     public
  37.         SendStream: TMemoryStream; // поток данных, который будет "отправлен" в линию (порт)
  38.         serial: TBlockSerial;   // порт, куда будут посылаться данные
  39.         RTS: boolean;   // флаг необходимости взводить RTS при отправке данных
  40.         RTS_On: word;   // кол-во милисекунд от взведения RTS до отправки данных
  41.         RTS_Off: word;  // кол-во милисекунд от отправки данных до выключения RTS
  42.         constructor Create(CreateSuspended: boolean);
  43.     end;
  44.  
  45.     DCB = record
  46.           DCBlength : DWORD;
  47.           BaudRate : DWORD;
  48.           flags : DWORD;
  49.           wReserved : WORD;
  50.           XonLim : WORD;
  51.           XoffLim : WORD;
  52.           ByteSize : BYTE;
  53.           Parity : BYTE;
  54.           StopBits : BYTE;
  55.           XonChar : char;
  56.           XoffChar : char;
  57.           ErrorChar : char;
  58.           EofChar : char;
  59.           EvtChar : char;
  60.           wReserved1 : WORD;
  61.        end;
  62.  
  63.     { TPascal_Modbus_RTU }
  64.  
  65.     TPascal_Modbus_RTU = class(TObject)
  66.     private
  67.         FConnected: boolean;        // подключен к порту
  68.         FDiagStr: TDiagStr;         // процедура вывода диаг. сообщений (временная)
  69.         FIsMaster: boolean;         // являемся мастером
  70.         FLastErrorDesc: string;     // описание последней ошибки (не использовал)
  71.         FListenError: TListenError; // процедура обработки ошибки прослушивания линии
  72.         FListenErrorCode: cardinal; // номер последней ошибки прослушивания линии
  73.         FMaxSizePDU: cardinal;      // максимальный размер пакета данных ModBus
  74.         FObjectTag: integer;
  75.         FResponceBreakTime: cardinal;   // время (в мс) тишины до ошибки "прерванного ответа"
  76.         FResponceError: TResponceError; // обработчик ошибки ответа контроллера
  77.         FResponceReadProcedure: TProcedureReadModbus;  // обработчик нормального ответа контроллера
  78.         FRTS_Off_Delay: word;       // кол-во милисекунд от отправки данных до выключения RTS
  79.         FRTS_On_Delay: word;        // кол-во милисекунд от взведения RTS до отправки данных
  80.         FRTS_use: boolean;          // флаг использования RTS для отправки данных
  81.         FSendErrorMessage: boolean; // флаг "посылать контроллеру сообщения об ошибких"
  82.         FSilenceCount: cardinal;    // текущее время "тишины" в линии, мс
  83.         FTimeBeforeSend: cardinal;  // сколько осталось "тишины" до разрешения отправлять в линию, мс
  84.         FTimeOutResponce: cardinal; // время таймаута на прием ответа, мс
  85.         FReadyForSend: boolean;     // флаг "готов посылать в линию"
  86.  
  87.         FirstStart: boolean;        // флаг "первый запуск"
  88.         FTimeToSleepRx: cardinal;   // время бездействия после окончания приема данных  (?)
  89.         TimeToSleepTx: cardinal;    // сколько осталось после окончания передачи данных до таймаута
  90.         InputStream: TMemoryStream; // поток с данными из линии
  91.         OutputStream: TMemoryStream;  // поток для передачи данных обработчикам
  92.         InputMessageStream: TMemoryStream;  // ??? похоже - рудимент (?)
  93.         SendStream: TMemoryStream;  // поток данных для передачи в линию
  94.         SendedSize: word;           // сколько контроллеру послали
  95.         SendedFunction: byte;       // последняя функция, посланная контроллеру
  96.         SendedStation: byte;        // послений контроллер, которому посылали запрос
  97.         SendedAddress: word;        // регистр последнего запроса контроллеру
  98.         Serial: TBlockSerial;       // COM-порт
  99.         BaudRate: cardinal;         // скорость обмена
  100.         MessageFromMaster: boolean; // --- не нужно, это для когда мы слейв
  101.         SendThread: TSendThread;    // процесс передачи данных
  102.         WaitingResponce: boolean;   // флаг "ждем ответа"
  103.         stime: tdatetime;           // когда началась тишина
  104.  
  105.         procedure SendFinished(Sender: TObject);
  106.         procedure SetDiagStr(AValue: TDiagStr);
  107.  
  108.         procedure SetIsMaster(AValue: boolean);
  109.         procedure SetListenError(AValue: TListenError);
  110.         procedure SetMaxSizePDU(AValue: cardinal);
  111.         procedure SetObjectTag(AValue: integer);
  112.         procedure SetResponceBreakTime(AValue: cardinal);
  113.         procedure SetResponceError(AValue: TResponceError);
  114.         procedure SetResponceReadProcedure(AValue: TProcedureReadModbus);
  115.         procedure SetRTS_Off_Delay(AValue: word);
  116.         procedure SetRTS_On_Delay(AValue: word);
  117.         procedure SetRTS_use(AValue: boolean);
  118.         procedure SetSendErrorMessage(AValue: boolean);
  119.         procedure SetTimeOutResponce(AValue: cardinal);
  120.         procedure SetTimeToSleepRx(AValue: cardinal);
  121.     protected
  122.  
  123.     public
  124.         // описание последней ошибки
  125.         property LastErrorDesc: string read FLastErrorDesc ;
  126.         // номер последней ошибки прослушивания линии
  127.         property ListenErrorCode: cardinal read FListenErrorCode;
  128.         // текущее время "тишины" в линии, мс
  129.         property SilenceCount: cardinal read FSilenceCount;
  130.         // сколько осталось "тишины" до разрешения отправлять в линию, мс
  131.         property TimeBeforeSend: cardinal read FTimeBeforeSend;
  132.         // подключен к порту
  133.         property Connected: boolean read FConnected;
  134.         // флаг "готов посылать в линию"
  135.         property ReadyForSend: boolean read FReadyForSend;
  136.  
  137.         constructor Create;
  138.         destructor Free;
  139.         // команда на чтение регистров (функции ... )
  140.         function Read(Station, FunctionCode: byte; StartAddress, Count: word): cardinal;
  141.         // команда на запись регистров (функции ... )
  142.         function Write(Station, FunctionCode: byte; StartAddress, Count: word;
  143.             WriteStream: Tmemorystream): cardinal;
  144.         // Подключиться к COM-порту
  145.         function ConnectCOM(ComPort: string): integer;
  146.         // отключиться от порта
  147.         procedure DisconnectCom;
  148.         // настроить параметры COM-порта (после подключения)
  149.         procedure ConfigCOM(baud, bits: integer; parity: char; stop: integer;
  150.             softflow, hardflow: boolean);
  151.         procedure ListenLine;
  152.    published
  153.         // время таймаута на прием ответа, мс
  154.         property TimeOutResponce: cardinal read FTimeOutResponce write SetTimeOutResponce;
  155.         // флаг "посылать контроллеру сообщения об ошибких"
  156.         property SendErrorMessage: boolean read FSendErrorMessage write SetSendErrorMessage;
  157.         // обработчик нормального ответа контроллера
  158.         property ResponceReadProcedure: TProcedureReadModbus
  159.             read FResponceReadProcedure write SetResponceReadProcedure;
  160.         // обработчик ошибки ответа контроллера
  161.         property ResponceError: TResponceError read FResponceError write SetResponceError;
  162.         // обработчик ошибки прослушивания линии
  163.         property ListenError: TListenError read FListenError write SetListenError;
  164.         { TODO : удалить ObjectTag - не нужен }
  165.         property ObjectTag: integer read FObjectTag write SetObjectTag;
  166.         // мы - мастер (не нужно?)
  167.         property IsMaster: boolean read FIsMaster write SetIsMaster;
  168.         // максимальный размер пакета данных ModBus
  169.         property MaxSizePDU: cardinal read FMaxSizePDU write SetMaxSizePDU;
  170.         // время бездействия после окончания приема данных
  171.         property TimeToSleepRx: cardinal read FTimeToSleepRx write SetTimeToSleepRx;
  172.         // время (в мс) тишины до ошибки "прерванного ответа"
  173.         property ResponceBreakTime: cardinal read FResponceBreakTime write SetResponceBreakTime;
  174.         // флаг использования RTS для отправки данных
  175.         property RTS_use: boolean read FRTS_use write SetRTS_use;
  176.         // кол-во милисекунд от взведения RTS до отправки данных
  177.         property RTS_On_Delay: word read FRTS_On_Delay write SetRTS_On_Delay;
  178.         // кол-во милисекунд от отправки данных до выключения RTS
  179.         property RTS_Off_Delay: word read FRTS_Off_Delay write SetRTS_Off_Delay;
  180.         // вывод диагностических сообщений
  181.         property DiagStr: TDiagStr read FDiagStr write SetDiagStr;
  182.     end;
  183.  
  184.     { TTimerThread }
  185.  
  186.     TTimerThread = class(TThread)
  187.     private
  188.         procedure Timer;
  189.     protected
  190.         procedure Execute; override;
  191.     public
  192.         StopTimer: Boolean;
  193.         mbrtu: TPascal_Modbus_RTU;
  194.         constructor Create(CreateSuspended: boolean);
  195.     end;
  196.  
  197. implementation
  198. procedure Register;
  199. begin
  200.   RegisterComponents('Modbus',[TPascal_Modbus_RTU]);
  201. end;
  202.                                                                    

Please find attached the actual (not working) pas file.

Konrad

PS
If the component works and if it is Ok for Yuri, I will publish this component

PascalDragon

  • Hero Member
  • *****
  • Posts: 5481
  • Compiler Developer
Re: How to register a component
« Reply #1 on: April 21, 2020, 09:48:17 am »
On compiling the new package I get this error message:
Code: Pascal  [Select][+][-]
  1. Pascal_Modbus_RTU.pas(225,51) Error: Incompatible type for arg no. 2: Got "{Array Of Const/Constant Open} Array of Class Of TPascal_Modbus_RTU", expected "{Open} Array Of TComponentClass"

Please read the error message. It tells you exactly what is the problem. You want to register a component, so you need to inherit from TComponent. Your TPascal_Modbus_RTU however inherits from TObject.

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
Re: How to register a component
« Reply #2 on: April 21, 2020, 03:27:03 pm »
If your plan is to release the components for public use, then it would be nice to get rid of C like names for units and some methods. Something like modbus.rtu instead of Pascal_Modbus_RTU, modbus.tcp instead of psmodbustcp, and modbus.crc instead of crc16_stream would be much more preferred. If that is not to your liking then please ignore this suggestion.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

KoBraSoft

  • New Member
  • *
  • Posts: 20
Re: How to register a component
« Reply #3 on: April 22, 2020, 12:17:19 pm »
My plan is to release this component for public use if the example application is ready. Your suggestion (as well as other suggestions) is highly welcome.
Is there a written guideline for naming?     

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
Re: How to register a component
« Reply #4 on: April 23, 2020, 02:33:27 am »
Is there a written guideline for naming?
For unit naming: https://edn.embarcadero.com/article/10280#3.1
For method naming: https://edn.embarcadero.com/article/10280#3.4

That very good Object Pascal Style Guide is a little dated. In modern Lazarus/FreePascal you should also use namespaces https://wiki.lazarus.freepascal.org/Namespaces for better units organization and to minimize risk that some other package/component can have the same unit name. Although PascalCase is nice for naming units in code, if you target cross platform then it might be good idea to keep lower case unit file names since otherwise there are some file systems where non lower case file names can lead to some annoyances. Compiler will find lower case unit files even if in code you used PascalCase.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

 

TinyPortal © 2005-2018