1

I am re-engineering the DJI Robomaster S1 App in Python based on code in Golang (https://git.bug-br.org.br/bga/robomasters1/src/master/app/internal/dji/unity/bridge/wrapper). In this code they used a unitybridge.dll that does most of the communication with the robot. The communication with this dll mostly works through (ansynchronous) callbacks. I used ctypes for accessing the code in C.
I used a C-library "libffcall" that returns a pointer to a callback (also used in Go). Since the code is very complex I will make a small example here that should work, but doesn't. Normally this should create, init the bridge and start a connection (by sending a specific event). These all seem to work. When setting a callback when a specific event (chosen by me since it occurs every few seconds) occurs in the bridge nothing happens. \

alloc_helper.c: makes the callback by using libffcall. To make things as simple as possible, the callback just prints something:

#include <stdio.h>
#include "alloc_helper.h"
#include "event_callback_windows.h"
#include <stdlib.h>

callback_t alloc_callback_python(void* data) {
   
    return alloc_callback(&event_callback, data);
}

event_callback_windows.c: should be called by unitybridge.dll and will eventually call the python function (not done in this example)

void event_callback(void* context, va_alist alist) {
    prinf("This should print");
}

example.py: the values in the arguments are the same as in Go

from ctypes import *
import time

# load the C-code
dll = CDLL("./unitybridge.dll")
alloc_helper = CDLL("./alloc_helper.so")

# create bridge args: str name, bool debuggable
dll.CreateUnityBridge(c_char_p(b"Robomaster", c_int(1))

# init bridge (returns True if successfull)
b = dll.UnityBridgeInitialize()
print("BOOL after init: {}".format(b))

# send event that starts connection
# args: event_code, data, sub_type
dll.UnitySendEvent(c_unint64(100 << 32), None, 0)

# set returntype
alloc_helper.alloc_callback_python.restype = POINTER(c_int)

# make callback
cb = alloc_helper.alloc_callback_python(None) # None to make is as simple as possible

# set event callback
# args: event_code (when this events occurs: call cb), callback
dll.UnitySetEventCallback(c_uint(304 << 32), cb)

time.sleep(3) # to give the bridge some time to make callbacks

# uninit and destroy bridge
dll.UnityBridgeUninitialze() # typo is not a mistake -> defined that way in dll
dll.DestroyUnityBridge()
time.sleep(5)

This is my first post, so feel free to ask more information since I probably forgot some. I tried (almost) everything and really want to fix this.

Thanks in advance <3

ViktorVH
  • 11
  • 1
  • `ctypes` can directly wrap a Python function and pass it to a C call so this looks extra complicated. Also make sure to set `.argtypes` correctly on your functions. It is often the reason for failures and you won't have to wrap parameters in `ctypes` objects, such as `c_uint64(100<<32)`. If `.argtypes` is set correctly, `ctypes` will use the correct type to wrap Python objects. You'll have better luck with an answer if you can illustrate your problem with a [mcve]. Make a C `.so/.dll` with a similar interface with requiring a 3rd party library and reproduce the issue. – Mark Tolonen Sep 14 '20 at 21:25
  • FYI, callback example in Python: https://stackoverflow.com/a/56780695/235698 – Mark Tolonen Sep 15 '20 at 00:07
  • I fixed it yesterday. I didn't destroy the bridge for one run (out of ideas, was just trying some stuff) and somehow the next run it worked. But thank you for the answer. Also, as you said, the types really need to be correct which can be hard if you don't get an error message. – ViktorVH Sep 15 '20 at 12:18

0 Answers0