X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fconnectivity%2Fsrc%2Fbt_le_adapter%2Flinux%2Fcaleinterface.c;h=364737850f09d6f6f309c4ade42e3918e271bb8a;hb=8229635f6d207516ccbbdf23b13be164e0fc1787;hp=632240a23b2c87aeff27d16b71ad7d0c189fe515;hpb=f156a5121851f45a6f803be854197d5d3c6184e2;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c index 632240a..3647378 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c @@ -55,11 +55,13 @@ static bool CALESetUpBlueZObjects(CALEContext * context); 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 @@ -114,11 +116,6 @@ static void CALEOnInterfaceProxyPropertiesChanged( (void)manager; (void)object_proxy; (void)invalidated_properties; - OIC_LOG_V(DEBUG, - TAG, - "Properties Changed on %s:\n", - g_dbus_object_get_object_path( - G_DBUS_OBJECT(object_proxy))); char const * const interface_name = g_dbus_proxy_get_interface_name(interface_proxy); @@ -135,12 +132,23 @@ static void CALEOnInterfaceProxyPropertiesChanged( 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)) { @@ -150,26 +158,10 @@ static void CALEOnInterfaceProxyPropertiesChanged( 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 @@ -214,7 +206,7 @@ static void CALEHandleInterfaceAdded(GList ** proxy_list, return; } - ca_mutex_lock(g_context.lock); + oc_mutex_lock(g_context.lock); /* Add the object information to the list. @@ -225,7 +217,7 @@ static void CALEHandleInterfaceAdded(GList ** proxy_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 @@ -238,7 +230,7 @@ static void CALEHandleInterfaceAdded(GList ** proxy_list, */ if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0) { - ca_cond_signal(g_context.condition); + oc_cond_signal(g_context.condition); } } @@ -337,7 +329,7 @@ static void CALEOnInterfacesRemoved(GDBusConnection * connection, 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)) { @@ -346,6 +338,11 @@ static void CALEOnInterfacesRemoved(GDBusConnection * connection, 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); @@ -355,7 +352,7 @@ static void CALEOnInterfacesRemoved(GDBusConnection * connection, } } - ca_mutex_unlock(g_context.lock); + oc_mutex_unlock(g_context.lock); g_variant_unref(child); } @@ -366,40 +363,6 @@ static void CALEOnInterfacesRemoved(GDBusConnection * connection, } } -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) -{ - (void)connection; - (void)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) -{ - (void)connection; - (void)user_data; - CALEDumpDBusSignalParameters(sender_name, - object_path, - interface_name, - signal_name, - parameters); -} - static void CALESubscribeToSignals(CALEContext * context, GDBusConnection * connection, GDBusObjectManager * object_manager) @@ -437,65 +400,17 @@ 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) @@ -556,10 +471,10 @@ 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); @@ -575,7 +490,7 @@ static void CALETearDownDBus(CALEContext * 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; @@ -594,15 +509,11 @@ static void CALETearDownDBus(CALEContext * context) 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); @@ -626,10 +537,6 @@ static void CALETearDownDBus(CALEContext * context) 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); } } @@ -676,7 +583,6 @@ static bool CALEDeviceFilter(GDBusProxy * device) return accepted; } - static bool CALESetUpBlueZObjects(CALEContext * context) { bool success = false; @@ -693,9 +599,9 @@ static bool CALESetUpBlueZObjects(CALEContext * context) 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 @@ -711,9 +617,9 @@ static bool CALESetUpBlueZObjects(CALEContext * context) // 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); } /* @@ -729,16 +635,28 @@ static bool CALESetUpBlueZObjects(CALEContext * context) // 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; @@ -749,13 +667,6 @@ static void CALEStartEventLoop(void * 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); /* @@ -764,22 +675,51 @@ static void CALEStartEventLoop(void * data) 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) { @@ -791,10 +731,7 @@ static void CALEStopEventLoop(CALEContext * context) if (loop_context != NULL) { g_main_context_wakeup(loop_context); - g_main_context_unref(loop_context); } - - g_main_loop_unref(event_loop); } } @@ -812,13 +749,13 @@ static bool CALEWaitForNonEmptyList(GList * const * list, { 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 @@ -828,53 +765,11 @@ static bool CALEWaitForNonEmptyList(GList * const * list, } } - 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() @@ -889,11 +784,6 @@ CAResult_t CAInitializeLEAdapter() g_type_init(); #endif - g_context.lock = ca_mutex_new(); - g_context.condition = ca_cond_new(); - - CAPeripheralInitialize(); - return CA_STATUS_OK; } @@ -911,7 +801,7 @@ CAResult_t CAStartLEAdapter() // Only start if we were previously stopped. if (CALECheckStarted()) { - return result; + return result; } /** @@ -926,94 +816,196 @@ CAResult_t CAStartLEAdapter() * 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); + &g_context, NULL); - if (result != CA_STATUS_OK) + /* + 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) { - return result; + static time_t const relative_timeout = 2; // seconds + abs_timeout.tv_sec += relative_timeout; + + int const wait_result = + sem_timedwait(&g_context.le_started, &abs_timeout); + + if (wait_result == 0) + { + result = CA_STATUS_OK; + } } + return result; +} + +CAResult_t CAStopLEAdapter() +{ /* - Wait until initialization completes before continuing, basically - until some Bluetooth adapters were found. + This function is called by the connectivity abstraction when + CAUnselectNetwork(CA_ADAPTER_GATT_BTLE) is called by the user. */ - // Number of times to wait for initialization to complete. - static int const retries = 2; - - static uint64_t const timeout = - 2 * MICROSECS_PER_SEC; // Microseconds + OIC_LOG(DEBUG, TAG, "Stop Linux BLE adapter."); - if (CALEWaitForNonEmptyList(&g_context.adapters, retries, timeout)) + // 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) @@ -1067,7 +1059,7 @@ 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) { @@ -1111,7 +1103,7 @@ CAResult_t CAGetLEAddress(char **local_address) break; } - ca_mutex_unlock(g_context.lock); + oc_mutex_unlock(g_context.lock); return *local_address != NULL ? CA_STATUS_OK : CA_STATUS_FAILED; } @@ -1123,135 +1115,59 @@ CAResult_t CAStartLEGattServer() 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, uint8_t const * value, uint32_t valueLen) { - (void)address; - (void)value; - (void)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(uint8_t const * value, uint32_t valueLen) { - (void)value; - (void)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, - uint8_t const * data, - uint32_t dataLen, - CALETransferType_t type, - int32_t position) -{ - (void)remoteAddress; - (void)data; - (void)dataLen; - (void)type; - (void)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 CAUpdateCharacteristicsToAllGattServers(uint8_t const * data, - uint32_t length) -{ - OIC_LOG(DEBUG, TAG, "Send data to all"); + CAResult_t result = CACentralStart(&g_context); - /* - 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. @@ -1264,17 +1180,7 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(uint8_t const * data, 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; } } @@ -1288,32 +1194,74 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(uint8_t const * data, 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? @@ -1322,44 +1270,44 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(uint8_t const * data, 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); }