static void discover_ccc_cb(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct heartrate *hr = user_data; struct att_data_list *list; uint8_t format; int i; if (status != 0) { error("Discover Heart Rate Measurement descriptors failed: %s", att_ecode2str(status)); return; } list = dec_find_info_resp(pdu, len, &format); if (list == NULL) return; if (format != ATT_FIND_INFO_RESP_FMT_16BIT) goto done; for (i = 0; i < list->num; i++) { uint8_t *value; uint16_t handle, uuid; char *msg; uint8_t attr_val[2]; value = list->data[i]; handle = att_get_u16(value); uuid = att_get_u16(value + 2); if (uuid != GATT_CLIENT_CHARAC_CFG_UUID) continue; hr->measurement_ccc_handle = handle; if (g_slist_length(hr->hradapter->watchers) == 0) { att_put_u16(0x0000, attr_val); msg = g_strdup("Disable measurement"); } else { att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, attr_val); msg = g_strdup("Enable measurement"); } gatt_write_char(hr->attrib, handle, attr_val, sizeof(attr_val), char_write_cb, msg); break; } done: att_data_list_free(list); }
static void cmd_char_write_common(int argcp, char **argvp, int with_response) { uint8_t *value; size_t plen; int handle; if (conn_state != STATE_CONNECTED) { resp_error(err_BAD_STATE); return; } if (argcp < 3) { resp_error(err_BAD_PARAM); return; } handle = strtohandle(argvp[1]); if (handle <= 0) { resp_error(err_BAD_PARAM); return; } plen = gatt_attr_data_from_string(argvp[2], &value); if (plen == 0) { resp_error(err_BAD_PARAM); return; } if (with_response) gatt_write_char(attrib, handle, value, plen, char_write_req_cb, NULL); else { gatt_write_char(attrib, handle, value, plen, NULL, NULL); resp_begin(rsp_WRITE); resp_end(); } g_free(value); }
static void read_supported_locations(struct csc *csc) { struct controlpoint_req *req; req = g_new0(struct controlpoint_req, 1); req->csc = csc; req->opcode = REQUEST_SUPPORTED_SENSOR_LOC; csc->pending_req = req; gatt_write_char(csc->attrib, csc->controlpoint_val_handle, &req->opcode, sizeof(req->opcode), controlpoint_write_cb, req); }
static void set_report(struct uhid_event *ev, void *user_data) { struct hog_device *hogdev = user_data; struct report *report; void *data; int size; int err; /* uhid never sends reqs in parallel; if there's a req, it timed out */ if (hogdev->setrep_att) { g_attrib_cancel(hogdev->attrib, hogdev->setrep_att); hogdev->setrep_att = 0; } hogdev->setrep_id = ev->u.set_report.id; report = find_report(hogdev, ev->u.set_report.rtype, ev->u.set_report.rnum); if (!report) { err = ENOTSUP; goto fail; } data = ev->u.set_report.data; size = ev->u.set_report.size; if (hogdev->has_report_id && size > 0) { data++; --size; } DBG("Sending report type %d ID %d to handle 0x%X", report->type, report->id, report->decl->value_handle); if (hogdev->attrib == NULL) return; hogdev->setrep_att = gatt_write_char(hogdev->attrib, report->decl->value_handle, data, size, set_report_cb, hogdev); if (!hogdev->setrep_att) { err = ENOMEM; goto fail; } return; fail: /* cancel the request on failure */ set_report_cb(err, NULL, 0, hogdev); }
static void write_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle, const uint8_t *value, size_t vlen, GAttribResultFunc func, gpointer user_data) { struct gatt_request *req; unsigned int id; req = create_request(bas, user_data); id = gatt_write_char(attrib, handle, value, vlen, func, req); set_and_store_gatt_req(bas, req, id); }
static void cmd_char_write(int argcp, char **argvp) { uint8_t *value; size_t plen; int handle; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp < 3) { printf("Usage: %s <handle> <new value>\n", argvp[0]); return; } handle = strtohandle(argvp[1]); if (handle <= 0) { printf("A valid handle is required\n"); return; } plen = gatt_attr_data_from_string(argvp[2], &value); if (plen == 0) { g_printerr("Invalid value\n"); return; } if (g_strcmp0("char-write-req", argvp[0]) == 0) gatt_write_char(g_connection->attrib, handle, value, plen, char_write_req_cb, NULL); else gatt_write_char(g_connection->attrib, handle, value, plen, NULL, NULL); g_free(value); }
static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle, const uint8_t *value, size_t vlen, GAttribResultFunc func, gpointer user_data) { unsigned int id; id = gatt_write_char(attrib, handle, value, vlen, func, user_data); if (queue_push_head(scan->gatt_op, UINT_TO_PTR(id))) return; error("scpp: Could not read char"); g_attrib_cancel(attrib, id); }
static void forward_report(struct uhid_event *ev, void *user_data) { struct bt_hog *hog = user_data; struct report *report; GSList *l; void *data; int size; guint type; if (hog->has_report_id) { data = ev->u.output.data + 1; size = ev->u.output.size - 1; } else { data = ev->u.output.data; size = ev->u.output.size; } switch (ev->type) { case UHID_OUTPUT: type = HOG_REPORT_TYPE_OUTPUT; break; case UHID_FEATURE: type = HOG_REPORT_TYPE_FEATURE; break; default: return; } l = g_slist_find_custom(hog->reports, GUINT_TO_POINTER(type), report_type_cmp); if (!l) return; report = l->data; DBG("Sending report type %d to handle 0x%X", type, report->decl->value_handle); if (hog->attrib == NULL) return; if (report->decl->properties & GATT_CHR_PROP_WRITE) gatt_write_char(hog->attrib, report->decl->value_handle, data, size, output_written_cb, hog); else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP) gatt_write_cmd(hog->attrib, report->decl->value_handle, data, size, NULL, NULL); }
static void enable_measurement(gpointer data, gpointer user_data) { struct heartrate *hr = data; uint16_t handle = hr->measurement_ccc_handle; uint8_t value[2]; char *msg; if (hr->attrib == NULL || !handle) return; att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value); msg = g_strdup("Enable measurement"); gatt_write_char(hr->attrib, handle, value, sizeof(value), char_write_cb, msg); }
static void disable_measurement(gpointer data, gpointer user_data) { struct heartrate *hr = data; uint16_t handle = hr->measurement_ccc_handle; uint8_t value[2]; char *msg; if (hr->attrib == NULL || !handle) return; att_put_u16(0x0000, value); msg = g_strdup("Disable measurement"); gatt_write_char(hr->attrib, handle, value, sizeof(value), char_write_cb, msg); }
int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, void* buffer, size_t buffer_len) { int write_completed = FALSE; guint ret = gatt_write_char(connection->attrib, handle, buffer, buffer_len, gattlib_write_result_cb, &write_completed); if (ret == 0) { return 1; } // Wait for completion of the event while(write_completed == FALSE) { g_main_context_iteration(g_gattlib_thread.loop_context, FALSE); } return 0; }
static void discover_descriptor_cb(uint8_t status, GSList *descs, void *user_data) { struct scan *scan = user_data; struct gatt_desc *desc; uint8_t value[2]; if (status != 0) { error("Discover descriptors failed: %s", att_ecode2str(status)); return; } /* There will be only one descriptor on list and it will be CCC */ desc = descs->data; put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value); gatt_write_char(scan->attrib, desc->handle, value, sizeof(value), ccc_written_cb, user_data); }
static void cmd_anki_vehicle_lights_pattern(int argcp, char **argvp) { uint8_t *value; size_t plen; int handle; if (conn_state != STATE_CONNECTED) { failed("Disconnected\n"); return; } if (argcp < 6) { rl_printf("Usage: %s <channel> <effect> <start> <end> <cycles_per_min>\n", argvp[0]); rl_printf(" channels: RED, TAIL, BLUE, GREEN, FRONTL, FRONTR\n"); rl_printf(" effects: STEADY, FADE, THROB, FLASH, RANDOM\n"); return; } handle = vehicle.write_char.value_handle; uint8_t channel = get_channel_by_name(argvp[1]); if (channel == channel_invalid) { rl_printf("Unrecognized channel: %s\n", argvp[1]); return; } uint8_t effect = get_effect_by_name(argvp[2]); if (effect == effect_invalid) { rl_printf("Unrecognized channel: %s\n", argvp[2]); return; } uint8_t start = atoi(argvp[3]); uint8_t end = atoi(argvp[4]); uint16_t cycles_per_min = atoi(argvp[5]); anki_vehicle_msg_t msg; plen = anki_vehicle_msg_lights_pattern(&msg, channel, effect, start, end, cycles_per_min); value = (uint8_t *)&msg; gatt_write_char(attrib, handle, value, plen, NULL, NULL); }
static DBusMessage *write_val(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; struct characteristic *chr = data; struct gatt_service *gatt = chr->gatt; char* value; char* write_method; uint16_t len = 0; uint16_t offset = 0; uint16_t timeout = 0; guint retvalue = 0; struct write_val_op *op; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY,DBUS_TYPE_BYTE, &value, &len, DBUS_TYPE_STRING, &write_method, DBUS_TYPE_UINT16, &offset, DBUS_TYPE_UINT16, &timeout, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); DBG("WriteValue");// chr=%s value[0]=%d len=%d write_method=%s offset=%d timeout=%d",chr->path, value[0], len, write_method, offset, timeout); op = g_new0(struct write_val_op, 1); op->msg = dbus_message_ref(msg); op->conn = conn; op->chr = chr; if (g_str_equal("WriteWithResponse", write_method)) { INFO("write with response"); retvalue = gatt_write_char(chr->gatt->attrib, chr->handle, (uint8_t*)value, len, write_req_cb, op); } else if (g_str_equal("WriteWithoutResponse", write_method)) { INFO("write without response"); retvalue = gatt_write_cmd(chr->gatt->attrib, chr->handle, (uint8_t*)value, len, write_cmd_cb, op); } else { ERROR("write_method %s is not supported at the moment.",write_method); return btd_error_not_supported(msg); } return NULL; }
static void exchange_mtu_cb( guint8 status, guint8 const* pdu, guint16 plen, gpointer user_data) { uint16_t mtu; user_data_t* ud = static_cast<user_data_t*>(user_data); if (status != 0) { std::cout << "Exchange MTU Request failed: " << att_ecode2str(status) << std::endl; disconnect(ud->attrib, ud->chan); g_main_loop_quit(event_loop); return; } if (!dec_mtu_resp(pdu, plen, &mtu)) { std::cout << "Protocol error" << std::endl; disconnect(ud->attrib, ud->chan); g_main_loop_quit(event_loop); return; } mtu = std::min(mtu, ud->mtu); /* Set new value for MTU in client */ if (g_attrib_set_mtu(ud->attrib, mtu)) { std::cout << "MTU was exchanged successfully:" << mtu << std::endl; gatt_write_char( ud->attrib, ud->handle, reinterpret_cast<uint8_t const*>(&ud->value), sizeof(ud->value), gatt_write_char_cb, nullptr); } else { std::cout << "Error exchanging MTU" << std::endl; disconnect(ud->attrib, ud->chan); g_main_loop_quit(event_loop); } }
static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle, const uint8_t *value, size_t vlen, GAttribResultFunc func, gpointer user_data) { struct gatt_request *req; unsigned int id; req = create_request(scan, user_data); if (!req) return; id = gatt_write_char(attrib, handle, value, vlen, func, req); if (set_and_store_gatt_req(scan, req, id)) return; error("scpp: Could not read char"); g_attrib_cancel(attrib, id); free(req); }
static void char_discovered_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct monitor *monitor = user_data; struct att_char *chr; uint8_t value = str2level(monitor->linklosslevel); if (status) { error("Discover Link Loss handle: %s", att_ecode2str(status)); return; } DBG("Setting alert level \"%s\" on Reporter", monitor->linklosslevel); /* Assume there is a single Alert Level characteristic */ chr = characteristics->data; monitor->linklosshandle = chr->value_handle; gatt_write_char(monitor->attrib, monitor->linklosshandle, &value, 1, linkloss_written, monitor); }
static int write_alert_level(struct monitor *monitor) { struct att_range *linkloss = monitor->linkloss; bt_uuid_t uuid; if (monitor->linklosshandle) { uint8_t value = str2level(monitor->linklosslevel); gatt_write_char(monitor->attrib, monitor->linklosshandle, &value, 1, linkloss_written, monitor); return 0; } bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID); /* FIXME: use cache (requires service changed support) ? */ gatt_discover_char(monitor->attrib, linkloss->start, linkloss->end, &uuid, char_discovered_cb, monitor); return 0; }
static void discover_desc_cb(guint8 status, GSList *descs, gpointer user_data) { struct characteristic *ch = user_data; struct gatt_desc *desc; uint8_t attr_val[2]; char *msg = NULL; if (status != 0) { error("Discover %s descriptors failed: %s", ch->uuid, att_ecode2str(status)); goto done; } /* There will be only one descriptor on list and it will be CCC */ desc = descs->data; if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0) { ch->csc->measurement_ccc_handle = desc->handle; if (g_slist_length(ch->csc->cadapter->watchers) == 0) { put_le16(0x0000, attr_val); msg = g_strdup("Disable measurement"); } else { put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, attr_val); msg = g_strdup("Enable measurement"); } } else if (g_strcmp0(ch->uuid, SC_CONTROL_POINT_UUID) == 0) { put_le16(GATT_CLIENT_CHARAC_CFG_IND_BIT, attr_val); msg = g_strdup("Enable SC Control Point indications"); } else { goto done; } gatt_write_char(ch->csc->attrib, desc->handle, attr_val, sizeof(attr_val), char_write_cb, msg); done: g_free(ch); }
static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg, void *data) { struct heartrate *hr = data; uint8_t value; char *vmsg; if (!hr->hrcp_val_handle) return btd_error_not_supported(msg); if (!hr->attrib) return btd_error_not_available(msg); value = 0x01; vmsg = g_strdup("Reset Control Point"); gatt_write_char(hr->attrib, hr->hrcp_val_handle, &value, sizeof(value), char_write_cb, vmsg); DBG("Energy Expended Value has been reset"); return dbus_message_new_method_return(msg); }
static int cmd_char_write(gpointer user_data, const char *handle, const char* data, int type) { GAttrib *attrib = user_data; uint8_t *value; size_t len; int hdl, ret; /* we need to enable notifications very early, as well change mode * when we receive an exception to quit */ if ((get_state() != STATE_DATARCVD) && (get_state() != STATE_CONNECTED)) { printf("Device is not connected\n"); return -1; } hdl = strtohandle(handle); if (hdl <= 0) { printf("A valid handle is needed\n"); return -2; } len = gatt_attr_data_from_string(data, &value); if (len == 0) { printf("Invalid value(s) passed\n"); return -3; } if (type == WRITE_REQUEST) { ret = gatt_write_char(attrib, hdl, value, len, NULL, NULL); } else if (type == WRITE_COMMAND) { ret = gatt_write_cmd(attrib, hdl, value, len, NULL, NULL); } g_free(value); return 0; }
static void cmd_anki_vehicle_get_version(int argcp, char **argvp) { uint8_t *value; size_t plen; int handle; if (conn_state != STATE_CONNECTED) { failed("Disconnected\n"); return; } if (argcp < 1) { rl_printf("Usage: %s\n", argvp[0]); return; } handle = vehicle.write_char.value_handle; anki_vehicle_msg_t msg; plen = anki_vehicle_msg_get_version(&msg); value = (uint8_t *)&msg; gatt_write_char(attrib, handle, value, plen, NULL, NULL); }