xref: /btstack/platform/embedded/hci_dump_segger_rtt_stdout.c (revision 7e71cd90741790aea51a44b55df7604bd417df41)
1128d6c99SMatthias Ringwald /*
2128d6c99SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3128d6c99SMatthias Ringwald  *
4128d6c99SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5128d6c99SMatthias Ringwald  * modification, are permitted provided that the following conditions
6128d6c99SMatthias Ringwald  * are met:
7128d6c99SMatthias Ringwald  *
8128d6c99SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9128d6c99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10128d6c99SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11128d6c99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12128d6c99SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13128d6c99SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14128d6c99SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15128d6c99SMatthias Ringwald  *    from this software without specific prior written permission.
16128d6c99SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17128d6c99SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18128d6c99SMatthias Ringwald  *    monetary gain.
19128d6c99SMatthias Ringwald  *
20128d6c99SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21128d6c99SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22128d6c99SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25128d6c99SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26128d6c99SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27128d6c99SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28128d6c99SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29128d6c99SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30128d6c99SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31128d6c99SMatthias Ringwald  * SUCH DAMAGE.
32128d6c99SMatthias Ringwald  *
33128d6c99SMatthias Ringwald  * Please inquire about commercial licensing options at
34128d6c99SMatthias Ringwald  * [email protected]
35128d6c99SMatthias Ringwald  *
36128d6c99SMatthias Ringwald  */
37128d6c99SMatthias Ringwald 
38128d6c99SMatthias Ringwald #define BTSTACK_FILE__ "hci_dump_embedded_stdout.c"
39128d6c99SMatthias Ringwald 
40128d6c99SMatthias Ringwald /*
41128d6c99SMatthias Ringwald  *  Dump HCI trace on stdout
42128d6c99SMatthias Ringwald  */
43128d6c99SMatthias Ringwald 
44128d6c99SMatthias Ringwald #include "btstack_config.h"
45da39cc4eSMatthias Ringwald 
46da39cc4eSMatthias Ringwald #ifdef ENABLE_SEGGER_RTT
47da39cc4eSMatthias Ringwald 
48da39cc4eSMatthias Ringwald #include "hci_dump.h"
49128d6c99SMatthias Ringwald #include "btstack_util.h"
50128d6c99SMatthias Ringwald #include "hci.h"
51*7e71cd90SMatthias Ringwald #include "hci_dump_segger_rtt_stdout.h"
52128d6c99SMatthias Ringwald 
53128d6c99SMatthias Ringwald #include "SEGGER_RTT.h"
54128d6c99SMatthias Ringwald 
557dfe4b1cSMatthias Ringwald // [00:00:37.514] LOG -- xxx\n
567dfe4b1cSMatthias Ringwald #define ADDITIONAL_CHARS_PER_LINE (14+1+6+1+1)
577dfe4b1cSMatthias Ringwald 
587dfe4b1cSMatthias Ringwald static void hci_dump_segger_rtt_stdout_timestamp(void);
597dfe4b1cSMatthias Ringwald 
607dfe4b1cSMatthias Ringwald #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
617dfe4b1cSMatthias Ringwald 
627dfe4b1cSMatthias Ringwald // avoid trunkated log lines by calculating requires space in rtt buffer
637dfe4b1cSMatthias Ringwald // if message needs to be skipped, report number skipped messages
647dfe4b1cSMatthias Ringwald 
657dfe4b1cSMatthias Ringwald static const char * message_packets_skipped = "RTT buffer full, %3u packet(s) skipped";
667dfe4b1cSMatthias Ringwald 
hci_dump_segger_prepare_message(uint16_t message_size)677dfe4b1cSMatthias Ringwald static bool hci_dump_segger_prepare_message(uint16_t message_size){
687dfe4b1cSMatthias Ringwald 
697dfe4b1cSMatthias Ringwald     static uint32_t hci_dump_rtt_num_skipped = 0;
707dfe4b1cSMatthias Ringwald 
717dfe4b1cSMatthias Ringwald     // calculate num chars required for line
727dfe4b1cSMatthias Ringwald     uint16_t required_space = ADDITIONAL_CHARS_PER_LINE + message_size;
737dfe4b1cSMatthias Ringwald 
747dfe4b1cSMatthias Ringwald     // if we have dropped packets before, we want to print a warning
757dfe4b1cSMatthias Ringwald     if (hci_dump_rtt_num_skipped > 0){
767dfe4b1cSMatthias Ringwald         required_space += ADDITIONAL_CHARS_PER_LINE + strlen(message_packets_skipped);
777dfe4b1cSMatthias Ringwald     }
787dfe4b1cSMatthias Ringwald 
797dfe4b1cSMatthias Ringwald     // not enough space yet, drop message
807dfe4b1cSMatthias Ringwald     if (required_space > SEGGER_RTT_GetAvailWriteSpace(0)){
817dfe4b1cSMatthias Ringwald         hci_dump_rtt_num_skipped++;
827dfe4b1cSMatthias Ringwald         return false;
837dfe4b1cSMatthias Ringwald     }
847dfe4b1cSMatthias Ringwald 
857dfe4b1cSMatthias Ringwald     // print message if dropped packets
867dfe4b1cSMatthias Ringwald     if (hci_dump_rtt_num_skipped > 0){
877dfe4b1cSMatthias Ringwald         hci_dump_segger_rtt_stdout_timestamp();
887dfe4b1cSMatthias Ringwald         SEGGER_RTT_printf(0, "LOG -- ");
897dfe4b1cSMatthias Ringwald         SEGGER_RTT_printf(0, message_packets_skipped, hci_dump_rtt_num_skipped);
907dfe4b1cSMatthias Ringwald         SEGGER_RTT_printf(0, "\n");
917dfe4b1cSMatthias Ringwald         hci_dump_rtt_num_skipped = 0;
927dfe4b1cSMatthias Ringwald     }
937dfe4b1cSMatthias Ringwald     return true;
947dfe4b1cSMatthias Ringwald }
957dfe4b1cSMatthias Ringwald #endif
967dfe4b1cSMatthias Ringwald 
hci_dump_segger_rtt_hexdump(const void * data,int size)97128d6c99SMatthias Ringwald static void hci_dump_segger_rtt_hexdump(const void *data, int size){
98128d6c99SMatthias Ringwald     char buffer[4];
99128d6c99SMatthias Ringwald     buffer[2] = ' ';
100128d6c99SMatthias Ringwald     buffer[3] =  0;
101128d6c99SMatthias Ringwald     const uint8_t * ptr = (const uint8_t *) data;
102128d6c99SMatthias Ringwald     while (size > 0){
103128d6c99SMatthias Ringwald         uint8_t byte = *ptr++;
104128d6c99SMatthias Ringwald         buffer[0] = char_for_nibble(byte >> 4);
105128d6c99SMatthias Ringwald         buffer[1] = char_for_nibble(byte & 0x0f);
106128d6c99SMatthias Ringwald         SEGGER_RTT_Write(0, buffer, 3);
107128d6c99SMatthias Ringwald         size--;
108128d6c99SMatthias Ringwald     }
109128d6c99SMatthias Ringwald     SEGGER_RTT_PutChar(0, '\n');
110128d6c99SMatthias Ringwald }
111128d6c99SMatthias Ringwald 
hci_dump_segger_rtt_stdout_timestamp(void)112128d6c99SMatthias Ringwald static void hci_dump_segger_rtt_stdout_timestamp(void){
113128d6c99SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_get_time_ms();
114128d6c99SMatthias Ringwald     int      seconds = time_ms / 1000u;
115128d6c99SMatthias Ringwald     int      minutes = seconds / 60;
116128d6c99SMatthias Ringwald     unsigned int hours = minutes / 60;
117128d6c99SMatthias Ringwald 
118128d6c99SMatthias Ringwald     uint16_t p_ms      = time_ms - (seconds * 1000u);
119128d6c99SMatthias Ringwald     uint16_t p_seconds = seconds - (minutes * 60);
120128d6c99SMatthias Ringwald     uint16_t p_minutes = minutes - (hours   * 60u);
121128d6c99SMatthias Ringwald     SEGGER_RTT_printf(0, "[%02u:%02u:%02u.%03u] ", hours, p_minutes, p_seconds, p_ms);
122128d6c99SMatthias Ringwald }
123128d6c99SMatthias Ringwald 
hci_dump_segger_rtt_stdout_packet(uint8_t packet_type,uint8_t in,uint8_t * packet,uint16_t len)124128d6c99SMatthias Ringwald static void hci_dump_segger_rtt_stdout_packet(uint8_t packet_type, uint8_t in, uint8_t * packet, uint16_t len){
125128d6c99SMatthias Ringwald     switch (packet_type){
126128d6c99SMatthias Ringwald         case HCI_COMMAND_DATA_PACKET:
127128d6c99SMatthias Ringwald             SEGGER_RTT_printf(0, "CMD => ");
128128d6c99SMatthias Ringwald             break;
129128d6c99SMatthias Ringwald         case HCI_EVENT_PACKET:
130128d6c99SMatthias Ringwald             SEGGER_RTT_printf(0, "EVT <= ");
131128d6c99SMatthias Ringwald             break;
132128d6c99SMatthias Ringwald         case HCI_ACL_DATA_PACKET:
133128d6c99SMatthias Ringwald             if (in) {
134128d6c99SMatthias Ringwald                 SEGGER_RTT_printf(0, "ACL <= ");
135128d6c99SMatthias Ringwald             } else {
136128d6c99SMatthias Ringwald                 SEGGER_RTT_printf(0, "ACL => ");
137128d6c99SMatthias Ringwald             }
138128d6c99SMatthias Ringwald             break;
139128d6c99SMatthias Ringwald         case HCI_SCO_DATA_PACKET:
140128d6c99SMatthias Ringwald             if (in) {
141128d6c99SMatthias Ringwald                 SEGGER_RTT_printf(0, "SCO <= ");
142128d6c99SMatthias Ringwald             } else {
143128d6c99SMatthias Ringwald                 SEGGER_RTT_printf(0, "SCO => ");
144128d6c99SMatthias Ringwald             }
145128d6c99SMatthias Ringwald             break;
1465a831baeSMatthias Ringwald         case HCI_ISO_DATA_PACKET:
1475a831baeSMatthias Ringwald             if (in) {
1485a831baeSMatthias Ringwald                 SEGGER_RTT_printf(0, "ISO <= ");
1495a831baeSMatthias Ringwald             } else {
1505a831baeSMatthias Ringwald                 SEGGER_RTT_printf(0, "ISO => ");
1515a831baeSMatthias Ringwald             }
1525a831baeSMatthias Ringwald             break;
153128d6c99SMatthias Ringwald         default:
154128d6c99SMatthias Ringwald             return;
155128d6c99SMatthias Ringwald     }
156128d6c99SMatthias Ringwald     hci_dump_segger_rtt_hexdump(packet, len);
157128d6c99SMatthias Ringwald }
158128d6c99SMatthias Ringwald 
hci_dump_segger_rtt_stdout_log_packet(uint8_t packet_type,uint8_t in,uint8_t * packet,uint16_t len)159128d6c99SMatthias Ringwald static void hci_dump_segger_rtt_stdout_log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
1607dfe4b1cSMatthias Ringwald #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
1617dfe4b1cSMatthias Ringwald     uint16_t message_len = len * 3;
1627dfe4b1cSMatthias Ringwald     bool ready = hci_dump_segger_prepare_message(message_len);
1637dfe4b1cSMatthias Ringwald     if (!ready) return;
1647dfe4b1cSMatthias Ringwald #endif
1657dfe4b1cSMatthias Ringwald 
1667dfe4b1cSMatthias Ringwald     // print packet
167128d6c99SMatthias Ringwald     hci_dump_segger_rtt_stdout_timestamp();
168128d6c99SMatthias Ringwald     hci_dump_segger_rtt_stdout_packet(packet_type, in, packet, len);
169128d6c99SMatthias Ringwald }
170128d6c99SMatthias Ringwald 
hci_dump_segger_rtt_stdout_log_message(int log_level,const char * format,va_list argptr)1712d17d4c0SMatthias Ringwald static void hci_dump_segger_rtt_stdout_log_message(int log_level, const char * format, va_list argptr){
1722d17d4c0SMatthias Ringwald     UNUSED(log_level);
1737dfe4b1cSMatthias Ringwald #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
1747dfe4b1cSMatthias Ringwald     // to avoid using snprintf for this, we cheat and assume that the messages is less then HCI_DUMP_MAX_MESSAGE_LEN
1757dfe4b1cSMatthias Ringwald     bool ready = hci_dump_segger_prepare_message(HCI_DUMP_MAX_MESSAGE_LEN);
1767dfe4b1cSMatthias Ringwald     if (!ready) return;
1777dfe4b1cSMatthias Ringwald #endif
1787dfe4b1cSMatthias Ringwald 
1797dfe4b1cSMatthias Ringwald     // print message
180128d6c99SMatthias Ringwald     hci_dump_segger_rtt_stdout_timestamp();
181128d6c99SMatthias Ringwald     SEGGER_RTT_printf(0, "LOG -- ");
182128d6c99SMatthias Ringwald     SEGGER_RTT_vprintf(0, format, &argptr);
183128d6c99SMatthias Ringwald     SEGGER_RTT_printf(0, "\n");
184128d6c99SMatthias Ringwald }
185128d6c99SMatthias Ringwald 
hci_dump_segger_rtt_stdout_get_instance(void)186128d6c99SMatthias Ringwald const hci_dump_t * hci_dump_segger_rtt_stdout_get_instance(void){
187128d6c99SMatthias Ringwald     static const hci_dump_t hci_dump_instance = {
188128d6c99SMatthias Ringwald         // void (*reset)(void);
189128d6c99SMatthias Ringwald         NULL,
190128d6c99SMatthias Ringwald         // void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
191128d6c99SMatthias Ringwald         &hci_dump_segger_rtt_stdout_log_packet,
192128d6c99SMatthias Ringwald         // void (*log_message)(int log_level, const char * format, va_list argptr);
193128d6c99SMatthias Ringwald         &hci_dump_segger_rtt_stdout_log_message,
194128d6c99SMatthias Ringwald     };
195128d6c99SMatthias Ringwald     return &hci_dump_instance;
196128d6c99SMatthias Ringwald }
197da39cc4eSMatthias Ringwald 
198da39cc4eSMatthias Ringwald #endif
199