[GELOEST] Einlesen von Binärdaten

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

[GELOEST] Einlesen von Binärdaten

Beitrag von photor »

Hallo Forum,

ich habe Daten, die in einen alten C-Programm in der folgende Struktur vorgehalten und als solche direkt binär gespeichert wurden:

Code: Alles auswählen

 
struct rl_date
{
   char         vers[6];        /* Versionsstring zur Erkennung (max. 5 Zeichen!!)*/
   char         name[128];      /* Name der Maschine */
/* allg. Maschienendaten */
   double       gewicht;        /* Gesamtgewicht (fahrfertig) in kg */
   double       sx;             /* Koordinaten des Schwerpunktes (m) */
   double       sy;
   double       radst;          /* Radstand (m) */
   double       flaeche;        /* Frontfl<E4>che (m^2) */
   double       cw;             /* cw-Wert */
   double       umfang;         /* Umfang des Antriebsrades (m) */
   double       mu;             /* Haftkoef. Rad-Stra<DF>e */
/* Getriebe- und Antriebsdaten */
   double       i_prim;         /* Prim<E4>r<FC>bersetzung */
   int          z_ritz;         /* # Z<E4>hne Ritzel */
   int          z_blatt;        /* # Z<E4>hne Kettenblatt */
   int          gaenge;         /* # G<E4>nge */
   double       i_getr[MAXGANG];/* die Getriebe-<DC>bersetzungen */
   double       i_ges[MAXGANG]; /* die Gesamt-<DC>bersetzungen */
   double       n_kuppl;        /* Einkupplungsdrehzahl (U/min) */
   double       n_schalt;       /* Schaltdrehzahl (U/min)*/
/* Kennlinien-Daten */
   int          pnt;            /* # St<FC>tzpunkte */
   double       n[MAXPNT];      /* Array mit den Drehzahlen */
   double       n_max;          /* Maximal-Drehzahl */
   double       p[MAXPNT];      /* Array mit der Leistung dazu */
   double       p_max;          /* maximale Leistung */
   double       n_p_max;        /* Drehzahl von P_max */
   double       m[MAXPNT];      /* Array mit dem Drehmoment */
   double       m_max;          /* maximales Drehmoment */
   double       n_m_max;        /* Drehzahl von M_max */
/* Umwelt-Daten */
   double       steigung;       /* Hangsteigung (%) */
   double       wind;           /* Windgeschwindigkeit (km/s) */
   double       fahrer;         /* Gewicht des Fahrers (kg) */
   double       zuladung;       /* Zuladung (kg) */
};
 


Diese versuche ich jetzt in einem FreePascal-Programm wieder einzulesen und habe dazu folgende Struktur definiert:

Code: Alles auswählen

 
type
  TRoadLoadData = record
    Vers : array[0..5] of char;
    //Name : string[127];
    Name : array[0..127] of char;
    //dummy1, dummy2 : char;
    Gewicht : double;   { Gewicht der Maschine in kg }
    sx, sy : double;    { Koordinaten des Schwerpunkts [m]}
    Radstand : double;  { Radstand [m] }
    Flaeche : double;   { Windwiderstandsflaeche [m²] }
    cw : double;        { Luftwiderstandsbeiwert (cw-Wert) [-] }
    Umfang : double;    { Radumfang Antriebsrad [m] }
    mu : double;        { Haftreibungskoeffizient Rad-Strasse [-] }
    { Getriebe- und Antriebsdaten }
    i_prim : double;
    z_ritzel : int32; { Anzahl der Zaehne auf dem Ritzel [-] }
    z_blatt : int32;  { Anzahl der Zaehne auf dem Kettenblatt [-] }
    n_gaenge : int32; { Anzahl Gaenge [-] }    { <----------- bis hierhin werden die Daten richtig eingelesen}
    z_ritzel : integer; { Anzahl der Zaehne auf dem Ritzel [-] }
    z_blatt : integer;  { Anzahl der Zaehne auf dem Kettenblatt [-] }
    n_gaenge : integer; { Anzahl Gaenge [-] }
    i_getriebe : array[1..MAXGANG] of double;
    i_ges : array[1..MAXGANG] of double;
    n_kuppl : double;   { Einkuppeldrehzahl [U/min] }
    n_schalt : double;  { Schaltdrehzahl [U/min] }
    { Kennliniendaten }
    pnt : integer;
    n : array[1..MAXPNT] of double;   { Array der Drehzahlen d. Stuetzpunkte }
    n_max : double;     { Maximaldrehzahl }
    p : array[1..MAXPNT] of double;     { Array mit der Leistung dazu }
    p_max : double;        { maximale Leistung }
    n_p_max : double;     { Drehzahl von P_max }
    m : array[1..MAXPNT] of double;     { Array Drehmoment-Kennlinie }
    m_max : double;        { maximales Drehmoment }
    n_m_max : double;     { Drehzahl von M_max }
    { Umwelt-Daten }
    Steigung : double;   { Hangsteigung [%] }
    Wind : double;        { Windgeschwindigkeit [km/h] }
    Gew_Fahrer : double;  { Gewicht des Fahrers [kg] }
    Gew_Zuladung : double;  { Zuladung [kg] }
  end;                                     
 

Eingelesen wird das ganze mit

Code: Alles auswählen

 
memBuffer := TMemoryStream.Create;
memBuffer.LoadFromFile (filename);
nbytes := memBuffer.Read(RoadLoadData,1 * SizeOf(RoadLoadData));
memBuffer.Free;
 


Bis zu der Markierten Stelle werden die Daten auch richtig eingelesen. Danach werden die Daten/Bytes wohl nicht mehr richtig zugeordnet. Ich habe mir mit die Binärdaten auch im Hex-Editor angesehen. Dort liegen die Bytes schön in der richtigen Reihenfolge und ich kann die Positionen des einzelnen Parameter richtig zuordnen.

Warum kommt die FreePascal-Routine aus dem Tritt?

Ciao,

Photor

PS: heutzutage würde man das wohl besser als ASCII oder im INI-File-Format speichern.
Zuletzt geändert von photor am Di 27. Okt 2015, 19:22, insgesamt 1-mal geändert.

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Einlesen von Binärdaten

Beitrag von Mathias »

Wie gross ist ein int in C, ist 16/32 oder sogar 64Bit ?

alten C-Programm

Wie alt ? Früher war ein int 16Bit.
int16 schon probiert ?

Vielleicht ist es auch ein Little/Big-Endian Problem.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Einlesen von Binärdaten

Beitrag von wp_xyz »

Außerdem würde ich beim Einlesen von binären Dateien die Records generell als "packed" deklarieren (TRoadLoadData = packed record), sonst werden die Record-Elemente an der Breite des Datenbusses ausgerichtet. Bei Nicht-8-Bit-System z.B. würden dann die beiden Bytes in

Code: Alles auswählen

 
type
  TDataRecord = record
    B1: byte;
    B2: Byte;
  end

im Speicher durch Füllbytes getrennt. Nur bei

Code: Alles auswählen

 
type
  TDataRecord = packed record
    B1: byte;
    B2: Byte;
  end;

steht B2 direkt hinter B1.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Einlesen von Binärdaten

Beitrag von Socke »

wp_xyz hat geschrieben:Außerdem würde ich beim Einlesen von binären Dateien die Records generell als "packed" deklarieren (TRoadLoadData = packed record), sonst werden die Record-Elemente an der Breite des Datenbusses ausgerichtet.

C führt auch ein Alignment durch. Besser wäre:

Code: Alles auswählen

{$PACKRECORDS C}

Damit ist das Alignment an den C-Standard angeglichen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

Mathias hat geschrieben:Wie gross ist ein int in C, ist 16/32 oder sogar 64Bit ?


Im hex-Editor sind die Integer 32-bit-ig im File ...

Wie alt ? Früher war ein int 16Bit.
int16 schon probiert ?

... weshalb ich als nächstes int32 probieren wollte. Das C-Programm ist bestimmt 15 Jahre alt (auf einem Linux von damals, also mit dem gcc compiliert).

Vielleicht ist es auch ein Little/Big-Endian Problem.
Auch schon dran gedacht; im Hex-Editor will er den Haken bei "Anzeige Little-Endian" haben. Ich weiß jetzt allerdings nicht genau, welche Endianess Lazarus (auf Linux) hat.

Danke auf jedenfall für die Tipps. Es gibt noch ein paar Enden an denen man noch zupfen kann.

Ciao,

Photor

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

Hallo wp_xyz, hallo Socke

sowas in der Art war auch mein Verdacht. Also werde ich das mit dem packed array bzw der Compiler-Direktive ausprobieren. Vielen Dank für den Hinweis; ich melde mich mit dem Ergebnis.

Ciao,

Photot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

wp_xyz hat geschrieben:

Code: Alles auswählen

 
type
  TDataRecord = packed record
    B1: byte;
    B2: Byte;
  end;

steht B2 direkt hinter B1.


Mit packed record geht es leider überhaupt nicht. Selbst die Felder, die bisher stimmten, zeigen die wildesten Werte :shock:

Die Definition der Integer als int32 ergibt das gleiche Ergebnis, wie integer; bei [i}int16[/i] sind auch die Integer-Werte selbst schon flasch. int32 (und auch integer) ist also schon die richtige Deklaration.

Fragt sich nur, warum die anschließenden double-Werte nicht richtig eingelesen werden (wahrscheinlich, weil nicht richtig ausgerichtet).

BTW: sizeof(RoadLoadData) liefert genau die Anzahl Bytes, die auch auf der Platte gespeichert sind.

Ciao,

Photor

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Einlesen von Binärdaten

Beitrag von wp_xyz »

Überprüfe nochmals die Pascal-Record-Definition. In der C-Version zähle ich nach "Name" 9 Double-Werte bis zum 1. Integer, in der Pascal-Version sind's nur 8.

[EDIT]
Kommando zurück: sx und sy stehen im Pascal-Record in derselben Zeile --> es sind auch 9 Double-Werte beim Pascal-Record.

[Noch ein EDIT]
Aber trotzdem: Nach "gaenge" unterscheiden sich die Record-Definitionen! In der Pascal-Definition werden z_ritzel, z_blatt, n_gaenge wiederholt.
Zuletzt geändert von wp_xyz am So 25. Okt 2015, 20:50, insgesamt 4-mal geändert.

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Einlesen von Binärdaten

Beitrag von Mathias »

Fragt sich nur, warum die anschließenden double-Werte nicht richtig eingelesen werden (wahrscheinlich, weil nicht richtig ausgerichtet).

Wie ich das sehe, ist das die Array mit den double.
Vielleicht hast du da noch eine Fehler eingebaut.
Die Char-Array am Anfang beginnst du mit 0, und die mit double mit 1.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Einlesen von Binärdaten

Beitrag von af0815 »

Was ist wenst du die werte mal, Wert für Wert liest und anschliessend erst für den record entscheidest. Vorteil du kannst schneller sehen ob die Werte stimmen.

Ist zwar IMHO mehr arbeit, geht aber vermutlich doch insgesammt schneller.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

wp_xyz hat geschrieben:[Noch ein EDIT]
Aber trotzdem: Nach "gaenge" unterscheiden sich die Record-Definitionen! In der Pascal-Definition werden z_ritzel, z_blatt, n_gaenge wiederholt.


Oh verdammt! Du hast recht. :o Allerdings ist das nur beim Kopieren hier in's Forum passiert - im File steht's nicht doppelt. Unten nochmal die Definition aus dem .pas-File in einem Schwung (und mit den auskommentierten Versuchen mit integer und int32 bzw. der letzte Versuch mit int16, der aber erst recht alles ):

Code: Alles auswählen

 
type
  TRoadLoadData = record
    Vers : array[0..5] of char;
    Name : array[0..127] of char;
    Gewicht : double;   { Gewicht der Maschine in kg }
    sx, sy : double;    { Koordinaten des Schwerpunkts [m]}
    Radstand : double;  { Radstand [m] }
    Flaeche : double;   { Windwiderstandsflaeche [m²] }
    cw : double;        { Luftwiderstandsbeiwert (cw-Wert) [-] }
    Umfang : double;    { Radumfang Antriebsrad [m] }
    mu : double;        { Haftreibungskoeffizient Rad-Strasse [-] }
    { Getriebe- und Antriebsdaten }
    i_prim : double;
    z_ritzel : int16; { Anzahl der Zaehne auf dem Ritzel [-] }
    z_blatt : int16;  { Anzahl der Zaehne auf dem Kettenblatt [-] }
    n_gaenge : int16; { Anzahl Gaenge [-] }
//    z_ritzel : integer; { Anzahl der Zaehne auf dem Ritzel [-] }
//    z_blatt : integer;  { Anzahl der Zaehne auf dem Kettenblatt [-] }
//    n_gaenge : integer; { Anzahl Gaenge [-] }
    i_getriebe : array[1..MAXGANG] of double;
    i_ges : array[1..MAXGANG] of double;
    n_kuppl : double;   { Einkuppeldrehzahl [U/min] }
    n_schalt : double;  { Schaltdrehzahl [U/min] }
    { Kennliniendaten }
    pnt : integer;
    n : array[1..MAXPNT] of double;   { Array der Drehzahlen d. Stuetzpunkte }
    n_max : double;     { Maximaldrehzahl }
    p : array[1..MAXPNT] of double;       { Array mit der Leistung dazu }
    p_max : double;               { maximale Leistung }
    n_p_max : double;     { Drehzahl von P_max }
    m : array[1..MAXPNT] of double;       { Array Drehmoment-Kennlinie }
    m_max : double;               { maximales Drehmoment }
    n_m_max : double;     { Drehzahl von M_max }
    { Umwelt-Daten }
    Steigung : double;  { Hangsteigung [%] }
    Wind : double;                { Windgeschwindigkeit [km/h] }
    Gew_Fahrer : double;  { Gewicht des Fahrers [kg] }
    Gew_Zuladung : double;  { Zuladung [kg] }
  end;
 
var
  RoadLoadData : TRoadLoadData;
 


Ciao,

Photor

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Einlesen von Binärdaten

Beitrag von wp_xyz »

Wenn du jetzt noch die Datei postest, könnte man sich das ganze näher ansehen. In ein zip gepackt müsste die Datei hochzuladen sein. Und dann bitte auch die Werte beilegen, die du z.B. für den 1. Record erwartest.
Zuletzt geändert von wp_xyz am Mo 26. Okt 2015, 17:11, insgesamt 1-mal geändert.

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

af0815 hat geschrieben:Was ist wenst du die werte mal, Wert für Wert liest und anschliessend erst für den record entscheidest. Vorteil du kannst schneller sehen ob die Werte stimmen.

Ist zwar IMHO mehr arbeit, geht aber vermutlich doch insgesammt schneller.


Moin Andreas AKA af0815,

Als Fehler-Such-Strategie hatte ich mir das auch schon überlegt - und werde das wohl auch probieren, wenn ich nicht so zum Ergebnis komme. Aber eleganter ist es im Endeffekt schon, den ganzen Pack Daten auf einen Schlag zu laden. Geschwindigkeit ist dabei auch nicht das Problem - bei einer Datensatzgröße von 1864 Bytes.

Ciao,

Photor

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Einlesen von Binärdaten

Beitrag von Mathias »

Hast du mein Post wegen der Array auch gesehen ?

Ist bei i_getriebe[1] der erste Fehler ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

wp_xyz hat geschrieben:Wenn du jetzt noch die Datei postest, könnte man sich das ganze näher ansehen. In ein zip gepackt müsste die Datei hochzuladen sein.


Eigentlich hast Du recht. Und bei einer Dateigröße von 1864 Bytes bringt das ZIPen auch nicht viel. Ich habe sie angehängt (bin aber nicht sicher, ob das klappt).

EDIT: OK, klappt wg. der Endung nicht. Also ein ZIP draus gemacht.

Ciao,

Photor
Dateianhänge
sr500.rlx.zip
(1.04 KiB) 67-mal heruntergeladen
Zuletzt geändert von photor am Mo 26. Okt 2015, 17:18, insgesamt 1-mal geändert.

Antworten