Пример #1
0
static void cmd_included(int argcp, char **argvp)
{
	int start = 0x0001;
	int end = 0xffff;

	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	if (argcp > 1) {
		start = strtohandle(argvp[1]);
		if (start < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
		end = start;
	}

	if (argcp > 2) {
		end = strtohandle(argvp[2]);
		if (end < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	}

	gatt_find_included(attrib, start, end, included_cb, NULL);
}
Пример #2
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;
    }

    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);
    }
}
Пример #3
0
static void cmd_char_desc(int argcp, char **argvp)
{
	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	if (argcp > 1) {
		start = strtohandle(argvp[1]);
		if (start < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	} else
		start = 0x0001;

	if (argcp > 2) {
		end = strtohandle(argvp[2]);
		if (end < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	} else
		end = 0xffff;

	gatt_discover_char_desc(attrib, start, end, char_desc_cb, NULL);
}
Пример #4
0
static void cmd_gatts(int argcp, char **argvp)
{
    if (argcp == 2) {
        GAttribResultFunc cb_func = NULL;
        uint8_t *opdu = NULL;
        size_t olen = gatt_attr_data_from_string(argvp[1], &opdu);

        DBG("GATTS %p %d %zd", opdu, opt_mtu, olen);

        /* Check if it is a value gatt server request */
        if (opdu && (opt_mtu == 0 || olen <= opt_mtu) &&
            !(opdu[0] == BT_ATT_OP_MTU_REQ ||
              opdu[0] == BT_ATT_OP_FIND_INFO_REQ ||
              opdu[0] == BT_ATT_OP_FIND_BY_TYPE_VAL_REQ ||
              opdu[0] == BT_ATT_OP_READ_BY_TYPE_REQ ||
              opdu[0] == BT_ATT_OP_READ_REQ ||
              opdu[0] == BT_ATT_OP_READ_BLOB_REQ ||
              opdu[0] == BT_ATT_OP_READ_MULT_REQ ||
              opdu[0] == BT_ATT_OP_READ_BY_GRP_TYPE_REQ ||
              opdu[0] == BT_ATT_OP_WRITE_REQ ||
              opdu[0] == BT_ATT_OP_PREP_WRITE_REQ ||
              opdu[0] == BT_ATT_OP_EXEC_WRITE_REQ)) {
            if (opdu[0] == BT_ATT_OP_HANDLE_VAL_IND) {
                cb_func = on_indicate_complete;
            }
            g_attrib_send(attrib, 0, opdu, olen, cb_func, NULL, NULL);
        } else {
            resp_error(err_BAD_PARAM);;
        }
        g_free(opdu);
    } else {
        resp_error(err_BAD_PARAM);;
    }
}
Пример #5
0
static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	uint16_t mtu;

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	if (!dec_mtu_resp(pdu, plen, &mtu)) {
		resp_error(err_PROTO_ERR);
		return;
	}

	mtu = MIN(mtu, opt_mtu);
	/* Set new value for MTU in client */
	if (g_attrib_set_mtu(attrib, mtu))
        {
                opt_mtu = mtu;
		cmd_status(0, NULL);
        }
	else
        {
		printf("# Error exchanging MTU\n");
		resp_error(err_COMM_ERR);
        }
}
Пример #6
0
static void cmd_mtu(int argcp, char **argvp)
{
	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	assert(!opt_psm);

	if (argcp < 2) {
		resp_error(err_BAD_PARAM);
		return;
	}

	if (opt_mtu) {
		resp_error(err_BAD_STATE);
                /* Can only set once per connection */
		return;
	}

	errno = 0;
	opt_mtu = strtoll(argvp[1], NULL, 16);
	if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) {
		resp_error(err_BAD_PARAM);
		return;
	}

	gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL);
}
Пример #7
0
static void cmd_connect(int argcp, char **argvp)
{
        GError *gerr=NULL;
	if (conn_state != STATE_DISCONNECTED)
		return;

	if (argcp > 1) {
		g_free(opt_dst);
		opt_dst = g_strdup(argvp[1]);

		g_free(opt_dst_type);
		if (argcp > 2)
			opt_dst_type = g_strdup(argvp[2]);
		else
			opt_dst_type = g_strdup("public");
	}

	if (opt_dst == NULL) {
		resp_error(err_BAD_PARAM);
		return;
	}

	set_state(STATE_CONNECTING);
	iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
						opt_psm, opt_mtu, connect_cb,&gerr);

	if (iochannel == NULL)
		set_state(STATE_DISCONNECTED);
	else
		g_io_add_watch(iochannel, G_IO_HUP, channel_watcher, NULL);
}
Пример #8
0
static void char_read_single_cb(guint8 status, const guint8 *pdu, guint16 plen,
                            gpointer user_data)
{
    uint8_t value[plen];
    ssize_t vlen;

    if (status != 0) {
        resp_error_comm(status);
        return;
    }

    if ((pdu != NULL) && (plen >= 1)) {
        if (pdu[0] == ATT_OP_READ_RESP)
            vlen = dec_read_resp(pdu, plen, value, sizeof(value));
        else
            vlen = dec_read_blob_resp(pdu, plen, value, sizeof(value));
    } else {
        vlen = -EINVAL;
    }
    if (vlen < 0) {
        resp_error(err_PROTO_ERR);
        return;
    }

    resp_begin(rsp_READ);
    send_data(value, vlen);
    resp_end();
}
Пример #9
0
static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
		resp_error(err_PROTO_ERR);
		return;
	}

        resp_begin(rsp_WRITE);
        resp_end();
}
Пример #10
0
static void cmd_discoverable(int argcp, char **argvp)
{
    struct mgmt_cp_set_discoverable cp = {0, 0};
    uint16_t opcode = MGMT_OP_SET_DISCOVERABLE;

    if (argcp < 2) {
        resp_mgmt(err_BAD_PARAM);
        return;
    }

    if (!on_or_off(argvp[1], &cp.val)) {
        resp_mgmt(err_BAD_PARAM);
        return;
    }

    if (!mgmt_master) {
        resp_error(err_NO_MGMT);
        return;
    }

    if (mgmt_send(mgmt_master, opcode, opt_src_idx, sizeof(cp),
        &cp, set_mode_complete, NULL, NULL) == 0)
    {
        DBG("mgmt_send(MGMT_OP_SET_DISCOVERABLE) failed");
        resp_mgmt(err_PROTO_ERR);
        return;
    }
}
Пример #11
0
static bool set_mode_with_cb(uint16_t opcode, char *p_mode, mgmt_request_func_t callback)
{
    struct mgmt_mode cp;
    uintptr_t user_data;

    memset(&cp, 0, sizeof(cp));

    if (!on_or_off(p_mode, &cp.val))
        return false;

    /* Save the configured value in the user_data */
    if (cp.val) user_data = 1;
    else user_data = 0;

    if (!mgmt_master) {
        resp_error(err_NO_MGMT);
        return true;
    }

    if (mgmt_send(mgmt_master, opcode,
            opt_src_idx, sizeof(cp), &cp,
            callback, (void *)user_data, NULL) == 0) {
        resp_mgmt(err_SUCCESS);
    }
    return true;
}
Пример #12
0
static void parse_line(char *line_read)
{
	gchar **argvp;
	int argcp;
	int i;

	line_read = g_strstrip(line_read);

	if (*line_read == '\0')
		goto done;

	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);

	for (i = 0; commands[i].cmd; i++)
		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
			break;

	if (commands[i].cmd)
		commands[i].func(argcp, argvp);
	else
		resp_error(err_BAD_CMD);

	g_strfreev(argvp);

done:
	free(line_read);
}
Пример #13
0
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
    uint16_t mtu;
    uint16_t cid;
    GError *gerr = NULL;

    DBG("io = %p, err = %p", io, err);
    if (err) {
        DBG("err = %s", err->message);
        set_state(STATE_DISCONNECTED);
        resp_error(err_CONN_FAIL);
        printf("# Connect error: %s\n", err->message);
        return;
    }

    bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &mtu,
                BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);

    if (gerr) {
        printf("# Can't detect MTU, using default");
        g_error_free(gerr);
        mtu = ATT_DEFAULT_LE_MTU;
    }
    else if (cid == ATT_CID)
        mtu = ATT_DEFAULT_LE_MTU;

    attrib = g_attrib_new(iochannel, mtu);

    g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
                        events_handler, attrib, NULL);
    g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
                        events_handler, attrib, NULL);
    g_attrib_register(attrib, ATT_OP_FIND_INFO_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_FIND_BY_TYPE_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_READ_BY_TYPE_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_READ_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_READ_BLOB_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_READ_MULTI_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_READ_BY_GROUP_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_WRITE_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_WRITE_CMD, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_SIGNED_WRITE_CMD, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_PREP_WRITE_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);
    g_attrib_register(attrib, ATT_OP_EXEC_WRITE_REQ, GATTRIB_ALL_HANDLES,
                        req_gatts, NULL, NULL);

    set_state(STATE_CONNECTED);
}
Пример #14
0
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	struct att_data_list *list;
	guint8 format;
	uint16_t handle = 0xffff;
	int i;

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	list = dec_find_info_resp(pdu, plen, &format);
	if (list == NULL) {
		resp_error(err_NOT_FOUND); // Todo: what does this mean?
		return;
	}

	resp_begin(rsp_DESCRIPTORS);
	for (i = 0; i < list->num; i++) {
		char uuidstr[MAX_LEN_UUID_STR];
		uint8_t *value;
		bt_uuid_t uuid;

		value = list->data[i];
		handle = att_get_u16(value);

		if (format == 0x01)
			uuid = att_get_uuid16(&value[2]);
		else
			uuid = att_get_uuid128(&value[2]);

		bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR);
		send_uint(tag_HANDLE, handle);
                send_str (tag_UUID, uuidstr);
	}
        resp_end();

	att_data_list_free(list);

	if (handle != 0xffff && handle < end)
		gatt_discover_char_desc(attrib, handle + 1, end, char_desc_cb, NULL);
}
Пример #15
0
static void cmd_sec_level(int argcp, char **argvp)
{
    GError *gerr = NULL;
    BtIOSecLevel sec_level;

    if (argcp < 2) {
        resp_error(err_BAD_PARAM);;
        return;
    }

    if (strcasecmp(argvp[1], "medium") == 0)
        sec_level = BT_IO_SEC_MEDIUM;
    else if (strcasecmp(argvp[1], "high") == 0)
        sec_level = BT_IO_SEC_HIGH;
    else if (strcasecmp(argvp[1], "low") == 0)
        sec_level = BT_IO_SEC_LOW;
    else {
        resp_error(err_BAD_PARAM);;
        return;
    }

    g_free(opt_sec_level);
    opt_sec_level = g_strdup(argvp[1]);

    if (conn_state != STATE_CONNECTED)
        return;

    assert(!opt_psm);

    bt_io_set(iochannel, &gerr,
            BT_IO_OPT_SEC_LEVEL, sec_level,
            BT_IO_OPT_INVALID);
    if (gerr) {
        printf("# Error: %s\n", gerr->message);
        resp_error(err_PROTO_ERR);
        g_error_free(gerr);
    }
    else {
        /* Tell bluepy the security level
         * has been changed successfuly */
        cmd_status(0, NULL);
    }
}
Пример #16
0
static void cmd_read_uuid(int argcp, char **argvp)
{
	struct characteristic_data *char_data;
	int start = 0x0001;
	int end = 0xffff;
	bt_uuid_t uuid;

	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	if (argcp < 2 ||
            bt_string_to_uuid(&uuid, argvp[1]) < 0) {
		resp_error(err_BAD_PARAM);
		return;
	}

	if (argcp > 2) {
		start = strtohandle(argvp[2]);
		if (start < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	}

	if (argcp > 3) {
		end = strtohandle(argvp[3]);
		if (end < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	}

	char_data = g_new(struct characteristic_data, 1);
	char_data->orig_start = start;
	char_data->start = start;
	char_data->end = end;
	char_data->uuid = uuid;

	gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
					char_read_by_uuid_cb, char_data);
}
Пример #17
0
int main(int argc, char *argv[])
{
    GIOChannel *pchan;
    gint events;
    const char *hci = "hci0";

    opt_sec_level = g_strdup("low");

    if (argc > 1)
        hci = argv[1];

    if (parse_dev_src(hci, &opt_src, &opt_src_idx)) {
        fprintf(stderr,"%s: expected optional argument 'hciX' valid and up\n", argv[0]);
        resp_error(err_BAD_HCI);
        return EXIT_FAILURE;
    }

    DBG("Using controller hci%d  addr:%s", opt_src_idx, opt_src);

    opt_dst = NULL;
    opt_dst_type = g_strdup("public");

    DBG(__FILE__ " built at " __TIME__ " on " __DATE__);

    mgmt_setup();

    event_loop = g_main_loop_new(NULL, FALSE);

    pchan = g_io_channel_unix_new(fileno(stdin));
    g_io_channel_set_close_on_unref(pchan, TRUE);
    events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
    g_io_add_watch(pchan, events, prompt_read, NULL);

    DBG("Starting loop");
    g_main_loop_run(event_loop);

    DBG("Exiting loop");
    cmd_disconnect(0, NULL);
    fflush(stdout);
    g_io_channel_unref(pchan);
    g_main_loop_unref(event_loop);

    g_free(opt_src);
    g_free(opt_dst);
    g_free(opt_dst_type);
    g_free(opt_sec_level);

    mgmt_unregister_index(mgmt_master, opt_src_idx);
    mgmt_cancel_index(mgmt_master, opt_src_idx);
    mgmt_unref(mgmt_master);
    mgmt_master = NULL;

    return EXIT_SUCCESS;
}
Пример #18
0
static void cmd_primary(int argcp, char **argvp)
{
	bt_uuid_t uuid;

	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	if (argcp == 1) {
		gatt_discover_primary(attrib, NULL, primary_all_cb, NULL);
		return;
	}

	if (bt_string_to_uuid(&uuid, argvp[1]) < 0) {
		resp_error(err_BAD_PARAM);
		return;
	}

	gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}
Пример #19
0
static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	uint8_t value[plen];
	ssize_t vlen;

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
	if (vlen < 0) {
		resp_error(err_COMM_ERR);
		return;
	}

	resp_begin(rsp_READ);
        send_data(value, vlen);
        resp_end();
}
Пример #20
0
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);
}
Пример #21
0
static void cmd_char(int argcp, char **argvp)
{
	int start = 0x0001;
	int end = 0xffff;

	if (conn_state != STATE_CONNECTED) {
		resp_error(err_BAD_STATE);
		return;
	}

	if (argcp > 1) {
		start = strtohandle(argvp[1]);
		if (start < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	}

	if (argcp > 2) {
		end = strtohandle(argvp[2]);
		if (end < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}
	}

	if (argcp > 3) {
		bt_uuid_t uuid;

		if (bt_string_to_uuid(&uuid, argvp[3]) < 0) {
			resp_error(err_BAD_PARAM);
			return;
		}

		gatt_discover_char(attrib, start, end, &uuid, char_cb, NULL);
		return;
	}

	gatt_discover_char(attrib, start, end, NULL, char_cb, NULL);
}
Пример #22
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);
}
Пример #23
0
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
	if (err) {
		set_state(STATE_DISCONNECTED);
		resp_error(err_CONN_FAIL);
                printf("# Connect error: %s\n", err->message);
		return;
	}

	attrib = g_attrib_new(iochannel);
	g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
						events_handler, attrib, NULL);
	g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
						events_handler, attrib, NULL);
	set_state(STATE_CONNECTED);
}
Пример #24
0
static void cmd_settings(int argcp, char **argvp)
{
    if (1 < argcp) {
        resp_mgmt(err_BAD_PARAM);
    }

    if (!mgmt_master) {
        resp_error(err_NO_MGMT);
        return;
    }

    if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO,
            opt_src_idx, 0, NULL,
            read_info_complete, NULL, NULL) == 0) {
        DBG("mgmt_send(MGMT_OP_READ_INFO) failed");
        resp_mgmt(err_PROTO_ERR);
    }
}
Пример #25
0
static void primary_by_uuid_cb(GSList *ranges, guint8 status,
							gpointer user_data)
{
	GSList *l;

	if (status) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	resp_begin(rsp_DISCOVERY);
	for (l = ranges; l; l = l->next) {
		struct att_range *range = l->data;
		send_uint(tag_RANGE_START, range->start);
                send_uint(tag_RANGE_END, range->end);
	}
        resp_end();
}
Пример #26
0
static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
{
	GSList *l;

	if (status) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	resp_begin(rsp_DISCOVERY);
	for (l = services; l; l = l->next) {
		struct gatt_primary *prim = l->data;
		send_uint(tag_RANGE_START, prim->range.start);
                send_uint(tag_RANGE_END, prim->range.end);
                send_str(tag_UUID, prim->uuid);
	}
        resp_end();

}
Пример #27
0
static void included_cb(GSList *includes, guint8 status, gpointer user_data)
{
	GSList *l;

	if (status) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	resp_begin(rsp_DISCOVERY);
	for (l = includes; l; l = l->next) {
		struct gatt_included *incl = l->data;
                send_uint(tag_HANDLE, incl->handle);
                send_uint(tag_RANGE_START, incl->range.start);
                send_uint(tag_RANGE_END,   incl->range.end);
                send_str(tag_UUID, incl->uuid);
	}
        resp_end();
}
Пример #28
0
static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
{
	GSList *l;

	if (status) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	resp_begin(rsp_DISCOVERY);
	for (l = characteristics; l; l = l->next) {
		struct gatt_char *chars = l->data;
                send_uint(tag_HANDLE, chars->handle);
                send_uint(tag_PROPERTIES, chars->properties);
                send_uint(tag_VALUE_HANDLE, chars->value_handle);
                send_str(tag_UUID, chars->uuid);
	}
        resp_end();
}
Пример #29
0
static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
					guint16 plen, gpointer user_data)
{
	struct characteristic_data *char_data = user_data;
	struct att_data_list *list;
	int i;

	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
				char_data->start != char_data->orig_start)
        {
		printf("# TODO case in char_read_by_uuid_cb\n");
		goto done;
        }

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		goto done;
	}

	list = dec_read_by_type_resp(pdu, plen);

	resp_begin(rsp_READ);
        if (list == NULL)
		goto nolist;

	for (i = 0; i < list->num; i++) {
		uint8_t *value = list->data[i];
		int j;

		char_data->start = att_get_u16(value) + 1;

		send_uint(tag_HANDLE, att_get_u16(value));
                send_data(value+2, list->len-2); // All the same length??
	}

	att_data_list_free(list);
nolist:
	resp_end();

done:
	g_free(char_data);
}
Пример #30
0
// Unlike Bluez, we follow BT 4.0 spec which renammed Device Discovery by Scan
static void scan(bool start)
{
    // mgmt_cp_start_discovery and mgmt_cp_stop_discovery are the same
    struct mgmt_cp_start_discovery cp = { (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM) };
    uint16_t opcode = start? MGMT_OP_START_DISCOVERY : MGMT_OP_STOP_DISCOVERY;

    DBG("Scan %s", start? "start" : "stop");

    if (!mgmt_master) {
        resp_error(err_NO_MGMT);
        return;
    }

    if (mgmt_send(mgmt_master, opcode, opt_src_idx, sizeof(cp),
        &cp, scan_cb, NULL, NULL) == 0)
    {
        DBG("mgmt_send(MGMT_OP_%s_DISCOVERY) failed", start? "START" : "STOP");
        resp_mgmt(err_PROTO_ERR);
        return;
    }
}