Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

help with XS pointers

by Bpl (Scribe)
on Jul 30, 2020 at 22:01 UTC ( [id://11120089]=perlquestion: print w/replies, xml ) Need Help??

Bpl has asked for the wisdom of the Perl Monks concerning the following question:

Hi monkers, in these days I was building an XS library, based on the librtlsdr library ( github link: https://github.com/librtlsdr/librtlsdr ) for now, some functions works fine but the "rtlsdr_open" call gives me some problems. For starting the code (from the github library) referred to the call is:
RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index); # where rtlsdr_dev_t is initialized as: typedef struct rtlsdr_dev rtlsdr_dev_t;
I think that my implementation of rtlsdr_dev is wrong, in the XS code I wrote
int rtlsdr_open(dev, index) RTLSDRDevice_T **dev uint32_t index # where RTLSDRDEVICE_T is typedef rtlsdr_dev_t RTLSDRDevice_T;
and from the TYPEMAP file the structure are declared as:
RTLSDRDevice_T * T_PTRREF RTLSDRDevice_T ** T_PTRREF
now, the problem is that, when I run this code:
use SDR::RTLSDR qw(:all); # my library my $serial_number = "00000001"; # from dmesg output my $index = rtlsdr_get_index_by_serial( $serial_number ); # it returns + 0, this is not an error value so I think is good my $device = rtlsdr_get_device_name( $index ); print rtlsdr_open( $device , $index)
I have the following error:
SDR::RTLSDR::rtlsdr_close: dev is not of type RTLSDRDevice_TPtr at sdr +.pl line 7.
Now, I think that the result is related to some pointer error but also with:
print rtlsdr_open( \$device , $index)
I had the same error code. hope in some helps Thanks Edoardo M.

Replies are listed 'Best First'.
Re: help with XS pointers
by syphilis (Archbishop) on Jul 31, 2020 at 02:24 UTC
    If you're having trouble with the basic functionality, I would recommend that you get that basic functionality of your code sorted out and tested in an Inline::C script before you even write SDR::RTLSDR.
    That's an approach that has always worked quite well for me.

    It also means that you can provide a script that shows everything you're trying to do.
    It's pretty hard to work out exactly what you're doing from a few snippets.

    I assume your module will link to the librtlsdr library, and I'm wondering why your XS code appears to be creating/declaring its own rtlsdr_open() when that function is already (presumably) provided by that library and the librtlsdr header.

    Anyway, for an Inline::C script, you'd want something like:
    use strict; use warnings; use Inline C => Config => #CLEAN_AFTER_BUILD => 0, # BUILD_NOISY => 1, # display the compilation inc => '-I/path/to/librtlsdr_headers', libs => '-L/path/to/librtsldr_library, ; use Inline C => <<'EOC'; #include<librtlsdr_header.h> void foo(<args>) { /* do something that uses librtlsdr and print out a success/fail message */ } void bar(<args>) { /* do something else that uses librtlsdr and print out a success/fail message */ } EOC foo(); bar();
    Add more functionality and complexity as you get things working.
    Inline::C provides typemapping and just about everything else that XS provides. (See the Inline::C documentation and cookbook.)

    In the code section, you're essentially just writing C code - but perl API functions can also be used.

    Inline::C works by first creating an XS file, which you can find in the ./_Inline directory if you include CLEAN_AFTER_BUILD in the Config section of the script before building.

    Cheers,
    Rob
      OK, no problem. The xs code is as follows:
      #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include <rtl-sdr.h> typedef rtlsdr_dev_t * SDR__RTLSDR; MODULE = SDR::RTLSDR PACKAGE = SDR::RTLSDR PROTOTYPES: DISABLE const char * rtlsdr_get_device_name(index) uint32_t index int rtlsdr_get_device_usb_strings( index, manufact, product, serial) uint32_t index char *manufact char *product char *serial int rtlsdr_get_index_by_serial(serial) const char *serial int rtlsdr_open(dev, index) SDR::RTLSDR **dev uint32_t index int rtlsdr_close(dev) SDR::RTLSDR *dev int rtlsdr_set_xtal_freq(dev, rtl_freq, tuner_freq) SDR::RTLSDR *dev uint32_t rtl_freq uint32_t *tuner_freq int rtlsdr_get_xtal_freq(dev, rtl_freq, tuner_freq) SDR::RTLSDR *dev uint32_t *rtl_freq uint32_t *tuner_freq int rtlsdr_get_usb_strings(dev, manufact, product, serial) SDR::RTLSDR *dev char *manufact char *product char *serial int rtlsdr_write_eeprom(dev, data, offset, len) RTLSDRDevice_T *dev uint8_t *data uint8_t offset uint16_t len int rtlsdr_read_eeprom(dev, data, offset, len) SDR::RTLSDR *dev uint8_t *data uint8_t offset uint16_t len int rtlsdr_set_center_freq(dev, freq) SDR::RTLSDR *dev uint32_t freq uint32_t rtlsdr_get_center_freq(dev) SDR::RTLSDR *dev int rtlsdr_set_freq_correction(dev, ppm) SDR::RTLSDR *dev int ppm int rtlsdr_get_freq_correction(dev) SDR::RTLSDR *dev int rtlsdr_get_tuner_gains( dev, gains ) SDR::RTLSDR *dev int *gains int rtlsdr_set_tuner_gain(dev, gain) SDR::RTLSDR *dev int gain int rtlsdr_set_tuner_bandwidth(dev, bw) SDR::RTLSDR *dev uint32_t bw int rtlsdr_get_tuner_gain(dev) SDR::RTLSDR *dev int rtlsdr_set_tuner_if_gain(dev, stage, gain) SDR::RTLSDR *dev int stage int gain int rtlsdr_set_tuner_gain_mode(dev, manual) SDR::RTLSDR *dev int manual int rtlsdr_set_sample_rate(dev, rate) SDR::RTLSDR *dev uint32_t rate uint32_t rtlsdr_get_sample_rate(dev) SDR::RTLSDR *dev int rtlsdr_set_testmode(dev, on) SDR::RTLSDR *dev int on int rtlsdr_set_agc_mode(dev, on) SDR::RTLSDR *dev int on int rtlsdr_set_direct_sampling(dev, on) SDR::RTLSDR *dev int on int rtlsdr_set_offset_tuning(dev, on) SDR::RTLSDR *dev int on int rtlsdr_get_offset_tuning(dev) SDR::RTLSDR *dev int rtlsdr_reset_bufferrtl(dev) SDR::RTLSDR *dev int rtlsdr_read_sync(dev,buf,len, n_read); SDR::RTLSDR *dev void *buf int len int *n_read
      while the TYMAP file is:
      TYPEMAP RTLSDRDevice_T * T_PTROBJ SDR::RTLSDR T_PTROBJ const char * T_PV int * T_PV char * T_PV unsigned long int T_U_LONG uint8_t T_U_SHORT uint8_t * T_U_SHORT uint16_t T_U_SHORT uint32_t * T_U_SHORT uint32_t T_U_SHORT
      the library code is:
      #ifndef __RTL_SDR_H #define __RTL_SDR_H #ifdef __cplusplus extern "C" { #endif #include <stdint.h> #include <rtl-sdr_export.h> typedef struct rtlsdr_dev rtlsdr_dev_t; RTLSDR_API uint32_t rtlsdr_get_device_count(void); RTLSDR_API const char* rtlsdr_get_device_name(uint32_t index); /*! * Get USB device strings. * * NOTE: The string arguments must provide space for up to 256 bytes. * * \param index the device index * \param manufact manufacturer name, may be NULL * \param product product name, may be NULL * \param serial serial number, may be NULL * \return 0 on success */ RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index, char *manufact, char *product, char *serial); /*! * Get device index by USB serial string descriptor. * * \param serial serial string of the device * \return device index of first device where the name matched * \return -1 if name is NULL * \return -2 if no devices were found at all * \return -3 if devices were found, but none with matching name */ RTLSDR_API int rtlsdr_get_index_by_serial(const char *serial); RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index); RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev); /* configuration functions */ /*! * Set crystal oscillator frequencies used for the RTL2832 and the tun +er IC. * * Usually both ICs use the same clock. Changing the clock may make se +nse if * you are applying an external clock to the tuner or to compensate th +e * frequency (and samplerate) error caused by the original (cheap) cry +stal. * * NOTE: Call this function only if you fully understand the implicati +ons. * * \param dev the device handle given by rtlsdr_open() * \param rtl_freq frequency value used to clock the RTL2832 in Hz * \param tuner_freq frequency value used to clock the tuner IC in Hz * \return 0 on success */ RTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_fr +eq, uint32_t tuner_freq);
      (this is only the first part, think that I need only the rtlsdr_open function, the other function before it works and return the correct output. Regards Edoardo M.
Re: help with XS pointers
by bliako (Monsignor) on Jul 31, 2020 at 11:32 UTC

    After you posted more code, I can see that:

    const char * rtlsdr_get_device_name(index) uint32_t index

    And so this:

    my $device = rtlsdr_get_device_name( $index );

    returns the device name as a string, given device index (integer), and not a pointer to a rtlsdr_dev_t structure as you assumed.

    Given:

    int rtlsdr_open(dev, index) SDR::RTLSDR **dev uint32_t index

    I am guessing that one must open a device by specifying the index. The function rtlsdr_open() should probably return the status as an integer and allocates internally the device, that's what I assume when it tells you to supply the double pointer for device: "Give me a memory location and I will do the internal decoration".

    Here is a stand-alone C example to demonstrate this pattern:

    #include <stdio.h> #include <malloc.h> typedef struct { int a; } s_t; int open_device(s_t **dev, int index); int main(void){ s_t *device = NULL; open_device(&device, 1); printf("A=%d\n", device->a); free(device); } int open_device(s_t **dev, int index){ *dev = (s_t *)malloc(sizeof(s_t)); (*dev)->a = 42; return 1; }

    How does that translate to Perl? Hmmm again a guess:

    my $serial_number = "00000001"; # from dmesg output my $index = rtlsdr_get_index_by_serial( $serial_number ); # it returns + 0, this is not an error value so I think is good my $name = rtlsdr_get_device_name( $index ); print "device name '$name'\n"; my $device = undef; # = SDL::...->new() ??? # i don't think so/how? my $status = rtlsdr_open( \$device , $index) print "status $status for index $index\n";

    cool project!

    bw, bliako

      Hi bliako, yes, you're right when assign the NULL value to the $device variable, yesterday I found a similar example from this site: http://sdr.f4gkr.org/trac/browser/gkSDR/Logiciel/rwhw/rtlsdr_iface.cpp?rev=9 which confirm also the idea of the status code (the correct return would be "0"). the initial idea was right but the return code is the same as before:
      device name 'Generic RTL2832U OEM' SDR::RTLSDR::rtlsdr_open: dev is not of type RTLSDRDevice_TPtrPtr at s +dr.pl line 13.
      Regards Edoardo M.

        Does that make sense at all?

        my $device = SDR::RTLSDR->new(); my $status = rtlsdr_open( \$device , $index); print "status $status for index $index\n";

        also see this example perlxstypemap (search for T_PTROBJ_SPECIAL) and the Netconfig example in perlxs

        Does the error message you cited corresponds for the typemap source code you have shown?

Re: help with XS pointers
by perlfan (Vicar) on Jul 31, 2020 at 01:35 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11120089]
Approved by johngg
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (3)
As of 2024-04-26 04:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found