-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
python: Fix callback back to native gattlib
- Loading branch information
1 parent
ec9e5cd
commit 9fd8030
Showing
17 changed files
with
578 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org> | ||
*/ | ||
|
||
#include "gattlib_internal.h" | ||
|
||
void gattlib_connected_device_python_callback(void *adapter, const char *dst, gatt_connection_t* connection, int error, 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 | ||
// arguments: (void *adapter, const char *dst, gatt_connection_t* connection, void* user_data) | ||
if (sizeof(void*) == 8) { | ||
argument_string = "(LsLIO)"; | ||
} else { | ||
argument_string = "(IsIIO)"; | ||
} | ||
PyObject *arglist = Py_BuildValue(argument_string, adapter, dst, connection, error, 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 connection device handler has raised an exception."); | ||
PyErr_Print(); | ||
} | ||
|
||
ON_ERROR: | ||
PyGILState_Release(d_gstate); | ||
} | ||
|
||
static gpointer _gattlib_connected_device_thread(gpointer data) { | ||
gatt_connection_t* connection = data; | ||
gattlib_context_t* conn_context = connection->context; | ||
const gchar *device_mac_address = org_bluez_device1_get_address(conn_context->device); | ||
|
||
connection->on_connection.callback.connection_handler( | ||
conn_context->adapter, device_mac_address, connection, 0 /* no error */, | ||
connection->on_connection.user_data); | ||
return NULL; | ||
} | ||
|
||
static void* _connected_device_thread_args_allocator(va_list args) { | ||
gatt_connection_t* connection = va_arg(args, gatt_connection_t*); | ||
return connection; | ||
} | ||
|
||
void gattlib_on_connected_device(gatt_connection_t* connection) { | ||
gattlib_handler_dispatch_to_thread( | ||
&connection->on_connection, | ||
gattlib_connected_device_python_callback /* python_callback */, | ||
_gattlib_connected_device_thread /* thread_func */, | ||
"gattlib_connected_device" /* thread_name */, | ||
_connected_device_thread_args_allocator /* thread_args_allocator */, | ||
connection); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org> | ||
*/ | ||
|
||
#include "gattlib_internal.h" | ||
|
||
void gattlib_disconnected_device_python_callback(gatt_connection_t* connection, void *user_data) { | ||
struct gattlib_python_args* args = user_data; | ||
PyObject *result; | ||
PyGILState_STATE d_gstate; | ||
d_gstate = PyGILState_Ensure(); | ||
|
||
PyObject *arglist = Py_BuildValue("(O)", args->args); | ||
#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 disconnection handler has raised an exception."); | ||
PyErr_Print(); | ||
} | ||
|
||
PyGILState_Release(d_gstate); | ||
} | ||
|
||
static gpointer _gattlib_disconnected_device_thread(gpointer data) { | ||
gatt_connection_t* connection = data; | ||
|
||
connection->on_disconnection.callback.disconnection_handler(connection, connection->on_disconnection.user_data); | ||
return NULL; | ||
} | ||
|
||
static void* _disconnected_device_thread_args_allocator(va_list args) { | ||
gatt_connection_t* connection = va_arg(args, gatt_connection_t*); | ||
return connection; | ||
} | ||
|
||
void gattlib_on_disconnected_device(gatt_connection_t* connection) { | ||
gattlib_handler_dispatch_to_thread( | ||
&connection->on_disconnection, | ||
gattlib_disconnected_device_python_callback /* python_callback */, | ||
_gattlib_disconnected_device_thread /* thread_func */, | ||
"gattlib_disconnected_device" /* thread_name */, | ||
_disconnected_device_thread_args_allocator /* thread_args_allocator */, | ||
connection); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org> | ||
*/ | ||
|
||
#include "gattlib_internal.h" | ||
|
||
void gattlib_discovered_device_python_callback(void *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); | ||
} | ||
|
||
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; | ||
|
||
args->gattlib_adapter->ble_scan.discovered_device_callback.callback.discovered_device( | ||
args->gattlib_adapter, | ||
args->mac_address, args->name, | ||
args->gattlib_adapter->ble_scan.discovered_device_callback.user_data | ||
); | ||
|
||
free(args->mac_address); | ||
if (args->name != NULL) { | ||
free(args->name); | ||
} | ||
free(args); | ||
return NULL; | ||
} | ||
|
||
static void* _discovered_device_thread_args_allocator(va_list args) { | ||
struct gattlib_adapter* gattlib_adapter = va_arg(args, struct gattlib_adapter*); | ||
OrgBluezDevice1* device1 = va_arg(args, OrgBluezDevice1*); | ||
|
||
struct gattlib_discovered_device_thread_args* thread_args = malloc(sizeof(struct gattlib_discovered_device_thread_args)); | ||
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(struct gattlib_adapter* gattlib_adapter, OrgBluezDevice1* device1) { | ||
gattlib_handler_dispatch_to_thread( | ||
&gattlib_adapter->ble_scan.discovered_device_callback, | ||
gattlib_discovered_device_python_callback /* python_callback */, | ||
_gattlib_discovered_device_thread /* thread_func */, | ||
"gattlib_discovered_device" /* thread_name */, | ||
_discovered_device_thread_args_allocator /* thread_args_allocator */, | ||
gattlib_adapter, device1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org> | ||
*/ | ||
|
||
#include "gattlib_internal.h" | ||
|
||
void gattlib_notification_device_python_callback(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data) { | ||
struct gattlib_python_args* args = user_data; | ||
char uuid_str[MAX_LEN_UUID_STR + 1]; | ||
PyGILState_STATE d_gstate; | ||
PyObject *result; | ||
int ret; | ||
|
||
ret = gattlib_uuid_to_string(uuid, uuid_str, sizeof(uuid_str)); | ||
assert(ret == 0); | ||
|
||
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 = "(sLIO)"; | ||
} else { | ||
argument_string = "(sIIO)"; | ||
} | ||
PyObject *arglist = Py_BuildValue(argument_string, uuid_str, data, data_length, args->args); | ||
#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 notification handler has raised an exception."); | ||
PyErr_Print(); | ||
} | ||
|
||
PyGILState_Release(d_gstate); | ||
} | ||
|
||
struct gattlib_notification_device_thread_args { | ||
gatt_connection_t* connection; | ||
uuid_t* uuid; | ||
uint8_t* data; | ||
size_t data_length; | ||
}; | ||
|
||
static gpointer _gattlib_notification_device_thread(gpointer data) { | ||
struct gattlib_notification_device_thread_args* args = data; | ||
|
||
args->connection->notification.callback.notification_handler( | ||
args->uuid, args->data, args->data_length, | ||
args->connection->notification.user_data | ||
); | ||
|
||
if (args->uuid != NULL) { | ||
free(args->uuid); | ||
} | ||
if (args->data != NULL) { | ||
free(args->data); | ||
} | ||
return NULL; | ||
} | ||
|
||
static void* _notification_device_thread_args_allocator(va_list args) { | ||
gatt_connection_t* connection = va_arg(args, gatt_connection_t*); | ||
const uuid_t* uuid = va_arg(args, const uuid_t*); | ||
const uint8_t* data = va_arg(args, const uint8_t*); | ||
size_t data_length = va_arg(args, size_t); | ||
|
||
struct gattlib_notification_device_thread_args* thread_args = malloc(sizeof(struct gattlib_notification_device_thread_args)); | ||
thread_args->connection = connection; | ||
thread_args->uuid = malloc(sizeof(uuid_t)); | ||
if (thread_args->uuid != NULL) { | ||
memcpy(thread_args->uuid, uuid, sizeof(uuid_t)); | ||
} | ||
thread_args->data = malloc(data_length); | ||
if (thread_args->data != NULL) { | ||
memcpy(thread_args->data, data, data_length); | ||
} | ||
thread_args->data_length = data_length; | ||
|
||
return thread_args; | ||
} | ||
|
||
void gattlib_on_gatt_notification(gatt_connection_t* connection, const uuid_t* uuid, const uint8_t* data, size_t data_length) { | ||
gattlib_handler_dispatch_to_thread( | ||
&connection->on_connection, | ||
gattlib_notification_device_python_callback /* python_callback */, | ||
_gattlib_notification_device_thread /* thread_func */, | ||
"gattlib_notification_device" /* thread_name */, | ||
_notification_device_thread_args_allocator /* thread_args_allocator */, | ||
connection, uuid, data, data_length); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org> | ||
*/ | ||
|
||
#include "gattlib_internal.h" | ||
|
||
|
||
void* gattlib_python_callback_args(PyObject* python_callback, PyObject* python_args) { | ||
assert(python_callback != NULL); | ||
assert(python_args != NULL); | ||
|
||
struct gattlib_python_args* args = malloc(sizeof(struct gattlib_python_args)); | ||
if (args == NULL) { | ||
GATTLIB_LOG(GATTLIB_ERROR, "Failed to allocate Python arguments for Python callback."); | ||
return NULL; | ||
} | ||
Py_INCREF(python_callback); | ||
Py_INCREF(python_args); | ||
|
||
args->callback = python_callback; | ||
args->args = python_args; | ||
return args; | ||
} | ||
|
Oops, something went wrong.