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