diff --git a/android/gatt.c b/android/gatt.c
index ddba505..147c4d1 100644
--- a/android/gatt.c
+++ b/android/gatt.c
struct gatt_app *app;
struct queue *transactions;
int32_t id;
+
+ bool wait_execute_write;
};
static struct ipc *hal_ipc = NULL;
goto failed;
}
+ /*
+ * Remember that this application has ongoing prep write
+ * Need it later to find out where to send execute write
+ */
+ if (att_opcode == ATT_OP_PREP_WRITE_REQ)
+ conn->wait_execute_write = true;
+
/* Store the request data, complete callback and transaction id */
transaction = conn_add_transact(conn, att_opcode);
if (!transaction)
goto failed;
- /* TODO figure it out */
- if (att_opcode == ATT_OP_EXEC_WRITE_REQ)
- goto failed;
-
memset(ev, 0, sizeof(*ev));
bdaddr2android(bdaddr, &ev->bdaddr);
return transaction->id == PTR_TO_UINT(user_data);
}
+
+static bool find_conn_waiting_exec_write(const void *data,
+ const void *user_data)
+{
+ const struct app_connection *conn = data;
+
+ return conn->wait_execute_write;
+}
+
+static bool pending_execute_write(void)
+{
+ return queue_find(app_connections, find_conn_waiting_exec_write, NULL);
+}
+
static void handle_server_send_response(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_send_response *cmd = buf;
struct pending_trans_data *transaction;
+ uint16_t handle = cmd->handle;
struct app_connection *conn;
uint8_t status;
goto reply;
}
- send_gatt_response(transaction->opcode, cmd->handle, cmd->offset,
+ if (transaction->opcode == ATT_OP_EXEC_WRITE_REQ) {
+ conn->wait_execute_write = false;
+
+ /* Check for execute response from all server applications */
+ if (pending_execute_write())
+ goto done;
+
+ /* Make sure handle is 0. We need it to find pending request */
+ handle = 0;
+
+ /*
+ * FIXME: Handle situation when not all server applications
+ * respond with a success.
+ */
+ }
+
+ send_gatt_response(transaction->opcode, handle, cmd->offset,
cmd->status, cmd->len, cmd->data,
&conn->device->bdaddr);
+done:
/* Clean request data */
free(transaction);
return 0;
}
+static void send_server_write_execute_notify(void *data, void *user_data)
+{
+ struct hal_ev_gatt_server_request_exec_write *ev = user_data;
+ struct pending_trans_data *transaction;
+ struct app_connection *conn = data;
+
+ if (!conn->wait_execute_write)
+ return;
+
+ ev->conn_id = conn->id;
+
+ transaction = conn_add_transact(conn, ATT_OP_EXEC_WRITE_REQ);
+ if (!transaction) {
+ conn->wait_execute_write = false;
+ return;
+ }
+
+ ev->trans_id = transaction->id;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_REQUEST_EXEC_WRITE,
+ sizeof(*ev), ev);
+}
+
+static uint8_t write_execute_request(const uint8_t *cmd, uint16_t cmd_len,
+ struct gatt_device *dev)
+{
+ struct hal_ev_gatt_server_request_exec_write ev;
+ uint8_t value;
+ struct pending_request *data;
+
+ /*
+ * Check if there was any write prep before.
+ * TODO: Try to find better error code if possible
+ */
+ if (!pending_execute_write())
+ return ATT_ECODE_UNLIKELY;
+
+ if (!dec_exec_write_req(cmd, cmd_len, &value))
+ return ATT_ECODE_INVALID_PDU;
+
+ memset(&ev, 0, sizeof(ev));
+ bdaddr2android(&dev->bdaddr, &ev.bdaddr);
+ ev.exec_write = value;
+
+ data = new0(struct pending_request, 1);
+ if (!data)
+ return ATT_ECODE_INSUFF_RESOURCES;
+
+ data->state = REQUEST_PENDING;
+ if (!queue_push_tail(dev->pending_requests, data)) {
+ free(data);
+ return ATT_ECODE_INSUFF_RESOURCES;
+ }
+
+ queue_foreach(app_connections, send_server_write_execute_notify, &ev);
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
/* Client will handle this */
return;
case ATT_OP_EXEC_WRITE_REQ:
- /* TODO */
+ status = write_execute_request(ipdu, len, dev);
+ if (!status)
+ return;
+ break;
case ATT_OP_HANDLE_CNF:
case ATT_OP_READ_MULTI_REQ:
default: