main: nit, make scan/rfcomm/notify strict alternatives, share shutdown code
[libble/gsi.git] / main-bletest.c
blob06b24ebc8d719c069e5282f32d0511ca2809cb81
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_scan_bt(desc, duration, scan_cb, "BT");
41 if (rc < 0)
42 return -1;
44 ble_log_append(1, "scan: low energy\n");
45 rc = ble_scan_le(desc, duration, scan_cb, "LE");
46 if (rc < 0)
47 return -1;
49 return 0;
52 static int do_rfcomm(struct ble_desc *desc, size_t channel, int read_delay)
54 static const char *texts[] = {
55 "Hi server, I am the client.",
56 "This is the first line of text.",
57 "Here is another line of text.",
58 "Bye server, nice talking to you.",
59 NULL,
61 size_t idx;
62 const char *text;
63 char buff[256];
64 int rc;
66 rc = ble_connect_rfcomm(desc, channel);
67 if (rc < 0)
68 return -2;
69 for (idx = 0; text = texts[idx]; idx++) {
70 rc = ble_write(desc, text, strlen(text));
71 if (rc > 0)
72 ble_log_append(0, "sent: %s\n", text);
73 do {
74 rc = ble_read(desc, buff, sizeof(buff));
75 if (rc > 0) {
76 buff[rc] = '\0';
77 ble_log_append(0, "rcvd: %s\n", buff);
79 } while (rc > 0);
80 if (read_delay) {
81 usleep(read_delay * 1000);
82 do {
83 rc = ble_read(desc, buff, sizeof(buff));
84 if (rc > 0) {
85 buff[rc] = '\0';
86 ble_log_append(0, "rcvd: %s\n", buff);
88 } while (rc > 0);
91 ble_disconnect(desc);
92 return 0;
95 /* No processing, mere dump of received payload bytes. */
96 int process(void *cb_data, uint8_t *data, size_t len)
99 (void)cb_data;
101 if (raw_bytes) {
102 fwrite(data, sizeof(uint8_t), len, stdout);
103 fflush(stdout);
104 return 0;
107 ble_log_append(1, "BLE payload data: %zu bytes", len);
108 if (len)
109 ble_log_append(1, ":");
110 while (len-- > 0)
111 ble_log_append(1, " %02x", *data++);
112 ble_log_append(1, "\n");
113 fflush(stdout);
115 return 0;
118 static int do_ble_indnot(struct ble_desc *desc, uint16_t read_handle,
119 uint16_t write_handle, uint16_t write_value, int read_delay)
121 int rc;
123 rc = ble_connect_ble(desc);
124 if (rc) {
125 ble_log_append(0, "Failed to connect, rc %d\n", rc);
126 return -2;
128 ble_log_append(3, "Connected.\n");
130 /* Initiate reception of data, and have the received data processed. */
131 rc = ble_start_notify(desc, read_handle, write_handle, write_value);
132 if (rc < 0) {
133 ble_log_append(0, "Failed to setup notifications, rc %d\n", rc);
134 return -1;
136 ble_log_append(3, "Receiving notifications.\n");
137 while (rc == 0) {
138 rc = ble_check_notify(desc, process, NULL);
139 if (rc)
140 ble_log_append(0, "Failed to check notifications, rc %d\n", rc);
141 if (read_delay)
142 usleep(read_delay * 1000);
144 ble_log_append(3, "Done receiving.\n");
146 ble_log_append(3, "Disconnecting.\n");
147 ble_disconnect(desc);
148 return 0;
151 static void synopsis(FILE *f)
154 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);
155 fprintf(f, "options:\n");
156 fprintf(f, "\t-h\tprint builtin help (this text)\n");
157 fprintf(f, "\t-v, -q\tadjust verbosity\n");
158 fprintf(f, "\t-i, -I\tspecify local adapter to use\n");
159 fprintf(f, "\t-s\tscan for the specified length (number times 1.28s)\n");
160 fprintf(f, "\t-m\tspecify (remote) device address\n");
161 fprintf(f, "\t-R\tconnect to this channel of an RFCOMM server\n");
162 fprintf(f, "\t-r, -w\tspecify read/write handle\n");
163 fprintf(f, "\t-W\tspecify write value\n");
164 fprintf(f, "\t-b\tdump raw bytes to output (text by default)\n");
165 fprintf(f, "\t-d\tdelay between reads for this many msecs\n");
168 int main(int argc, char **argv)
170 int scan_time;
171 int read_delay;
172 const char *local_mac;
173 const char *remote_mac;
174 size_t rfcomm_channel;
175 uint16_t read_handle;
176 uint16_t write_handle, write_value;
177 int c, num;
178 struct ble_desc *desc;
179 int rc;
181 /* Preset defaults. */
182 progname = basename(argv[0]);
183 ble_log_setup(verbose);
184 scan_time = 0;
185 local_mac = NULL;
186 remote_mac = DEFAULT_MAC_ADDR;
187 rfcomm_channel = 0;
188 read_handle = DEFAULT_READ_HANDLE;
189 write_handle = DEFAULT_WRITE_HANDLE;
190 write_value = DEFAULT_WRITE_VALUE;
192 /* Scan command line arguments. */
193 while ((c = getopt(argc, argv, "bd:hi:I:m:qr:R:s:vw:W:")) != EOF) {
194 switch (c) {
195 case 'b':
196 raw_bytes = 1;
197 break;
198 case 'd':
199 read_delay = strtol(optarg, NULL, 0);
200 break;
201 case 'h':
202 synopsis(stdout);
203 return 0;
204 case 'i':
205 if (local_mac)
206 free((void *)local_mac);
207 local_mac = strdup(optarg);
208 break;
209 case 'I':
210 if (local_mac)
211 free((void *)local_mac);
212 num = strtol(optarg, NULL, 0);
213 local_mac = ble_adapter_get_address(num);
214 if (!local_mac) {
215 ble_log_append(0, "cannot get address for HCI dev %d\n", num);
216 return -1;
218 break;
219 case 'm':
220 remote_mac = optarg;
221 break;
222 case 'q':
223 verbose--;
224 break;
225 case 'r':
226 read_handle = strtol(optarg, NULL, 0);
227 break;
228 case 'R':
229 rfcomm_channel = strtol(optarg, NULL, 0);
230 break;
231 case 's':
232 scan_time = strtol(optarg, NULL, 0);
233 break;
234 case 'v':
235 verbose++;
236 break;
237 case 'w':
238 write_handle = strtol(optarg, NULL, 0);
239 break;
240 case 'W':
241 write_value = strtol(optarg, NULL, 0);
242 break;
243 default:
244 synopsis(stderr);
245 return -1;
248 argc -= optind;
249 argv += optind;
250 ble_log_setup(verbose);
252 if (local_mac)
253 ble_log_append(2, "local addr '%s'\n", local_mac);
254 if (remote_mac)
255 ble_log_append(2, "device addr '%s'\n", remote_mac);
256 ble_log_append(3, "Preparing.\n");
257 desc = ble_desc_new(local_mac, remote_mac);
258 if (!desc) {
259 ble_log_append(0, "Failed to create BLE descriptor.\n");
260 return -1;
263 if (scan_time) {
264 ble_log_append(2, "scanning for devices\n");
265 rc = do_scan(desc, scan_time);
266 } else if (rfcomm_channel) {
267 ble_log_append(2, "RFCOMM client, channel %d\n", rfcomm_channel);
268 rc = do_rfcomm(desc, rfcomm_channel, read_delay);
269 } else {
270 ble_log_append(2, "indications/notifications\n");
271 ble_log_append(2, "read/write handles %u/%u\n", read_handle, write_handle);
272 ble_log_append(2, "write value %u\n", write_value);
273 rc = do_ble_indnot(desc, read_handle, write_handle, write_value, read_delay);
276 ble_desc_free(desc);
277 return 0;