From: Seonah Moon Date: Thu, 29 Jul 2021 09:49:48 +0000 (+0900) Subject: Modify the initiation logic for GATT connection X-Git-Tag: submit/tizen/20210831.025107~3^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5d4c53f16c3a5423064ae700f37a3c96c96b88f7;p=platform%2Fcore%2Fapi%2Fvine.git Modify the initiation logic for GATT connection - Manage connection state callbacks globally - Add the new characteristic used in initiation phase - Do not call bt_gatt_disconnect() Change-Id: Id5fbacd2f8e19ab46c901795e3c82d30bf597f39 --- diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index af7dbc5..b3a0d5b 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -29,9 +29,15 @@ using namespace std; // TODO: change UUIDs #define VINE_GATT_SERVICE_UUID "000018f2-0000-1000-8000-00805f9b34fb" -#define VINE_GATT_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb" +#define VINE_GATT_CONNECTION_CHAR_UUID "5fbfd598-ab0f-4c20-9966-60a11a41e974" +#define VINE_GATT_READ_WRITE_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb" #define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66" +// 2-way handshake for VINE GATT connection +#define VINE_GATT_CONNECTION_SYN "VINE_GATT_CONNECTION_SYN" +#define VINE_GATT_CONNECTION_ACK "VINE_GATT_CONNECTION_ACK" +#define VINE_GATT_CONNECTION_FIN "VINE_GATT_CONNECTION_FIN" + #define BT_ADDRESS_LEN 17 #define BT_GATT_ATT_DATA_LEN_MAX 512 @@ -65,8 +71,10 @@ struct vine_gatt_s { int eventfd; bt_gatt_h service; - bt_gatt_h characteristic; - bt_gatt_h descriptor; + bt_gatt_h connection_char; + bt_gatt_h connection_desc; + bt_gatt_h read_write_char; + bt_gatt_h read_write_desc; vine_gatt_role_e type; union { @@ -93,9 +101,25 @@ static vine_dp_plugin_callbacks g_callbacks = { static map g_eventfds; +// Wrapper for bt_gatt_connection_state_changed_cb() +typedef void (*gatt_connection_state_cb)(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data); +typedef struct { + vine_gatt_s *gatt; + gatt_connection_state_cb func; + void *user_data; +} conn_state_cb_data; +static multimap g_conn_state_cbs; + static vine_gatt_s *_create_gatt(void); static int __write_to_client(vine_gatt_s *gatt); static int __write_to_server(vine_gatt_s *gatt); +static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt); +static void __handle_connected_client(vine_gatt_s *gatt, const char *address); +static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address); +static void __send_conn_syn(vine_gatt_s *gatt, const char *remote_address); +static void __send_conn_ack(vine_gatt_s *gatt, const char *remote_address); +static void __send_conn_fin(vine_gatt_s *gatt, const char *remote_address); static vine_data_path_error __convert_bt_error_to_data_path_error(int error) { @@ -218,14 +242,53 @@ static void __invoke_terminated_cb(void *user_data) } // Server Callbacks +static void __gatt_server_read_connection_value_requested_cb( + const char *remote_address, int request_id, + bt_gatt_server_h server, bt_gatt_h gatt_handle, + int offset, void *user_data) +{ + // Do nothing. +} + +static void __gatt_server_write_connection_value_requested_cb(const char *remote_address, + int request_id, bt_gatt_server_h server, + bt_gatt_h gatt_handle, bool response_needed, int offset, + const char *value, int len, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + VINE_LOGI("Got write init value[%s] request from %s.", value, remote_address); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + + if (bt_gatt_server_send_response(request_id, BT_GATT_REQUEST_TYPE_WRITE, + offset, BT_ERROR_NONE, "", 0) != BT_ERROR_NONE) { + VINE_LOGE("Failed to send initiation message"); + return; + } + + if (strncmp(value, VINE_GATT_CONNECTION_SYN, len) == 0) { + VINE_LOGI("Got SYN mesage from %s", remote_address); + __send_conn_ack(gatt, remote_address); + __handle_connected_client(gatt, remote_address); + } else if (strncmp(value, VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN) == 0)) { + VINE_LOGI("Got FIN message from %s", remote_address); + __handle_disconnected_client(gatt, remote_address); + } +} + +void __gatt_server_noti_connection_state_changed_cb(bool notify, bt_gatt_server_h server, + bt_gatt_h gatt_handle, void *user_data) +{ + // Do nothing. + VINE_LOGI("+"); +} + static void __gatt_server_read_value_requested_cb( const char *remote_address, int request_id, bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset, void *user_data) { - // TODO: Send response. - // TODO: Save data - // Is this function needed for VINE? + // Do nothing. } static void __gatt_server_write_value_requested_cb(const char *remote_address, @@ -318,6 +381,148 @@ void __gatt_server_noti_sent_cb(int result, } // Client Callbacks +void __gatt_client_read_write_char_changed_cb(bt_gatt_h characteristic, + char *value, int len, void *user_data) +{ + VINE_LOGD("+"); + RET_IF(user_data == NULL, "user_data is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + gatt_data_s *recv_data =__create_gatt_data(gatt, value, len, true); + RET_IF(recv_data == NULL, "recv_data is NULL"); + + gatt->recv_buffer->push(recv_data); + + VINE_LOGD("recv_data[%p] is pushed to recv_buffer. length[%zd]", recv_data, len); + if (g_callbacks.received_cb) + g_callbacks.received_cb(len, gatt->user); +} + +void __gatt_client_connection_char_changed_cb(bt_gatt_h characteristic, + char *value, int len, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + if (strncmp(value, VINE_GATT_CONNECTION_ACK, strlen(VINE_GATT_CONNECTION_ACK)) == 0) { + VINE_LOGI("Got ACK message."); + if (bt_gatt_client_set_characteristic_value_changed_cb(gatt->read_write_char, + __gatt_client_read_write_char_changed_cb, gatt) != BT_ERROR_NONE) { + VINE_LOGE("Failed to set characteristic_value_changed_cb"); + // TODO: disconnect. + return; + } + gatt->ready_to_write = true; + __invoke_connected_cb(0, gatt->user); + } else if (strncmp(value, VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN) == 0)) { + VINE_LOGI("Got FIN message."); + __invoke_terminated_cb(gatt->user); + } else { + VINE_LOGI("Unknown message. [%s]", value); + } +} + +void __send_conn_syn_completed_cb(int result, bt_gatt_h gatt_handle, void *user_data) +{ + // Do nothing. +} + +static void __send_conn_syn(vine_gatt_s *gatt, const char *remote_address) +{ + // Only the client can send a SYN. + RET_IF(gatt->type != VINE_GATT_ROLE_CLIENT, "gatt isn't a client"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_SYN, strlen(VINE_GATT_CONNECTION_SYN)); + bt_gatt_client_write_value(gatt->connection_char, + __send_conn_syn_completed_cb, (void *)gatt); +} + +static void __send_conn_ack_completed_cb(int result, + const char *remote_address, bt_gatt_server_h server, bt_gatt_h characteristic, + bool completed, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_ack(vine_gatt_s *gatt, const char *remote_address) +{ + VINE_LOGI("+"); + // Only the server can send a ACK. + RET_IF(gatt->type != VINE_GATT_ROLE_SERVER, "gatt isn't a server"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_ACK, strlen(VINE_GATT_CONNECTION_ACK)); + bt_gatt_server_notify_characteristic_changed_value(gatt->connection_char, + __send_conn_ack_completed_cb, gatt->remote_address, (void *)gatt); +} + +void __send_conn_fin_to_server_completed_cb(int result, bt_gatt_h gatt_handle, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_fin_to_client_completed_cb(int result, + const char *remote_address, bt_gatt_server_h server, bt_gatt_h characteristic, + bool completed, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_fin(vine_gatt_s *gatt, const char *remote_address) +{ + VINE_LOGI("+"); + RET_IF(gatt->type == VINE_GATT_ROLE_UNKNOWN, "Unknown type"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN)); + + if (gatt->type == VINE_GATT_ROLE_SERVER) { + bt_gatt_server_notify_characteristic_changed_value(gatt->connection_char, + __send_conn_fin_to_client_completed_cb, gatt->remote_address, (void *)gatt); + } else if (gatt->type = VINE_GATT_ROLE_CLIENT) { + bt_gatt_client_write_value(gatt->connection_char, + __send_conn_fin_to_server_completed_cb, (void *)gatt); + } +} + +static void __gatt_client_state_changed_cb(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data) +{ + RET_IF(gatt == NULL, "gatt is NULL"); + VINE_LOGI("gatt[%p] connected[%d] remote address[%s]", gatt, connected, remote_address); + + if (!connected) { + // TODO: unregister here? + __invoke_terminated_cb(gatt->user); + return; + } + + if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) { + __send_conn_fin(gatt, remote_address); + return; + } + + __send_conn_syn(gatt, remote_address); +} + +static void __gatt_accepted_client_state_changed_cb(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data) +{ + RET_IF(gatt == NULL, "gatt is NULL"); + VINE_LOGI("gatt[%p] connected[%d] remote address[%s]", gatt, connected, remote_address); + + if (connected) { // Do nothing. + VINE_LOGI("[%p] is already connected.", user_data); + return; + } + + __handle_disconnected_client(gatt, remote_address); +} + static void __gatt_client_mtu_changed_cb(bt_gatt_client_h client, const bt_gatt_client_att_mtu_info_s *mtu_info, void *user_data) { @@ -358,23 +563,6 @@ void __gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *us __notify_write_event(gatt); } -void __gatt_client_characteristic_value_changed_cb(bt_gatt_h characteristic, - char *value, int len, void *user_data) -{ - VINE_LOGD("+"); - RET_IF(user_data == NULL, "user_data is NULL"); - - vine_gatt_s *gatt = (vine_gatt_s *)user_data; - gatt_data_s *recv_data =__create_gatt_data(gatt, value, len, true); - RET_IF(recv_data == NULL, "recv_data is NULL"); - - gatt->recv_buffer->push(recv_data); - - VINE_LOGD("recv_data[%p] is pushed to recv_buffer. length[%zd]", recv_data, len); - if (g_callbacks.received_cb) - g_callbacks.received_cb(len, gatt->user); -} - static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt) { RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "gatt is NULL"); @@ -383,6 +571,7 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g bt_gatt_client_h client = NULL; bt_gatt_h service = NULL; + bt_gatt_h connection_char = NULL; bt_gatt_h characteristic = NULL; int ret = BT_ERROR_OPERATION_FAILED; @@ -406,12 +595,20 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g if (ret != BT_ERROR_NONE) goto ERR; - ret = bt_gatt_service_get_characteristic(service, VINE_GATT_CHAR_UUID, &characteristic); + ret = bt_gatt_service_get_characteristic(service, + VINE_GATT_CONNECTION_CHAR_UUID, &connection_char); if (ret != BT_ERROR_NONE) goto ERR; - ret = bt_gatt_client_set_characteristic_value_changed_cb(characteristic, - __gatt_client_characteristic_value_changed_cb, gatt); + ret = bt_gatt_client_set_characteristic_value_changed_cb(connection_char, + __gatt_client_connection_char_changed_cb, gatt); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to set characteristic_value_changed_cb"); + goto ERR; + } + + ret = bt_gatt_service_get_characteristic(service, + VINE_GATT_READ_WRITE_CHAR_UUID, &characteristic); if (ret != BT_ERROR_NONE) goto ERR; @@ -420,7 +617,8 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g goto ERR; gatt->service = service; - gatt->characteristic = characteristic; + gatt->connection_char = connection_char; + gatt->read_write_char = characteristic; gatt->remote_address = STRDUP(remote_address); VINE_LOGI("Succeeded to update GATT service info."); @@ -448,13 +646,65 @@ static vine_gatt_s *__create_accepted_gatt(const char *remote_address, vine_gatt accepted_gatt->remote_address = STRDUP(remote_address); // refer to server's gatt handles. accepted_gatt->service = gatt->service; - accepted_gatt->characteristic = gatt->characteristic; - accepted_gatt->descriptor = gatt->descriptor; + accepted_gatt->connection_char = gatt->connection_char; + accepted_gatt->connection_desc = gatt->connection_desc; + accepted_gatt->read_write_char = gatt->read_write_char; + accepted_gatt->read_write_desc = gatt->read_write_desc; accepted_gatt->user = user; return accepted_gatt; } +static void __gatt_connection_state_changed_cb(int result, bool connected, + const char *remote_address, void *user_data) +{ + VINE_LOGI("result[%d] connected[%d] remote address[%s]", result, connected, remote_address); + + typedef multimap::iterator iterator; + pair iter_pair = g_conn_state_cbs.equal_range(remote_address); + + for (iterator it = iter_pair.first; it != iter_pair.second; ++it) { + conn_state_cb_data *cb_data = it->second; + if (cb_data && cb_data->func) + cb_data->func(cb_data->gatt, connected, remote_address, cb_data->user_data); + } +} + +static int _register_conn_state_changed_cb(vine_gatt_s *gatt, + const char *addr, gatt_connection_state_cb func, void *user_data) +{ + conn_state_cb_data *cb_data = (conn_state_cb_data *)calloc(1, sizeof(conn_state_cb_data)); + RET_VAL_IF(cb_data == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "cb_data is NULL"); + + cb_data->gatt = gatt; + cb_data->func = func; + cb_data->user_data = user_data; + g_conn_state_cbs.insert(pair(addr, cb_data)); + VINE_LOGD("cb_data[%p] is registered.", cb_data); + + return VINE_DATA_PATH_ERROR_NONE; +} + +static int _unregister_conn_state_changed_cb(vine_gatt_s *gatt, const char *addr, void *user_data) +{ + typedef multimap::iterator iterator; + pair iter_pair = g_conn_state_cbs.equal_range(addr); + + for (iterator it = iter_pair.first; it != iter_pair.second; ++it) { + conn_state_cb_data *cb_data = it->second; + if (cb_data && cb_data->gatt == gatt && cb_data->user_data == user_data) { + VINE_LOGD("cb_data[%p] is unregistered.", cb_data); + g_conn_state_cbs.erase(it); + cb_data->gatt = NULL; + cb_data->func = NULL; + cb_data->user_data = NULL; + free(cb_data); + break; + } + } + return VINE_DATA_PATH_ERROR_NONE; +} + static void __handle_connected_client(vine_gatt_s *gatt, const char *address) { RET_IF(gatt == NULL, "Invalid parameter."); @@ -465,6 +715,9 @@ static void __handle_connected_client(vine_gatt_s *gatt, const char *address) RET_IF(accepted_gatt == NULL, "Failed to create accepted gatt."); gatt->role.server->client_list->insert(std::make_pair(string(address), accepted_gatt)); + _register_conn_state_changed_cb(gatt, address, + __gatt_accepted_client_state_changed_cb, (void *)accepted_gatt); + VINE_LOGI("%s is connected.", address); __invoke_accepted_cb(accepted_gatt, accepted_gatt->user); } @@ -476,44 +729,16 @@ static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address) RET_IF(gatt->role.server == NULL || gatt->role.server->client_list == NULL, "Invalid parameter."); + // TODO: Get client gatt from parameter. vine_gatt_s *client_gatt = __find_client_gatt(gatt, address); RET_IF(client_gatt == NULL, "Cannot find a client[%s].", address); gatt->role.server->client_list->erase(address); + _unregister_conn_state_changed_cb(gatt, address, (void *)client_gatt); __invoke_terminated_cb(client_gatt->user); VINE_LOGI("%s is disconnected.", address); } -static void __gatt_connection_state_changed_cb(int result, bool connected, - const char *remote_address, void *user_data) -{ - RET_IF(user_data == NULL, "user_data is NULL"); - - vine_gatt_s *gatt = (vine_gatt_s *)user_data; - - VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s] role[%d]", - gatt, result, connected, remote_address, gatt->type); - - if (!connected) { - if (gatt->type == VINE_GATT_ROLE_SERVER) - __handle_disconnected_client(gatt, remote_address); - else - __invoke_terminated_cb(gatt->user); - return; - } - - if (gatt->type == VINE_GATT_ROLE_SERVER && gatt->role.server) { - __handle_connected_client(gatt, remote_address); - } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { - if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) { - bt_gatt_disconnect(remote_address); - result = -1; - } - gatt->ready_to_write = true; - __invoke_connected_cb(result, gatt->user); - } -} - static vine_gatt_s *_create_gatt(void) { vine_gatt_s *gatt = (vine_gatt_s *)calloc(1, sizeof(vine_gatt_s)); @@ -526,13 +751,6 @@ static vine_gatt_s *_create_gatt(void) return NULL; } - if (bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb, - (void *)gatt) != BT_ERROR_NONE) { - VINE_LOGE("Failed to register GATT connection state changed callback"); - free(gatt); - return NULL; - } - gatt->eventfd = fd; g_eventfds[gatt->eventfd] = gatt; gatt->recv_buffer = new VineQueue; @@ -540,30 +758,33 @@ static vine_gatt_s *_create_gatt(void) return gatt; } -static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, vine_dp_plugin_h handle) +static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, + const char *uuid, + bt_gatt_server_read_value_requested_cb read_requested_cb, + bt_gatt_server_write_value_requested_cb write_requested_cb, + bt_gatt_server_characteristic_notification_state_changed_cb noti_changed_cb, + vine_dp_plugin_h handle) { bt_gatt_h characteristic = NULL; char initial_value[1] = {'0'}; // TODO: will be changed. int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE; int properties = BT_GATT_PROPERTY_BROADCAST | BT_GATT_PROPERTY_READ | - BT_GATT_PROPERTY_WRITE - | BT_GATT_PROPERTY_INDICATE; + BT_GATT_PROPERTY_WRITE | BT_GATT_PROPERTY_INDICATE; - if (bt_gatt_characteristic_create(VINE_GATT_CHAR_UUID, - permissions, properties, + if (bt_gatt_characteristic_create(uuid, permissions, properties, initial_value, sizeof(initial_value), &characteristic) != BT_ERROR_NONE) return NULL; if (bt_gatt_server_set_read_value_requested_cb(characteristic, - __gatt_server_read_value_requested_cb, handle) != BT_ERROR_NONE) + read_requested_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_server_set_write_value_requested_cb(characteristic, - __gatt_server_write_value_requested_cb, handle) != BT_ERROR_NONE) + write_requested_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_server_set_characteristic_notification_state_change_cb(characteristic, - __gatt_server_noti_state_changed_cb, handle) != BT_ERROR_NONE) + noti_changed_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_service_add_characteristic(service, characteristic) != BT_ERROR_NONE) @@ -620,11 +841,11 @@ static int __write_to_server(vine_gatt_s *gatt) gatt_data_s *data = __get_pending_write_data(gatt); RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); + int ret = bt_gatt_set_value(gatt->read_write_char, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); - ret = bt_gatt_client_write_value(gatt->characteristic, + ret = bt_gatt_client_write_value(gatt->read_write_char, __gatt_client_write_complete_cb, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_client_write_value() failed."); @@ -668,11 +889,11 @@ static int __write_to_client(vine_gatt_s *gatt) gatt_data_s *data = __get_pending_write_data(gatt); RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); + int ret = bt_gatt_set_value(gatt->read_write_char, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); - ret = bt_gatt_server_notify_characteristic_changed_value(gatt->characteristic, + ret = bt_gatt_server_notify_characteristic_changed_value(gatt->read_write_char, __gatt_server_noti_sent_cb, gatt->remote_address, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_server_notify_characteristic_changed_value() failed."); @@ -721,7 +942,7 @@ void gatt_process_event(int fd, int events) return; } - // TODO: handle pending write events. + // Handle pending write events. vine_gatt_s *gatt = it->second; VINE_LOGI("found gatt[%p]", gatt); @@ -738,6 +959,13 @@ int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user) RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); RET_VAL_IF(user == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "user is NULL"); + // TODO: need to find proper point to register callback. + int ret = bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb, NULL); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to register GATT connection state changed callback"); + return __convert_bt_error_to_data_path_error(ret); + } + vine_gatt_s *gatt = plugin_data ? (vine_gatt_s *)plugin_data :_create_gatt(); RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OPERATION_FAILED, "Failed to create GATT handle"); @@ -757,8 +985,10 @@ int gatt_destroy(vine_dp_plugin_h handle) _destroy_gatt_server(gatt->role.server); gatt->role.server = NULL; bt_gatt_service_destroy(gatt->service); - bt_gatt_characteristic_destroy(gatt->characteristic); - bt_gatt_descriptor_destroy(gatt->descriptor); + bt_gatt_characteristic_destroy(gatt->connection_char); + bt_gatt_descriptor_destroy(gatt->connection_desc); + bt_gatt_characteristic_destroy(gatt->read_write_char); + bt_gatt_descriptor_destroy(gatt->read_write_desc); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { // bt_gatt_h handles will be freed during bt_gatt_client_destroy(). _destroy_gatt_client(gatt->role.client); @@ -767,8 +997,10 @@ int gatt_destroy(vine_dp_plugin_h handle) close(gatt->eventfd); gatt->service = NULL; - gatt->characteristic = NULL; - gatt->descriptor = NULL; + gatt->connection_char = NULL; + gatt->connection_desc = NULL; + gatt->read_write_char = NULL; + gatt->read_write_desc = NULL; free(gatt->remote_address); gatt->remote_address = NULL; free(gatt); @@ -785,8 +1017,10 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, vine_gatt_s *gatt = (vine_gatt_s *)handle; bt_gatt_server_h server = NULL; bt_gatt_h service = NULL; - bt_gatt_h characteristic = NULL; - bt_gatt_h descriptor = NULL; + bt_gatt_h connection_char = NULL; + bt_gatt_h connection_desc = NULL; + bt_gatt_h read_write_char = NULL; + bt_gatt_h read_write_desc = NULL; int ret = BT_ERROR_OPERATION_FAILED; // This returns OPERATION_FAILED when already initialized. ignore it. @@ -799,30 +1033,44 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, } ret = bt_gatt_service_create(VINE_GATT_SERVICE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &service); - if (ret != BT_ERROR_NONE) { + if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to create service."); goto ERR; } - characteristic = _add_gatt_characteristic(service, handle); - if (!characteristic) { + connection_char = _add_gatt_characteristic(service, VINE_GATT_CONNECTION_CHAR_UUID, + __gatt_server_read_connection_value_requested_cb, + __gatt_server_write_connection_value_requested_cb, + __gatt_server_noti_connection_state_changed_cb, handle); + + connection_desc = _add_gatt_descriptor(connection_char); + if (!connection_desc) { + VINE_LOGE("Failed to add descriptor."); + goto ERR; + } + + read_write_char = _add_gatt_characteristic(service, VINE_GATT_READ_WRITE_CHAR_UUID, + __gatt_server_read_value_requested_cb, + __gatt_server_write_value_requested_cb, + __gatt_server_noti_state_changed_cb, handle); + if (!read_write_char) { VINE_LOGE("Failed to add characteristc."); goto ERR; } - descriptor = _add_gatt_descriptor(characteristic); - if (!descriptor) { + read_write_desc = _add_gatt_descriptor(read_write_char); + if (!read_write_desc) { VINE_LOGE("Failed to add descriptor."); goto ERR; } - ret = bt_gatt_server_register_service(server, service); + ret = bt_gatt_server_register_service(server, service); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to register service."); goto ERR; } - ret = bt_gatt_server_start(); + ret = bt_gatt_server_start(); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to start GATT server."); goto ERR; @@ -834,8 +1082,10 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, goto ERR; gatt->service = service; - gatt->characteristic = characteristic; - gatt->descriptor = descriptor; + gatt->connection_char = connection_char; + gatt->connection_desc = connection_desc; + gatt->read_write_char = read_write_char; + gatt->read_write_desc = read_write_desc; VINE_LOGI("Succeeded to start GATT server."); @@ -848,16 +1098,20 @@ ERR: bt_gatt_server_destroy(server); if (service) bt_gatt_service_destroy(service); - if (characteristic) - bt_gatt_characteristic_destroy(characteristic); - if (descriptor) - bt_gatt_descriptor_destroy(descriptor); + if (connection_char) + bt_gatt_characteristic_destroy(connection_char); + if (connection_desc) + bt_gatt_descriptor_destroy(connection_desc); + if (read_write_char) + bt_gatt_characteristic_destroy(read_write_char); + if (read_write_desc) + bt_gatt_descriptor_destroy(read_write_desc); return ret; } // All parameters except handle and addr are not used in BT GATT. int gatt_connect(vine_dp_plugin_h handle, int addr_family, - const char *addr, int gatt_port, const char *iface_name, vine_dp_ssl ssl) + const char *addr, int port, const char *iface_name, vine_dp_ssl ssl) { RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL"); @@ -865,11 +1119,13 @@ int gatt_connect(vine_dp_plugin_h handle, int addr_family, vine_gatt_s *gatt = (vine_gatt_s *)handle; int ret; + _register_conn_state_changed_cb(gatt, addr, __gatt_client_state_changed_cb, NULL); gatt->type = VINE_GATT_ROLE_CLIENT; ret = bt_gatt_connect(addr, false); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to connect remote LE based service."); gatt->type = VINE_GATT_ROLE_UNKNOWN; + _unregister_conn_state_changed_cb(gatt, addr, NULL); return __convert_bt_error_to_data_path_error(ret); } @@ -968,7 +1224,7 @@ int gatt_close(vine_dp_plugin_h handle) ret = bt_gatt_server_unregister_service(gatt->role.server->server, gatt->service); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { VINE_LOGI("Disconnect from %s", gatt->remote_address); - ret = bt_gatt_disconnect(gatt->remote_address); + // TODO: Send disconnect message. } return __convert_bt_error_to_data_path_error(ret); }