mirror of https://github.com/labapart/gattlib
gattlib: Add stream API
parent
2831cdf765
commit
4f8625cedf
|
@ -83,6 +83,7 @@ include_directories(. ${CMAKE_SOURCE_DIR}/common ${CMAKE_CURRENT_BINARY_DIR} ${G
|
|||
set(gattlib_SRCS gattlib.c
|
||||
gattlib_adapter.c
|
||||
gattlib_char.c
|
||||
gattlib_stream.c
|
||||
bluez5/lib/uuid.c
|
||||
${CMAKE_SOURCE_DIR}/common/gattlib_common.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-adaptater1.c
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
*
|
||||
* GattLib - GATT Library
|
||||
*
|
||||
* Copyright (C) 2016-2019 Olivier Martin <olivier@labapart.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "gattlib_internal.h"
|
||||
|
||||
#if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 48)
|
||||
|
||||
int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t* uuid, gatt_stream_t **stream, uint16_t *mtu)
|
||||
{
|
||||
return GATTLIB_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int gattlib_write_char_stream_write(gatt_stream_t *stream, const void *buffer, size_t buffer_len)
|
||||
{
|
||||
return GATTLIB_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int gattlib_write_char_stream_close(gatt_stream_t *stream)
|
||||
{
|
||||
return GATTLIB_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t* uuid, gatt_stream_t **stream, uint16_t *mtu)
|
||||
{
|
||||
struct dbus_characteristic dbus_characteristic = get_characteristic_from_uuid(connection, uuid);
|
||||
GError *error = NULL;
|
||||
GUnixFDList *fd_list;
|
||||
GVariant *out_fd;
|
||||
int fd;
|
||||
|
||||
GVariantBuilder *variant_options = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
org_bluez_gatt_characteristic1_call_acquire_write_sync(
|
||||
dbus_characteristic.gatt,
|
||||
g_variant_builder_end(variant_options),
|
||||
NULL /* fd_list */,
|
||||
&out_fd, mtu,
|
||||
&fd_list,
|
||||
NULL /* cancellable */, &error);
|
||||
if (error != NULL) {
|
||||
fprintf(stderr, "Failed to acquired write DBus GATT characteristic: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return GATTLIB_ERROR_DBUS;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(out_fd), &error);
|
||||
if (error != NULL) {
|
||||
fprintf(stderr, "Failed to retrieve Unix File Descriptor: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return GATTLIB_ERROR_DBUS;
|
||||
}
|
||||
|
||||
// We abuse the pointer 'stream' to pass the 'File Descriptor'
|
||||
*stream = (gatt_stream_t*)(unsigned long)fd;
|
||||
|
||||
return GATTLIB_SUCCESS;
|
||||
}
|
||||
|
||||
int gattlib_write_char_stream_write(gatt_stream_t *stream, const void *buffer, size_t buffer_len)
|
||||
{
|
||||
write((unsigned long)stream, buffer, buffer_len);
|
||||
return GATTLIB_SUCCESS;
|
||||
}
|
||||
|
||||
int gattlib_write_char_stream_close(gatt_stream_t *stream)
|
||||
{
|
||||
close((unsigned long)stream);
|
||||
return GATTLIB_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* #if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 48) */
|
|
@ -78,6 +78,10 @@ gattlib_read_char_by_uuid.argtypes = [c_void_p, POINTER(GattlibUuid), POINTER(c_
|
|||
gattlib_write_char_by_uuid = gattlib.gattlib_write_char_by_uuid
|
||||
gattlib_write_char_by_uuid.argtypes = [c_void_p, POINTER(GattlibUuid), c_void_p, c_size_t]
|
||||
|
||||
# int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t* uuid, gatt_stream_t **stream, uint16_t *mtu)
|
||||
gattlib_write_char_by_uuid_stream_open = gattlib.gattlib_write_char_by_uuid_stream_open
|
||||
gattlib_write_char_by_uuid_stream_open.argtypes = [c_void_p, POINTER(GattlibUuid), POINTER(c_void_p), POINTER(c_uint16)]
|
||||
|
||||
# int gattlib_notification_start(gatt_connection_t* connection, const uuid_t* uuid);
|
||||
gattlib_notification_start = gattlib.gattlib_notification_start
|
||||
gattlib_notification_start.argtypes = [c_void_p, POINTER(GattlibUuid)]
|
||||
|
|
|
@ -3,6 +3,35 @@ from .uuid import gattlib_uuid_to_uuid, gattlib_uuid_to_int
|
|||
from .exception import handle_return
|
||||
|
||||
|
||||
class GattStream():
|
||||
|
||||
def __init__(self, fd, mtu):
|
||||
self._fd = fd
|
||||
self._mtu = mtu
|
||||
|
||||
@property
|
||||
def mtu(self):
|
||||
# Remove ATT Header (3 bytes)
|
||||
return self._mtu - 3
|
||||
|
||||
def write(self, data, mtu=None):
|
||||
if mtu is None:
|
||||
mtu = self.mtu
|
||||
|
||||
while len(data) > 0:
|
||||
frame = data[0:mtu]
|
||||
data = data[mtu:]
|
||||
|
||||
buffer_type = c_char * len(frame)
|
||||
buffer = frame
|
||||
buffer_len = len(frame)
|
||||
|
||||
gattlib.gattlib_write_char_stream_write(self._fd, buffer_type.from_buffer_copy(buffer), buffer_len)
|
||||
|
||||
def close(self):
|
||||
gattlib.gattlib_write_char_stream_close(self._fd)
|
||||
|
||||
|
||||
class GattService():
|
||||
|
||||
def __init__(self, device, gattlib_primary_service):
|
||||
|
@ -62,6 +91,15 @@ class GattCharacteristic():
|
|||
ret = gattlib_write_char_by_uuid(self.connection, self._gattlib_characteristic.uuid, buffer_type.from_buffer_copy(buffer), buffer_len)
|
||||
handle_return(ret)
|
||||
|
||||
def stream_open(self):
|
||||
_stream = c_void_p(None)
|
||||
_mtu = c_uint16(0)
|
||||
|
||||
ret = gattlib_write_char_by_uuid_stream_open(self.connection, self._gattlib_characteristic.uuid, byref(_stream), byref(_mtu))
|
||||
handle_return(ret)
|
||||
|
||||
return GattStream(_stream, _mtu.value)
|
||||
|
||||
def register_notification(self, callback, user_data=None):
|
||||
self._device._notification_add_gatt_characteristic_callback(self, callback, user_data)
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ extern "C" {
|
|||
#define GATTLIB_DISCOVER_FILTER_USE_RSSI (1 << 1)
|
||||
|
||||
typedef struct _gatt_connection_t gatt_connection_t;
|
||||
typedef struct _gatt_stream_t gatt_stream_t;
|
||||
|
||||
typedef void (*gattlib_event_handler_t)(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data);
|
||||
|
||||
|
@ -336,6 +337,10 @@ int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle,
|
|||
*/
|
||||
int gattlib_write_without_response_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t buffer_len);
|
||||
|
||||
int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t* uuid, gatt_stream_t **stream, uint16_t *mtu);
|
||||
int gattlib_write_char_stream_write(gatt_stream_t *stream, const void *buffer, size_t buffer_len);
|
||||
int gattlib_write_char_stream_close(gatt_stream_t *stream);
|
||||
|
||||
/**
|
||||
* @brief Function to write without response to the GATT characteristic handle
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue