프로그래밍 초보 탈출

Libraries/Delphi Library

[Protocol] Modbus RTU Packet Library

째즈토끼 2022. 6. 17. 18:35
unit LibModBusProtocol_RTU;

interface

uses
  Windows;

type
  TModBus_RTUPacket = AnsiString;
  TModBus_RTUParam = AnsiString;

function ModBusRTU_CheckPacketCRC(const Packet: TModBus_RTUPacket): Boolean;

function ModBusRTU_MakePacket(SlaveAddress: BYTE; Func: BYTE; Param: Pointer; ParamLen: WORD): TModBus_RTUPacket; overload;
function ModBusRTU_MakePacket(SlaveAddress: BYTE; Func: BYTE; Param: TModBus_RTUParam): TModBus_RTUPacket; overload;

function ModBusRTU_MakeReadHoldingRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
function ModBusRTU_MakeReadHoldingRegister_ResponsePacket(SlaveAddress: BYTE; DataCount: BYTE; Data: array of WORD): TModBus_RTUPacket;

function ModBusRTU_MakeReadInputRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
function ModBusRTU_MakeReadInputRegister_ResponsePacket(SlaveAddress: BYTE; DataCount: BYTE; Data: array of WORD): TModBus_RTUPacket;

function ModBusRTU_MakeWriteSingleRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; Data: WORD): TModBus_RTUPacket;
function ModBusRTU_MakeWriteSingleRegister_ResponsePacket(SlaveAddress: BYTE; StartingAddress: WORD; Data: WORD): TModBus_RTUPacket;

function ModBusRTU_MakeWriteMultipleRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD; Data: array of WORD): TModBus_RTUPacket;
function ModBusRTU_MakeWriteMultipleRegister_ResponsePacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
{
function CalcCRC(const Packet: TModBus_RTUPacket; Len: Integer): WORD;
const
  POLYNORMIAL = $A001;
var
  PT: PBYTE;
  I : Integer;
  FL: WORD;
begin
  PT := PBYTE(PChar(Packet));
  RESULT := $FFFF;
  while Len > 0 do begin
     RESULT := RESULT xor PT^;
     Inc(PT);
     for I:=1 to 8 do begin
         FL := RESULT and $0001;
         RESULT := RESULT shr 1;
         if FL = $0001 then RESULT := RESULT xor POLYNORMIAL;
     end;
end;
}

{ CRC table for calculate with polynom 0xA001 with init value 0xFFFF, High half word }
const CRC_Table_Hi: array[0..255] of BYTE = (
      $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81,
      $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0,
      $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01,
      $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41,
      $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81,
      $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,
      $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $01,
      $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40,
      $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81,
      $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0,
      $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01,
      $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41,
      $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81,
      $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0,
      $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $01,
      $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41,
      $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81,
      $40  );
{ CRC table for calculate with polynom $A001 with init value $FFFF, Low half word }
const CRC_Table_Lo: array[0..255] of BYTE = (
      $00, $C0, $C1, $01, $C3, $03, $02, $C2, $C6, $06, $07, $C7, $05, $C5, $C4,
      $04, $CC, $0C, $0D, $CD, $0F, $CF, $CE, $0E, $0A, $CA, $CB, $0B, $C9, $09,
      $08, $C8, $D8, $18, $19, $D9, $1B, $DB, $DA, $1A, $1E, $DE, $DF, $1F, $DD,
      $1D, $1C, $DC, $14, $D4, $D5, $15, $D7, $17, $16, $D6, $D2, $12, $13, $D3,
      $11, $D1, $D0, $10, $F0, $30, $31, $F1, $33, $F3, $F2, $32, $36, $F6, $F7,
      $37, $F5, $35, $34, $F4, $3C, $FC, $FD, $3D, $FF, $3F, $3E, $FE, $FA, $3A,
      $3B, $FB, $39, $F9, $F8, $38, $28, $E8, $E9, $29, $EB, $2B, $2A, $EA, $EE,
      $2E, $2F, $EF, $2D, $ED, $EC, $2C, $E4, $24, $25, $E5, $27, $E7, $E6, $26,
      $22, $E2, $E3, $23, $E1, $21, $20, $E0, $A0, $60, $61, $A1, $63, $A3, $A2,
      $62, $66, $A6, $A7, $67, $A5, $65, $64, $A4, $6C, $AC, $AD, $6D, $AF, $6F,
      $6E, $AE, $AA, $6A, $6B, $AB, $69, $A9, $A8, $68, $78, $B8, $B9, $79, $BB,
      $7B, $7A, $BA, $BE, $7E, $7F, $BF, $7D, $BD, $BC, $7C, $B4, $74, $75, $B5,
      $77, $B7, $B6, $76, $72, $B2, $B3, $73, $B1, $71, $70, $B0, $50, $90, $91,
      $51, $93, $53, $52, $92, $96, $56, $57, $97, $55, $95, $94, $54, $9C, $5C,
      $5D, $9D, $5F, $9F, $9E, $5E, $5A, $9A, $9B, $5B, $99, $59, $58, $98, $88,
      $48, $49, $89, $4B, $8B, $8A, $4A, $4E, $8E, $8F, $4F, $8D, $4D, $4C, $8C,
      $44, $84, $85, $45, $87, $47, $46, $86, $82, $42, $43, $83, $41, $81, $80,
      $40  );

procedure CalcCRC(const Packet: TModBus_RTUPacket; Len: Integer; var CRC_Hi,CRC_Lo: BYTE);
var
  PT: PBYTE;
  Index: Integer;
begin
  CRC_Hi := $FF;
  CRC_Lo := $FF;
  PT := PBYTE(PChar(Packet));

  while Len > 0 do begin
     Index  := CRC_Lo xor PT^;
     CRC_Lo := CRC_Hi xor CRC_Table_Hi[Index];
     CRC_Hi := CRC_Table_Lo[Index];
     Dec(Len);
     Inc(PT);
     end;
end;
procedure AppendCRC(var Packet: TModBus_RTUPacket);
var
  CRC_Hi, CRC_Lo: BYTE;
begin
  CalcCRC(Packet, Length(Packet), CRC_Hi, CRC_Lo);
  Packet := Packet + CHR(CRC_Lo) + CHR(CRC_Hi); // Lo First
end;

function ModBusRTU_CheckPacketCRC(const Packet: TModBus_RTUPacket): Boolean;
var
  CRC_Hi, CRC_Lo: BYTE;
  Len : Integer;
begin
  Len := Length(Packet)-2;
  CalcCRC(Packet, Len, CRC_Hi, CRC_Lo);
  RESULT := (ORD(Packet[Len+1]) = CRC_Lo) and (ORD(Packet[Len+2]) = CRC_Hi);
end;

function Make_RTUParam(W: WORD): TModBus_RTUParam;
begin
  RESULT := CHR(BYTE(W shr 8)) + CHR(BYTE(W));
end;

function ModBusRTU_MakePacket(SlaveAddress: BYTE; Func: BYTE; Param: Pointer; ParamLen: WORD): TModBus_RTUPacket;
begin
  SetLength(RESULT, ParamLen + 2);
  RESULT[1] := CHR(SlaveAddress);
  RESULT[2] := CHR(Func);
  if ParamLen > 0 then CopyMemory(PAnsiChar(RESULT)+2, Param, ParamLen);
  AppendCRC(RESULT);
end;

function ModBusRTU_MakePacket(SlaveAddress: BYTE; Func: BYTE; Param: TModBus_RTUParam): TModBus_RTUPacket;
begin
  RESULT := CHR(SlaveAddress) + CHR(Func) + Param;
  AppendCRC(RESULT);
end;
function ModBusRTU_MakeReadHoldingRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
begin
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $03, Make_RTUParam(StartingAddress) + Make_RTUParam(NumberOfRegister));
end;

function ModBusRTU_MakeReadHoldingRegister_ResponsePacket(SlaveAddress: BYTE; DataCount: BYTE; Data: array of WORD): TModBus_RTUPacket;
var
  I : Integer;
  Param : TModBus_RTUParam;
begin
  Param := '';
  for I:=0 to DataCount-1 do Param := Param + Make_RTUParam(Data[I]);
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $03, CHR(Length(Param)) + Param);
end;


function ModBusRTU_MakeReadInputRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
begin
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $04, Make_RTUParam(StartingAddress) + Make_RTUParam(NumberOfRegister));
end;

function ModBusRTU_MakeReadInputRegister_ResponsePacket(SlaveAddress: BYTE; DataCount: BYTE; Data: array of WORD): TModBus_RTUPacket;
var
  I : Integer;
  Param : TModBus_RTUParam;
begin
  Param := '';
  for I:=0 to DataCount-1 do Param := Param + Make_RTUParam(Data[I]);
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $04, CHR(Length(Param)) + Param);
end;


function ModBusRTU_MakeWriteSingleRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; Data: WORD): TModBus_RTUPacket;
begin
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $06, Make_RTUParam(StartingAddress) + Make_RTUParam(Data));
end;

function ModBusRTU_MakeWriteSingleRegister_ResponsePacket(SlaveAddress: BYTE; StartingAddress: WORD; Data: WORD): TModBus_RTUPacket;
begin
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $06, Make_RTUParam(StartingAddress) + Make_RTUParam(Data));
end;


function ModBusRTU_MakeWriteMultipleRegister_RequestPacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD; Data: array of WORD): TModBus_RTUPacket;
var
  I : Integer;
  Param : TModBus_RTUParam;
begin
  Param := '';
  for I:=0 to NumberOfRegister-1 do Param := Param + Make_RTUParam(Data[I]);
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $10, Make_RTUParam(StartingAddress) + Make_RTUParam(NumberOfRegister)
                + CHR(Length(Param)) + Param);
end;

function ModBusRTU_MakeWriteMultipleRegister_ResponsePacket(SlaveAddress: BYTE; StartingAddress: WORD; NumberOfRegister: WORD): TModBus_RTUPacket;
begin
  RESULT := ModBusRTU_MakePacket(SlaveAddress, $10, Make_RTUParam(StartingAddress) + Make_RTUParam(NumberOfRegister));
end;

'Libraries > Delphi Library' 카테고리의 다른 글

[System] System Const Library  (0) 2022.06.17
[System] OS Version Library  (0) 2022.06.17
[System] Execute Library 2  (0) 2022.06.17
[System] Process Token Library  (0) 2022.06.17
[System] Process Information Library  (0) 2022.06.17