Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Übersetzung von C nach Delphi (IOCTL) (https://www.delphipraxis.net/187686-uebersetzung-von-c-nach-delphi-ioctl.html)

Rads 22. Dez 2015 09:17


Übersetzung von C nach Delphi (IOCTL)
 
Morgen zusammen,

Ich musste den folgenden C-Code nach Delphi portieren, um den GPIO-Baustein anzusprechen.

C-Headerdatei:

Code:

/* Device type
#define GPIO_IOCTL_TYPE 0x9000

#define IOCTL_GPIO_WRITE \
    CTL_CODE( GPIO_IOCTL_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS)

#define IOCTL_GPIO_DIRECTION \
    CTL_CODE( GPIO_IOCTL_TYPE, 0x902, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

#define ...


Typedef Enum
{
    CONNECT_MODE_INVALID = 0,
    CONNECT_MODE_INPUT,
    CONNECT_MODE_OUTPUT,
    CONNECT_MODE_MAXIMUM = CONNECT_MODE_OUTPUT
} GPIO_CONNECT_IO_PINS_MODE;


typedef struct
{
    ULONG pin;
    union
    {
        ULONG data_B;
        GPIO_CONNECT_IO_PINS_MODE ConnectMode;
    } ABC;
} GPIO_PIN_PARAMS, *PGPIO_PIN_PARAMS;
Ich habe das so übersetzt:
Daraus ergibt sich dann in Delphi folgendes ?
Delphi-Quellcode:

const
  GPIO_IOCTL_TYPE = $9000;
  GPIO_Device    ='\\.\DEVICE';//Name
  IOCTL_GPIO_WRITE    = DWORD((GPIO_IOCTL_TYPE shl 16) or (2 shl 14) or ($901 shl 2) or 0);
  IOCTL_GPIO_DIRECTION = DWORD((GPIO_IOCTL_TYPE shl 16) or (2 shl 14) or ($902 shl 2) or 0);
  //...

(* ----------------------------------------------------------- *)
Type // Typedef Enum
  _GPIO_Connect_IO_PINS_MODE = (
    CONNECT_MODE_INVALID = 0,
    CONNECT_MODE_INPUT,
    CONNECT_MODE_OUTPUT,
    CONNECT_MODE_MAXIMUM = CONNECT_MODE_OUTPUT
  );
  GPIO_Connect_IO_PINS_MODE = _GPIO_Connect_IO_PINS_MODE;
(* ----------------------------------------------------------- *)
Type
  C_Enum =(Var_Cardinal, Var_GPIO);
(* ----------------------------------------------------------- *)
Type
  PABC = ^TABC;
  TABC = Record
    case _Pin : C_Enum of
      Var_Cardinal :(data_B: Cardinal);
      Var_GPIO    :(Var_ConnectMode: _GPIO_Connect_IO_PINS_MODE);
    end;
(* ----------------------------------------------------------- *)
Type // TypeDef struct
  PPGIO_PARAMS = ^TPGIO_PARAMS;
  TPGIO_PARAMS = record
    Pin : Cardinal;
    ABC : TABC;
  end;
Da der Zugriff (auf die GPIO-Schnittstelle) nicht funktioniert, wollte ich erstmal fragen ob meine Übersetzung stimmt??

Ich möchte einen Pin (z.B: 1) als Ausgang konfigurieren und ihn dann setzen:

Die Procedure sieht dann so aus:
Delphi-Quellcode:
var
  frmMain : TfrmMain;
  DeviceHandle : THandle;
  Params       : TPGIO_PARAMS;
  nReturn      : DWORD;


procedure TfrmMain.Button1Click(Sender: TObject);
begin
  DeviceHandle := CreateFile(Pchar(GPIO_Device), GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR
                  FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL OR
                  FILE_FLAG_NO_BUFFERING, 0);

  if DeviceHandle <> INVALID_HANDLE_VALUE then
  begin
    //Konfiguration (Direction): Output
    Params.Pin := 1; //Pin 1
    Params.ABC.Var_ConnectMode := Connect_Mode_OutPut; //Pin Direction is set to Output
    DeviceIoControl(DeviceHandle, IOCTL_GPIO_DIRECTION, @Params, SizeOf(Params), Nil, 0, nReturn, nil);
    //Zugriff :Write
    Params.ABC.Data_B := 0;//255 // Hier bin ich mir nicht sicher, was ich hier eingeben muss ???
    Params.Pin       := 1;
    DeviceIoControl(DeviceHandle, IOCTL_GPIO_Write, @Params, SizeOf(Params), Nil, 0, nReturn, nil);
    CloseHandle(DriveHandle);
  end
  else
  begin
    MessageDlg('Error!', mtWarning, [mbOK], 0);
  end;
end;
Der Compiler bringt keine Fehlermeldung, aber es funktioniert nicht..

Danke schonmal im Voraus für die Hilfe

4dk2 22. Dez 2015 10:35

AW: Übersetzung von C nach Delphi (IOCTL)
 
haste schonmal statt
Delphi-Quellcode:
T.. = Record
mit
Delphi-Quellcode:
T... = packed Record
probiert?

Neutral General 22. Dez 2015 11:02

AW: Übersetzung von C nach Delphi (IOCTL)
 
Zitat:

Delphi-Quellcode:
Params.ABC.Data_B := 0;//255 // Hier bin ich mir nicht sicher, was ich hier eingeben muss ???

Du weißt nicht was du eingeben musst, aber du bist dir sicher dass es nicht funktioniert?
Das ist eben das Feld für die Daten die du an den Pin senden willst. Was für Daten das sind hängt wohl von der Funktion des Pins (bzw. dem was dahinter liegt) ab.
Also bist du dir sicher, dass die 0 in Data_B überhaupt etwas (merkbares/sichtbares) tut?

Oder gibt DeviceIoControl schon einen Fehlercode zurück?

grenni999 22. Dez 2015 12:01

AW: Übersetzung von C nach Delphi (IOCTL)
 
Eigentlich müsste es so sein, das Data_B ein Port ist. Auf einen Port werden meist 8 IO´s zusammengefasst.
Der Wert den du auf den Port zuweist, stellt in Binärschreibweise dann den Zustand der Pins dar.
Also wenn du dezimal 4 zuweist, ist das binär 0000 0100
und damit TRUE oder 1 an Pin 3.

Um nur einzellne Pins eines Ports unabhängig vom Zustand der restlichen Pins zu schalten, nimmt man eine Bitmaske und verknüpft den aktuellen Wert des Ports mit der Bitmaske und schreibt den Wert dann auf den Port.

Bitmaske für Pin 3 -> 0000 0100
ang. aktueller Zustand Data_B -> 1000 0011
Die beiden mit logisch ODER verknüpft ergibt 1000 0111
Und dies dann wieder auf Data_B zuweisen.
Dann ist Pin 3 gesetzt worden.

Rads 22. Dez 2015 12:17

AW: Übersetzung von C nach Delphi (IOCTL)
 
Danke schonmal für die Antworten :-)

Zitat:

haste schonmal statt
T.. = Record mit
T... = packed Record probiert?
Ja habe ich..

Zitat:

Also bist du dir sicher, dass die 0 in Data_B überhaupt etwas (merkbares/sichtbares) tut?
...
Nein. ich habe halt probiert. (0 war nur ein Beispiel. weil ich nicht weiß was ich da eingeben muss. Ist in der Dokumentation leider nicht beschrieben.

Zitat:

Oder gibt DeviceIoControl schon einen Fehlercode zurück?
Nein. Die Funktion wird immer erfolgreich ausgeführt. Es fehlt die (richtige) Zuweisung von Pin und Data_B

Zitat:

Eigentlich müsste es so sein, das Data_B ein Port ist. Auf einen Port werden meist 8 IO´s zusammengefasst.
Der Wert den du auf den Port zuweist, stellt in Binärschreibweise dann den Zustand der Pins dar.
Also wenn du dezimal 4 zuweist, ist das binär 0000 0100
und damit TRUE oder 1 an Pin 3.

Um nur einzellne Pins eines Ports unabhängig vom Zustand der restlichen Pins zu schalten, nimmt man eine Bitmaske und verknüpft den aktuellen Wert des Ports mit der Bitmaske und schreibt den Wert dann auf den Port.

Bitmaske für Pin 3 -> 0000 0100
ang. aktueller Zustand Data_B -> 1000 0011
Die beiden mit logisch ODER verknüpft ergibt 1000 0111
Und dies dann wieder auf Data_B zuweisen.
Dann ist Pin 3 gesetzt worden.
ich finde nirgends ein Beispiel
Danke. Ich probier's gleich

SMO 22. Dez 2015 14:58

AW: Übersetzung von C nach Delphi (IOCTL)
 
Delphi-Quellcode:
  TABC = Record
    case _Pin : C_Enum of
      Var_Cardinal :(data_B: Cardinal);
      Var_GPIO :(Var_ConnectMode: _GPIO_Connect_IO_PINS_MODE);
    end;
Ist dir klar, dass das Feld "Var_ConnectMode" hier das Feld "data_B" nicht komplett überdeckt?
Das könnte dein Problem verursachen oder auch nicht, aber du solltest dir dessen in jedem Fall bewusst sein.
Standardmäßig macht Delphi Aufzählungstypen (Enumerations) so klein wie möglich (8, 16, 32 Bits), in C dagegen sind sie automatisch 32 Bits, soweit ich weiß.
Benutze die Direktive {$MINENUMSIZE 4} vor der Deklaration des ersten Aufzählungstyps, damit er auch in Delphi denselben Speicherplatz belegt.

Sonst lässt nämlich eine Zuweisung wie
Delphi-Quellcode:
Params.ABC.Var_ConnectMode := Connect_Mode_OutPut;
ganze 3 Bytes von data_B unberührt, was durchaus Fehler verursachen kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:00 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