![]() |
CRC von C in Delphi übersetze
Hallo zusammen,
ich kämpfe schon seit einiger Zeit mit der Aufgabe, eine gegebene C-Funktion ins Delphi zu übersetzen und brauche hierbei leider Hilfe. Kurz der Hintergrund: die Kommunikation mit einem Gerät erfolgt über eine Serielle Schnittstelle. Dabei werden Kommandos an das Gerät übertragen, dass dann entsprechend antwortet. Grundsätzlicher Aufbau der Nachrichten ist: <Command><CRC><cr> Im Prinzip nichts schwieriges. Der Teufel steckt im CRC, das mit jedem Kommando gesendet werden muss. Ist der CRC (2 Byte cuclic redundancy check code) falsch, wird der gesendete Befehl zwar empfangen - die Ausführung jedoch verweigert. Mit der Gerätedoku habe ich eine CRC Routine in C bekommen:
Code:
Sinn der Funktion al_crc_half sollte sein, dass für einen übergebenen
INT16U cal_crc_half(INT8U far *pin, INT8U len)
{ INT16U crc; INT8U da; INT8U far *ptr; INT8U bCRCHign; INT8U bCRCLow; INT16U crc_ta[16]= { /* CRC look up table */ 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef }; ptr=pin; crc=0; len--; while(len--!=0) { da=((INT8U)(crc>>8))>>4; /* CRC high four bits */ crc<<=4; /* The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. */ crc^=crc_ta[da^(*ptr>>4)]; /* Add the upper 4 bits of the CRC and the first half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. */ da=((INT8U)(crc>>8))>>4; /* CRC high four bits */ crc<<=4; /* The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. */ crc^=crc_ta[da^(*ptr&0x0f)]; /* Add the upper 4 bits of the CRC and the last half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. */ ptr++; } bCRCLow = crc; bCRCHign= (INT8U)(crc>>8); if(bCRCLow==0x28||bCRCLow==0x0d||bCRCLow==0x0a) { bCRCLow++; } if(bCRCHign==0x28||bCRCHign==0x0d||bCRCHign==0x0a) { bCRCHign++; } crc = ((INT16U)bCRCHign)<<8; crc += bCRCLow; return(crc); }
Delphi-Quellcode:
ein 2-Byte CRC Wert (
string
Delphi-Quellcode:
) nach obiger Vorgabe berechnet wird.
word
Das ist naturgemäss für CRC viel Bitschieberei. Soweit ich erkennen konnte, scheint das ein proprietärer CRC Prozess zu sein. Leider bin ich nahezu unerfahren, was C angeht und auch sehr ungeübt, was Bitoperationen in Delphi angeht. Daher die Frage: kann mir jemand das wenigstens ungefähr in Delphi übersetzen? Anmerkung: ich habe nicht vor auf diesem Wege Arbeit durch copy-paste programmieren zu sparen. Leider bin ich nach einigen Stunden noch am Anfang der Aufgabe - daher die Bitte um Unterstützung. Danke für alle Hinweise und Unterstützung. Markus |
AW: CRC von C in Delphi übersetze
Ich habe mir den Spass erlaubt den Bing Bot in Skype zu fragen. Er sagt Sure, here is the Delphi version of the code:
Delphi-Quellcode:
Am Schluss noch: I hope this helps! Let me know if you have any other questions.
function cal_crc_half(pin: PByte; len: Byte): Word;
var crc: Word; da: Byte; ptr: PByte; bCRCHign: Byte; bCRCLow: Byte; crc_ta: array[0..15] of Word = ($0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7, $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef); begin ptr := pin; crc := 0; len := len - 1; while (len <> 0) do begin da := (crc shr 8) shr 4; // CRC high four bits crc := crc shl 4; // The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. crc := crc xor crc_ta[da xor (ptr^ shr 4)]; // Add the upper 4 bits of the CRC and the first half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. da := (crc shr 8) shr 4; // CRC high four bits crc := crc shl 4; // The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. crc := crc xor crc_ta[da xor (ptr^ and $0f)]; // Add the upper 4 bits of the CRC and the last half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. Inc(ptr); Dec(len); end; bCRCLow := crc and $FF; bCRCHign := crc shr 8; if (bCRCLow = $28) or (bCRCLow = $0d) or (bCRCLow = $0a) then Inc(bCRCLow); if (bCRCHign = $28) or (bCRCHign = $0d) or (bCRCHign = $0a) then Inc(bCRCHign); crc := (bCRCHign shl 8) + bCRCLow; Result := crc; end; |
AW: CRC von C in Delphi übersetze
Das teste ich gleich!
Warum ich darauf selbst nicht gekommen bin ... Untercoffeinnebel wahrscheinlich. Vielen DANK! |
AW: CRC von C in Delphi übersetze
Putzig, dass er sogar die falschen Sourcecode Kommentare übernommen hat (<< ist left shift und kein right shift, wie im Kommentar steht)
|
AW: CRC von C in Delphi übersetze
Ja, faszinierend.
Vor allem, weil einen diese Kommentare beim "Selbstversuch" erst einmal in die Denkschleife schicken .... :oops: |
AW: CRC von C in Delphi übersetze
Also manchmal ist ChatGPT schon zu gebrauchen, finde ich. Hab letztens eine Funktion optimiert und hab der KI gesagt, sie solle sie mal umschreiben, ohne die Nutzung von PChar und Pointern. Hat er/sie/es fix erledigt. Hätte mich ein paar Minuten mehr gekostet. Kontrolle des Codes geht dann durch mich schneller.
|
AW: CRC von C in Delphi übersetze
eine erste Rückmeldung und Frage zur CRC Funktion:
das übergebene Funktionsargument
Delphi-Quellcode:
ist nach meinem Verständnis ein Byte.
pin
Es wird im Folgenden als Pointer auf das erste Zeichen der zu behandelnden Zeichenkette mit Länge
Delphi-Quellcode:
(2. Argument) verwendet.
len
Ich habe dies gefunden: ![]() Um die CRC Funktion aufzurufen, verwende ich zum Test folgende Funktion:
Delphi-Quellcode:
Lasse ich das mit Text = 'QPIGS' laufen und setzte einen Haltepunkt vor dem Aufruf von cal_crc_half, habe ich folgende Werte:
function ErzeugeSolarisCRCWord(Text: string): word;
var tmpAnsiString: AnsiString; tmpPAnsiString: PByte; tmpPAnsiChar: PAnsiChar; tmpLength: Byte; tmpTextLength, i : integer; begin // initialisieren result := 0; tmpTextLength := Length(Text); // validieren if ((tmpTextLength = 0) or (tmpTextLength > 256)) then exit; // Merker setzen tmpAnsiString := Text; i := 1; tmpPAnsiString := Addr(tmpAnsiString); tmpPAnsiChar := Addr(tmpAnsiString[i]); tmpLength := Length(tmpAnsiString); // CRC berechnen // function cal_crc_half(pin: PByte; len: Byte): Word; result := cal_crc_half(Addr(tmpPAnsiChar), tmpLength); end;
Delphi-Quellcode:
In der Funkton cal_crc_half ist nach der Zuweisung
tmpPAnsiString = $12FBD8
tmpPAnsiChar = 'QPIGS' tmpLength := 5 Addr(tmpPAnsiChar) = $12FBD0
Delphi-Quellcode:
der Wert von
ptr := pin;
Delphi-Quellcode:
Meinem bisherigen Verständnis nach sollte jedoch der derefernierte Wert von
ptr = $12FBD0
ptr^ = 12
Delphi-Quellcode:
ASCII-Wert des ersten Buchstaben von
ptr
Delphi-Quellcode:
bzw. von
Text
Delphi-Quellcode:
sein - also "Q = ASCII 81".
tmpPAnsiChar
Delphi-Quellcode:
liefert jedoch 12.
ptr^
Ich verstehe das nicht, wahrscheinlich weil ich das Thema Pointer, AnsiChar und AnsiString nicht durchblickt habe. Kann mir jemand helfen? |
AW: CRC von C in Delphi übersetze
tmpPAnsiChar ist doch schon ein Pointer, Du übergibts also, denke ich, die Adresse auf die Adresse Addr(tmpPAnsiChar)
|
AW: CRC von C in Delphi übersetze
mhm - das ist sicher richtig. Jedoch bekomme ich ohne
Delphi-Quellcode:
diese Fehlermeldung beim Kompilieren:
Addr()
[Fehler] uCRCSolaris.pas(174): Inkompatible Typen: 'Char' und 'Byte' Wie gesagt, ich bin beim Thema Pointer und Adressen sehr unerfahren. |
AW: CRC von C in Delphi übersetze
weiter probiert und mit
Delphi-Quellcode:
kann ich ohne Fehler kompilieren.
PByte()
So sieht die Aufruffunktion jetzt aus:
Delphi-Quellcode:
Beim Test sind jetzt in
function ErzeugeSolarisCRCWord(Text: string): word;
var tmpAnsiString: AnsiString; tmpPAnsiCharByte, tmpPAnsiString: PByte; tmpPAnsiChar: PAnsiChar; tmpLength: Byte; tmpTextLength, i : integer; begin // initialisieren result := 0; tmpTextLength := Length(Text); // validieren if ((tmpTextLength = 0) or (tmpTextLength > 256)) then exit; // Merker setzen tmpAnsiString := Erzeuge8BitCharString(Text); i := 1; tmpPAnsiString := Addr(tmpAnsiString); tmpPAnsiChar := Addr(tmpAnsiString[i]); tmpLength := Length(tmpAnsiString); tmpPAnsiCharByte := PByte(tmpPAnsiChar); // CRC berechnen // function cal_crc_half(pin: PByte; len: Byte): Word; result := cal_crc_half(tmpPAnsiCharByte, tmpLength); end;
Delphi-Quellcode:
folgende Werte abrufbar (<STRG>+<F7>):
function cal_crc_half(pin: PByte; len: Byte): Word;
Delphi-Quellcode:
Ok, soweit läuft das also.
ptr = $B7980C
ptr^ = 81 Char(ptr^) = 'Q' Leider bin ich nun zurück bei meinem Ausgangsproblem - der CRC Berechnung. Ich erhalte als CRC Wert $D2$36 Laut der Doku der CRC-C-Routine sollte jedoch der CRC für "QPIGS" den Wert $B7$A9 lauten. Also ist entweder A - die "Übersetzung C->Delphi" nicht korrekt B - die Doku falsch C - oder ich mache noch einen völlig anderen Fehler Tipps und Hinweise sind ausdrücklich willkommen! |
AW: CRC von C in Delphi übersetze
Folgendes Programm liefert bei mir das korrekt Ergebnis
Delphi-Quellcode:
program CRCTest;
{$APPTYPE CONSOLE} {$R *.res} uses SysUtils; function cal_crc_half(pin: PByte; len: Byte): Word; var crc: Word; da: Byte; ptr: PByte; bCRCHign: Byte; bCRCLow: Byte; const crc_ta: array[0..15] of Word = ($0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7, $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef); begin ptr := pin; crc := 0; while (len > 0) do begin da := crc shr 12; // CRC high four bits crc := crc shl 4; // The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. crc := crc xor crc_ta[da xor (ptr^ shr 4)]; // Add the upper 4 bits of the CRC and the first half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. da := crc shr 12; // CRC high four bits crc := crc shl 4; // The CRC is shifted to the right by 4 bits, which is equivalent to taking the lower 12 bits of the CRC. crc := crc xor crc_ta[da xor (ptr^ and $0f)]; // Add the upper 4 bits of the CRC and the last half of the byte and look up the table to calculate the CRC, then add the remainder of the last CRC. Inc(ptr); Dec(len); end; bCRCLow := crc and $FF; bCRCHign := crc shr 8; if (bCRCLow = $28) or (bCRCLow = $0d) or (bCRCLow = $0a) then Inc(bCRCLow); if (bCRCHign = $28) or (bCRCHign = $0d) or (bCRCHign = $0a) then Inc(bCRCHign); crc := (bCRCHign shl 8) + bCRCLow; Result := crc; end; var Test: AnsiString; CRC: Word; begin try Test := 'QPIGS'; CRC := cal_crc_half(Pointer(Test), Length(Test)); writeln(IntToHex(CRC, 4)); ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. |
AW: CRC von C in Delphi übersetze
Zitat:
Delphi-Quellcode:
Die Übersetzung ist nahe am C-Code und bestätigt die Doku:
{$R-}
function CalcCRC(const pmcText: AnsiString): Word; const CRC_TABLE: array[0..15] of Word = ( $0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7, $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef); var p: PAnsiChar; crc: Word; tbl: Byte; crcLo: Byte; crcHi: Byte; begin if pmcText = '' then Exit(0); //=> crc := 0; p := Pointer(pmcText); while p^ <> #0 do begin tbl := crc shr 12; crc := crc shl 4; crc := crc xor CRC_TABLE[tbl xor (Ord(p^) shr 4)]; tbl := crc shr 12; crc := crc shl 4; crc := crc xor CRC_TABLE[tbl xor (Ord(p^) and $0f)]; Inc(p); end; crcLo := crc and $ff; crcHi := crc shr 8; if (crcLo = $28) or (crcLo = $0d) or (crcLo = $0a) then Inc(crcLo); if (crcHi = $28) or (crcHi = $0d) or (crcHi = $0a) then Inc(crcHi); crc := (crcHi shl 8) + crcLo; Result := crc; end; {$R+}
Delphi-Quellcode:
Bis bald...
var
txt: AnsiString; begin txt := 'QPIGS'; ShowMessage(CalcCRC(txt).ToHexString(4)); // => $B7A9 Thomas |
AW: CRC von C in Delphi übersetze
Guten Morgen!
sorry - am Freitag spät Abends war ich platt, aber ich hatte eine Lösung! Diese Seite hat mich auf die richtige Spur gebracht: ![]() Es handelt sich bei meiner Aufgabe um ein CCITT XMODEM CRC. So habe ich es dann gelöst:
Delphi-Quellcode:
Meinen ausdrücklichen Dank an alle Helfer hier!
function CAL_CRC_CCITT_XMODEM(data: PByte; len: Integer): Word;
const poly = $1021; var i, j: Integer; crc: Word; begin crc := 0; for i := 0 to len-1 do begin crc := crc xor (Word(data^) shl 8); for j := 0 to 7 do begin if (crc and $8000) > 0 then crc := (crc shl 1) xor poly else crc := crc shl 1; end; Inc(data); end; Result := crc; end; Es ist wirklich schön zu wissen, dass man nach Hilfe fragen kann und diese auch bekommt. Danke! Gruß und und eine schöne Woche Markus |
AW: CRC von C in Delphi übersetze
Zitat:
Zitat:
Delphi-Quellcode:
Teste deine Version mal gegen das C-Original für folgende Eingaben: YO, ZOL, DIHN, VRY77, PK20OM, 6A07EBH
{$R-}
function CalcCRC(pmPText: PAnsiChar): Word; const CRC_TABLE: array[0..15] of Word = ( $0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7, $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef); var idx: Byte; crc: WordRec absolute Result; begin Result := 0; if pmPText = Nil then Exit; //=> while pmPText^ <> #0 do begin idx := (Result shr 12) xor (Ord(pmPText^) shr 4); Result := (Result shl 4) xor CRC_TABLE[idx]; idx := (Result shr 12) xor (Ord(pmPText^) and $0f); Result := (Result shl 4) xor CRC_TABLE[idx]; Inc(pmPText); end; if (crc.Lo = $28) or (crc.Lo = $0d) or (crc.Lo = $0a) then Inc(crc.Lo); if (crc.Hi = $28) or (crc.Hi = $0d) or (crc.Hi = $0a) then Inc(crc.Hi); end; {$R+} var txt: AnsiString; begin for var i: Integer := 0 to 1000000 do begin txt := TSynTestCase.RandomIdentifier(1 + Random(20)); if CalcCRC(Pointer(txt)) <> CAL_CRC_CCITT_XMODEM(Pointer(txt), Length(txt)) then TSynLog.Add.Log(sllInfo, Utf8ToString(txt)); Bis bald... Thomas |
AW: CRC von C in Delphi übersetze
richtig, das ist NICHT der usrprünglich gepostete Code. Dieser war eine C nach Delphi Übersetzung des Codes aus der Dokumentation des Geräteherstellers.
Das Problem ist, dass die Doku schlicht falsch ist. Der richtige CRC Ansatz ist: Zitat:
Nochmals Dank für die Mühe. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz