[go: up one dir, main page]

File: btletest.c

package info (click to toggle)
altos 1.9-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 67,272 kB
  • sloc: ansic: 90,607; java: 39,048; makefile: 6,591; sh: 3,008; xml: 1,972; pascal: 1,597
file content (183 lines) | stat: -rw-r--r-- 3,925 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * Copyright © 2017 Keith Packard <keithp@keithp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/l2cap.h>
#include <poll.h>

#define ATT_OP_MTU_REQ		0x02
#define ATT_OP_MTU_RESP		0x03
#define ATT_OP_WRITE_CMD	0x52
#define ATT_OP_HANDLE_NOTIFY	0x1b
#define CID_ATT			0x0004
#define TX_ENDPOINT		0x003a
#define RX_ENDPOINT		0x0037
#define RX_NOTIFY		0x0038

int
main(int argc, char **argv)
{
	int sk;
	int psm;
	struct sockaddr_l2 src_addr = { 0 };
	struct sockaddr_l2 dst_addr = { 0 };
	char buf[1024];
	struct pollfd	fd[2];
	int n, i;
	char *btaddr;
	int	mtu;

	btaddr = argc > 1 ? argv[1] : "D8:80:39:F3:4E:A5";

	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
	if (sk < 0) {
		perror("socket");
		exit(1);
	}

	src_addr.l2_family = AF_BLUETOOTH;
	/* Leave src_addr.l2_bdaddr all zeros */
	src_addr.l2_cid = htobs(CID_ATT);
	src_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
	if (bind(sk, (struct sockaddr *) &src_addr, sizeof (src_addr)) < 0) {
		perror("bind");
		exit(1);
	}

	dst_addr.l2_family = AF_BLUETOOTH;
	str2ba(btaddr, &dst_addr.l2_bdaddr);
	dst_addr.l2_cid = htobs(CID_ATT);
	dst_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;

	if (connect(sk, (struct sockaddr *) &dst_addr, sizeof(dst_addr)) < 0) {
		perror("connect");
		exit(1);
	}

	buf[0] = ATT_OP_MTU_REQ;
	buf[1] = sizeof(buf) & 0xff;
	buf[2] = sizeof(buf) >> 8;
	n = write(sk, buf, 3);
	if (n != 3) {
		perror("write mtu\n");
		exit(1);
	}

	fd[0].fd = sk;
	fd[0].events = POLLIN;
	for (;;) {
		n = poll(fd, 1, 3000);
		if (n <= 0) {
			printf("timeout waiting for MTU response\n");
			exit(1);
		}
		if (fd[0].revents & POLLIN) {
			n = read(sk, buf, sizeof(buf));
			printf("read %d\n", n);
			for (i = 0; i < n; i++)
				printf("%02x\n", buf[i]);
			if (buf[0] == ATT_OP_MTU_RESP) {
				mtu = (buf[1] & 0xff) | ((buf[2] & 0xff) << 8);
				break;
			}
		}
	}
	printf("mtu %d\n", mtu);

	buf[0] = ATT_OP_WRITE_CMD;
	buf[1] = RX_NOTIFY & 0xff;
	buf[2] = RX_NOTIFY >> 8;
	buf[3] = 1;
	n = write(sk, buf, 4);
	if (n != 4) {
		perror("write notify");
		exit(1);
	}

	fd[0].fd = 0;
	fd[0].events = POLLIN;
	fd[1].fd = sk;
	fd[1].events = POLLIN;

	for (;;) {
		n = poll(fd, 2, -1);
		if (n == 0)
			continue;
		if (fd[0].revents & POLLIN) {
			char	*b;
			n = read(0, buf+3, sizeof(buf)-3);
			if (n < 0) {
				perror("read stdin");
				exit(1);
			}
			if (n == 0)
				break;

			b = buf;
			while (n > 0) {
				int this = n;
				if (this > mtu - 3)
					this = mtu - 3;

				b[0] = ATT_OP_WRITE_CMD;
				b[1] = TX_ENDPOINT;
				b[2] = TX_ENDPOINT >> 8;
				if (write(sk, b, this + 3) != this + 3) {
					perror("write sk");
					exit(1);
				}
				b += this;
				n -= this;
			}
		}
		if (fd[1].revents & POLLIN) {
			uint16_t	ch;

			n = read(sk, buf, sizeof(buf));
			if (n < 0) {
				perror("read sk");
				exit(1);
			}
			if (n == 0)
				continue;
			ch = buf[1] | (buf[2] << 8);
			switch (buf[0]) {
			case ATT_OP_HANDLE_NOTIFY:
				if (ch == RX_ENDPOINT)
					write(1, buf+3, n-3);
				break;
			}
		}
		if (fd[1].revents & (POLLERR|POLLHUP))
			break;
	}
	close(sk);

	return 0;
}