kindlebt
Bluetooth functionality for Kindle 11th gen and up
Loading...
Searching...
No Matches
kindlebt_utils.c
1#include <kindlebt/kindlebt_utils.h>
2
3#include <errno.h>
4#include <pthread.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10
12#include <kindlebt/kindlebt_log.h>
13
14#define ADDR_WITH_COLON_LEN 17
15#define ADDR_WITHOUT_COLON_LEN 12
16#define PRINT_UUID_STR_LEN 49
17
18static void remove_all_chars(char* str, char c) {
19 char *pr = str, *pw = str;
20 while (*pr) {
21 *pw = *pr++;
22 pw += (*pw != c);
23 }
24 *pw = '\0';
25}
26
27void utilsConvertBdAddrToStr(bdAddr_t* paddr, char* outStr) {
28 sprintf(
29 outStr, "%02X:%02X:%02X:%02X:%02X:%02X", paddr->address[0], paddr->address[1],
30 paddr->address[2], paddr->address[3], paddr->address[4], paddr->address[5]
31 );
32}
33
34uint8_t utilsConvertCharToHex(char input) {
35 if (input >= '0' && input <= '9') {
36 return (uint8_t)(input - '0');
37 } else if (input >= 'A' && input <= 'F') {
38 return (uint8_t)(input - 'A') + 10;
39 } else if (input >= 'a' && input <= 'f') {
40 return (uint8_t)(input - 'a') + 10;
41 } else {
42 return 0;
43 }
44}
45
46uint16_t utilsConvertHexStrToByteArray(char* input, uint8_t* output) {
47 uint8_t length = 0;
48 char* hex_string = input;
49 uint8_t hex_length = strlen(input);
50
51 for (int i = 0; i < hex_length; i += 2) {
52 uint8_t value = utilsConvertCharToHex(hex_string[i]) << 4;
53
54 if (i + 1 < hex_length) {
55 value |= utilsConvertCharToHex(hex_string[i + 1]);
56 }
57 output[length] = value;
58 length++;
59 }
60
61 return length;
62}
63
64status_t utilsConvertStrToBdAddr(char* str, bdAddr_t* pAddr) {
65 if (str == NULL || pAddr == NULL) {
66 return ACE_STATUS_BAD_PARAM;
67 }
68
69 int length = strlen(str);
70 if (length != ADDR_WITH_COLON_LEN && length != ADDR_WITHOUT_COLON_LEN) {
71 log_error("Invalid string format. Must be xx:xx:xx:xx:xx:xx or xxxxxxxxxxxx");
72 return ACE_STATUS_BAD_PARAM;
73 }
74 // Check if string is in : format
75 if (length == ADDR_WITH_COLON_LEN && str[2] == ':' && str[5] == ':' && str[8] == ':' &&
76 str[11] == ':' && str[14] == ':') {
77 remove_all_chars(str, ':');
78 }
79
80 if (strlen(str) != ADDR_WITHOUT_COLON_LEN) {
81 log_error("Invalid string format. Must be xx:xx:xx:xx:xx:xx or xxxxxxxxxxxx");
82 return ACE_STATUS_BAD_PARAM;
83 }
84
85 for (int i = 0; i < ADDR_WITHOUT_COLON_LEN; i++) {
86 if (!((str[i] >= '0' && str[i] <= '9') || (str[i] >= 'A' && str[i] <= 'F') ||
87 (str[i] >= 'a' && str[i] <= 'f'))) {
88 log_error("Contains non-hex character at index %d", i);
89 return ACE_STATUS_BAD_PARAM;
90 }
91 }
92
93 log_debug("Converting str->BT addr, str: %s", str);
94
95 length = utilsConvertHexStrToByteArray(str, pAddr->address);
96 if (length != MAC_ADDR_LEN) {
97 return ACE_STATUS_BAD_PARAM;
98 }
99
100 return ACE_STATUS_OK;
101}
102
103void utilsPrintUuid(char* uuid_str, uuid_t* uuid, int max) {
104 snprintf(
105 uuid_str, max,
106 "%02x %02x %02x %02x %02x %02x %02x %02x %02x"
107 " %02x %02x %02x %02x %02x %02x %02x",
108 uuid->uu[0], uuid->uu[1], uuid->uu[2], uuid->uu[3], uuid->uu[4], uuid->uu[5], uuid->uu[6],
109 uuid->uu[7], uuid->uu[8], uuid->uu[9], uuid->uu[10], uuid->uu[11], uuid->uu[12],
110 uuid->uu[13], uuid->uu[14], uuid->uu[15]
111 );
112}
113
114char* utilsDumpServer(bleGattsService_t* server, char* log_buff, size_t* size, size_t* offset) {
115 if (!server) return NULL;
116
117 int inc_svc_count = 0;
118 char buff[PRINT_UUID_STR_LEN];
119 memset(buff, 0, sizeof(char) * PRINT_UUID_STR_LEN);
120 utilsPrintUuid(buff, &server->uuid, PRINT_UUID_STR_LEN);
121 log_buff = append_to_buffer(
122 log_buff, size, offset, "Service 0 uuid %s serviceType %d\n", buff, server->serviceType
123 );
124
125 struct aceBT_gattIncSvcRec_t* svc_rec;
126 STAILQ_FOREACH(svc_rec, &server->incSvcList, link) {
127 memset(buff, 0, sizeof(char) * PRINT_UUID_STR_LEN);
128 utilsPrintUuid(buff, &svc_rec->value.uuid, PRINT_UUID_STR_LEN);
129 log_buff = append_to_buffer(
130 log_buff, size, offset, "Included Services %d service Type %d uuid %s\n",
131 inc_svc_count++, svc_rec->value.serviceType, buff
132 );
133 }
134 uint8_t char_count = 0;
135 struct aceBT_gattCharRec_t* char_rec = NULL;
136 STAILQ_FOREACH(char_rec, &server->charsList, link) {
137 memset(buff, 0, sizeof(char) * PRINT_UUID_STR_LEN);
138 utilsPrintUuid(buff, &char_rec->value.gattRecord.uuid, PRINT_UUID_STR_LEN);
139 if (char_rec->value.gattDescriptor.is_notify && char_rec->value.gattDescriptor.is_set) {
140 log_buff = append_to_buffer(
141 log_buff, size, offset, "\tGatt Characteristics with Notifications %d uuid %s\n",
142 char_count++, buff
143 );
144 } else {
145 log_buff = append_to_buffer(
146 log_buff, size, offset, "\tGatt Characteristics %d uuid %s\n", char_count++, buff
147 );
148 }
149
150 if (char_rec->value.gattDescriptor.is_set) {
151 utilsPrintUuid(
152 buff, &char_rec->value.gattDescriptor.gattRecord.uuid, PRINT_UUID_STR_LEN
153 );
154 log_buff = append_to_buffer(log_buff, size, offset, "\t\tDescriptor UUID %s\n", buff);
155
156 } else if (char_rec->value.multiDescCount) {
157 uint8_t desc_num = 1;
158 struct aceBT_gattDescRec_t* desc_rec = NULL;
159 /* Traverse descriptor linked list */
160 STAILQ_FOREACH(desc_rec, &char_rec->value.descList, link) {
161 utilsPrintUuid(buff, &desc_rec->value.gattRecord.uuid, PRINT_UUID_STR_LEN);
162 log_buff = append_to_buffer(
163 log_buff, size, offset, "\t\tDescriptor %d UUID %s\n", desc_num++, buff
164 );
165 }
166 }
167 }
168
169 return log_buff;
170}
171
172struct aceBT_gattCharRec_t* utilsFindCharRec(uuid_t uuid, uint8_t uuid_len) {
173 struct aceBT_gattCharRec_t* char_rec = NULL;
174
175 if (!pGgatt_service) {
176 log_error("GATT DB has not been populated yet!");
177 return (NULL);
178 }
179
180 // Iterate through all services
181 for (uint32_t i = 0; i < gNo_svc; i++) {
182 bleGattsService_t* services = &pGgatt_service[i];
183
184 // Iterate through all characteristics and look for char uuid
185 STAILQ_FOREACH(char_rec, &services->charsList, link) {
186 // If char uuid matches, read characteristic
187 if (!memcmp(char_rec->value.gattRecord.uuid.uu, &uuid.uu, uuid_len)) {
188 return (char_rec);
189 }
190 }
191 }
192 log_error("GATT Characteristic UUID could not be found!");
193 return (NULL);
194}
195
196void setGattBlobFromBytes(
197 bleGattCharacteristicsValue_t* chars_value, const uint8_t* data, uint16_t size
198) {
199 if (chars_value == NULL || data == NULL || size == 0) return;
200
201 free(chars_value->blobValue.data);
202
203 uint8_t* blob = malloc(size);
204 if (blob == NULL) return;
205
206 memcpy(blob, data, size);
207
208 chars_value->blobValue.data = blob;
209 chars_value->blobValue.size = size;
210 chars_value->blobValue.offset = 0;
211 chars_value->format = BLE_FORMAT_BLOB;
212}
213
214void freeGattBlob(bleGattCharacteristicsValue_t* chars_value) {
215 if (chars_value == NULL || chars_value->blobValue.data == NULL) return;
216
217 free(chars_value->blobValue.data);
218 chars_value->blobValue.data = NULL;
219 chars_value->blobValue.size = 0;
220 chars_value->blobValue.offset = 0;
221}
222
223status_t waitForCondition(pthread_mutex_t* lock, pthread_cond_t* cond, bool* flag) {
224 struct timespec ts;
225
226 clock_gettime(CLOCK_REALTIME, &ts);
227 ts.tv_sec += 10;
228
229 pthread_mutex_lock(lock);
230 while (!(*flag)) {
231 int res = pthread_cond_timedwait(cond, lock, &ts);
232 if (res == ETIMEDOUT) {
233 pthread_mutex_unlock(lock);
234 log_error("Timed out waiting for condition");
235 return ACE_STATUS_TIMEOUT;
236 }
237 }
238 pthread_mutex_unlock(lock);
239
240 return ACE_STATUS_OK;
241}
242
243void setCallbackVariable(pthread_mutex_t* lock, pthread_cond_t* cond, bool* flag, bool value) {
244 pthread_mutex_lock(lock);
245 *flag = value;
246 pthread_cond_signal(cond);
247 pthread_mutex_unlock(lock);
248}
aceBT_bdAddr_t bdAddr_t
Bluetooth address.
ace_status_t status_t
Bluetooth API status codes.
#define MAC_ADDR_LEN
MAC address length.
aceBT_bleGattsService_t bleGattsService_t
Structure for a GATT Server service.
aceBT_uuid_t uuid_t
Bluetooth UUID struct.
#define BLE_FORMAT_BLOB
BLOB format.
aceBT_bleGattCharacteristicsValue_t bleGattCharacteristicsValue_t
BLE GATT Characteristic.
struct aceBT_gattCharRec_t * utilsFindCharRec(uuid_t uuid, uint8_t uuid_len)
Find a GATT Characteristic Record by UUID.
Internal definitions.
bleGattsService_t * pGgatt_service
Internal reference to a GATT service.
uint32_t gNo_svc
Internal number of GATT services, often paired with pGgatt_service.