Andry
Andry

Reputation: 13

Convert code from C to Delphi (work with DLL)

I need your help ;). Try to work with SDR-receiver (blade RF). I have dll (bladeRF.dll). I have some code on C (struct, enum and function). Code on C:

  typedef enum {
    BLADERF_BACKEND_ANY, 
    BLADERF_BACKEND_LINUX, 
    BLADERF_BACKEND_LIBUSB, 
    BLADERF_BACKEND_CYPRESS, 
    BLADERF_BACKEND_DUMMY = 100, 
   } bladerf_backend;

#define BLADERF_DESCRIPTION_LENGTH 33
#define BLADERF_SERIAL_LENGTH 33

struct bladerf_devinfo {
  bladerf_backend backend; 
  char serial[BLADERF_SERIAL_LENGTH]; 
  uint8_t usb_bus; 
  uint8_t usb_addr; 
  unsigned int instance; 
  char manufacturer[BLADERF_DESCRIPTION_LENGTH];
  char product[BLADERF_DESCRIPTION_LENGTH]; 
};

int CALL_CONV bladerf_get_device_list(struct bladerf_devinfo **devices);

I need transform this code on Delphi (Embarcadero 10.3). Can you help me? My code on Delphi:

Bladerf_Backend = (BLADERF_BACKEND_ANY,  BLADERF_BACKEND_LINUX,  BLADERF_BACKEND_LIBUSB,  BLADERF_BACKEND_CYPRESS,  BLADERF_BACKEND_DUMMY = 100);

PDevices = ^TDevices;
TDevices = record
  backend  : Bladerf_Backend;
  serial   : PAnsiChar;
  usb_bus  : Byte;
  usb_addr : Byte;
  instance : Integer;
  manufacturer :PAnsiChar;
  product :PAnsiChar;
end;

bladerf_get_device_list: function(point: PDevices): integer; cdecl;

//Try to execute
procedure TForm1.Button1Click(Sender: TObject);
var
  myblade : TDevices;
  pointer : PDevices;
begin
  pointer := @myblade;
  dongle_count:= bladerf_get_device_list(pointer);
  myblade := pointer^;
  Memo1.Lines.Add(myblade.serial);
  Memo1.Lines.Add(myblade.manufacturer);
  Memo1.Lines.Add(myblade.product);
end;

Function return value (1). But record has mistake values. Need your help. Thanks.

Upvotes: 0

Views: 169

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598299

Your translation of the char[] arrays is wrong. They need to be declared as array[0..high] of AnsiChar fixed arrays, not as PAnsiChar pointers.

Also, your declaration of bladerf_get_device_list() is wrong. The devices parameter is an output parameter, it returns to you a pointer to an array of devices, so the function needs to be able to alter a pointer that you give it, which means the parameter must be declared as either var or out of a pointer type. Without that, you are declaring devices as an input parameter instead, and thus the function can't alter your pointer.

Also, don't forget to call bladerf_free_device_list() when you are done using the list.

A literal translation of the C code would look more like this instead:

type
  bladerf_backend = (
    BLADERF_BACKEND_ANY, 
    BLADERF_BACKEND_LINUX, 
    BLADERF_BACKEND_LIBUSB, 
    BLADERF_BACKEND_CYPRESS, 
    BLADERF_BACKEND_DUMMY = 100, 
  );

const
  BLADERF_DESCRIPTION_LENGTH = 33;
  BLADERF_SERIAL_LENGTH = 33;

type
  pbladerf_devinfo = ^bladerf_devinfo;
  bladerf_devinfo = record
    backend: bladerf_backend; 
    serial: array[0..BLADERF_SERIAL_LENGTH-1] of AnsiChar; 
    usb_bus: UInt8;
    usb_addr: UInt8; 
    instance: UInt32; 
    manufacturer: array[0..BLADERF_DESCRIPTION_LENGTH-1] of AnsiChar;
    product: array[0..BLADERF_DESCRIPTION_LENGTH-1] of AnsiChar; 
  end;

const
  libbladeRF = 'libbladeRF.dll'; // or whatever the actual DLL filename is...

function bladerf_get_device_list(out devices: pbladerf_devinfo): Int32; cdecl; external libbladeRF;

procedure bladerf_free_device_list(devices: pbladerf_devinfo); cdecl; external libbladeRF;

And then you can use it like this:

{$POINTERMATH ON}
procedure TForm1.Button1Click(Sender: TObject);
var
  devices: pbladerf_devinfo;
  dongle_count, i: Int32;
begin
  dongle_count := bladerf_get_device_list(devices);
  if dongle_count < 0 then
    // error handling ...
  try
    for i := 0 to dongle_count-1 do
    begin
      Memo1.Lines.Add(String(devices[i].serial));
      Memo1.Lines.Add(String(devices[i].manufacturer));
      Memo1.Lines.Add(String(devices[i].product));
    end;
  finally
    bladerf_free_device_list(devices);
  end;
end;

Alternatively:

procedure TForm1.Button1Click(Sender: TObject);
var
  devices, device: pbladerf_devinfo;
  dongle_count, i: Int32;
begin
  dongle_count := bladerf_get_device_list(devices);
  if dongle_count < 0 then
    // error handling ...
  try
    device := devices;
    for i := 0 to dongle_count-1 do
    begin
      Memo1.Lines.Add(String(device^.serial));
      Memo1.Lines.Add(String(device^.manufacturer));
      Memo1.Lines.Add(String(device^.product));
      Inc(device);
    end;
  finally
    bladerf_free_device_list(devices);
  end;
end;

Upvotes: 2

Olivier
Olivier

Reputation: 18260

I won't give a complete answer here but some elements to help you. There are several issues with the code.

The record should be called TDevice (not TDevices) because it represents a single device. It should embed buffers for the strings (serial, manufacturer, product) with the correct sizes; putting pointers instead (PAnsiChar) won't work.

bladerf_get_device_list() takes a pointer to a pointer to a TDevice. That's not what you give it.

bladerf_get_device_list() allocates an array of TDevice and returns its size. You should check the returned value. After you're done using the array, you should use bladerf_free_device_list() to free it.

Upvotes: 2

Related Questions