Aha oplevelse af de gode:

4 views
Skip to first unread message

Thomas Riedel, LogiHouse

unread,
Feb 6, 2025, 2:33:57 AM2/6/25
to DAPUG

Jeg har fået til opgave at skulle skrive fra mit program  til nogle små elektroniske displays.
Der var en kæmpe rodet kildekode i C# + en DLL og en lang og knasende tør referencemanual (PDF-dokument).
Efter at have bøvlet med at oversætte C# til Delphi, fandt jeg på at give referencemanualen til ChatGPT, og bede den om at lave delphi kode ud af den, og vupti kom denne glimrende kode.
Og med dette skriver jeg direkte til controlleren, udenom  DLLen.
Cool!


unit uAtopTCP;

interface

uses
  SysUtils, Classes, IdTCPClient;

const
  MESSAGE_TYPE = $60;

  // Sub-Commands
  CMD_SHOW_STRING = $01;
  CMD_SHOW_QR_CODE = $02;
  CMD_CLEAR_ELEMENT = $03;
  CMD_SAVE_PAGE = $10;
  CMD_ERASE_PAGE = $11;
  CMD_LOAD_PAGE = $20;
  CMD_MODIFY_COLOR = $C0;

  CMD_SHOW_DATA = $00;
  CMD_CLEAR_DISPLAY = $01;
  CMD_LED_ON = $02;
  CMD_LED_OFF = $03;
  CMD_BUZZER_ON = $04;
  CMD_BUZZER_OFF = $05;
  CMD_QUERY_DEVICE_MALFUNCTION = $0B;
  CMD_FLASH_ALPHANUMERIC = $10;
  CMD_FLASH_LED = $11;
  CMD_SET_FLASH_TIMER = $12;
  CMD_SHOW_TAG_ADDRESS = $13;
  CMD_RESET_DEVICE = $14;
  CMD_DISABLE_SHORTAGE_BUTTON = $15;
  CMD_ENABLE_SHORTAGE_BUTTON = $16;
  CMD_EMULATE_CONFIRM_BUTTON = $17;
  CMD_EMULATE_SHORTAGE_BUTTON = $18;
  CMD_SWITCH_TO_STOCK_MODE = $19;
  CMD_SWITCH_TO_PICKING_MODE = $1A;
  CMD_DISABLE_CONFIRM_BUTTON = $1B;
  CMD_ENABLE_CONFIRM_SHORTAGE_BUTTONS = $1C;
  CMD_SET_VALID_DIGITS = $1E;
  CMD_SET_MULTIPLE_CONFIG = $1F;
  CMD_SET_NODE_ADDRESS = $3A;
  CMD_GET_DEVICE_DETAIL = $FC;
  CMD_GET_DEVICE_MODEL = $FA;
  CMD_ADV_CONFIG_NODE_ADDRESS = $FB;
  CMD_ALARM_STATUS_CONTROL = $F7;


  // Default Port
  DEFAULT_PORT = 6000;

  // Other Constants
  BROADCAST_NODE = $FC;

type
  TAdvancedLCDPTL = class
  private
    FTCPClient: TIdTCPClient;
    procedure SendCommand(SubCommand: Byte; SubNode: Byte; const Data: TBytes);
  public
    constructor Create;
    destructor Destroy; override;

    procedure Connect(const Host: string; Port: Integer = DEFAULT_PORT);
    procedure Disconnect;

    procedure ShowData(PageNumber: Byte; Value: Integer);
    procedure ShowString(PageNumber, RowIndex, ElementIndex: Byte; const Text: string);
    procedure ShowQRCode(PageNumber: Byte; const QRData: string);
    procedure ClearElement(PageNumber, RowIndex, ElementIndex: Byte);
    procedure SavePage(PageNumber: Byte);
    procedure ErasePage(PageNumber: Byte);
    procedure LoadPage(PageNumber: Byte);
    procedure ModifyColor(PageNumber, RowIndex, ElementIndex: Byte; Color: Word);

    procedure ClearDisplay;
    procedure LEDIndicator(OnOff: Boolean);
    procedure Buzzer(OnOff: Boolean);
    procedure QueryDeviceMalfunction;
    procedure FlashAlphanumeric;
    procedure FlashLED;
    procedure SetFlashTimer(TimerValue: Byte);
    procedure ShowTagAddress;
    procedure ResetDevice;
    procedure DisableShortageButton;
    procedure EnableShortageButton;
    procedure EmulateConfirmButton;
    procedure EmulateShortageButton;
    procedure SwitchToStockMode;
    procedure SwitchToPickingMode;
    procedure DisableConfirmButton;
    procedure EnableConfirmShortageButtons;
    procedure SetValidDigits(Count: Byte);
    procedure SetMultipleConfiguration(Config: Byte);
    procedure SetNodeAddress(Address: Byte);
    procedure GetDeviceDetail;
    procedure GetDeviceModel;
    procedure AdvancedConfigNodeAddress(Address: Byte);
    procedure AlarmStatusControl(Status: Byte);


  end;

implementation

constructor TAdvancedLCDPTL.Create;
begin
  inherited;
  FTCPClient := TIdTCPClient.Create(nil);
end;

destructor TAdvancedLCDPTL.Destroy;
begin
  FTCPClient.Free;
  inherited;
end;

procedure TAdvancedLCDPTL.Connect(const Host: string; Port: Integer);
begin
  FTCPClient.Host := Host;
  FTCPClient.Port := Port;
  FTCPClient.Connect;
end;

procedure TAdvancedLCDPTL.Disconnect;
begin
  FTCPClient.Disconnect;
end;

procedure TAdvancedLCDPTL.SendCommand(SubCommand: Byte; SubNode: Byte; const Data: TBytes);
var
  Packet: TBytes;
  LengthLow, LengthHigh: Byte;
  TotalLength: Word;
begin
  TotalLength := 8 + Length(Data);
  LengthLow := TotalLength and $FF;
  LengthHigh := (TotalLength shr 8) and $FF;

  SetLength(Packet, TotalLength);
  Packet[0] := LengthLow;
  Packet[1] := LengthHigh;
  Packet[2] := MESSAGE_TYPE;
  Packet[3] := 0; // Reserved
  Packet[4] := 0; // Reserved
  Packet[5] := 0; // Reserved
  Packet[6] := SubCommand;
  Packet[7] := SubNode;
  Move(Data[0], Packet[8], Length(Data));

  FTCPClient.IOHandler.Write(@Packet, TotalLength);
end;

procedure TAdvancedLCDPTL.ShowData(PageNumber: Byte; Value: Integer);
var
  Data: TBytes;
begin
  SetLength(Data, 8);
  Data[0] := CMD_SHOW_DATA;
  Data[1] := PageNumber;
  Move(Value, Data[2], 4);
  SendCommand(CMD_SHOW_DATA, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.ClearDisplay;
begin
  SendCommand(CMD_CLEAR_DISPLAY, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.LEDIndicator(OnOff: Boolean);
begin
  if OnOff then
    SendCommand(CMD_LED_ON, BROADCAST_NODE, [])
  else
    SendCommand(CMD_LED_OFF, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.Buzzer(OnOff: Boolean);
begin
  if OnOff then
    SendCommand(CMD_BUZZER_ON, BROADCAST_NODE, [])
  else
    SendCommand(CMD_BUZZER_OFF, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.QueryDeviceMalfunction;
begin
  SendCommand(CMD_QUERY_DEVICE_MALFUNCTION, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.FlashAlphanumeric;
begin
  SendCommand(CMD_FLASH_ALPHANUMERIC, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.FlashLED;
begin
  SendCommand(CMD_FLASH_LED, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.SetFlashTimer(TimerValue: Byte);
begin
  SendCommand(CMD_SET_FLASH_TIMER, BROADCAST_NODE, [TimerValue]);
end;

procedure TAdvancedLCDPTL.ShowTagAddress;
begin
  SendCommand(CMD_SHOW_TAG_ADDRESS, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.ResetDevice;
begin
  SendCommand(CMD_RESET_DEVICE, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.DisableShortageButton;
begin
  SendCommand(CMD_DISABLE_SHORTAGE_BUTTON, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.EnableShortageButton;
begin
  SendCommand(CMD_ENABLE_SHORTAGE_BUTTON, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.EmulateConfirmButton;
begin
  SendCommand(CMD_EMULATE_CONFIRM_BUTTON, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.EmulateShortageButton;
begin
  SendCommand(CMD_EMULATE_SHORTAGE_BUTTON, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.SwitchToStockMode;
begin
  SendCommand(CMD_SWITCH_TO_STOCK_MODE, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.SwitchToPickingMode;
begin
  SendCommand(CMD_SWITCH_TO_PICKING_MODE, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.DisableConfirmButton;
begin
  SendCommand(CMD_DISABLE_CONFIRM_BUTTON, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.EnableConfirmShortageButtons;
begin
  SendCommand(CMD_ENABLE_CONFIRM_SHORTAGE_BUTTONS, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.SetValidDigits(Count: Byte);
begin
  SendCommand(CMD_SET_VALID_DIGITS, BROADCAST_NODE, [Count]);
end;

procedure TAdvancedLCDPTL.SetMultipleConfiguration(Config: Byte);
begin
  SendCommand(CMD_SET_MULTIPLE_CONFIG, BROADCAST_NODE, [Config]);
end;

procedure TAdvancedLCDPTL.SetNodeAddress(Address: Byte);
begin
  SendCommand(CMD_SET_NODE_ADDRESS, BROADCAST_NODE, [Address]);
end;

procedure TAdvancedLCDPTL.GetDeviceDetail;
begin
  SendCommand(CMD_GET_DEVICE_DETAIL, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.GetDeviceModel;
begin
  SendCommand(CMD_GET_DEVICE_MODEL, BROADCAST_NODE, []);
end;

procedure TAdvancedLCDPTL.AdvancedConfigNodeAddress(Address: Byte);
begin
  SendCommand(CMD_ADV_CONFIG_NODE_ADDRESS, BROADCAST_NODE, [Address]);
end;

procedure TAdvancedLCDPTL.AlarmStatusControl(Status: Byte);
begin
  SendCommand(CMD_ALARM_STATUS_CONTROL, BROADCAST_NODE, [Status]);
end;



procedure TAdvancedLCDPTL.ShowString(PageNumber, RowIndex, ElementIndex: Byte; const Text: string);
var
  Data: TBytes;
  TextBytes: TBytes;
begin
  TextBytes := TEncoding.ANSI.GetBytes(Text);
  SetLength(Data, 6 + Length(TextBytes));
  Data[0] := CMD_SHOW_STRING;
  Data[1] := PageNumber;
  Data[2] := RowIndex;
  Data[3] := ElementIndex;
  Data[4] := 0; // String data type
  Data[5] := 0; // New data
  Move(TextBytes[0], Data[6], Length(TextBytes));

  SendCommand(CMD_SHOW_STRING, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.ShowQRCode(PageNumber: Byte; const QRData: string);
var
  Data: TBytes;
  QRBytes: TBytes;
begin
  QRBytes := TEncoding.ANSI.GetBytes(QRData);
  SetLength(Data, 3 + Length(QRBytes));
  Data[0] := CMD_SHOW_QR_CODE;
  Data[1] := PageNumber;
  Data[2] := 0; // New QR code data
  Move(QRBytes[0], Data[3], Length(QRBytes));

  SendCommand(CMD_SHOW_QR_CODE, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.ClearElement(PageNumber, RowIndex, ElementIndex: Byte);
var
  Data: TBytes;
begin
  SetLength(Data, 4);
  Data[0] := CMD_CLEAR_ELEMENT;
  Data[1] := PageNumber;
  Data[2] := RowIndex;
  Data[3] := ElementIndex;

  SendCommand(CMD_CLEAR_ELEMENT, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.SavePage(PageNumber: Byte);
var
  Data: TBytes;
begin
  SetLength(Data, 2);
  Data[0] := CMD_SAVE_PAGE;
  Data[1] := PageNumber;

  SendCommand(CMD_SAVE_PAGE, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.ErasePage(PageNumber: Byte);
var
  Data: TBytes;
begin
  SetLength(Data, 2);
  Data[0] := CMD_ERASE_PAGE;
  Data[1] := PageNumber;

  SendCommand(CMD_ERASE_PAGE, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.LoadPage(PageNumber: Byte);
var
  Data: TBytes;
begin
  SetLength(Data, 2);
  Data[0] := CMD_LOAD_PAGE;
  Data[1] := PageNumber;

  SendCommand(CMD_LOAD_PAGE, BROADCAST_NODE, Data);
end;

procedure TAdvancedLCDPTL.ModifyColor(PageNumber, RowIndex, ElementIndex: Byte; Color: Word);
var
  Data: TBytes;
begin
  SetLength(Data, 5);
  Data[0] := CMD_MODIFY_COLOR;
  Data[1] := RowIndex;
  Data[2] := ElementIndex;
  Data[3] := (Color shr 8) and $FF; // High byte
  Data[4] := Color and $FF;         // Low byte

  SendCommand(CMD_MODIFY_COLOR, BROADCAST_NODE, Data);
end;

end.


--
LogiHouse A/S
tlf +45 2840 1070
Thomas Riedel
Storkebakken 10
2400 København NV

Jens Fudge

unread,
Feb 6, 2025, 2:36:28 AM2/6/25
to da...@googlegroups.com

Fedt.

Dejligt at læse.

Ja, vi har det nogen gange med at stirre os blinde på ting der på ingen måde er essentielle for opgaven.

Og tak fordi du delte den gode historie :-)


--
Du har modtaget denne besked, fordi du abonnerer på gruppen "DAPUG" i Google Grupper.
Hvis du vil ophæve abonnementet på denne gruppe og ikke længere modtage mails fra den, skal du sende en mail til dapug+un...@googlegroups.com.
Du kan se denne diskussion ved at gå til https://groups.google.com/d/msgid/dapug/CAAyHz-mXmhtPE7P3ALSvrsytw6TGB7Fj9jXq1QoCmYN%2B1f%2B_nA%40mail.gmail.com.

GlennKonnekt | Glenn Dufke

unread,
Feb 6, 2025, 9:15:57 AM2/6/25
to Thomas Riedel, LogiHouse, DAPUG
Hej Thomas,

Godt at høre du fandt en løsning på problemet.

Et par kommentare til koden.

I stedet for indy kan der opnås bedre performance med TSocket klassen fra System.Net.Socket.

Kommandoerne kunne renses lidt op med et scoped enum.

De mest brugte pakker kunne simplificeres med en packed record og så "lagt oven på" en TBytes array, inden de sendes afsted til din aktive socket.

Det ser dog ikke ud til der er en thread safe lock når der sendes data og der kommer noget retur, så du kan godt rende ind i problemer her.

--------------------------------------------------------------------
Med venlig hilsen / Best regards

Glenn Dufke
Embarcadero MVP - Building the next gen apps with Delphi
Phone:  +45 38 40 99 27
Mobile: +45 51 21 99 27
g...@gkon.dk
GlennKonnekt - Sikrer de vigtige forbindelser.
GlennKonnekt - Securing important connections.
Software, Automation and Network design and development.
LinkedIn: www.linkedin.com/in/glenn-dufke-b3538a39

Confidentiality notice
This e-mail, including any attachment, may contain confidential and privileged information.
If you have received it by mistake, please notify us by e-mail and delete this e-mail and any attachment from your system.
Thank you!

Fortrolighedserklæring
Denne e-mail og vedhæftede bilag kan indeholde fortrolige og beskyttede oplysninger.
Hvis De ved en fejl har modtaget denne e-mail, anmodes De venligst straks om at give afsenderen besked via e-mail og slette denne e-mail og bilag fra Deres system.
Mange tak!


------ Original Message ------
From "Thomas Riedel, LogiHouse" <t...@logihouse.dk>
Date 06/02/2025 08.33.42
Subject [DAPUG] Aha oplevelse af de gode:

--
Reply all
Reply to author
Forward
0 new messages