// 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
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 {
static map<int, struct vine_gatt_s *> 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<string, conn_state_cb_data *> 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)
{
}
// 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,
}
// 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)
{
__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");
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;
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;
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.");
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<string, conn_state_cb_data *>::iterator iterator;
+ pair<iterator, iterator> 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<string, conn_state_cb_data *>(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<string, conn_state_cb_data *>::iterator iterator;
+ pair<iterator, iterator> 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.");
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);
}
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));
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<gatt_data_s *>;
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)
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.");
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.");
return;
}
- // TODO: handle pending write events.
+ // Handle pending write events.
vine_gatt_s *gatt = it->second;
VINE_LOGI("found gatt[%p]", gatt);
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");
_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);
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);
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.
}
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;
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.");
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");
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);
}
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);
}