![]() |
BDV001 Protokoll und CheckSum
Hallo,
ich muss für einen Verpflegungsautomaten eine Anbindung schreiben und habe jetzt ein Problem beim Berechnen der CheckSum des Protokolls. Hier mal die Beschreibung aus der Doku des Protokolls Zitat:
Mit einem Münzer habe ich mal mitgeloggt, was der an den Automaten sendet und folgendes kommt heraus. Zitat:
Zitat:
Zitat:
Zitat:
Kann mir jemand weiterhelfen? Danke Sven |
Re: BDV001 Protokoll und CheckSum
am besten du frägst mal beim hersteller nach dem algo. nach. denke es macht nicht viel sinn, wenn wir hier herumraten... und unter "calculated" kann man einiges verstehen...
|
Re: BDV001 Protokoll und CheckSum
bin ich jetzt zu doof, oder paßt XOR doch? wohl auch zuviele nullen gesehn :shock:
und eine Addition Ergebnis := Byte1 + Byte2 + Byte3 + ... + Byte8; paßt och nicht. dieses "has a value equal to 0." scheint wohl Einfluß zu haben :gruebel: vielleicht hilft ja sowas in der Richtung? ![]() ![]() Aber den Hersteller zu Fragen wäre wohl doch bestimmt einfacher. PS: and und or kann so auf einfach verbindung nicht gehn > bei AND wäre immer ein 0, sobald auch nur ein Wert 0 ist (also eigentlich fast immer) > und bei OR wäre es immer 1, sobal auch nur ein Wert 1 ist (ebenfalls fast immer) und XOR schaltet das Bit um, sobald eine 1 vorkommt (also immer hin und her ... ungerade 1-bits-Anzahl = 1) "ignoring any overflow" weißt aber mehr auf eine Addition (oder andere Rechenweise) hin ... bei XOR/AND/OR gibt es ja keinen Überlauf. wobei hier die Ergebnise auch teilweise übereinstimmen
Code:
wis auf das Linke/Hi-Bit stimmt es doch mit einer addition (glaub ich) überein
Beispiel 1
10000001 Byte 1 00001010 Byte 2 00001011 Byte 3 00100000 Byte 4 00000000 Byte 5 10110000 Byte 6 00000101 Byte 7 00000000 Byte 8 1[color=#ff0000]0010101[/color] Ergebnis hi....lo-bit und wenn ich beim Hi-Bit keinen überlauf zulasse und nicht weiterrechne, dann kommt daauch die eins raus
Delphi-Quellcode:
W :=
// für Beispiel 1 ... bei Bsp2 paßt es wieder nicht :(
W: Word; W := Word(Byte1) + Byte2 + Byte3 + Byte3 + ... + Byte8; If W > $FF Then W := Byte(W) or $80 Else W := Byte(W); [add] ja, hab grad mal lange Weile ... also besser fragst du mal beim Hersteller :stupid: |
Re: BDV001 Protokoll und CheckSum
Ich verstehe die Anleitung so: Du addierst alle Bytes bis auf das Checksum Byte zusammen. Dabei darfst du nur immer Byte-weise addieren, irgendwelcher Überlauf geht wieder auf 0 + Rest. Wenn du das alles zusammen hast, dann ist die Checksum genau die Differenz die du brauchst, damit durch Addition direkt 0 rauskommt.
Also ein wenig Pseudocode:
Delphi-Quellcode:
Die übergebenen Datengröße müssen die reinen Rohdaten sein, ohne das Feld für die Checksumme (oder wenn doch mit Checksummenfeld, dann muss dieses mit 0 gefüllt sein).
function CalcChecksum(const AData: pointer; const ADataSize: integer): Byte;
var lPtr: PByte; lCheckSum: Integer; begin lPtr := AData; lCheckSum := 0; for i := 1 to ADataSize do begin Inc(lCheckSum, lPtr^); Inc(lPtr); lCheckSum := lCheckSum mod 256; end; result := 256 - lCheckSum; end; Diese Methode gibt's vor allem bei seriellen Protokollen und ein paar Dateiformaten. |
Re: BDV001 Protokoll und CheckSum
Danke für Eure Hilfe.
@Muetze1 Irgendwie habe ich ein Brett vor dem Kopf. Ich komme nicht drauf, wie ich Deine funktion benutzen soll, wie rufe ich die auf? Mit Pointern usw. habe ich es nicht so. Ich habe mal alle Bytes als Bits (0+1) nacheinander in ein Memo gestellt. 10000001000010100000101100100000000000001011000000 00010100000000 Die Funktion rufe ich dann wie folgt auf:
Delphi-Quellcode:
Kann man das so machen? Als Ergebnis kommt dann dezimal 88 raus. Beim Beispiel 1 ist die Prüfsumme aber dezimal 149.
Edit1.Text := IntToStr(CalcChecksum(PChar(Memo1.Lines[0]), Length(Memo1.Lines[0])))
Ich werde mal einen Kollegen anhauen, der das Protokoll besorgt hat, der soll da mal nachfragen. Sven |
Re: BDV001 Protokoll und CheckSum
Zitat:
Beispiel: Das Array sind die zu sendenden Daten, der letzte Eintrag im Array ist die Checksumme:
Delphi-Quellcode:
Wenn du die Daten mit 0 und 1 im Memo darstellst, dann machst du aus einem Bit 8 Bit, da 0 oder 1 jeweils ein Zeichen somit ein Byte darstellt. Dadurch verzerrst du die eigentlichen Informationen, du blähst die Daten auf das 8x ihrer eigentlichen Grösse auf. Somit kann da nichts richtiges mehr rauskommen, da du komplett andere Daten angibst.
procedure SendData;
var lData: packed array[5] of byte; begin lData[0] := $44; lData[1] := $55; // deine Daten halt lData[2] := $33; lData[3] := $33; lData[4] := CalcChecksum(lData[0], 4); Serial.SendBytes(lData); end; Du musst zwischen den Daten und der Formatierung der Daten zur Ausgabe unterscheiden. Letzteres sollte immer nur in eine Richtung gehen, also nur zur Ausgabe. Zitat:
|
Re: BDV001 Protokoll und CheckSum
Super Danke.
Ich mache schon seit zwei kompletten Tagen jeweils von ca. 09:00 bis ca. 23:00 Uhr da rum und hatte schon so viel getestet, dass ich im Moment wirklich nichts mehr verstehe. Du hast natürlich vollkommen recht, dass ich die Bytes nicht als String übergeben kann. Deine Funktion CalcChecksum funktioniert und die SendData musste ich wie folgt abändernund und habe sie mal für meine Beispiele angepasst und Dezimalzahlen anstatt Hexzahlen verwendet.
Delphi-Quellcode:
Meine vier Beispiel habe ich damit mal getestet und es kam immer die richtge Prüfsumme heraus. Ich werde das ganze mal in meine "richte" Applikation einbauen und dann noch mal direkt mit dem Automaten testen. Ich melde mich dann noch mal.
procedure SendData;
var lData: packed array[0..7] of byte; begin lData[0] := 129; lData[1] := 10; lData[2] := 11; lData[3] := 0; lData[4] := 1; lData[5] := 176; lData[6] := 5; lData[7] := 0; // Checksum = 180 Edit1.Text := CalcChecksum(@lData[0], 8); end; Sven |
Re: BDV001 Protokoll und CheckSum
Zitat:
Ansonsten musst du natürlich keine festen Arrays verwenden. Du hast ja bestimmt unterschiedlich Lange Daten. Dort wäre die Arbeit mit Pointern genauso möglich wie mit einem dynamischen Array. Nur nochmal zur Vollständigkeit:
Delphi-Quellcode:
Und wenn ich das richtig sehe, sollte das 8. Byte (Index 7) die Checksumme sein? dann kann man es in der Endapplikation gleich so zusammenfassen.
procedure SendData;
var lData: packed array of byte; begin SetLength(lData, 8); lData[0] := 129; lData[1] := 10; lData[2] := 11; lData[3] := 0; lData[4] := 1; lData[5] := 176; lData[6] := 5; lData[7] := 0; // Checksum = 180 Edit1.Text := CalcChecksum(@lData[0], length(lData)); end;
Delphi-Quellcode:
Wie ich zuvor schon geschrieben hatte: Das Byte mit der zu berechnenden CRC muss 0 sein, dann kann man den CRC Berechnungscode mit darüber laufen lassen. Man kann sich das auch sparen und das Byte nicht initialisieren und einfach direkt die CRC berechnen und zuweisen. Von daher auch length(lData)-1. Alternativ kann man sich die Subtraktion noch ersparen, wenn man high(lData) verwendet.
procedure SendData;
var lData: packed array of byte; begin SetLength(lData, 8); lData[0] := 129; lData[1] := 10; lData[2] := 11; lData[3] := 0; lData[4] := 1; lData[5] := 176; lData[6] := 5; lData[7] := CalcChecksum(@lData[0], length(lData)-1); end; Viel Erfolg! |
Re: BDV001 Protokoll und CheckSum
Alles OK. Es funktioniert jetzt auch in meiner Anwendung.
Ganz so einfach ist das ganze dann aber doch nicht, das Protokoll (von 1984 glaube ich) doch etwas umständlich ist. Heute würde ich das etwas anders machen. Hier mal der Code, mit dem ich das gesamte "DataFile" für Filetype 11 zusammenbaue.
Delphi-Quellcode:
Nochmals vielen Dank an Dich Muetze1. Ich habe zwar Deine Funktion noch nicht ganz verstanden, aber das versuche ich noch mal, wenn ich etwas klarer im Kopf bin. Heute mache ich da jetzt nichts mehr dran, am Montag geht es damit weiter.
procedure EncodeBDVMoney(Value: Real);
var cDigits: String; lData: array[0..7] of Byte; n: Byte; CheckSum: Byte; begin // Hier wird der Preis als 5 Digits übergeben FMessageList := FMessageList + AcceptBlockChar; //3Dh lData[0] := 129; // 1000 0001 - Low Nibble 0001 = Receiving Pripheral ident, 001 = VMC // - High Nibble 1000 = Transmitting Pripheral ident, 1000 = Master lData[1] := 10; // 0000 1010 - Datafile length in Bytes lData[2] := 11; // 0000 1011 - Filetype Identification Number = Filetype 11 // Wenn z.B. 20 Cent (€ 0,20) eingeworfen sind, dann soll das herauskommen 00020 cDigits := StrRight( '00000' + IntToStr(Round(Value * 100)), 5); lData[3] := (StrToInt(cDigits[4]) shl 4) or StrToInt(cDigits[5]); // Digit 2 + Digit 1 lData[4] := (StrToInt(cDigits[2]) shl 4) or StrToInt(cDigits[3]); // Digit 4 + Digit 3 // ExactChangeFlag + Dezimal Point Position if FExactChangeFlag then begin lData[5] := (11 shl 4) or StrToInt(cDigits[1]); // 11 = 1011 + Digit 5 end else begin lData[5] := (3 shl 4) or StrToInt(cDigits[1]);; // 3 = 0011 + Digit 5 end; // immer fest auf 5 Cent lData[6] := 5; // 0000 0101 Lowest Coin Real Currency Value BCD Digits 1 + 0 lData[7] := 0; // 0000 0000 Lowest Coin Real Currency Value BCD Digits 3 + 2 CheckSum := CalcChecksum(@lData[0], 8); // PID = Peripheral Identifier = $20 for n := 0 to 7 do begin FMessageList := FMessageList + chr( PID + (lData[n] and 15)); // + Low Nibble - Fh FMessageList := FMessageList + chr( PID + ((lData[n] and 240) shr 4)); // + High Nibble - F0f end; FMessageList := FMessageList + chr(PID + (CheckSum and 15)); FMessageList := FMessageList + chr(PID + 0); FMessageList := FMessageList + chr(PID + 0); FMessageList := FMessageList + chr(PID + ((CheckSum and 240) shr 4)); FMessageList := FMessageList + DataSyncChar; //39h end; Grüße Sven |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:24 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