static void discover_descriptor_cb(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct report *report; struct hog_device *hogdev; struct att_data_list *list; uint8_t format; int i; if (status != 0) { error("Discover all characteristic 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++) { uint16_t uuid16, handle; uint8_t *value; value = list->data[i]; handle = att_get_u16(value); uuid16 = att_get_u16(&value[2]); switch (uuid16) { case GATT_CLIENT_CHARAC_CFG_UUID: report = user_data; write_ccc(handle, report->hogdev); break; case GATT_REPORT_REFERENCE: report = user_data; gatt_read_char(report->hogdev->attrib, handle, report_reference_cb, report); break; case GATT_EXTERNAL_REPORT_REFERENCE: hogdev = user_data; gatt_read_char(hogdev->attrib, handle, external_report_reference_cb, hogdev); break; } } done: att_data_list_free(list); }
static void report_reference_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct report *report = user_data; if (status != 0) { error("Read Report Reference descriptor failed: %s", att_ecode2str(status)); return; } if (plen != 3) { error("Malformed ATT read response"); return; } report->id = pdu[1]; report->type = pdu[2]; DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]); /* Enable notifications only for Input Reports */ if (report->type == HOG_REPORT_TYPE_INPUT) gatt_read_char(report->hog->attrib, report->ccc_handle, ccc_read_cb, report); }
static void cmd_read_hnd(int argcp, char **argvp) { int handle; if (conn_state != STATE_CONNECTED) { resp_error(err_BAD_STATE); return; } if (argcp < 2) { resp_error(err_BAD_PARAM);; return; } handle = strtohandle(argvp[1]); if (handle < 0) { resp_error(err_BAD_PARAM);; return; } if (argcp == 2) { gatt_read_char(attrib, handle, char_read_cb, attrib); } else { char *end; int offset = strtol(argvp[2], &end, 0); if (*end != '\0') { resp_error(err_BAD_PARAM);; return; } gatt_read_char_single(attrib, handle, offset, char_read_single_cb, attrib); } }
static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data) { struct heartrate *hr = user_data; if (status) { error("Discover HRS characteristics failed: %s", att_ecode2str(status)); return; } for (; chars; chars = chars->next) { struct gatt_char *c = chars->data; if (g_strcmp0(c->uuid, HEART_RATE_MEASUREMENT_UUID) == 0) { struct gatt_char *c_next = (chars->next ? chars->next->data : NULL); hr->measurement_val_handle = c->value_handle; discover_measurement_ccc(hr, c, c_next); } else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) { DBG("Body Sensor Location supported"); gatt_read_char(hr->attrib, c->value_handle, read_sensor_location_cb, hr); } else if (g_strcmp0(c->uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) { DBG("Heart Rate Control Point supported"); hr->hrcp_val_handle = c->value_handle; } } }
static gboolean characteristics_read(gpointer user_data) { GAttrib *attrib = user_data; if (opt_uuid != NULL) { struct characteristic_data *char_data; char_data = g_new(struct characteristic_data, 1); char_data->attrib = attrib; char_data->start = opt_start; char_data->end = opt_end; gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid, char_read_by_uuid_cb, char_data); return FALSE; } if (opt_handle <= 0) { g_printerr("A valid handle is required\n"); g_main_loop_quit(event_loop); return FALSE; } gatt_read_char(attrib, opt_handle, char_read_cb, attrib); return FALSE; }
static void get_report(struct uhid_event *ev, void *user_data) { struct hog_device *hogdev = user_data; struct report *report; guint8 err; /* uhid never sends reqs in parallel; if there's a req, it timed out */ if (hogdev->getrep_att) { g_attrib_cancel(hogdev->attrib, hogdev->getrep_att); hogdev->getrep_att = 0; } hogdev->getrep_id = ev->u.get_report.id; report = find_report(hogdev, ev->u.get_report.rtype, ev->u.get_report.rnum); if (!report) { err = ENOTSUP; goto fail; } hogdev->getrep_att = gatt_read_char(hogdev->attrib, report->decl->value_handle, get_report_cb, hogdev); if (!hogdev->getrep_att) { err = ENOMEM; goto fail; } return; fail: /* cancel the request on failure */ get_report_cb(err, NULL, 0, hogdev); }
//reads a certain handle and places value into buf, returns length int ble_char_read(int handle, unsigned char* buf){ //auto connect if not connected if(!ble_connected){ ble_connect(name); } ble_read = 0; gettimeofday(&t1, NULL); gatt_read_char(attrib, handle, char_read_cb, attrib); while(!ble_read){ usleep(10000); gettimeofday(&t2, NULL); elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms if (elapsedTime > 250) //timeout of 250ms { printf("read error: %lf\n", elapsedTime); ble_disconnect(); return 0; } } //printf("(%lfms) len: %d\n", elapsedTime, (int)ble_read_len); /*for (i = 0; i < ble_read_len; i++){ printf("%02x ", ble_read_val[i]); } printf("\n");*/ memcpy(buf, ble_read_val, ble_read_len); return ble_read_len; }
static void discover_report_cb(uint8_t status, GSList *descs, void *user_data) { struct report *report = user_data; struct bt_hog *hog = report->hog; if (status != 0) { error("Discover report descriptors failed: %s", att_ecode2str(status)); return; } for ( ; descs; descs = descs->next) { struct gatt_desc *desc = descs->data; switch (desc->uuid16) { case GATT_CLIENT_CHARAC_CFG_UUID: report->ccc_handle = desc->handle; break; case GATT_REPORT_REFERENCE: gatt_read_char(hog->attrib, desc->handle, report_reference_cb, report); break; } } }
static void cmd_read_hnd(int argcp, char **argvp) { int handle; int offset = 0; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp < 2) { printf("Missing argument: handle\n"); return; } handle = strtohandle(argvp[1]); if (handle < 0) { printf("Invalid handle: %s\n", argvp[1]); return; } if (argcp > 2) { char *e; errno = 0; offset = strtol(argvp[2], &e, 0); if (errno != 0 || *e != '\0') { printf("Invalid offset: %s\n", argvp[2]); return; } } gatt_read_char(g_connection->attrib, handle, offset, char_read_cb, g_connection->attrib); }
static void discover_char_cb(uint8_t status, GSList *chars, void *user_data) { struct csc *csc = user_data; uint16_t feature_val_handle = 0; if (status) { error("Discover CSCS characteristics: %s", att_ecode2str(status)); return; } for (; chars; chars = chars->next) { struct gatt_char *c = chars->data; struct gatt_char *c_next = (chars->next ? chars->next->data : NULL); if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) { csc->attio_measurement_id = g_attrib_register(csc->attrib, ATT_OP_HANDLE_NOTIFY, c->value_handle, measurement_notify_handler, csc, NULL); discover_desc(csc, c, c_next); } else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) { feature_val_handle = c->value_handle; } else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) { DBG("Sensor Location supported"); gatt_read_char(csc->attrib, c->value_handle, read_location_cb, csc); } else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) { DBG("SC Control Point supported"); csc->controlpoint_val_handle = c->value_handle; csc->attio_controlpoint_id = g_attrib_register( csc->attrib, ATT_OP_HANDLE_IND, c->value_handle, controlpoint_ind_handler, csc, NULL); discover_desc(csc, c, c_next); } } if (feature_val_handle > 0) gatt_read_char(csc->attrib, feature_val_handle, read_feature_cb, csc); }
static void read_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle, GAttribResultFunc func, gpointer user_data) { struct gatt_request *req; unsigned int id; req = create_request(bas, user_data); id = gatt_read_char(attrib, handle, func, req); set_and_store_gatt_req(bas, req, id); }
static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr) { struct report *report; report = g_new0(struct report, 1); report->hog = hog; report->decl = g_memdup(chr, sizeof(*chr)); hog->reports = g_slist_append(hog->reports, report); gatt_read_char(hog->attrib, chr->value_handle, report_read_cb, report); return report; }
static void discover_descriptor_cb(uint8_t status, GSList *descs, void *user_data) { struct report *report; struct hog_device *hogdev; GAttrib *attrib = NULL; if (status != 0) { error("Discover all descriptors failed: %s", att_ecode2str(status)); return; } for ( ; descs; descs = descs->next) { struct gatt_desc *desc = descs->data; switch (desc->uuid16) { case GATT_CLIENT_CHARAC_CFG_UUID: report = user_data; report->ccc_handle = desc->handle; enable_report_notifications(report, true); break; case GATT_REPORT_REFERENCE: report = user_data; attrib = report->hogdev->attrib; gatt_read_char(attrib, desc->handle, report_reference_cb, report); break; case GATT_EXTERNAL_REPORT_REFERENCE: hogdev = user_data; attrib = hogdev->attrib; gatt_read_char(attrib, desc->handle, external_report_reference_cb, hogdev); break; } } }
static void read_tx_power(struct monitor *monitor) { struct att_range *txpower = monitor->txpower; bt_uuid_t uuid; if (monitor->txpowerhandle != 0) { gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0, tx_power_read_cb, monitor); return; } bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID); gatt_discover_char(monitor->attrib, txpower->start, txpower->end, &uuid, tx_power_handle_cb, monitor); }
static void discover_external_cb(uint8_t status, GSList *descs, void *user_data) { struct bt_hog *hog = user_data; if (status != 0) { error("Discover external descriptors failed: %s", att_ecode2str(status)); return; } for ( ; descs; descs = descs->next) { struct gatt_desc *desc = descs->data; gatt_read_char(hog->attrib, desc->handle, external_report_reference_cb, hog); } }
static void tx_power_handle_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct monitor *monitor = user_data; struct att_char *chr; if (status) { error("Discover Tx Power handle: %s", att_ecode2str(status)); return; } chr = characteristics->data; monitor->txpowerhandle = chr->value_handle; DBG("Tx Power handle: 0x%04x", monitor->txpowerhandle); gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0, tx_power_read_cb, monitor); }
static void read_char(struct bt_dis *dis, GAttrib *attrib, uint16_t handle, GAttribResultFunc func, gpointer user_data) { struct gatt_request *req; unsigned int id; req = create_request(dis, user_data); if (!req) return; id = gatt_read_char(attrib, handle, func, req); if (set_and_store_gatt_req(dis, req, id)) return; error("dis: Could not read characteristic"); g_attrib_cancel(attrib, id); free(req); }
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; INFO("%s",chr->path); if (status == 0) { g_free(chr->desc); chr->desc = g_malloc(len); memcpy(chr->desc, pdu + 1, len - 1); chr->desc[len - 1] = '\0'; store_attribute(gatt, current->handle, GATT_CHARAC_USER_DESC_UUID, (void *) chr->desc, len); } else if (status == ATT_ECODE_INSUFF_ENC) { GIOChannel *io = g_attrib_get_channel(gatt->attrib); BtIOSecLevel level = BT_IO_SEC_HIGH; bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, &level, BT_IO_OPT_INVALID); if (level < BT_IO_SEC_HIGH) level++; if (bt_io_set(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, level, BT_IO_OPT_INVALID)) { gatt_read_char(gatt->attrib, current->handle, 0, update_char_desc, current); return; } } add_characteristic_descriptor(current, GATT_CHARAC_USER_DESC_UUID); query_list_remove(gatt, current); g_free(current); }
static void cmd_anki_vehicle_read(int argcp, char **argvp) { if (conn_state != STATE_CONNECTED) { failed("Disconnected\n"); return; } if (argcp < 1) { error("Missing argument: handle\n"); return; } int handle = vehicle.read_char.value_handle; if (handle < 0) { error("Invalid handle: %s\n", argvp[1]); return; } gatt_read_char(attrib, handle, char_read_cb, attrib); }
static int cmd_read_char(gpointer user_data, const char *handle) { GAttrib *attrib = user_data; int hdl, ret; if (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; } gatt_read_char(attrib, hdl, char_read_cb, attrib); g_main_loop_run(event_loop); return 0; }
static void cmd_read_hnd(int argcp, char **argvp) { int handle; if (conn_state != STATE_CONNECTED) { resp_error(err_BAD_STATE); return; } if (argcp < 2) { resp_error(err_BAD_PARAM); return; } handle = strtohandle(argvp[1]); if (handle < 0) { resp_error(err_BAD_PARAM); return; } gatt_read_char(attrib, handle, char_read_cb, attrib); }
static void cmd_read_hnd(int argcp, char **argvp) { int handle; if (conn_state != STATE_CONNECTED) { failed("Disconnected\n"); return; } if (argcp < 2) { error("Missing argument: handle\n"); return; } handle = strtohandle(argvp[1]); if (handle < 0) { error("Invalid handle: %s\n", argvp[1]); return; } gatt_read_char(attrib, handle, char_read_cb, attrib); }
static gboolean characteristics_read(gpointer user_data) { GAttrib *attrib = user_data; if (opt_uuid != NULL) { gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid, char_read_by_uuid_cb, NULL); return FALSE; } if (opt_handle <= 0) { g_printerr("A valid handle is required\n"); g_main_loop_quit(event_loop); return FALSE; } gatt_read_char(attrib, opt_handle, char_read_cb, attrib); return FALSE; }
static void update_char_value(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; if (status == 0) characteristic_set_value(chr, pdu + 1, len - 1); else if (status == ATT_ECODE_INSUFF_ENC) { GIOChannel *io = g_attrib_get_channel(gatt->attrib); if (bt_io_set(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH, BT_IO_OPT_INVALID)) { gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, current); return; } } query_list_remove(gatt, current); g_free(current); }
static DBusMessage *read_val(DBusConnection *conn, DBusMessage *msg, void *data) { struct characteristic *chr = data; DBusMessage *reply = NULL; DBusMessageIter iter; uint16_t offset = 0; uint16_t timeout = 0; guint retvalue = 0; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &offset, DBUS_TYPE_UINT16, &timeout, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); DBG("ReadValue chr=%s offset=%d timeout=%d",chr->path, offset, timeout); retvalue = gatt_read_char(chr->gatt->attrib,chr->handle,offset, read_val_cb,chr); if (retvalue == 0) return btd_error_failed(msg,"gatt_read_char failed"); return dbus_message_new_method_return(msg); }
static void process_deviceinfo_char(struct characteristic *ch) { if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0) gatt_read_char(ch->d->attrib, ch->attr.value_handle, read_pnpid_cb, ch); }
static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data) { struct bt_hog *hog = user_data; struct gatt_primary *primary = hog->primary; bt_uuid_t report_uuid, report_map_uuid, info_uuid; bt_uuid_t proto_mode_uuid, ctrlpt_uuid; struct report *report; GSList *l; uint16_t info_handle = 0, proto_mode_handle = 0; if (status != 0) { const char *str = att_ecode2str(status); DBG("Discover all characteristics failed: %s", str); return; } bt_uuid16_create(&report_uuid, HOG_REPORT_UUID); bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID); bt_uuid16_create(&info_uuid, HOG_INFO_UUID); bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID); bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID); for (l = chars; l; l = g_slist_next(l)) { struct gatt_char *chr, *next; bt_uuid_t uuid; uint16_t start, end; chr = l->data; next = l->next ? l->next->data : NULL; DBG("0x%04x UUID: %s properties: %02x", chr->handle, chr->uuid, chr->properties); bt_string_to_uuid(&uuid, chr->uuid); start = chr->value_handle + 1; end = (next ? next->handle - 1 : primary->range.end); if (bt_uuid_cmp(&uuid, &report_uuid) == 0) { report = report_new(hog, chr); discover_report(hog->attrib, start, end, report); } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) { gatt_read_char(hog->attrib, chr->value_handle, report_map_read_cb, hog); discover_external(hog->attrib, start, end, hog); } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0) info_handle = chr->value_handle; else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0) proto_mode_handle = chr->value_handle; else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0) hog->ctrlpt_handle = chr->value_handle; } if (proto_mode_handle) { hog->proto_mode_handle = proto_mode_handle; gatt_read_char(hog->attrib, proto_mode_handle, proto_mode_read_cb, hog); } if (info_handle) gatt_read_char(hog->attrib, info_handle, info_read_cb, hog); }
static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; struct att_data_list *list; guint8 format; int i; INFO("%s status=%d",chr->path,status); if (status != 0) { chr->descriptor_count = 0; if (att_device_connected(gatt)) goto update; else goto done; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) { INFO("%s no descriptors",chr->path); chr->descriptor_count = 0; goto update; } INFO("%s %d descriptors",chr->path,list->num); chr->descriptor_count = list->num; for (i = 0; i < list->num; i++) { guint16 handle; bt_uuid_t uuid; uint8_t *dinfo = list->data[i]; struct query_data *qfmt; guint ret = 0; handle = att_get_u16(dinfo); if (format == 0x01) { uuid = att_get_uuid16(&dinfo[2]); } else { /* Currently, only "user description" and "presentation * format" descriptors are used, and both have 16-bit * UUIDs. Therefore there is no need to support format * 0x02 yet. */ INFO("unkown format"); add_characteristic_descriptor(current,0x0000); continue; } qfmt = g_new0(struct query_data, 1); qfmt->gatt = current->gatt; qfmt->chr = current->chr; qfmt->handle = handle; if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) { query_list_append(gatt, qfmt); ret = gatt_read_char(gatt->attrib, handle, 0, update_char_desc, qfmt); } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) { query_list_append(gatt, qfmt); ret = gatt_read_char(gatt->attrib, handle, 0, update_char_format, qfmt); } else if (uuid_desc16_cmp(&uuid, GATT_CLIENT_CHARAC_CFG_UUID) == 0) { query_list_append(gatt, qfmt); ret = gatt_read_char(gatt->attrib, handle, 0, update_char_client_conf, qfmt); } else if (uuid_desc16_cmp(&uuid, GATT_SERVER_CHARAC_CFG_UUID) == 0) { query_list_append(gatt, qfmt); ret = gatt_read_char(gatt->attrib, handle, 0, update_char_server_conf, qfmt); } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_EXT_PROPER_UUID) == 0) { query_list_append(gatt, qfmt); ret = gatt_read_char(gatt->attrib, handle, 0, update_char_ext_props, qfmt); } else g_free(qfmt); if (ret == 0) add_characteristic_descriptor(current,0x0000); } att_data_list_free(list); update: check_updated_characteristics(gatt); done: query_list_remove(gatt, current); g_free(current); }