Using ccall for C function with out-parameter pointer to pointer to struct

Hi, I’m wrapping libfreenect into Julia. The excellent BinaryBuilder maintainers have helped me get a jll into Yggdrasil, but now I’m working on a more Julian wrapper.

One of the functions I’m wrapping takes a pointer to pointer to struct as an argument. Here’s the relevant parts of the C side.

typedef enum {
	TILT_STATUS_STOPPED = 0x00, /**< Tilt motor is stopped */
	TILT_STATUS_LIMIT   = 0x01, /**< Tilt motor has reached movement limit */
	TILT_STATUS_MOVING  = 0x04, /**< Tilt motor is currently moving to new position */
} freenect_tilt_status_code;

/// Data from the tilt motor and accelerometer
typedef struct {
	int16_t                   accelerometer_x; /**< Raw accelerometer data for X-axis, see FREENECT_COUNTS_PER_G for conversion */
	int16_t                   accelerometer_y; /**< Raw accelerometer data for Y-axis, see FREENECT_COUNTS_PER_G for conversion */
	int16_t                   accelerometer_z; /**< Raw accelerometer data for Z-axis, see FREENECT_COUNTS_PER_G for conversion */
	int8_t                    tilt_angle;      /**< Raw tilt motor angle encoder information */
	freenect_tilt_status_code tilt_status;     /**< State of the tilt motor (stopped, moving, etc...) */
} freenect_raw_tilt_state;

FREENECTAPI_SYNC int freenect_sync_get_tilt_state(freenect_raw_tilt_state **state, int index);
/*  Tilt state function, starts the runloop if it isn't running
    Args:
        state: Populated with an updated tilt state pointer
		    index: Device index (0 is the first)
    Returns:
        Nonzero on error.
*/

As you can see, the function freenect_sync_get_tilt_state accepts a pointer to pointer to struct, and will provide a struct for me to read at that pointer. From other documentation, this pointer is valid until the next time I call freenect_sync_get_tilt_state.

In Julia, I’ve tried to do:

struct RawTiltState
    accelerometer_x::Cshort
    accelerometer_y::Cshort
    accelerometer_z::Cshort
    tilt_angle::Cchar
    tilt_status::Cchar
end

index = 0
state = Ref{Ptr{RawTiltState}}(C_NULL)
ccall((:freenect_sync_get_tilt_state, :libfreenect_sync), Cint, (Ref{Ptr{RawTiltState}}, Cint), state, index)

I can see that the pointer gets populated after this call

julia> state
Base.RefValue{Ptr{RawTiltState}}(Ptr{RawTiltState} @0x00000000010d9280)

But when I try to interpret this as a Julia object, I get a segfault:

julia> unsafe_pointer_to_objref(state[])

signal (11): Segmentation fault

Thanks!

I think you’ll want unsafe_load(state[]).

That was exactly it. Thanks!

freenect_raw_tilt_state **state is a array of pointer to struct freenect_raw_tilt_state. Using unsafe_load(state) can only get the first element of the array. How to get the other elements ?

Using pointer arithmetics or unsafe_wrap to load the whole array.