2016-08-05 63 views
0

我正在嘗試接口到一個軟件定義的接收器DLL,該DLL需要回調以提供接收到的I/Q數據。在Delphi中實現DLL回調

我可以調用DLL很好,但我無法弄清楚如何編寫回調。

這是主要的模塊的一部分:

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; 

這是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. 

任何人有這個回調,我可以用一個簡單的例子?

+0

這是相當令人費解。如果你能削減它,這將是一件好事。您沒有解決回叫的通話約定。我們只能看到一些類型。 –

+0

你的問題不清楚 – Sami

+0

因爲所有的Dll funcs都是stdcall,回調也應該是stdcall呢? – Fritzw

回答

4

根據libHackRF API documentationsource code,包裝單元中有一些錯誤。

首先,所有DLL函數都使用cdecl作爲Windows上的調用約定,而不是stdcall

其次,hackrf_start_rx()函數沒有聲明任何調用約定,因此它使用Delphi的默認register約定。與THackrf_sample__block_cb_fn相同。您需要將cdecl添加到他們的聲明中。

第三,使用var Pointerhackrf_transfer參數THackrf_sample__block_cb_fn與實際的hackrf_sample_block_cb_fn回調類型的簽名不匹配。正確的回調聲明應該更像這個:

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

hackrf_transfer本身需要聲明是這樣的(假設它尚未在uSETITypes單元中聲明):

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; 

哪兒了Trtlsdr_read_async_cb_t從哪裏來?這不是API的一部分。

與所有的說,適當的包裝單元的

現在看起來應該更像這個:

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. 

現在,你可以寫一個回調:

​​
+0

雷米 - 感謝您的意見。翻譯API調用很困難,至少可以說。不過,我確實有一個問題。 不應在設備列表如下所示: hackrf_device_list_t =記錄 然後 // hackrf_device_list_t = hackrf_device_list; –

+0

@SetiNet你*可以*這樣做。我所展示的是*文字*翻譯。 API聲明一個實際的'hackrf_device_list'結構,然後聲明一個'hackrf_device_list_t'別名。所以我也這樣做了。 –

+0

這就是讓我困惑的部分。該結構的API名稱是hackrf_device_list_t。我根本找不到那個別名。 –