1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "hci_dump_embedded_stdout.c" 39 40 /* 41 * Dump HCI trace on stdout 42 */ 43 44 #include "btstack_config.h" 45 46 #ifdef ENABLE_SEGGER_RTT 47 48 #include "hci_dump.h" 49 #include "btstack_util.h" 50 #include "hci.h" 51 #include "hci_dump_segger_rtt_stdout.h" 52 53 #include "SEGGER_RTT.h" 54 55 // [00:00:37.514] LOG -- xxx\n 56 #define ADDITIONAL_CHARS_PER_LINE (14+1+6+1+1) 57 58 static void hci_dump_segger_rtt_stdout_timestamp(void); 59 60 #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL 61 62 // avoid trunkated log lines by calculating requires space in rtt buffer 63 // if message needs to be skipped, report number skipped messages 64 65 static const char * message_packets_skipped = "RTT buffer full, %3u packet(s) skipped"; 66 67 static bool hci_dump_segger_prepare_message(uint16_t message_size){ 68 69 static uint32_t hci_dump_rtt_num_skipped = 0; 70 71 // calculate num chars required for line 72 uint16_t required_space = ADDITIONAL_CHARS_PER_LINE + message_size; 73 74 // if we have dropped packets before, we want to print a warning 75 if (hci_dump_rtt_num_skipped > 0){ 76 required_space += ADDITIONAL_CHARS_PER_LINE + strlen(message_packets_skipped); 77 } 78 79 // not enough space yet, drop message 80 if (required_space > SEGGER_RTT_GetAvailWriteSpace(0)){ 81 hci_dump_rtt_num_skipped++; 82 return false; 83 } 84 85 // print message if dropped packets 86 if (hci_dump_rtt_num_skipped > 0){ 87 hci_dump_segger_rtt_stdout_timestamp(); 88 SEGGER_RTT_printf(0, "LOG -- "); 89 SEGGER_RTT_printf(0, message_packets_skipped, hci_dump_rtt_num_skipped); 90 SEGGER_RTT_printf(0, "\n"); 91 hci_dump_rtt_num_skipped = 0; 92 } 93 return true; 94 } 95 #endif 96 97 static void hci_dump_segger_rtt_hexdump(const void *data, int size){ 98 char buffer[4]; 99 buffer[2] = ' '; 100 buffer[3] = 0; 101 const uint8_t * ptr = (const uint8_t *) data; 102 while (size > 0){ 103 uint8_t byte = *ptr++; 104 buffer[0] = char_for_nibble(byte >> 4); 105 buffer[1] = char_for_nibble(byte & 0x0f); 106 SEGGER_RTT_Write(0, buffer, 3); 107 size--; 108 } 109 SEGGER_RTT_PutChar(0, '\n'); 110 } 111 112 static void hci_dump_segger_rtt_stdout_timestamp(void){ 113 uint32_t time_ms = btstack_run_loop_get_time_ms(); 114 int seconds = time_ms / 1000u; 115 int minutes = seconds / 60; 116 unsigned int hours = minutes / 60; 117 118 uint16_t p_ms = time_ms - (seconds * 1000u); 119 uint16_t p_seconds = seconds - (minutes * 60); 120 uint16_t p_minutes = minutes - (hours * 60u); 121 SEGGER_RTT_printf(0, "[%02u:%02u:%02u.%03u] ", hours, p_minutes, p_seconds, p_ms); 122 } 123 124 static void hci_dump_segger_rtt_stdout_packet(uint8_t packet_type, uint8_t in, uint8_t * packet, uint16_t len){ 125 switch (packet_type){ 126 case HCI_COMMAND_DATA_PACKET: 127 SEGGER_RTT_printf(0, "CMD => "); 128 break; 129 case HCI_EVENT_PACKET: 130 SEGGER_RTT_printf(0, "EVT <= "); 131 break; 132 case HCI_ACL_DATA_PACKET: 133 if (in) { 134 SEGGER_RTT_printf(0, "ACL <= "); 135 } else { 136 SEGGER_RTT_printf(0, "ACL => "); 137 } 138 break; 139 case HCI_SCO_DATA_PACKET: 140 if (in) { 141 SEGGER_RTT_printf(0, "SCO <= "); 142 } else { 143 SEGGER_RTT_printf(0, "SCO => "); 144 } 145 break; 146 case HCI_ISO_DATA_PACKET: 147 if (in) { 148 SEGGER_RTT_printf(0, "ISO <= "); 149 } else { 150 SEGGER_RTT_printf(0, "ISO => "); 151 } 152 break; 153 default: 154 return; 155 } 156 hci_dump_segger_rtt_hexdump(packet, len); 157 } 158 159 static void hci_dump_segger_rtt_stdout_log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 160 #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL 161 uint16_t message_len = len * 3; 162 bool ready = hci_dump_segger_prepare_message(message_len); 163 if (!ready) return; 164 #endif 165 166 // print packet 167 hci_dump_segger_rtt_stdout_timestamp(); 168 hci_dump_segger_rtt_stdout_packet(packet_type, in, packet, len); 169 } 170 171 static void hci_dump_segger_rtt_stdout_log_message(int log_level, const char * format, va_list argptr){ 172 UNUSED(log_level); 173 #if SEGGER_RTT_MODE_DEFAULT != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL 174 // to avoid using snprintf for this, we cheat and assume that the messages is less then HCI_DUMP_MAX_MESSAGE_LEN 175 bool ready = hci_dump_segger_prepare_message(HCI_DUMP_MAX_MESSAGE_LEN); 176 if (!ready) return; 177 #endif 178 179 // print message 180 hci_dump_segger_rtt_stdout_timestamp(); 181 SEGGER_RTT_printf(0, "LOG -- "); 182 SEGGER_RTT_vprintf(0, format, &argptr); 183 SEGGER_RTT_printf(0, "\n"); 184 } 185 186 const hci_dump_t * hci_dump_segger_rtt_stdout_get_instance(void){ 187 static const hci_dump_t hci_dump_instance = { 188 // void (*reset)(void); 189 NULL, 190 // void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len); 191 &hci_dump_segger_rtt_stdout_log_packet, 192 // void (*log_message)(int log_level, const char * format, va_list argptr); 193 &hci_dump_segger_rtt_stdout_log_message, 194 }; 195 return &hci_dump_instance; 196 } 197 198 #endif 199