gattlib/common/gattlib_callback_discovered...

111 lines
3.4 KiB
C

/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org>
*/
#include "gattlib_internal.h"
#if defined(WITH_PYTHON)
void gattlib_discovered_device_python_callback(gattlib_adapter_t* adapter, const char* addr, const char* name, void *user_data) {
struct gattlib_python_args* args = user_data;
PyObject *result;
// In case of Python support, we ensure we acquire the GIL (Global Intepreter Lock) to have
// a thread-safe Python execution.
PyGILState_STATE d_gstate = PyGILState_Ensure();
const char* argument_string;
// We pass pointer into integer/long parameter. We need to check the address size of the platform
if (sizeof(void*) == 8) {
argument_string = "(LssO)";
} else {
argument_string = "(IssO)";
}
PyObject *arglist = Py_BuildValue(argument_string, adapter, addr, name, args->args);
if (arglist == NULL) {
GATTLIB_LOG(GATTLIB_ERROR, "Could not convert argument list to Python arguments");
PyErr_Print();
goto ON_ERROR;
}
#if PYTHON_VERSION >= PYTHON_VERSIONS(3, 9)
result = PyObject_Call(args->callback, arglist, NULL);
#else
result = PyEval_CallObject(args->callback, arglist);
#endif
Py_DECREF(arglist);
if (result == NULL) {
GATTLIB_LOG(GATTLIB_ERROR, "Python discovered device handler has raised an exception.");
PyErr_Print();
}
ON_ERROR:
PyGILState_Release(d_gstate);
}
#endif
struct gattlib_discovered_device_thread_args {
struct _gattlib_adapter* gattlib_adapter;
char* mac_address;
char* name;
OrgBluezDevice1* device1;
};
static gpointer _gattlib_discovered_device_thread(gpointer data) {
struct gattlib_discovered_device_thread_args* args = data;
g_rec_mutex_lock(&args->gattlib_adapter->discovered_device_callback.mutex);
if (!gattlib_has_valid_handler(&args->gattlib_adapter->discovered_device_callback)) {
goto EXIT;
}
args->gattlib_adapter->discovered_device_callback.callback.discovered_device(
args->gattlib_adapter,
args->mac_address, args->name,
args->gattlib_adapter->discovered_device_callback.user_data
);
EXIT:
g_rec_mutex_unlock(&args->gattlib_adapter->discovered_device_callback.mutex);
free(args->mac_address);
if (args->name != NULL) {
free(args->name);
args->name = NULL;
}
free(args);
return NULL;
}
static void* _discovered_device_thread_args_allocator(va_list args) {
gattlib_adapter_t* gattlib_adapter = va_arg(args, gattlib_adapter_t*);
OrgBluezDevice1* device1 = va_arg(args, OrgBluezDevice1*);
struct gattlib_discovered_device_thread_args* thread_args = calloc(sizeof(struct gattlib_discovered_device_thread_args), 1);
thread_args->gattlib_adapter = gattlib_adapter;
thread_args->mac_address = strdup(org_bluez_device1_get_address(device1));
const char* device_name = org_bluez_device1_get_name(device1);
if (device_name != NULL) {
thread_args->name = strdup(device_name);
} else {
thread_args->name = NULL;
}
return thread_args;
}
void gattlib_on_discovered_device(gattlib_adapter_t* gattlib_adapter, OrgBluezDevice1* device1) {
gattlib_handler_dispatch_to_thread(
&gattlib_adapter->discovered_device_callback,
#if defined(WITH_PYTHON)
gattlib_discovered_device_python_callback /* python_callback */,
#else
NULL, // No Python support. So we do not need to check the callback against Python callback
#endif
_gattlib_discovered_device_thread /* thread_func */,
"gattlib_discovered_device" /* thread_name */,
_discovered_device_thread_args_allocator /* thread_args_allocator */,
gattlib_adapter, device1);
}