我正在尝试连接软件定义的接收器DLL,需要回调以提供接收的I / Q数据。
我可以调用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 :(得分:4)
基于libHackRF API documentation和source code,包装器单元中存在一些错误。
首先,所有DLL函数都使用cdecl
作为Windows上的调用约定, not stdcall
。
其次,hackrf_start_rx()
函数未使用任何调用约定声明,因此它使用Delphi的默认register
约定。与THackrf_sample__block_cb_fn
相同。您需要在其声明中添加cdecl
。
第三,对var Pointer
hackrf_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.
现在,你可以写一个回调:
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;