2
2
*
3
3
* GattLib - GATT Library
4
4
*
5
- * Copyright (C) 2016-2021 Olivier Martin <olivier@labapart.org>
5
+ * Copyright (C) 2016-2024 Olivier Martin <olivier@labapart.org>
6
6
*
7
7
*
8
8
* This program is free software; you can redistribute it and/or modify
22
22
*/
23
23
24
24
#include <assert.h>
25
+ #include <ctype.h>
26
+ #include <pthread.h>
27
+ #include <signal.h>
25
28
#include <stdio.h>
26
29
#include <stdlib.h>
27
- #include <signal.h>
28
30
29
31
#ifdef GATTLIB_LOG_BACKEND_SYSLOG
30
32
#include <syslog.h>
31
33
#endif
32
34
33
35
#include "gattlib.h"
34
36
35
- #define MIN (a ,b ) ((a)<(b)?(a):(b))
36
-
37
37
#define NUS_CHARACTERISTIC_TX_UUID "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
38
38
#define NUS_CHARACTERISTIC_RX_UUID "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
39
39
40
- gattlib_connection_t * m_connection ;
40
+ #define BLE_SCAN_TIMEOUT 10
41
+
42
+ #define MIN (a ,b ) ((a)<(b)?(a):(b))
41
43
42
- void notification_cb (const uuid_t * uuid , const uint8_t * data , size_t data_length , void * user_data ) {
43
- int i ;
44
+ static struct {
45
+ char * adapter_name ;
46
+ char * mac_address ;
47
+ } m_argument ;
48
+
49
+ // Declaration of thread condition variable
50
+ static pthread_cond_t m_connection_terminated = PTHREAD_COND_INITIALIZER ;
51
+
52
+ // declaring mutex
53
+ static pthread_mutex_t m_connection_terminated_lock = PTHREAD_MUTEX_INITIALIZER ;
54
+
55
+ static gattlib_connection_t * m_connection ;
56
+
57
+ static void usage (char * argv []) {
58
+ printf ("%s <device_address>\n" , argv [0 ]);
59
+ }
60
+
61
+ static void notification_handler (const uuid_t * uuid , const uint8_t * data , size_t data_length , void * user_data ) {
62
+ uintptr_t i ;
63
+
44
64
for (i = 0 ; i < data_length ; i ++ ) {
45
65
printf ("%c" , data [i ]);
46
66
}
47
67
fflush (stdout );
48
68
}
49
69
50
- static void usage (char * argv []) {
51
- printf ("%s <device_address>\n" , argv [0 ]);
52
- }
53
-
54
- void int_handler (int dummy ) {
70
+ static void int_handler (int dummy ) {
55
71
gattlib_disconnect (m_connection , false /* wait_disconnection */ );
56
72
exit (0 );
57
73
}
58
74
59
- int main (int argc , char * argv []) {
60
- char input [256 ];
61
- char * input_ptr ;
62
- int i , ret , total_length , length = 0 ;
75
+ static void on_device_connect (gattlib_adapter_t * adapter , const char * dst , gattlib_connection_t * connection , int error , void * user_data ) {
63
76
uuid_t nus_characteristic_tx_uuid ;
64
77
uuid_t nus_characteristic_rx_uuid ;
65
-
66
- if (argc != 2 ) {
67
- usage (argv );
68
- return 1 ;
69
- }
70
-
71
- #ifdef GATTLIB_LOG_BACKEND_SYSLOG
72
- openlog ("gattlib_nordic_uart" , LOG_CONS | LOG_NDELAY | LOG_PERROR , LOG_USER );
73
- setlogmask (LOG_UPTO (LOG_INFO ));
74
- #endif
75
-
76
- m_connection = gattlib_connect (NULL , argv [1 ],
77
- GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM |
78
- GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW );
79
- if (m_connection == NULL ) {
80
- GATTLIB_LOG (GATTLIB_ERROR , "Fail to connect to the bluetooth device." );
81
- return 1 ;
82
- }
78
+ char input [256 ];
79
+ char * input_ptr ;
80
+ int ret , total_length , length = 0 ;
83
81
84
82
// Convert characteristics to their respective UUIDs
85
83
ret = gattlib_string_to_uuid (NUS_CHARACTERISTIC_TX_UUID , strlen (NUS_CHARACTERISTIC_TX_UUID ) + 1 , & nus_characteristic_tx_uuid );
86
84
if (ret ) {
87
85
GATTLIB_LOG (GATTLIB_ERROR , "Fail to convert characteristic TX to UUID." );
88
- return 1 ;
86
+ goto EXIT ;
89
87
}
90
88
ret = gattlib_string_to_uuid (NUS_CHARACTERISTIC_RX_UUID , strlen (NUS_CHARACTERISTIC_RX_UUID ) + 1 , & nus_characteristic_rx_uuid );
91
89
if (ret ) {
92
90
GATTLIB_LOG (GATTLIB_ERROR , "Fail to convert characteristic RX to UUID." );
93
- return 1 ;
91
+ goto EXIT ;
94
92
}
95
93
96
94
// Look for handle for NUS_CHARACTERISTIC_TX_UUID
97
95
gattlib_characteristic_t * characteristics ;
98
96
int characteristic_count ;
99
- ret = gattlib_discover_char (m_connection , & characteristics , & characteristic_count );
97
+ ret = gattlib_discover_char (connection , & characteristics , & characteristic_count );
100
98
if (ret ) {
101
99
GATTLIB_LOG (GATTLIB_ERROR , "Fail to discover characteristic." );
102
- return 1 ;
100
+ goto EXIT ;
103
101
}
104
102
103
+ //
104
+ // Confirm the Nordic UART RX and TX GATT characteristics are present
105
+ //
105
106
uint16_t tx_handle = 0 , rx_handle = 0 ;
106
- for (i = 0 ; i < characteristic_count ; i ++ ) {
107
+ for (int i = 0 ; i < characteristic_count ; i ++ ) {
107
108
if (gattlib_uuid_cmp (& characteristics [i ].uuid , & nus_characteristic_tx_uuid ) == 0 ) {
108
109
tx_handle = characteristics [i ].value_handle ;
109
110
} else if (gattlib_uuid_cmp (& characteristics [i ].uuid , & nus_characteristic_rx_uuid ) == 0 ) {
@@ -112,23 +113,29 @@ int main(int argc, char *argv[]) {
112
113
}
113
114
if (tx_handle == 0 ) {
114
115
GATTLIB_LOG (GATTLIB_ERROR , "Fail to find NUS TX characteristic." );
115
- return 1 ;
116
+ goto FREE_GATT_CHARACTERISTICS ;
116
117
} else if (rx_handle == 0 ) {
117
118
GATTLIB_LOG (GATTLIB_ERROR , "Fail to find NUS RX characteristic." );
118
- return 1 ;
119
+ goto FREE_GATT_CHARACTERISTICS ;
119
120
}
120
- free (characteristics );
121
121
122
- // Register notification handler
123
- gattlib_register_notification (m_connection , notification_cb , NULL );
122
+ //
123
+ // Listen for Nordic UART TX GATT characteristic
124
+ //
125
+ ret = gattlib_register_notification (connection , notification_handler , NULL );
126
+ if (ret ) {
127
+ GATTLIB_LOG (GATTLIB_ERROR , "Fail to register notification callback." );
128
+ goto FREE_GATT_CHARACTERISTICS ;
129
+ }
124
130
125
- ret = gattlib_notification_start (m_connection , & nus_characteristic_rx_uuid );
131
+ ret = gattlib_notification_start (connection , & nus_characteristic_rx_uuid );
126
132
if (ret ) {
127
133
GATTLIB_LOG (GATTLIB_ERROR , "Fail to start notification." );
128
- return 2 ;
134
+ goto FREE_GATT_CHARACTERISTICS ;
129
135
}
130
136
131
137
// Register handler to catch Ctrl+C
138
+ m_connection = connection ;
132
139
signal (SIGINT , int_handler );
133
140
134
141
while (1 ) {
@@ -141,11 +148,97 @@ int main(int argc, char *argv[]) {
141
148
ret = gattlib_write_without_response_char_by_handle (m_connection , tx_handle , input_ptr , length );
142
149
if (ret ) {
143
150
GATTLIB_LOG (GATTLIB_ERROR , "Fail to send data to NUS TX characteristic." );
144
- return 1 ;
151
+ goto FREE_GATT_CHARACTERISTICS ;
145
152
}
146
153
input_ptr += length ;
147
154
}
148
155
}
149
156
157
+ FREE_GATT_CHARACTERISTICS :
158
+ free (characteristics );
159
+
160
+ EXIT :
161
+ gattlib_disconnect (connection , false /* wait_disconnection */ );
162
+
163
+ pthread_mutex_lock (& m_connection_terminated_lock );
164
+ pthread_cond_signal (& m_connection_terminated );
165
+ pthread_mutex_unlock (& m_connection_terminated_lock );
166
+ }
167
+
168
+ static int stricmp (char const * a , char const * b ) {
169
+ for (;; a ++ , b ++ ) {
170
+ int d = tolower ((unsigned char )* a ) - tolower ((unsigned char )* b );
171
+ if (d != 0 || !* a )
172
+ return d ;
173
+ }
174
+ }
175
+
176
+ static void ble_discovered_device (gattlib_adapter_t * adapter , const char * addr , const char * name , void * user_data ) {
177
+ int ret ;
178
+ int16_t rssi ;
179
+
180
+ if (stricmp (addr , m_argument .mac_address ) != 0 ) {
181
+ return ;
182
+ }
183
+
184
+ ret = gattlib_get_rssi_from_mac (adapter , addr , & rssi );
185
+ if (ret == 0 ) {
186
+ GATTLIB_LOG (GATTLIB_INFO , "Found bluetooth device '%s' with RSSI:%d" , m_argument .mac_address , rssi );
187
+ } else {
188
+ GATTLIB_LOG (GATTLIB_INFO , "Found bluetooth device '%s'" , m_argument .mac_address );
189
+ }
190
+
191
+ ret = gattlib_connect (adapter , addr , GATTLIB_CONNECTION_OPTIONS_NONE , on_device_connect , NULL );
192
+ if (ret != GATTLIB_SUCCESS ) {
193
+ GATTLIB_LOG (GATTLIB_ERROR , "Failed to connect to the bluetooth device '%s'" , addr );
194
+ }
195
+ }
196
+
197
+ static void * ble_task (void * arg ) {
198
+ char * addr = arg ;
199
+ gattlib_adapter_t * adapter ;
200
+ int ret ;
201
+
202
+ ret = gattlib_adapter_open (m_argument .adapter_name , & adapter );
203
+ if (ret ) {
204
+ GATTLIB_LOG (GATTLIB_ERROR , "Failed to open adapter." );
205
+ return NULL ;
206
+ }
207
+
208
+ ret = gattlib_adapter_scan_enable (adapter , ble_discovered_device , BLE_SCAN_TIMEOUT , addr );
209
+ if (ret ) {
210
+ GATTLIB_LOG (GATTLIB_ERROR , "Failed to scan." );
211
+ return NULL ;
212
+ }
213
+
214
+ // Wait for the device to be connected
215
+ pthread_mutex_lock (& m_connection_terminated_lock );
216
+ pthread_cond_wait (& m_connection_terminated , & m_connection_terminated_lock );
217
+ pthread_mutex_unlock (& m_connection_terminated_lock );
218
+
219
+ return NULL ;
220
+ }
221
+
222
+ int main (int argc , char * argv []) {
223
+ int ret ;
224
+
225
+ if (argc != 2 ) {
226
+ usage (argv );
227
+ return 1 ;
228
+ }
229
+
230
+ #ifdef GATTLIB_LOG_BACKEND_SYSLOG
231
+ openlog ("gattlib_nordic_uart" , LOG_CONS | LOG_NDELAY | LOG_PERROR , LOG_USER );
232
+ setlogmask (LOG_UPTO (LOG_INFO ));
233
+ #endif
234
+
235
+ m_argument .adapter_name = NULL ;
236
+ m_argument .mac_address = argv [1 ];
237
+
238
+ ret = gattlib_mainloop (ble_task , NULL );
239
+ if (ret != GATTLIB_SUCCESS ) {
240
+ GATTLIB_LOG (GATTLIB_ERROR , "Failed to create gattlib mainloop" );
241
+ }
242
+
150
243
return 0 ;
151
244
}
0 commit comments