doc: move "NOTES" to "README" document for improved visibility
[libble/gsi.git] / main-bletest.c
blobc4be7d27e65bb0e70fe09645a6a39328f29b28c6
1 /*
2 * Libble main test suite
3 */
5 #include "ble.h"
7 #include <libgen.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
14 #define DEFAULT_MAC_ADDR NULL
15 #define DEFAULT_READ_HANDLE 8
16 #define DEFAULT_WRITE_HANDLE 9
17 #define DEFAULT_WRITE_VALUE 0x0003
19 #ifndef ARRAY_SIZE
20 # define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
21 #endif
23 static char *progname;
24 static int verbose = 1;
25 static int raw_bytes = 0;
27 static void scan_cb(void *cb_data, const char *addr, const char *name)
29 char *text;
31 text = cb_data;
32 ble_log_append(1, "found: type %s, addr %s, name %s\n", text, addr, name);
35 static int do_scan(struct ble_desc *desc, int duration)
37 int rc;
39 ble_log_append(1, "scan: classic\n");
40 rc = ble_config_cb_scan(desc, scan_cb, "BT");
41 if (rc < 0)
42 return -1;
43 rc = ble_scan_bt(desc, duration);
44 if (rc < 0)
45 return -1;
47 ble_log_append(1, "scan: low energy\n");
48 rc = ble_config_cb_scan(desc, scan_cb, "LE");
49 if (rc < 0)
50 return -1;
51 rc = ble_scan_le(desc, duration);
52 if (rc < 0)
53 return -1;
55 return 0;
58 static int do_rfcomm(struct ble_desc *desc, int read_delay)
60 static const char *texts[] = {
61 "Hi server, I am the client.",
62 "This is the first line of text.",
63 "Here is another line of text.",
64 "Bye server, nice talking to you.",
65 NULL,
67 size_t idx;
68 const char *text;
69 char buff[256];
70 int rc;
72 rc = ble_connect_rfcomm(desc);
73 if (rc < 0)
74 return -2;
75 for (idx = 0; text = texts[idx]; idx++) {
76 rc = ble_write(desc, text, strlen(text));
77 if (rc > 0)
78 ble_log_append(0, "sent: %s\n", text);
79 do {
80 rc = ble_read(desc, buff, sizeof(buff));
81 if (rc > 0) {
82 buff[rc] = '\0';
83 ble_log_append(0, "rcvd: %s\n", buff);
85 } while (rc > 0);
86 if (read_delay) {
87 usleep(read_delay * 1000);
88 do {
89 rc = ble_read(desc, buff, sizeof(buff));
90 if (rc > 0) {
91 buff[rc] = '\0';
92 ble_log_append(0, "rcvd: %s\n", buff);
94 } while (rc > 0);
97 ble_disconnect(desc);
98 return 0;
101 /* No processing, mere dump of received payload bytes. */
102 int process(void *cb_data, uint8_t *data, size_t len)
105 (void)cb_data;
107 if (raw_bytes) {
108 fwrite(data, sizeof(uint8_t), len, stdout);
109 fflush(stdout);
110 return 0;
113 ble_log_append(1, "BLE payload data: %zu bytes", len);
114 if (len)
115 ble_log_append(1, ":");
116 while (len-- > 0)
117 ble_log_append(1, " %02x", *data++);
118 ble_log_append(1, "\n");
119 fflush(stdout);
121 return 0;
124 static int do_ble_indnot(struct ble_desc *desc, int read_delay)
126 int rc;
128 rc = ble_connect_ble(desc);
129 if (rc) {
130 ble_log_append(0, "Failed to connect, rc %d\n", rc);
131 return -2;
133 ble_log_append(3, "Connected.\n");
135 rc = ble_config_cb_data(desc, process, NULL);
136 if (rc < 0)
137 return -2;
139 /* Initiate reception of data, and have the received data processed. */
140 rc = ble_start_notify(desc);
141 if (rc < 0) {
142 ble_log_append(0, "Failed to setup notifications, rc %d\n", rc);
143 return -1;
145 ble_log_append(3, "Receiving notifications.\n");
146 while (rc >= 0) {
147 rc = ble_check_notify(desc);
148 if (rc < 0)
149 ble_log_append(0, "Failed to check notifications, rc %d\n", rc);
150 if (read_delay) {
151 ble_log_append(5, "usleep() start\n");
152 usleep(read_delay * 1000);
153 ble_log_append(5, "usleep() done\n");
156 ble_log_append(3, "Done receiving.\n");
158 ble_log_append(3, "Disconnecting.\n");
159 ble_disconnect(desc);
160 return 0;
163 static void synopsis(FILE *f)
166 fprintf(f, "synopsis: %s [-h] [-vq] [-i <addr>] [-I <nr>] [-s <len>] [-m <addr>] [-R <nr>] [-r <hdl>] [-w <hdl>] [-W <val>] [-b] [-d <msec>]\n", progname);
167 fprintf(f, "options:\n");
168 fprintf(f, "\t-h\tprint builtin help (this text)\n");
169 fprintf(f, "\t-v, -q\tadjust verbosity\n");
170 fprintf(f, "\t-i, -I\tspecify local adapter to use\n");
171 fprintf(f, "\t-s\tscan for the specified length (number times 1.28s)\n");
172 fprintf(f, "\t-m\tspecify (remote) device address\n");
173 fprintf(f, "\t-R\tconnect to this channel of an RFCOMM server\n");
174 fprintf(f, "\t-r, -w\tspecify read/write handle\n");
175 fprintf(f, "\t-W\tspecify write value\n");
176 fprintf(f, "\t-b\tdump raw bytes to output (text by default)\n");
177 fprintf(f, "\t-d\tdelay between reads for this many msecs\n");
180 int main(int argc, char **argv)
182 int scan_time;
183 int read_delay;
184 const char *local_mac;
185 const char *remote_mac;
186 size_t rfcomm_channel;
187 uint16_t read_handle;
188 uint16_t write_handle, write_value;
189 int c, num;
190 struct ble_desc *desc;
191 int rc;
193 /* Preset defaults. */
194 progname = basename(argv[0]);
195 ble_log_setup(verbose);
196 scan_time = 0;
197 read_delay = 0;
198 local_mac = NULL;
199 remote_mac = DEFAULT_MAC_ADDR;
200 rfcomm_channel = 0;
201 read_handle = DEFAULT_READ_HANDLE;
202 write_handle = DEFAULT_WRITE_HANDLE;
203 write_value = DEFAULT_WRITE_VALUE;
205 /* Scan command line arguments. */
206 while ((c = getopt(argc, argv, "bd:hi:I:m:qr:R:s:vw:W:")) != EOF) {
207 switch (c) {
208 case 'b':
209 raw_bytes = 1;
210 break;
211 case 'd':
212 read_delay = strtol(optarg, NULL, 0);
213 break;
214 case 'h':
215 synopsis(stdout);
216 return 0;
217 case 'i':
218 if (local_mac)
219 free((void *)local_mac);
220 local_mac = strdup(optarg);
221 break;
222 case 'I':
223 if (local_mac)
224 free((void *)local_mac);
225 num = strtol(optarg, NULL, 0);
226 local_mac = ble_adapter_get_address(num);
227 if (!local_mac) {
228 ble_log_append(0, "cannot get address for HCI dev %d\n", num);
229 return -1;
231 break;
232 case 'm':
233 remote_mac = optarg;
234 break;
235 case 'q':
236 verbose--;
237 break;
238 case 'r':
239 read_handle = strtol(optarg, NULL, 0);
240 break;
241 case 'R':
242 rfcomm_channel = strtol(optarg, NULL, 0);
243 break;
244 case 's':
245 scan_time = strtol(optarg, NULL, 0);
246 break;
247 case 'v':
248 verbose++;
249 break;
250 case 'w':
251 write_handle = strtol(optarg, NULL, 0);
252 break;
253 case 'W':
254 write_value = strtol(optarg, NULL, 0);
255 break;
256 default:
257 synopsis(stderr);
258 return -1;
261 argc -= optind;
262 argv += optind;
263 ble_log_setup(verbose);
265 desc = ble_desc_new();
266 if (!desc) {
267 ble_log_append(0, "Failed to create BLE descriptor.\n");
268 return -1;
270 if (local_mac) {
271 ble_log_append(2, "local addr '%s'\n", local_mac);
272 rc = ble_config_addr_local(desc, local_mac);
273 if (rc < 0)
274 return -1;
276 if (remote_mac) {
277 ble_log_append(2, "device addr '%s'\n", remote_mac);
278 rc = ble_config_addr_remote(desc, remote_mac);
279 if (rc < 0)
280 return -1;
282 ble_log_append(3, "Preparing.\n");
284 if (scan_time) {
285 ble_log_append(2, "scanning for devices\n");
286 rc = do_scan(desc, scan_time);
287 } else if (rfcomm_channel) {
288 ble_log_append(2, "RFCOMM client, channel %d\n", rfcomm_channel);
289 rc = ble_config_rfcomm(desc, rfcomm_channel);
290 if (rc < 0)
291 return -1;
292 rc = do_rfcomm(desc, read_delay);
293 } else {
294 ble_log_append(2, "indications/notifications\n");
295 ble_log_append(2, "read/write hdl %u/%u, write val %u\n", read_handle, write_handle, write_value);
296 rc = ble_config_notify(desc, read_handle, write_handle, write_value);
297 if (rc < 0)
298 return -1;
299 rc = do_ble_indnot(desc, read_delay);
302 ble_desc_free(desc);
303 return 0;