static bool CALECheckStarted()
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
- bool const started = (g_context.event_loop != NULL);
+ bool const started =
+ (g_context.event_loop != NULL
+ && g_main_loop_is_running(g_context.event_loop));
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
/**
* @todo Fix potential TOCTOU race condition. A LE transport
char const * signal_name,
GVariant * parameters)
{
+ (void)sender_name;
+ (void)object_path;
+ (void)interface_name;
+ (void)signal_name;
+ (void)parameters;
#ifdef TB_LOG
gchar * const param_dump =
g_variant_print(parameters, TRUE);
gchar const * const * invalidated_properties,
gpointer user_data)
{
- OIC_LOG_V(DEBUG,
- TAG,
- "Properties Changed on %s:\n",
- g_dbus_object_get_object_path(
- G_DBUS_OBJECT(object_proxy)));
+ (void)manager;
+ (void)object_proxy;
+ (void)invalidated_properties;
char const * const interface_name =
g_dbus_proxy_get_interface_name(interface_proxy);
return;
}
+ OIC_LOG_V(DEBUG,
+ TAG,
+ "%s properties Changed on %s:\n",
+ interface_name,
+ g_dbus_proxy_get_object_path(interface_proxy));
+
CALEContext * const context = user_data;
GVariantIter iter;
gchar const * key = NULL;
GVariant * value = NULL;
+ /**
+ * @todo Since we're only looking up one value here,
+ * i.e. "Powered", can't we just use
+ * g_variant_lookup_value() instead of this while() loop?
+ */
g_variant_iter_init(&iter, changed_properties);
while (g_variant_iter_next(&iter, "{&sv}", &key, &value))
{
Report a change in the availability of the bluetooth
adapter.
*/
-
gboolean const powered = g_variant_get_boolean(value);
CAAdapterState_t const status =
(powered ? CA_ADAPTER_ENABLED : CA_ADAPTER_DISABLED);
- CAEndpoint_t info =
- {
- .adapter = CA_ADAPTER_GATT_BTLE,
- };
-
- GVariant * const prop =
- g_dbus_proxy_get_cached_property(interface_proxy,
- "Address");
-
- gchar const * const address = g_variant_get_string(prop, NULL);
-
- OICStrcpy(info.addr, sizeof(info.addr), address);
-
- g_variant_unref(prop);
-
/**
* @todo Should we acquire the context lock here to
* prevent the @c CALEDeviceStateChangedCallback
return;
}
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
/*
Add the object information to the list.
*/
*proxy_list = g_list_prepend(*proxy_list, proxy);
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
/**
* Let the thread that may be blocked waiting for Devices to be
*/
if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0)
{
- ca_cond_signal(g_context.condition);
+ oc_cond_signal(g_context.condition);
}
}
GVariant * parameters,
gpointer user_data)
{
+ (void)connection;
+ (void)user_data;
CALEDumpDBusSignalParameters(sender_name,
object_path,
interface_name,
GVariant * parameters,
gpointer user_data)
{
+ (void)connection;
+ (void)user_data;
CALEDumpDBusSignalParameters(sender_name,
object_path,
interface_name,
gchar const * path = NULL;
g_variant_get_child(parameters, 0, "&o", &path);
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
for (GList * l = *list; l != NULL; l = g_list_next(l))
{
if (strcmp(path,
g_dbus_proxy_get_object_path(proxy)) == 0)
{
+ /**
+ * @todo If a BlueZ Device was removed, update the
+ * characteristic map, accordingly.
+ */
+
// Found a match!
g_object_unref(proxy);
}
}
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
g_variant_unref(child);
}
if (iter != NULL)
+ {
g_variant_iter_free(iter);
-}
-
-static void CALEOnPropertiesChanged(GDBusConnection * connection,
- char const * sender_name,
- char const * object_path,
- char const * interface_name,
- char const * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- CALEDumpDBusSignalParameters(sender_name,
- object_path,
- interface_name,
- signal_name,
- parameters);
-}
-
-static void CALEOnPropertyChanged(GDBusConnection * connection,
- char const * sender_name,
- char const * object_path,
- char const * interface_name,
- char const * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- CALEDumpDBusSignalParameters(sender_name,
- object_path,
- interface_name,
- signal_name,
- parameters);
+ }
}
static void CALESubscribeToSignals(CALEContext * context,
NULL, // user_data
NULL);
-#if GLIB_CHECK_VERSION(2,38,0)
- /*
- The G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH flag was introduced in
- GLib 2.38.
- */
- static GDBusSignalFlags const device_signal_flags =
- G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH;
-#else
- static GDBusSignalFlags const device_signal_flags =
- G_DBUS_SIGNAL_FLAGS_NONE;
-#endif
-
- /**
- * @todo Verify that this signal subscription is needed.
- *
- * @bug The arg0 argument below should be a D-Bus object path, not
- * interface name.
- */
- guint const properties_changed_sub_id =
- g_dbus_connection_signal_subscribe(
- connection,
- NULL, // sender
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- NULL, // object path
- "org.bluez.Device1", // arg0
- device_signal_flags,
- CALEOnPropertiesChanged,
- NULL, // user_data
- NULL);
-
- /**
- * @todo Verify that this signal subscription is needed.
- */
- guint const property_changed_sub_id =
- g_dbus_connection_signal_subscribe(connection,
- NULL, // sender
- BLUEZ_ADAPTER_INTERFACE,
- "PropertyChanged",
- NULL, // object path
- NULL, // arg0
- G_DBUS_SIGNAL_FLAGS_NONE,
- CALEOnPropertyChanged,
- NULL, // user_data
- NULL);
-
g_signal_connect(object_manager,
"interface-proxy-properties-changed",
G_CALLBACK(CALEOnInterfaceProxyPropertiesChanged),
context);
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
context->interfaces_added_sub_id = interfaces_added_sub_id;
context->interfaces_removed_sub_id = interfaces_removed_sub_id;
- context->properties_changed_sub_id = properties_changed_sub_id;
- context->property_changed_sub_id = property_changed_sub_id;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
}
static bool CALESetUpDBus(CALEContext * context)
CALESubscribeToSignals(context, connection, object_manager);
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
context->connection = connection;
context->object_manager = object_manager;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
success = CALESetUpBlueZObjects(context);
global state, and pushing resource finalization outside the global
lock.
*/
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
GDBusConnection * const connection = context->connection;
context->connection = NULL;
guint const interfaces_added = context->interfaces_added_sub_id;
guint const interfaces_removed = context->interfaces_removed_sub_id;
- guint const properties_changed = context->properties_changed_sub_id;
- guint const property_changed = context->property_changed_sub_id;
context->interfaces_added_sub_id = 0;
context->interfaces_removed_sub_id = 0;
- context->properties_changed_sub_id = 0;
- context->property_changed_sub_id = 0;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
// Destroy the device proxies list.
g_list_free_full(devices, g_object_unref);
interfaces_added);
g_dbus_connection_signal_unsubscribe(connection,
interfaces_removed);
- g_dbus_connection_signal_unsubscribe(connection,
- properties_changed);
- g_dbus_connection_signal_unsubscribe(connection,
- property_changed);
g_object_unref(connection);
}
}
return accepted;
}
- char const ** const UUIDs = g_variant_get_strv(prop, NULL);
+ gsize length = 0;
+ char const ** const UUIDs = g_variant_get_strv(prop, &length);
- /**
- * @note It would have been nice to use @c g_strv_contains() here,
- * but we would need to run it twice: once for the uppercase
- * form of the UUID and once for for the lowercase form.
- * Just run the loop manually, and use @c strcasecmp()
- * instead.
- */
- for (char const * const * u = UUIDs; u != NULL; ++u)
+ /*
+ It would have been nice to use g_strv_contains() here, but we
+ would need to run it twice: once for the uppercase form of the
+ UUID and once for for the lowercase form. Just run the loop
+ manually, and use strcasecmp() instead.
+ */
+ char const * const * const end = UUIDs + length;
+ for (char const * const * u = UUIDs; u != end; ++u)
{
if (strcasecmp(*u, CA_GATT_SERVICE_UUID) == 0)
{
return accepted;
}
-
static bool CALESetUpBlueZObjects(CALEContext * context)
{
bool success = false;
return success;
}
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
context->objects = objects;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
/*
Create a proxies to the org.bluez.Adapter1 D-Bus objects that
// An empty adapters list is NULL.
if (success && adapters != NULL)
{
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
context->adapters = adapters;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
}
/*
// An empty device list is NULL.
if (success && devices != NULL)
{
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
context->devices = devices;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
}
- /* success = CAGattClientInitialize(context); */
-
return success;
}
+/**
+ * Inform thread waiting for the event loop to start that the loop has
+ * started. This is done in the context of the event loop itself so
+ * that we can be certain that the event loop is indeed running.
+ */
+static gboolean CALEEventLoopStarted(gpointer user_data)
+{
+ sem_t * const sem = user_data;
+
+ (void) sem_post(sem);
+
+ return G_SOURCE_REMOVE;
+}
+
static void CALEStartEventLoop(void * data)
{
CALEContext * const context = data;
GMainContext * const loop_context = g_main_context_new();
GMainLoop * const event_loop = g_main_loop_new(loop_context, FALSE);
- ca_mutex_lock(context->lock);
-
- assert(context->event_loop == NULL);
- context->event_loop = event_loop;
-
- ca_mutex_unlock(context->lock);
-
g_main_context_push_thread_default(loop_context);
/*
signal handling occurs in the same thread as the one running the
GLib event loop.
*/
- if (!CALESetUpDBus(&g_context))
- return;
+ if (CALESetUpDBus(&g_context))
+ {
+ oc_mutex_lock(context->lock);
+
+ assert(context->event_loop == NULL);
+ context->event_loop = event_loop;
+
+ oc_mutex_unlock(context->lock);
- ca_cond_signal(g_context.condition);
+ /*
+ Add an idle handler that notifies a thread waiting for the
+ GLib event loop to run that the event loop is actually
+ running. We do this in the context of the event loop itself
+ to avoid race conditions.
+ */
+ GSource * const source = g_idle_source_new();
+ g_source_set_priority(source, G_PRIORITY_HIGH_IDLE);
+ g_source_set_callback(source,
+ CALEEventLoopStarted,
+ &context->le_started, // data
+ NULL); // notify
+ (void) g_source_attach(source, loop_context);
+ g_source_unref(source);
+
+ g_main_loop_run(event_loop); // Blocks until loop is quit.
+
+ CALETearDownDBus(&g_context);
+ }
- g_main_loop_run(event_loop);
+ /*
+ Clean up in the same thread to avoid having to explicitly bump
+ the ref count to retain ownership.
+ */
+ g_main_context_unref(loop_context);
+ g_main_loop_unref(event_loop);
}
static void CALEStopEventLoop(CALEContext * context)
{
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
GMainLoop * const event_loop = context->event_loop;
context->event_loop = NULL;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
if (event_loop != NULL)
{
if (loop_context != NULL)
{
g_main_context_wakeup(loop_context);
- g_main_context_unref(loop_context);
}
-
- g_main_loop_unref(event_loop);
}
}
{
bool success = false;
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
for (int i = 0; *list == NULL && i < retries; ++i)
{
- if (ca_cond_wait_for(g_context.condition,
+ if (oc_cond_wait_for(g_context.condition,
g_context.lock,
- timeout) == 0)
+ timeout) == OC_WAIT_SUCCESS)
{
/*
Condition variable was signaled before the timeout was
}
}
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
return success;
}
-static CAResult_t CALEStop()
-{
- CAResult_t result = CA_STATUS_FAILED;
-
- OIC_LOG(DEBUG, TAG, "Stop Linux BLE adapter.");
-
- // Only stop if we were previously started.
- if (!CALECheckStarted())
- return result;
-
- // Stop the event loop thread regardless of previous errors.
- CALEStopEventLoop(&g_context);
-
- CALETearDownDBus(&g_context);
-
- return result;
-}
-
-static void CALETerminate()
-{
- OIC_LOG(DEBUG, TAG, "Terminate BLE adapter.");
-
- CAPeripheralFinalize();
-
- ca_mutex_lock(g_context.lock);
-
- g_context.on_device_state_changed = NULL;
- g_context.on_server_received_data = NULL;
- g_context.on_client_received_data = NULL;
- g_context.client_thread_pool = NULL;
- g_context.server_thread_pool = NULL;
- g_context.on_client_error = NULL;
- g_context.on_server_error = NULL;
-
- ca_mutex_unlock(g_context.lock);
-
- ca_cond_free(g_context.condition);
- ca_mutex_free(g_context.lock);
-}
-
// -----------------------------------------------------------------------
CAResult_t CAInitializeLEAdapter()
g_type_init();
#endif
- g_context.lock = ca_mutex_new();
- g_context.condition = ca_cond_new();
-
- CAPeripheralInitialize();
-
return CA_STATUS_OK;
}
// Only start if we were previously stopped.
if (CALECheckStarted())
- return result;
+ {
+ return result;
+ }
/**
* Spawn a thread to run the GLib event loop that will drive D-Bus
* thread pool before the transport adapters prevents us
* from doing that without potentially triggering a
* @c pthread_join() call that blocks indefinitely due to
- * this event loop not be stopped. See the comments in the
- * @c CAGetLEInterfaceInformation() function below for
+ * this event loop not being stopped. See the comments in
+ * the @c CAGetLEInterfaceInformation() function below for
* further details.
*/
result = ca_thread_pool_add_task(g_context.client_thread_pool,
CALEStartEventLoop,
- &g_context);
-
- if (result != CA_STATUS_OK)
- return result;
+ &g_context, NULL);
/*
- Wait until initialization completes before continuing, basically
- until some Bluetooth adapters were found.
+ Wait for the GLib event loop to actually run before returning.
+
+ This addresses corner cases where operations are incorrectly
+ permitted to run in parallel before the event loop is run. For
+ example, the LE transport could have been stopped in a thread
+ parallel to the one starting the event loop start. In that case
+ the GLib event loop may never exit since the stop operation that
+ causes the event loop to exit occurred before event loop
+ started. That ultimately causes the CA layer termination to
+ block indefinitely on a pthread_join(). The solution is to only
+ return from the LE transport start operation once we know the
+ event loop is up and running.
*/
+ struct timespec abs_timeout;
+ if (result == CA_STATUS_OK
+ && clock_gettime(CLOCK_REALTIME, &abs_timeout) == 0)
+ {
+ static time_t const relative_timeout = 2; // seconds
+ abs_timeout.tv_sec += relative_timeout;
- // Number of times to wait for initialization to complete.
- static int const retries = 2;
+ int const wait_result =
+ sem_timedwait(&g_context.le_started, &abs_timeout);
+
+ if (wait_result == 0)
+ {
+ result = CA_STATUS_OK;
+ }
+ }
- static uint64_t const timeout =
- 2 * MICROSECS_PER_SEC; // Microseconds
+ return result;
+}
- if (CALEWaitForNonEmptyList(&g_context.adapters, retries, timeout))
+CAResult_t CAStopLEAdapter()
+{
+ /*
+ This function is called by the connectivity abstraction when
+ CAUnselectNetwork(CA_ADAPTER_GATT_BTLE) is called by the user.
+ */
+
+ OIC_LOG(DEBUG, TAG, "Stop Linux BLE adapter.");
+
+ // Only stop if we were previously started.
+ if (!CALECheckStarted())
{
- result = CA_STATUS_OK;
+ return CA_STATUS_FAILED;
}
- return result;
+ CALEStopEventLoop(&g_context);
+
+ return CA_STATUS_OK;
}
+
CAResult_t CAGetLEAdapterState()
{
- /**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
- */
- return CA_NOT_SUPPORTED;
+ CAResult_t result = CA_ADAPTER_NOT_ENABLED;
+
+ oc_mutex_lock(g_context.lock);
+
+ for (GList * l = g_context.adapters; l != NULL; l = l->next)
+ {
+ GDBusProxy * const adapter = G_DBUS_PROXY(l->data);
+ GVariant * const prop =
+ g_dbus_proxy_get_cached_property(adapter, "Powered");
+
+ if (prop == NULL)
+ {
+ // This should never happen!
+ result = CA_STATUS_FAILED;
+ break;
+ }
+
+ gboolean const powered = g_variant_get_boolean(prop);
+ g_variant_unref(prop);
+
+ if (powered)
+ {
+ result = CA_STATUS_OK;
+ break;
+
+ /*
+ No need to continue iterating since we have at least
+ one enabled Bluetooth adapter.
+ */
+ }
+ }
+
+ oc_mutex_unlock(g_context.lock);
+
+ return result;
}
CAResult_t CAInitializeLENetworkMonitor()
{
/**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
+ * @note "Network monitor" operations are started in the
+ * @c CAStartLEAdapter() function rather than this function
+ * due to glib/D-Bus signal handling threads related
+ * issues.
+ *
+ * @see @c CAStartLEAdapter() for further details.
+ */
+
+ g_context.lock = oc_mutex_new();
+ g_context.condition = oc_cond_new();
+
+ static int const PSHARED = 0; // shared between threads
+ static unsigned int const VALUE = 0; // force sem_wait() to block
+
+ if (sem_init(&g_context.le_started, PSHARED, VALUE) != 0)
+ {
+ return CA_STATUS_FAILED;
+ }
+
+ /*
+ The CA LE interface doesn't expose a CAInitializeLEGattServer()
+ function so perform initialization here.
*/
+ CAPeripheralInitialize();
+
return CA_STATUS_OK;
}
void CATerminateLENetworkMonitor()
{
/**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
+ * @note "Network monitor" operations are stopped in @c CALEStop()
+ * since they are started in @c CAStartLEAdapter() rather
+ * than @c CAInitializeLENetworkMonitor().
+ *
+ * @see @c CAStartLEAdapter() for further details.
+ */
+
+ /*
+ Since the CA LE interface doesn't expose a
+ CAInitializeLEGattServer() function, finalize the LE server
+ (peripheral) here rather than in CATerminateLEGattServer() to
+ ensure finalization is correctly paired with initialization.
*/
+ CAPeripheralFinalize();
+
+ (void) sem_destroy(&g_context.le_started);
+
+ oc_mutex_lock(g_context.lock);
+
+ g_context.on_device_state_changed = NULL;
+ g_context.on_server_received_data = NULL;
+ g_context.on_client_received_data = NULL;
+ g_context.client_thread_pool = NULL;
+ g_context.server_thread_pool = NULL;
+ g_context.on_client_error = NULL;
+ g_context.on_server_error = NULL;
+
+ oc_cond_free(g_context.condition);
+ g_context.condition = NULL;
+
+ oc_mutex_unlock(g_context.lock);
+
+ oc_mutex_free(g_context.lock);
+ g_context.lock = NULL;
}
-CAResult_t CASetLEAdapterStateChangedCb(CALEDeviceStateChangedCallback callback)
+CAResult_t CASetLEAdapterStateChangedCb(
+ CALEDeviceStateChangedCallback callback)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_device_state_changed = callback;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
return CA_STATUS_OK;
}
-CAResult_t CAInitLENetworkMonitorMutexVariables()
+CAResult_t CASetLENWConnectionStateChangedCb(CALEConnectionStateChangedCallback callback)
{
- /*
- This CA LE interface implementation doesn't use a network
- monitor as the other platform implementationd do.
- */
- return CA_STATUS_OK;
+ (void)callback;
+ return CA_NOT_SUPPORTED;
}
-void CATerminateLENetworkMonitorMutexVariables()
+CAResult_t CAUnSetLENWConnectionStateChangedCb()
{
- /*
- This CA LE interface implementation doesn't use a network
- monitor as the other platform implementationd do.
- */
+ return CA_NOT_SUPPORTED;
}
CAResult_t CAGetLEAddress(char **local_address)
*local_address = NULL;
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
for (GList * l = g_context.adapters; l != NULL; l = l->next)
{
break;
}
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
return *local_address != NULL ? CA_STATUS_OK : CA_STATUS_FAILED;
}
CAResult_t CAStopLEGattServer()
{
- CAResult_t result = CAPeripheralStop();
- CAResult_t const tmp = CALEStop();
-
- if (result == CA_STATUS_OK && tmp != CA_STATUS_OK)
- {
- result = tmp;
- }
+ return CAPeripheralStop();
+}
- return result;
+CAResult_t CAInitializeLEGattServer()
+{
+ return CA_STATUS_OK;
}
void CATerminateLEGattServer()
{
- CALETerminate();
+ /*
+ See CATerminateLENetworkMonitor() to understand why the LE
+ peripheral is not finalized here.
+ */
}
void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_server_received_data = callback;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}
CAResult_t CAUpdateCharacteristicsToGattClient(char const * address,
- char const * charValue,
- uint32_t charValueLen)
+ uint8_t const * value,
+ uint32_t valueLen)
{
- /**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
- */
- return CA_NOT_SUPPORTED;
+ return CAGattServerSendResponseNotification(address,
+ value,
+ valueLen);
}
-CAResult_t CAUpdateCharacteristicsToAllGattClients(char const * charValue,
- uint32_t charValueLen)
+CAResult_t CAUpdateCharacteristicsToAllGattClients(uint8_t const * value,
+ uint32_t valueLen)
{
- /**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
- */
- return CA_NOT_SUPPORTED;
+ return CAGattServerSendResponseNotificationToAll(value, valueLen);
}
CAResult_t CAStartLEGattClient()
{
- return CACentralStart(&g_context);
-}
-
-void CAStopLEGattClient()
-{
- (void) CACentralStop(&g_context);
- (void) CALEStop();
-}
-
-void CATerminateLEGattClient()
-{
- CALETerminate();
-}
-
-void CACheckLEData()
-{
- /*
- This function is only used in single-threaded builds, but this
- CA LE adapter implementation is multi-threaded. Consequently,
- this function is a no-op.
- */
-}
-
-CAResult_t CAUpdateCharacteristicsToGattServer(
- char const * remoteAddress,
- char const * data,
- uint32_t dataLen,
- CALETransferType_t type,
- int32_t position)
-{
- /**
- * @todo To be implemented shortly as part of the effort to
- * address a critical code review that stated this BLE
- * transport should implement the interface defined in
- * caleinterface.h.
- */
- return CA_NOT_SUPPORTED;
-}
+ CAResult_t result = CACentralStart(&g_context);
-CAResult_t CAUpdateCharacteristicsToAllGattServers(char const * data,
- uint32_t length)
-{
- OIC_LOG(DEBUG, TAG, "Send data to all");
-
- /*
- Multicast data is only sent when a request is sent from a client
- across all endpoints. We need not worry about sending a
- response from a server here.
- */
-
- CAResult_t result = CA_STATUS_FAILED;
+ if (result != CA_STATUS_OK)
+ {
+ return result;
+ }
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
bool found_peripherals = (g_context.devices != NULL);
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
if (!found_peripherals)
{
- /*
- Start discovery of LE peripherals that advertise the OIC
- Transport Profile.
- */
- result = CACentralStartDiscovery(&g_context);
-
- if (result != CA_STATUS_OK)
- {
- return -1;
- }
-
// Wait for LE peripherals to be discovered.
// Number of times to wait for discovery to complete.
retries,
timeout))
{
- return -1;
- }
-
- ca_mutex_lock(g_context.lock);
- found_peripherals = (g_context.devices == NULL);
- ca_mutex_unlock(g_context.lock);
-
- if (!found_peripherals)
- {
- // No peripherals discovered!
- return -1;
+ return result;
}
}
if (result != CA_STATUS_OK)
{
- return -1;
+ return result;
}
bool const connected = CACentralConnectToAll(&g_context);
if (!connected)
{
- return -1;
+ return result;
}
/**
- * @todo Start notifications on all response characteristics.
+ * @todo Verify notifications have been enabled on all response
+ * characteristics.
*/
+ return CAGattClientInitialize(&g_context);
+}
+
+void CAStopLEGattClient()
+{
+ CAGattClientDestroy();
+ (void) CACentralStop(&g_context);
+}
+
+CAResult_t CAInitializeLEGattClient()
+{
+ return CA_STATUS_OK;
+}
+
+void CATerminateLEGattClient()
+{
+}
+
+CAResult_t CAUpdateCharacteristicsToGattServer(
+ char const * remoteAddress,
+ uint8_t const * data,
+ uint32_t dataLen,
+ CALETransferType_t type,
+ int32_t position)
+{
+ (void) position;
+
+ if (type != LE_UNICAST)
+ {
+ return CA_STATUS_INVALID_PARAM;
+ }
+
/*
- Now send the request through all BLE connections through the
- corresponding OIC GATT request characterstics.
+ We can assume that we're already connected to the BLE device
+ with the given remote address - we wouldn't have a remote
+ address otherwise - so there is no need to start scanning for
+ BLE devices.
*/
- CAGattRequestInfo const info =
- {
- .characteristic_info = NULL, // g_context.characteristics
- .context = &g_context
- };
+ return CAGattClientSendData(remoteAddress,
+ data,
+ dataLen,
+ &g_context);
+}
- return CAGattClientSendDataToAll(&info, data, length);
+CAResult_t CAUpdateCharacteristicsToAllGattServers(uint8_t const * data,
+ uint32_t length)
+{
+ /*
+ Now send the request through all BLE connections through the
+ corresponding OIC GATT request characterstics.
+ */
+ return CAGattClientSendDataToAll(data, length, &g_context);
/**
* @todo Should we restart discovery after the send?
void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_client_received_data = callback;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}
void CASetLEServerThreadPoolHandle(ca_thread_pool_t handle)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.server_thread_pool = handle;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}
void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.client_thread_pool = handle;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}
CAResult_t CAUnSetLEAdapterStateChangedCb()
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_device_state_changed = NULL;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
return CA_STATUS_OK;
}
void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_client_error = callback;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}
void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_context.on_server_error = callback;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}