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