Autor |
Beitrag |
adina83
      
Beiträge: 29
|
Verfasst: Do 28.07.11 19:27
Hallo ich soll die Daten eines Controllers auslesen und habe dafür eine Tabelle mit
Nr. ,Adresse, Variablenname, Beschreibung, und Variablentyp.
Der Variablentyp variert wiederum zwischen unsigned int 8, signed / unsigned int 16, unsigned int 32 Variablen.
Wie kann ich diese Tabelle in Delphi mittels type / struct ansprechen.
Wäre der Variablentyp (zb. word) konstant so würde ich ein type anlegen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| type TVarTab = record nr : word; adr : word; name : string; descr : string; val : word; end;
VarTab : array [0..65] of TVarTab; |
Wie kann ich diese Typdeklaration mit unterschiedlichen Variablentypen erstellen.
Besten Dank im voraus. Moderiert von Narses: Topic aus VCL (Visual Component Library) verschoben am Fr 29.07.2011 um 00:40
|
|
motion
      
Beiträge: 295
XP, Linux
D7 Prof
|
Verfasst: Do 28.07.11 20:15
Meinst Du variante Records?
Google mal nach "variant records" bzw. "records with variant parts".
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 28.07.11 20:40
Da ist dann die Größe des Records allerdings so groß wie die größte Variante.
Mir ist aber noch nicht klar wo eigentlich das Problem ist, wie die Daten ausgelesen werden sollen und was genau bei dem Record das Problem mit den Integerwerten ist.
Wenn aus einem Speicher der Record als ganzes ausgelesen werden soll, würde ich eher eine sinnvollere Lösung wählen und das Auslesen manuell machen. Dann sind unterschiedliche Typen auch kein Problem, wenn man weiß wann welche benutzt werden.
Oder meinst du das so, dass du diese Tabelle hast und an diesen Speicherstellen Daten auslesen willst? Dann verstehe ich auch nicht wo das Problem mit unterschiedlichen Typen ist.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 28.07.11 21:47
Ich vermute mal (auf Grund fehlender Details), dass für die Software, die auf dem Controller läuft ein Mapfile bekannt ist, wo welche Variable im Speicher liegt. Anhand dieser Mapfile soll nun der Zustand des Kontrollers ausgelesen werden und der Inhalt der Variablen angezeigt werden.
Typisches Vorgehen: Man liest das Speicherabbild des Controllers soweit nötig vollständig aus (wenn man 20 Variablen hat, die beieinander liegen, aber paar Lücken aufweisen), liest man den Speicher vom Anfang der ersten Variable bis zum Ende der letzten inklusive der Lücken aus. Dieses Array of Byte betrachtete man nun unabhängig von der Variablen-Tabelle: Die Variablentabelle enthält nur Offset, Nr, Name, Desc UND den Datentyp.
Basierend auf Offset und Datentyp kann man sich dann eine Methode schreiben, die unter Angabe eines Speicherabbildes den Variablen-Wert ausliest oder setzt.
Kommt es auf Performance NICHT an, kann man für die Zugriffsmethoden Variants benutzen; benötigt man performance, schreibt man für den größten Datentyp (hier wahrscheinlich (un)signed Integer mit 32 Bit) eine Zugriffsmethode und nimmt für andere Datentypen eine entsprechende Konvertierung in der Zugriffsmethode vor.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
adina83 
      
Beiträge: 29
|
Verfasst: Fr 29.07.11 12:20
Danke für die Hinweise, war gestern leider nicht mehr online.
Die Adressen der Variablen werden mir auf Anfrage vom Controller mitgeteilt. Diese lese ich als erstes aus. Wieviel bytes ich ab einer Adresse auslesen muss sagt mir der Controller aber nicht. Das geht aus einem Protokoll hervor was mir vorliegt. Es kann durchaus möglich sein das die Adressen
weit auseinander liegen und somit macht es keinen Sinn die Lücken dazwischen zu Lesen (Performance-Gründe). Bsp.
Ich hab drei Variablen mit je drei Adressen aber unterschiedlichem Variablentyp (u16, s16, u32,). Somit müsste ich von Adresse 1 u 2 den 16Bit-Wert lesen und entspr interpretieren und von Adresse 3 den 16Bit-Wert und den nachfolgenden 16Bit-Wert und mir daraus einen 32Bit-Wert zusammenschieben.
Um die Variablen dann in einem Stringrid darzustellen wäre es vorteilhaft. Eine Struktur zu haben um über eine Schleife alle Werte mit Namen Bezeichnung und Adresse in dieses Stringgrid eintragen zu können. Wenn alle Variablen aus 16-Bit-Werten bestehen würden dann würde ich das wie folgt schreiben.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| with StringGrid_Eepdata do begin RowCount:=8+3; for i:=0 to 8 do begin Cells[0,i+1]:=inttostr(VarTab[i].nr); Cells[1,i+1]:=VarTab[i].name; Cells[2,i+1]:=inttostr(VarTab[i].adr); Cells[2,i+1]:=inttostr(VarTab[i].val); Cells[4,i+1]:=VarTab[i]einheit; end; end; |
Problem ist das es sich dabei um ungefähr 300 Variablen dreht die gelesen und geschrieben werden sollen und ich nicht jede Variable einzeln behandeln möchte.
Ich hoffe das Problem ist jetzt genauer dargestellt und nun heissts "Mittag".
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 29.07.11 13:23
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97:
| type TVarType = (uint8, uint16be, uint16le, uint32be, uint32le, int8, int16be, int16le, int32be, int32le); TVariable = record Index: Integer; Offset: Integer; Name: String; Description: String; VarType: TVarType; end; TMemorySegment = record BaseAddr: Integer; SegmentSize: Integer; Data: Array of Byte; Valid: array of Boolean; end;
var ControllerMemory: array of TMemorySegment;
function IsSigned(VT: TVarType): Boolean; begin Result := VT in [int8, int16be, int16le, int32be, int32le]; end;
function GetSegmentByOffset(Addr): TMemorySegment; begin end;
function ReadByte(Offset: Integer): Byte; var M: TMemorySegment; begin M := GetSegmentByOffset(Offset); Offset := Offset - M.BaseAddr; If not M.Valid[Offset] Then Begin end; Restul := M.Data[Offset]; end;
function WriteByte(Offset: Integer; Value: Byte); begin end;
Function GetSignedVar(V: TVariable): Integer; begin Case V.VarType of uint8: Raise Exception.Create('Conflict in Signed/Unsigned'); uint16be: Raise Exception.Create('Conflict in Signed/Unsigned'); uint16le: Raise Exception.Create('Conflict in Signed/Unsigned'); uint32be: Raise Exception.Create('Conflict in Signed/Unsigned'); uint32le: Raise Exception.Create('Conflict in Signed/Unsigned'); int8: begin Result := ReadByte(V.Offset); If Result >= 128 Then Result := Result - 256; end; int16be: begin Result := ReadByte(V.Offset) shl 8 + ReadByte(V.Offset + 1); If Result >= 32768 Then Result := Result - 65536; end; int16le: begin Result := ReadByte(V.Offset) + ReadByte(V.Offset + 1) shl 8; If Result >= 32768 Then Result := Result - 65536; end; int32be: begin Result := ReadByte(V.Offset) shl 24 + ReadByte(V.Offset + 1) shl 16 + ReadByte(V.Offset + 2) shl 8 + ReadByte(V.Offset + 3); end; int32le: begin Result := ReadByte(V.Offset) + ReadByte(V.Offset + 1) shl 8 + ReadByte(V.Offset + 2) shl 16 + ReadByte(V.Offset + 3) shl 24; end; else Raise Exception.Create('Not Implemented!'); end; end;
Function GetUnsignedVar(V: TVariable): Integer; begin end;
|
Nutzung dann im StringGrid zur Anzeige des Wertes:
Delphi-Quelltext 1: 2: 3: 4:
| If IsSigned(V.VarType) Then SG.Cells[i, 3] := IntToStr(GetSignedValue(V)) else SG.Cells[i, 3] := Int64ToStr(GetUnsignedValue(V) and (Int64(1) shl 32 - 1)); |
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
adina83 
      
Beiträge: 29
|
Verfasst: Fr 29.07.11 15:36
Danke genau so etwas meinte ich.
Schönes WE.
|
|
|