2016-08-05 67 views
0

Ich versuche, eine Schnittstelle zu einer Software Defined Receiver DLL herzustellen, die einen Rückruf erhalten muss, um empfangene I/Q-Daten zu übermitteln.Implementieren eines DLL-Callbacks in Delphi

Ich kann die DLL gut, aber ich kann nicht herausfinden, wie Sie den Rückruf Code.

Dieser Teil des Hauptmoduls ist:

uses 
    uReceiverHackRFDLLWrapper; 

procedure TForm1.btnIDClick(Sender: TObject); 
var 
    strptr: PAnsiChar; 
begin 
    hackrf_board_init(); 
    strptr := hackrf_board_id_name(0); 
    lblName.Caption := 'Name: ' + strptr; 
end; 

Dies ist der Wrapper für die DLL:

unit uReceiverHackRFDLLWrapper; 

interface 

uses Windows, uSETITypes, sysutils; 

{$MINENUMSIZE 4} 

type 
    // Trtlsdr_read_async_cb_t = procedure(buf: PAnsiChar; len: UINT32; ctx: Pointer); 
    // [UnmanagedFunctionPointer(CallingConvention.StdCall)] 
    // public unsafe delegate int hackrf_sample_block_cb_fn(hackrf_transfer* ptr); /* Return 0 if OK or -1 if error to stop */ 
    THackrf_sample__block_cb_fn = function(var hackrf_transfer: Pointer): integer; 

function hackrf_board_id_name(index: integer): Pointer; stdcall; 
function hackrf_board_init(): integer; stdcall; 
function hackrf_open(var dev: THackRF_dev): integer; stdcall; 

function hackrf_start_rx(dev: THackRF_dev; cb: THackrf_sample__block_cb_fn; rx_ctx: Pointer): integer; 

implementation 

var 
    DLLLoaded: Boolean = False; 
    SaveExit: Pointer; 
    DLLHandle: THandle; 

function SampleCallBack(var hackrf_transfer: Pointer): integer; 
var 
    i: integer; 
begin 
    i := 12345; 
end; 

function GetModuleFileNameStr(Instance: THandle): string; 
var 
    buffer: array [0 .. MAX_PATH] of Char; 
begin 
    GetModuleFileName(Instance, buffer, MAX_PATH); 

    Result := extractfilepath(buffer); 
end; 

function hackrf_board_id_name; external 'libhackrf.dll' name 'hackrf_board_id_name'; 
function hackrf_board_init; external 'libhackrf.dll' name 'hackrf_init'; 
function hackrf_open; external 'libhackrf.dll' name 'hackrf_open'; 

// [DllImport(LibHackRF, EntryPoint = "hackrf_start_rx", CallingConvention = CallingConvention.StdCall)] 
// public static extern int hackrf_start_rx(IntPtr dev, hackrf_sample_block_cb_fn cb, IntPtr rx_ctx); 
function hackrf_start_rx; external 'libhackrf.dll' name 'hackrf_start_rx'; 

initialization 

DLLHandle := LoadLibrary('libhackrf.dll'); 

end. 

Wer ein einfaches Beispiel für diesen Rückruf haben, die ich verwenden kann?

+0

Das ist ziemlich schwer zu verstehen . Es wäre gut, wenn Sie es reduzieren könnten. Sie haben die Anrufkonvention für Rückruf nicht angesprochen. Wir können nur einige der Typen sehen. –

+0

Deine Frage ist unklar – Sami

+0

da alle Dll-Funktionen stdcall sind, sollte der Callback auch stdcall sein? – Fritzw

Antwort

4

Basierend auf den libHackRF API documentation und source code, gibt es ein paar Fehler in der Wrapper-Einheit.

Zuerst alle der DLL-Funktionen verwenden cdecl als Aufrufkonvention auf Windows, nichtstdcall.

Zweitens ist die hackrf_start_rx()-Funktion nicht mit einer Aufrufkonvention deklariert, so dass Delphi die Standardkonvention register verwendet. Gleiches mit THackrf_sample__block_cb_fn. Sie müssen ihren Deklarationen cdecl hinzufügen.

Drittens mit var Pointer für die hackrf_transfer Parameter von THackrf_sample__block_cb_fn nicht die Unterschrift des tatsächlichen hackrf_sample_block_cb_fn Callback-Typs entspricht. Die richtige Rückruf Erklärung soll eher wie diese stattdessen sein:

THackrf_sample__block_cb_fn = function(var ptr: hackrf_transfer): integer; cdecl; 

Wo hackrf_transfer selbst muss so etwas wie dies deklariert werden (vorausgesetzt, es nicht bereits in der uSETITypes Einheit erklärt):

type 
    phackrf_device = ^hackrf_device; 
    hackrf_device = record 
    end; 

    ... 

    hackrf_transfer = record 
    device: phackrf_device; 
    buffer: PByte; 
    buffer_length: Integer; 
    valid_length: Integer; 
    rx_ctx: Pointer; 
    tx_ctx: Pointer; 
    end; 

Wo haben Trtlsdr_read_async_cb_t kommen aus? Das ist nicht Teil der API.

Jetzt mit all dies gesagt wurde, sollte eine richtige Wrapper Einheit etwas mehr wie folgt statt aussehen:

unit uHackRF; 

interface 

{$MINENUMSIZE 4} 

type 
    hackrf_error = (
    HACKRF_SUCCESS = 0, 
    HACKRF_TRUE = 1, 
    HACKRF_ERROR_INVALID_PARAM = -2, 
    HACKRF_ERROR_NOT_FOUND = -5, 
    HACKRF_ERROR_BUSY = -6, 
    HACKRF_ERROR_NO_MEM = -11, 
    HACKRF_ERROR_LIBUSB = -1000, 
    HACKRF_ERROR_THREAD = -1001, 
    HACKRF_ERROR_STREAMING_THREAD_ERR = -1002, 
    HACKRF_ERROR_STREAMING_STOPPED = -1003, 
    HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004, 
    HACKRF_ERROR_OTHER = -9999, 
); 

    hackrf_board_id = (
    BOARD_ID_JELLYBEAN = 0, 
    BOARD_ID_JAWBREAKER = 1, 
    BOARD_ID_HACKRF_ONE = 2, 
    BOARD_ID_INVALID = 0xFF, 
); 

    hackrf_usb_board_id = (
    USB_BOARD_ID_JAWBREAKER = 0x604B, 
    USB_BOARD_ID_HACKRF_ONE = 0x6089, 
    USB_BOARD_ID_RAD1O = 0xCC15, 
    USB_BOARD_ID_INVALID = 0xFFFF, 
); 

    rf_path_filter = (
    RF_PATH_FILTER_BYPASS = 0, 
    RF_PATH_FILTER_LOW_PASS = 1, 
    RF_PATH_FILTER_HIGH_PASS = 2, 
); 

    transceiver_mode_t = (
    TRANSCEIVER_MODE_OFF = 0, 
    TRANSCEIVER_MODE_RX = 1, 
    TRANSCEIVER_MODE_TX = 2, 
    TRANSCEIVER_MODE_SS = 3, 
    TRANSCEIVER_MODE_CPLD_UPDATE = 4 
); 

    phackrf_device = ^hackrf_device; 
    hackrf_device = record 
    end; 

    hackrf_transfer = record 
    device: phackrf_device; 
    buffer: PByte; 
    buffer_length: Integer; 
    valid_length: Integer; 
    rx_ctx: Pointer; 
    tx_ctx: Pointer; 
    end; 

    read_partid_serialno_t = record 
    part_id: array[0..1] of UInt32; 
    serial_no: array[0..3] of UInt32; 
    end; 

    hackrf_device_list = record 
    serial_numbers: PPAnsiChar; 
    usb_board_ids: ^hackrf_usb_board_id; 
    usb_device_index: PInteger; 
    devicecount: Integer; 

    usb_devices: PPointer; 
    usb_devicecount: Integer; 
    end; 

    hackrf_device_list_t = hackrf_device_list; 
    phackrf_device_list_t = ^hackrf_device_list_t; 

    hackrf_sample_block_cb_fn = function(var transfer: hackrf_transfer): Integer; cdecl; 

function hackrf_init: Integer; cdecl; 
function hackrf_exit: Integer; cdecl; 

function hackrf_device_list: phackrf_device_list_t; cdecl; 
function hackrf_device_list_open(list: phackrf_device_list_t; idx: Integer; var device: phackrf_device): Integer; cdecl; 
procedure hackrf_device_list_free(list: phackrf_device_list_t); cdecl; 

function hackrf_open(var device: phackrf_device): Integer; cdecl; 
function hackrf_open_by_serial(const desired_serial_number: PAnsiChar; var device: phackrf_device): Integer; cdecl;; 
function hackrf_close(device: phackrf_device): Integer; cdecl; 

function hackrf_start_rx(device: phackrf_device; callback: hackrf_sample_block_cb_fn; rx_ctx: Pointer): Integer; cdecl; 
function hackrf_stop_rx(device: phackrf_device): Integer; cdecl; 

function hackrf_start_tx(device: phackrf_device; callback: hackrf_sample_block_cb_fn; tx_ctx: Pointer): Integer; cdecl; 
function hackrf_stop_tx(device: phackrf_device): Integer; cdecl; 

{ return HACKRF_TRUE if success } 
function hackrf_is_streaming(device: phackrf_device): Integer; cdecl; 

function hackrf_max2837_read(device: phackrf_device; register_number: UInt8; var value: UInt16): Integer; cdecl; 
function hackrf_max2837_write(device: phackrf_device; register_number: UInt8; value: UInt16): Integer; cdecl; 

function hackrf_si5351c_read(device: phackrf_device; register_number: UInt16; var value: UInt16): Integer; cdecl; 
function hackrf_si5351c_write(device: phackrf_device; register_number: UInt16; value: UInt16): Integer; cdecl; 

function hackrf_set_baseband_filter_bandwidth(device: phackrf_device; const bandwidth_hz: UInt32): Integer; cdecl; 

function hackrf_rffc5071_read(device: phackrf_device; register_number: UInt8; var value: UInt16): Integer; cdecl; 
function hackrf_rffc5071_write(device: phackrf_device; register_number: UInt8; value: UInt16): Integer; cdecl; 

function hackrf_spiflash_erase(device: phackrf_device): Integer; cdecl; 
function hackrf_spiflash_write(device: phackrf_device; const address: UInt32; const length: UInt16; const data: PByte): Integer; cdecl; 
function hackrf_spiflash_read(device: phackrf_device; const address: UInt32; const length: UInt16; data: PByte): Integer; cdecl; 

{ device will need to be reset after hackrf_cpld_write } 
function hackrf_cpld_write(device: phackrf_device; const data: PByte; const total_length: UInt32): Integer; cdecl; 

function hackrf_board_id_read(device: phackrf_device; var value: UInt8): Integer; cdecl; 
function hackrf_version_string_read(device: phackrf_device; version: PAnsiChar; length: UInt8): Integer; cdecl; 

function hackrf_set_freq(device: phackrf_device; const freq_hz: UInt64): Integer; cdecl; 
function hackrf_set_freq_explicit(device: phackrf_device; const if_freq_hz, lo_freq_hz: UInt64; const path: rf_path_filter): Integer; cdecl; 

{ currently 8-20Mhz - either as a fraction, i.e. freq 20000000hz divider 2 -> 10Mhz or as plain old 10000000hz (double) 
    preferred rates are 8, 10, 12.5, 16, 20Mhz due to less jitter } 
function hackrf_set_sample_rate_manual(device: phackrf_device; const freq_hz, divider: UInt32): Integer; cdecl; 
function hackrf_set_sample_rate(device: phackrf_device; const freq_hz: Double): Integer; cdecl; 

{ external amp, bool on/off } 
function hackrf_set_amp_enable(device: phackrf_device; const value: UInt8): Integer; cdecl; 

function hackrf_board_partid_serialno_read(device: phackrf_device; var read_partid_serialno: read_partid_serialno_t): Integer; cdecl; 

{ range 0-40 step 8d, IF gain in osmosdr } 
function hackrf_set_lna_gain(device: phackrf_device; value: UInt32): Integer; cdecl; 

{ range 0-62 step 2db, BB gain in osmosdr } 
function hackrf_set_vga_gain(device: phackrf_device; value: UInt32): Integer; cdecl; 

{ range 0-47 step 1db } 
function hackrf_set_txvga_gain(device: phackrf_device; value: UInt32): Integer; cdecl; 

{ antenna port power control } 
function hackrf_set_antenna_enable(device: phackrf_device; const value: UInt8): Integer; cdecl; 

function hackrf_error_name(errcode: hackrf_error): PAnsiChar; cdecl; 
function hackrf_board_id_name(board_id: hackrf_board_id): PAnsiChar; cdecl; 
function hackrf_usb_board_id_name(usb_board_id: hackrf_usb_board_id): PAnsiChar; cdecl; 
function hackrf_filter_path_name(const path: rf_path_filter): PAnsiChar; cdecl; 

{ Compute nearest freq for bw filter (manual filter) } 
function hackrf_compute_baseband_filter_bw_round_down_lt(const bandwidth_hz: UInt32): UInt32; cdecl; 
{ Compute best default value depending on sample rate (auto filter) } 
function hackrf_compute_baseband_filter_bw(const bandwidth_hz: UInt32): UInt32; 

implementation 

const 
    LibHackRF = 'libhackrf.dll'; 

function hackrf_init; external LibHackRF name 'hackrf_init'; 
function hackrf_exit; external LibHackRF name 'hackrf_exit'; 

function hackrf_device_list; external LibHackRF name 'hackrf_device_list'; 
function hackrf_device_list_open; external LibHackRF name 'hackrf_device_list_open'; 
procedure hackrf_device_list_free; external LibHackRF name 'hackrf_device_list_free'; 

function hackrf_open; external LibHackRF name 'hackrf_open'; 
function hackrf_open_by_serial; external LibHackRF name 'hackrf_open_by_serial'; 
function hackrf_close; external LibHackRF name 'hackrf_close'; 

function hackrf_start_rx; external LibHackRF name 'hackrf_start_rx'; 
function hackrf_stop_rx; external LibHackRF name 'hackrf_stop_rx'; 

function hackrf_start_tx; external LibHackRF name 'hackrf_start_tx'; 
function hackrf_stop_tx; external LibHackRF name 'hackrf_stop_tx'; 

function hackrf_is_streaming; external LibHackRF name 'hackrf_is_streaming'; 

function hackrf_max2837_read; external LibHackRF name 'hackrf_max2837_read'; 
function hackrf_max2837_write; external LibHackRF name 'hackrf_max2837_write'; 

function hackrf_si5351c_read; external LibHackRF name 'hackrf_si5351c_read'; 
function hackrf_si5351c_write; external LibHackRF name 'hackrf_si5351c_write'; 

function hackrf_set_baseband_filter_bandwidth; external LibHackRF name 'hackrf_set_baseband_filter_bandwidth'; 

function hackrf_rffc5071_read; external LibHackRF name 'hackrf_rffc5071_read'; 
function hackrf_rffc5071_write; external LibHackRF name 'hackrf_rffc5071_write'; 

function hackrf_spiflash_erase; external LibHackRF name 'hackrf_spiflash_erase'; 
function hackrf_spiflash_write; external LibHackRF name 'hackrf_spiflash_write'; 
function hackrf_spiflash_read; external LibHackRF name 'hackrf_spiflash_read'; 

function hackrf_cpld_write; external LibHackRF name 'hackrf_cpld_write'; 

function hackrf_board_id_read; external LibHackRF name 'hackrf_board_id_read'; 
function hackrf_version_string_read; external LibHackRF name 'hackrf_version_string_read'; 

function hackrf_set_freq; external LibHackRF name 'hackrf_set_freq'; 
function hackrf_set_freq_explicit; external LibHackRF name 'hackrf_set_freq_explicit'; 

function hackrf_set_sample_rate_manual; external LibHackRF name 'hackrf_set_sample_rate_manual'; 
function hackrf_set_sample_rate; external LibHackRF name 'hackrf_set_sample_rate'; 

function hackrf_set_amp_enable; external LibHackRF name 'hackrf_set_amp_enable'; 

function hackrf_board_partid_serialno_read; external LibHackRF name 'hackrf_board_partid_serialno_read'; 

function hackrf_set_lna_gain; external LibHackRF name 'hackrf_set_lna_gain'; 

function hackrf_set_vga_gain; external LibHackRF name 'hackrf_set_vga_gain'; 

function hackrf_set_txvga_gain; external LibHackRF name 'hackrf_set_txvga_gain'; 

function hackrf_set_antenna_enable; external LibHackRF name 'hackrf_set_antenna_enable'; 

function hackrf_error_name; external LibHackRF name 'hackrf_error_name'; 
function hackrf_board_id_name; external LibHackRF name 'hackrf_board_id_name'; 
function hackrf_usb_board_id_name; external LibHackRF name 'hackrf_usb_board_id_name'; 
function hackrf_filter_path_name; external LibHackRF name 'hackrf_filter_path_name'; 

function hackrf_compute_baseband_filter_bw_round_down_lt; external LibHackRF name 'hackrf_compute_baseband_filter_bw_round_down_lt'; 
function hackrf_compute_baseband_filter_bw; external LibHackRF name 'hackrf_compute_baseband_filter_bw'; 

end. 

NOW, können Sie einen Rückruf schreiben:

uses 
    uHackRF; 

var 
    device: phackrf_device = nil; 

type 
    ELibHackRFError = class(Exception) 
    public 
    ErrorCode: Integer; 
    constructor CreateError(Err: Integer); 
    end; 

    constructor ELibHackRFError.CreateError(Err: Integer); 
    begin 
    inherited CreateFmt('LibHackRF Error %d', [Err]); 
    ErrorCode := Err; 
    end; 

function HackRFCheck(Res: Integer); 
begin 
    if Res < 0 then 
    raise ELibHackRFError.CreateError(Res); 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    HackRFCheck(hackrf_init()); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if device <> nil then 
    hackrf_close(device); 
    hackrf_exit(); 
end; 

procedure TForm1.btnIDClick(Sender: TObject); 
var 
    strptr: PAnsiChar; 
begin 
    strptr := hackrf_board_id_name(BOARD_ID_JELLYBEAN); 
    lblName.Caption := 'Name: ' + StrPas(strptr); 
end; 

function RxCallback(var transfer: hackrf_transfer): Integer; cdecl; 
begin 
    // use transfer members as needed... 
    // transfer.rx_ctx is a pointer to the TForm1 object... 
    //... 
    Result := HACKRF_SUCCESS; 
end; 

procedure TForm1.btnOpenClick(Sender: TObject); 
begin 
    if device = nil then 
    HackRFCheck(hackrf_open(device)); // or hackrf_device_list_open() or hackrf_open_by_serial() 
end; 

procedure TForm1.btnCloseClick(Sender: TObject); 
begin 
    if device <> nil then 
    begin 
    HackRFCheck(hackrf_close(device)); 
    device = nil; 
    end; 
end; 

procedure TForm1.btnStartRxClick(Sender: TObject); 
begin 
    if device <> nil then 
    HackRFCheck(hackrf_start_rx(device, RxCallback, Self)); 
end; 

procedure TForm1.btnStopRxClick(Sender: TObject); 
begin 
    if device <> nil then 
    HackRFCheck(hackrf_stop_rx(device)); 
end; 
+0

Remy - Danke für Ihre Eingabe. Übersetzen von API-Calls ist schwierig, um es gelinde auszudrücken. Ich hatte allerdings ein Problem. sollte nicht der Geräteliste wie folgt aussehen: hackrf_device_list_t = record Dann // hackrf_device_list_t = hackrf_device_list; –

+0

@SetiNet kannst du * so machen. Was ich gezeigt habe, ist eine * wörtliche * Übersetzung. Die API deklariert eine tatsächliche 'hackrf_device_list'-Struktur und deklariert dann einen' hashrf_device_list_t'-Alias ​​dafür. Also tat ich das Gleiche. –

+0

Das ist der Teil, der mich verwirrt. Der API-Name für die Struktur lautet hackrf_device_list_t.Ich kann diesen Alias ​​überhaupt nicht finden. –