AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Record mit variabler Länge

Ein Thema von oki · begonnen am 18. Dez 2009 · letzter Beitrag vom 19. Dez 2009
Antwort Antwort
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#1

Record mit variabler Länge

  Alt 18. Dez 2009, 12:47
Hi Leute!

Da ich nicht weis ob sowas überhaupt möglich ist möchte ich hier das Problem mal vorstellen. Kurz zur Erläuterung. Ich möchte einen Descriptor für ein USBDevice auslesen. Diesen bekomme ich als Zeiger auf ein ByteArray geliefert (mittels DLL Funktion) hier mal die Funktion:
Code:
DWORD (*MPUSBGetDeviceDescriptor)(HANDLE handle,      // Input
                               PVOID pDevDsc,      // Output
                               DWORD dwLen,        // Input
                               PDWORD pLength);    // Output

DWORD (*MPUSBGetConfigurationDescriptor)(HANDLE handle,      // Input
                               UCHAR bIndex,       // Input
                               PVOID pDevDsc,      // Output
                               DWORD dwLen,        // Input
                               PDWORD pLength);    // Output
Die Deskriptoren werden im Controller (PIC) wie folgt abgelegt:
Code:
/* Device Descriptor */
ROM USB_DEVICE_DESCRIPTOR device_dsc=
{
    0x12,                  // Size of this descriptor in bytes
    USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type
    0x0200,                // USB Spec Release Number in BCD format      
    0x00,                  // Class Code
    0x00,                  // Subclass code
    0x00,                  // Protocol code
    USB_EP0_BUFF_SIZE,         // Max packet size for EP0, see usb_config.h
    0x04D8,                // Vendor ID: 0x04D8 is Microchip's Vendor ID
    0x000c,                // Product ID: 0x0053
    0x0000,                // Device release number in BCD format
    0x01,                  // Manufacturer string index
    0x02,                  // Product string index
    0x00,                  // Device serial number string index
    0x01                    // Number of possible configurations
};

/* Configuration 1 Descriptor */
ROM BYTE configDescriptor1[]={
    /* Configuration Descriptor */
    0x09,//sizeof(USB_CFG_DSC),   // Size of this descriptor in bytes
    USB_DESCRIPTOR_CONFIGURATION,               // CONFIGURATION descriptor type
    0xD6,0x00,           // Total length of data for this cfg      changed on 14.12.2009 oki old Value 0x20, 0x00
    1,                     // Number of interfaces in this cfg
    1,                     // Index value of this configuration
    0,                     // Configuration string index
    _DEFAULT | _SELF,              // Attributes, see usb_device.h
    50,                    // Max power consumption (2X mA)
                     
    /* Interface Descriptor */
    0x09,//sizeof(USB_INTF_DSC),  // Size of this descriptor in bytes
    USB_DESCRIPTOR_INTERFACE,              // INTERFACE descriptor type
    0,                     // Interface Number
    0,                     // Alternate Setting Number
    28,                     // Number of endpoints in this intf (alle IN und OUT ohne Endpoint 0)
    0xFF,                  // Class code
    0xFF,                  // Subclass code
    0xFF,                  // Protocol code
    0,                     // Interface string index
   
    /* Endpoint Descriptor */
    0x07,                      /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,   //Endpoint Descriptor
    _EP01_OUT,                 //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,       //size
    4,                        //Interval
   
    0x07,                      /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,   //Endpoint Descriptor
    _EP01_IN,                  //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,       //size
    4,                         //Interval

   // Aditional Endpoints appanded on 14.12.2009 oki
    0x07,                      //sizeof(USB_EP_DSC)
    USB_DESCRIPTOR_ENDPOINT,   //Endpoint Descriptor
    _EP02_OUT,                 //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,       //size
    4,                        //Interval
   
    0x07,                      //sizeof(USB_EP_DSC)
    USB_DESCRIPTOR_ENDPOINT,   //Endpoint Descriptor
    _EP02_IN,                  //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,       //size
    4,                         //Interval
....
Die ganze Sache ist so organisiert, dass jeder Configuration-Deskriptor mehrere Interface-Deskriptoren und jeder Interface-Deskribtor mehrere Endpoint-Deskriptoren haben kann. Dies ist in der Struktur wie folgt definiert:

Code:
    /* Configuration Descriptor */
    0x09,//sizeof(USB_CFG_DSC),   // Size of this descriptor in bytes
    USB_DESCRIPTOR_CONFIGURATION,               // CONFIGURATION descriptor type
    0xD6,0x00,           // Total length of data for this cfg      changed on 14.12.2009 oki old Value 0x20, 0x00
    [color=#ff003f]1,                     // Number of interfaces in this cfg[/color]
    1,                     // Index value of this configuration
    0,                     // Configuration string index
    _DEFAULT | _SELF,              // Attributes, see usb_device.h
    50,                    // Max power consumption (2X mA)

    /* Interface Descriptor */
    0x09,//sizeof(USB_INTF_DSC),  // Size of this descriptor in bytes
    USB_DESCRIPTOR_INTERFACE,              // INTERFACE descriptor type
    0,                     // Interface Number
    0,                     // Alternate Setting Number
    [color=#ff003f]28,                     // Number of endpoints in this intf (alle IN und OUT ohne Endpoint 0)[/color]
    0xFF,                  // Class code
    0xFF,                  // Subclass code
    0xFF,                  // Protocol code
    0,                     // Interface string index
Blöd, ich wollte es so schön farbig machen, aber da stehen nur die Tags. Es geht um diese beiden Einträge:
Code:
    1,                     // Number of interfaces in this cfg
...
    28,                     // Number of endpoints in this intf (alle IN und OUT ohne Endpoint 0)
Dort ist jeweils angegeben, wie viele Interfaces und jeweils wie viele Endpoints kommen.

Nun dachte ich mir, nichts leichter als dass, legst du dir die passenden Records an. Gedacht, getan:
Delphi-Quellcode:
  TEndPointDescriptor = packed record
    Length : Byte; // sollte 0x07 sein
    EndpointDescriptor : Byte; // Endpoint Deskriptor (Typangabe)
    EndpointAddress : Byte; // Endpoint Address (IN0-IN15 0x80 - 0x8F; OUT0-OUT15 0x00 - 0x0F)
    Attributes : TControlTransfer; // _BULK, _INT, _ISO, and _CTRL
    BufferSize : Word; // 8, 16, 32 Byte; as Byte Array "64,0"
    Intervall : Byte; // Polling Intervall
  end;

  TInterfaceDescriptor = packed record
    Length : Byte; // sollte 0x09 sein
    InterfaceDescriptor : Byte; // Interface Deskriptor (Typangabe)
    InterfaceNumber : Byte; // Interface Nummer
    AlternateSettingNumber : Byte; // Alternate Setting Number
    EndpointCount : Byte; // Number of Endpoints (exclude Endpoint 0)
    ClassCode : Byte;
    SubClassCode : Byte;
    ProtokollCode : Byte;
    InterfaceStringIndex: Byte;
// EndPoints : Array[EndpointCount] of TEndPointDescriptor;
  end;

  TConfigurationDescriptor = packed record
    Lengt : Byte; // sollte 0x09 sein
    ConfigurationDescriptor : Byte; // Typangabe
    TotalLength : Word; // Gesamtlänge des Descriptors as Byte Array "xx,0"
    InterfaceCount : Byte;
    ConfigurationIndex : Byte; // Index of this Configuration
    ConfigurationStringIndex : Byte;// Configuration string index
    Attributes : Byte; // _DEFAULT, _SELF ...
    PowerConsumtion : Byte; // Max power consumption (2X mA)
// IterfaceDescriptors : Array[InterfaceCount] of TInterfaceDescriptor;
  end;
Tja, böse Falle. Ihr seht schon meine auskommentierten Zeilen in den Records. Mir war dann eigentlich gleich klar, dass das so nicht geht, hab es aber mal da auskommentiert gelassen, damit ihr seht, wo mein Problem steckt.

Hat jemand eine Idee wie ich das hinbekommen kann? Mein Ziel war es eigentlich einen Zeiger auf eine Recordvariable vom Typ TConfigurationDescriptor zu übergeben und dann schön sauber alles parat zu haben. Natürlich kann ich die auskommentierten Zeilen auch als dynamische Arrays anlegen und mittels Funktion das ByteArray scheibchenweise in die Records gießen und zur Laufzeit die Längen der Arrays setzen.

Aber vielleicht gibt es ja auch eine richtig trickreiche Idee die mir nicht einfällt?

Ich dank euch schon mal für die Mühe,

Gruß oki


[edit] Uppps, noch schnell hinten dran, aktuelle Projekt in Delphi 2010! [/edit]
42
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#2

Re: Record mit variabler Länge

  Alt 18. Dez 2009, 16:39
Delphi-Quellcode:
type
  PEndPointDescriptor = ^TEndPointDescriptor;
  TEndPointDescriptor = packed record
    Length : Byte; // sollte 0x07 sein
    EndpointDescriptor : Byte; // Endpoint Deskriptor (Typangabe)
    EndpointAddress : Byte; // Endpoint Address (IN0-IN15 0x80 - 0x8F; OUT0-OUT15 0x00 - 0x0F)
    Attributes : TControlTransfer; // _BULK, _INT, _ISO, and _CTRL
    BufferSize : Word; // 8, 16, 32 Byte; as Byte Array "64,0"
    Intervall : Byte; // Polling Intervall
  end;

  PInterfaceDescriptor = ^TInterfaceDescriptor;
  TInterfaceDescriptor = packed record
    Length : Byte; // sollte 0x09 sein
    InterfaceDescriptor : Byte; // Interface Deskriptor (Typangabe)
    InterfaceNumber : Byte; // Interface Nummer
    AlternateSettingNumber : Byte; // Alternate Setting Number
    EndpointCount : Byte; // Number of Endpoints (exclude Endpoint 0)
    ClassCode : Byte;
    SubClassCode : Byte;
    ProtokollCode : Byte;
    InterfaceStringIndex: Byte;
  private
    function GetItem(AIndex: Integer): PEndPointDescriptor;
    function GetEndPoint(AIndex: Integer): PEndPointDescriptor;
  public
    function GetSize: Integer;
    property EndPoints[AIndex: Integer]: PEndPointDescriptor read GetEndPoint;
  end;

  PConfigurationDescriptor = ^TConfigurationDescriptor;
  TConfigurationDescriptor = packed record
    Length : Byte; // sollte 0x09 sein
    ConfigurationDescriptor : Byte; // Typangabe
    TotalLength : Word; // Gesamtlänge des Descriptors as Byte Array "xx,0"
    InterfaceCount : Byte;
    ConfigurationIndex : Byte; // Index of this Configuration
    ConfigurationStringIndex : Byte;// Configuration string index
    Attributes : Byte; // _DEFAULT, _SELF ...
    PowerConsumtion : Byte; // Max power consumption (2X mA)
  private
    function GetItem(AIndex: Integer): PInterfaceDescriptor;
    function GetIterfaceDescriptor(AIndex: Integer): PInterfaceDescriptor;
  public
    function GetSize: Integer;
    property IterfaceDescriptors[AIndex: Integer]: PInterfaceDescriptor read GetIterfaceDescriptor;
  end;

implementation

{ TConfigurationDescriptor }

function TConfigurationDescriptor.GetItem(AIndex: Integer): PInterfaceDescriptor;
var
  i: Integer;
begin
  Result := @Self;
  Inc(LongWord(Result), Self.Length);
  for i := 0 to AIndex - 1 do
    Inc(LongWord(Result), Result^.GetSize);
end;

function TConfigurationDescriptor.GetIterfaceDescriptor(
  AIndex: Integer): PInterfaceDescriptor;
begin
  if (AIndex >= 0) and (AIndex < InterfaceCount) then
    Result := GetItem(AIndex)
  else
    Result := nil; // oder Exception auslösen
end;

function TConfigurationDescriptor.GetSize: Integer;
begin
  Result := LongWord(GetItem(InterfaceCount)) - LongWord(@Self);
end;

{ TInterfaceDescriptor }

function TInterfaceDescriptor.GetEndPoint(AIndex: Integer): PEndPointDescriptor;
begin
  if (AIndex >= 0) and (AIndex < EndpointCount) then
    Result := GetItem(AIndex)
  else
    Result := nil; // oder Exception auslösen
end;

function TInterfaceDescriptor.GetItem(AIndex: Integer): PEndPointDescriptor;
var
  i: Integer;
begin
  Result := @Self;
  Inc(LongWord(Result), Self.Length);
  for i := 0 to AIndex - 1 do
    Inc(LongWord(Result), Result^.Length);
end;

function TInterfaceDescriptor.GetSize: Integer;
begin
  Result := LongWord(GetItem(EndpointCount)) - LongWord(@Self);
end;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.105 Beiträge
 
Delphi 12 Athens
 
#3

Re: Record mit variabler Länge

  Alt 18. Dez 2009, 20:52
EndPoints : Array[0..0] of TEndPointDescriptor; ergibt ein statisches Array mit einem Fehld, aber ohne Bereichsprüfung.

Nun kann man also mit GetMem den Speicher für seinen Record reservieren und muß nur aufpassen, daß man genügend Speicher für sein Array reserviert.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#4

Re: Record mit variabler Länge

  Alt 19. Dez 2009, 00:41
Hallo,

ich würde eine Klasse konstruieren mit einem variablen array of byte für den record. Zuerst die ersten paar Bytes lesen und die Länge entnehmen, dann Array-Länge setzen und den ganzen Record lesen.

Zum Zugriff arbeitet man am besten mit Pointern wie in C und schreibt eine Methode für jeden Typ Descriptor, die sich an den gegebenen Pointern entlanghangelt und einen Pointer auf den gewünschten Descriptor zurückliefert. Das funktioniert auch im allgemeinsten Fall: in TTF-Dateien z.B. können Details wie Namen oder Glyphen im Prinzip irgendwo stehen - es gibt nur eine Headertabelle mit Pointern dahin, und dort stehen dann oft Sub-Tabellen mit Pointern. Wenn man es braucht, kann man auch die ganzen Daten in eine Baumstruktur einlesen, aber das lohnt sich nicht, wenn man nur ein bestimmtes Detail braucht.

Gruss Reinhard
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#5

Re: Record mit variabler Länge

  Alt 19. Dez 2009, 17:04
Hallo,

erst mal herzlichen Dank für eure Antworten. Mir gefällt Blups Code-Beispiel eigentlich am Besten. Es macht auch einen eleganten Eindruck. Ich denke so werde ich es testen.

@Himitsu: Auch wenn ich Blup's Variante nehmen werde habe ich mit deinem Hinweis zum Array mit den Grenzen [0..0] wieder was neues gelernt. Dank dafür.

@Reinhard: Ja, so hätte ich es gemacht, wenn keiner geantwortet hätte. Ich denke Blup's Beispiel realisiert diese Idee elegant mit den neuen Mitteln der Records. Ich hatte schon so was geaht und deshalb auch extra vermerkt, dass ich das Problem unter D2010 löse.

Nochmals herzlich Dank an alle,

Gruß oki
42
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:42 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz