1 /*
2 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include "hci_log/bt_hci_log.h"
10 #include "bt_common.h"
11 #include "osi/mutex.h"
12 #include "esp_attr.h"
13
14 #if (BT_HCI_LOG_INCLUDED == TRUE)
15 #define BT_HCI_LOG_PRINT_TAG (1)
16 #define BT_HCI_LOG_DATA_BUF_SIZE (1024 * HCI_LOG_DATA_BUFFER_SIZE)
17 #define BT_HCI_LOG_ADV_BUF_SIZE (1024 * HCI_LOG_ADV_BUFFER_SIZE)
18
19 typedef struct {
20 osi_mutex_t mutex_lock;
21 uint64_t log_record_in;
22 uint64_t log_record_out;
23 uint64_t buf_size;
24 uint8_t *p_hci_log_buffer;
25 uint8_t index;
26 bool overflow;
27 } bt_hci_log_t;
28
29 static const char s_hex_to_char_mapping[16] = {
30 '0', '1', '2', '3', '4', '5', '6', '7',
31 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
32 };
33
34 static bt_hci_log_t g_bt_hci_log_data_ctl = {0};
35 static bt_hci_log_t g_bt_hci_log_adv_ctl = {0};
36
bt_hci_log_init(void)37 esp_err_t bt_hci_log_init(void)
38 {
39 uint8_t *g_bt_hci_log_data_buffer = NULL;
40 uint8_t *g_bt_hci_log_adv_buffer = NULL;
41
42 g_bt_hci_log_data_buffer = malloc(BT_HCI_LOG_DATA_BUF_SIZE);
43 if (!g_bt_hci_log_data_buffer) {
44 return ESP_ERR_NO_MEM;
45 }
46 g_bt_hci_log_adv_buffer = malloc(BT_HCI_LOG_ADV_BUF_SIZE);
47 if (!g_bt_hci_log_adv_buffer) {
48 if (g_bt_hci_log_data_buffer) {
49 free(g_bt_hci_log_data_buffer);
50 g_bt_hci_log_data_buffer = NULL;
51 }
52 return ESP_ERR_NO_MEM;
53 }
54
55 memset(g_bt_hci_log_data_buffer, 0, BT_HCI_LOG_DATA_BUF_SIZE);
56 memset(g_bt_hci_log_adv_buffer, 0, BT_HCI_LOG_ADV_BUF_SIZE);
57
58 memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t));
59 g_bt_hci_log_data_ctl.buf_size = BT_HCI_LOG_DATA_BUF_SIZE;
60 g_bt_hci_log_data_ctl.p_hci_log_buffer = g_bt_hci_log_data_buffer;
61
62 memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t));
63 g_bt_hci_log_adv_ctl.buf_size = BT_HCI_LOG_ADV_BUF_SIZE;
64 g_bt_hci_log_adv_ctl.p_hci_log_buffer = g_bt_hci_log_adv_buffer;
65
66 osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock);
67 osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock);
68
69 return ESP_OK;
70 }
71
bt_hci_log_deinit(void)72 esp_err_t bt_hci_log_deinit(void)
73 {
74 if (g_bt_hci_log_data_ctl.p_hci_log_buffer) {
75 free(g_bt_hci_log_data_ctl.p_hci_log_buffer);
76 g_bt_hci_log_data_ctl.p_hci_log_buffer = NULL;
77 }
78
79 if (g_bt_hci_log_adv_ctl.p_hci_log_buffer) {
80 free(g_bt_hci_log_adv_ctl.p_hci_log_buffer);
81 g_bt_hci_log_adv_ctl.p_hci_log_buffer = NULL;
82 }
83
84 osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock);
85 osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock);
86
87 memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t));
88 memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t));
89
90 return ESP_OK;
91 }
92
93 #if (BT_HCI_LOG_PRINT_TAG)
bt_data_type_to_str(uint8_t data_type)94 static char IRAM_ATTR *bt_data_type_to_str(uint8_t data_type)
95 {
96 char *tag = NULL;
97 switch (data_type)
98 {
99 case HCI_LOG_DATA_TYPE_COMMAND:
100 // hci cmd data
101 tag = "C";
102 break;
103 case HCI_LOG_DATA_TYPE_H2C_ACL:
104 // host to controller hci acl data
105 tag = "H";
106 break;
107 case HCI_LOG_DATA_TYPE_SCO:
108 // hci sco data
109 tag = "S";
110 break;
111 case HCI_LOG_DATA_TYPE_EVENT:
112 // hci event
113 tag = "E";
114 break;
115 case HCI_LOG_DATA_TYPE_ADV:
116 // controller adv report data
117 tag = NULL;
118 break;
119 case HCI_LOG_DATA_TYPE_C2H_ACL:
120 // controller to host hci acl data
121 tag = "D";
122 break;
123 case HCI_LOG_DATA_TYPE_SELF_DEFINE:
124 // self-defining data
125 tag = "S";
126 break;
127 default:
128 // unknown data type
129 tag = "U";
130 break;
131 }
132
133 return tag;
134 }
135 #endif
136
bt_hci_log_record_hex(bt_hci_log_t * p_hci_log_ctl,uint8_t * hex,uint8_t hex_len)137 void bt_hci_log_record_hex(bt_hci_log_t *p_hci_log_ctl, uint8_t *hex, uint8_t hex_len)
138 {
139 uint8_t hci_log_char;
140 uint8_t *g_hci_log_buffer;
141
142 g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;
143
144 while (hex_len--)
145 {
146 hci_log_char = ((*hex) >> 4);
147
148 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char];
149
150 if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
151 p_hci_log_ctl->log_record_in = 0;
152 }
153 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
154 p_hci_log_ctl->overflow = true;
155 }
156
157 hci_log_char = ((*hex) & 0x0f);
158
159 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char];
160
161 if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
162 p_hci_log_ctl->log_record_in = 0;
163 }
164
165 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
166 p_hci_log_ctl->overflow = true;
167 }
168
169 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ' ';
170
171 if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
172 p_hci_log_ctl->log_record_in = 0;
173 }
174 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
175 p_hci_log_ctl->overflow = true;
176 }
177
178 ++ hex;
179 }
180 }
181
bt_hci_log_record_string(bt_hci_log_t * p_hci_log_ctl,char * string)182 void bt_hci_log_record_string(bt_hci_log_t *p_hci_log_ctl, char *string)
183 {
184 uint8_t *g_hci_log_buffer;
185
186 g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;
187
188 while (*string != '\0') {
189 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = *string;
190 ++string;
191
192 if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
193 p_hci_log_ctl->log_record_in = 0;
194 }
195
196 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
197 p_hci_log_ctl->overflow = true;
198 }
199 }
200 }
201
bt_hci_log_record_data(bt_hci_log_t * p_hci_log_ctl,char * str,uint8_t data_type,uint8_t * data,uint8_t data_len)202 esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *str, uint8_t data_type, uint8_t *data, uint8_t data_len)
203 {
204 osi_mutex_t mutex_lock;
205 uint8_t *g_hci_log_buffer;
206
207 if (!p_hci_log_ctl->p_hci_log_buffer) {
208 return ESP_FAIL;
209 }
210
211 g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;
212
213 if (!g_hci_log_buffer) {
214 return ESP_FAIL;
215 }
216
217 mutex_lock = p_hci_log_ctl->mutex_lock;
218 osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT);
219
220 #if (1)
221 // Add hci data index
222 bt_hci_log_record_hex(p_hci_log_ctl, &p_hci_log_ctl->index, 1);
223 #endif
224
225 #if (BT_HCI_LOG_PRINT_TAG)
226 char *tag = NULL;
227 tag = bt_data_type_to_str(data_type);
228
229 if (tag) {
230 bt_hci_log_record_string(p_hci_log_ctl, tag);
231
232 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ':';
233
234 if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
235 p_hci_log_ctl->log_record_in = 0;
236 }
237
238 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
239 p_hci_log_ctl->overflow = true;
240 }
241 }
242 #endif
243
244 if (str) {
245 bt_hci_log_record_string(p_hci_log_ctl, str);
246 }
247
248 bt_hci_log_record_hex(p_hci_log_ctl, data, data_len);
249
250 g_hci_log_buffer[p_hci_log_ctl->log_record_in] = '\n';
251
252 if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
253 p_hci_log_ctl->log_record_in = 0;
254 }
255
256 if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) {
257 p_hci_log_ctl->overflow = true;
258 }
259
260 p_hci_log_ctl->index ++;
261
262 osi_mutex_unlock(&mutex_lock);
263
264 return ESP_OK;
265 }
266
bt_hci_log_data_show(bt_hci_log_t * p_hci_log_ctl)267 void bt_hci_log_data_show(bt_hci_log_t *p_hci_log_ctl)
268 {
269 volatile uint64_t log_record_in,log_record_out;
270 uint8_t *g_hci_log_buffer;
271
272 if (!p_hci_log_ctl->p_hci_log_buffer) {
273 return;
274 }
275
276 osi_mutex_t mutex_lock = p_hci_log_ctl->mutex_lock;
277
278 osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT);
279
280 log_record_in = p_hci_log_ctl->log_record_in;
281 log_record_out = p_hci_log_ctl->log_record_out;
282
283 g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;
284
285 if (p_hci_log_ctl->overflow) {
286 log_record_out = log_record_in;
287 printf("%c",g_hci_log_buffer[log_record_out]);
288
289 if (++log_record_out >= p_hci_log_ctl->buf_size) {
290 log_record_out = 0;
291 }
292 }
293
294 while (log_record_in != log_record_out)
295 {
296 printf("%c",g_hci_log_buffer[log_record_out]);
297
298 if (++log_record_out >= p_hci_log_ctl->buf_size) {
299 log_record_out = 0;
300 }
301 }
302
303 p_hci_log_ctl->log_record_out = log_record_out;
304 p_hci_log_ctl->overflow = false;
305
306 osi_mutex_unlock(&mutex_lock);
307 }
308 static bool enable_hci_log_flag = true;
bt_hci_log_record_hci_enable(bool enable)309 void bt_hci_log_record_hci_enable(bool enable)
310 {
311 enable_hci_log_flag = enable;
312 }
313
bt_hci_log_record_hci_data(uint8_t data_type,uint8_t * data,uint8_t data_len)314 esp_err_t IRAM_ATTR bt_hci_log_record_hci_data(uint8_t data_type, uint8_t *data, uint8_t data_len)
315 {
316 if (!enable_hci_log_flag) return ESP_OK;
317 return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, NULL, data_type, data, data_len);
318 }
319
bt_hci_log_record_custom_data(char * string,uint8_t * data,uint8_t data_len)320 esp_err_t IRAM_ATTR bt_hci_log_record_custom_data(char *string, uint8_t *data, uint8_t data_len)
321 {
322 if (!enable_hci_log_flag) return ESP_OK;
323 return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, string, HCI_LOG_DATA_TYPE_SELF_DEFINE, data, data_len);
324 }
325
bt_hci_log_record_hci_adv(uint8_t data_type,uint8_t * data,uint8_t data_len)326 esp_err_t IRAM_ATTR bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len)
327 {
328 if (!enable_hci_log_flag) return ESP_OK;
329 return bt_hci_log_record_data(&g_bt_hci_log_adv_ctl, NULL, data_type, data, data_len);
330 }
331
bt_hci_log_hci_data_show(void)332 void bt_hci_log_hci_data_show(void)
333 {
334 bt_hci_log_data_show(&g_bt_hci_log_data_ctl);
335 }
336
bt_hci_log_hci_adv_show(void)337 void bt_hci_log_hci_adv_show(void)
338 {
339 bt_hci_log_data_show(&g_bt_hci_log_adv_ctl);
340 }
341
342 #endif // (BT_HCI_LOG_INCLUDED == TRUE)
343