xref: /btstack/src/hci_dump.c (revision 8cbbcccdda01807650583e5dc712acc4367be5d3)
179662672Smatthias.ringwald /*
2a0c35809S[email protected]  * Copyright (C) 2014 BlueKitchen GmbH
31713bceaSmatthias.ringwald  *
41713bceaSmatthias.ringwald  * Redistribution and use in source and binary forms, with or without
51713bceaSmatthias.ringwald  * modification, are permitted provided that the following conditions
61713bceaSmatthias.ringwald  * are met:
71713bceaSmatthias.ringwald  *
81713bceaSmatthias.ringwald  * 1. Redistributions of source code must retain the above copyright
91713bceaSmatthias.ringwald  *    notice, this list of conditions and the following disclaimer.
101713bceaSmatthias.ringwald  * 2. Redistributions in binary form must reproduce the above copyright
111713bceaSmatthias.ringwald  *    notice, this list of conditions and the following disclaimer in the
121713bceaSmatthias.ringwald  *    documentation and/or other materials provided with the distribution.
131713bceaSmatthias.ringwald  * 3. Neither the name of the copyright holders nor the names of
141713bceaSmatthias.ringwald  *    contributors may be used to endorse or promote products derived
151713bceaSmatthias.ringwald  *    from this software without specific prior written permission.
166b64433eSmatthias.ringwald  * 4. Any redistribution, use, or modification is done solely for
176b64433eSmatthias.ringwald  *    personal benefit and not for any commercial purpose or for
186b64433eSmatthias.ringwald  *    monetary gain.
191713bceaSmatthias.ringwald  *
20a0c35809S[email protected]  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
211713bceaSmatthias.ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
221713bceaSmatthias.ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
231713bceaSmatthias.ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
241713bceaSmatthias.ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
251713bceaSmatthias.ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
261713bceaSmatthias.ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
271713bceaSmatthias.ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
281713bceaSmatthias.ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
291713bceaSmatthias.ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
301713bceaSmatthias.ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311713bceaSmatthias.ringwald  * SUCH DAMAGE.
321713bceaSmatthias.ringwald  *
33a0c35809S[email protected]  * Please inquire about commercial licensing options at
34a0c35809S[email protected]  * [email protected]
356b64433eSmatthias.ringwald  *
361713bceaSmatthias.ringwald  */
371713bceaSmatthias.ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hci_dump.c"
39ab2c6ae4SMatthias Ringwald 
401713bceaSmatthias.ringwald /*
4179662672Smatthias.ringwald  *  hci_dump.c
4279662672Smatthias.ringwald  *
43fe1ed1b8Smatthias.ringwald  *  Dump HCI trace in various formats:
44fe1ed1b8Smatthias.ringwald  *
45fe1ed1b8Smatthias.ringwald  *  - BlueZ's hcidump format
46fe1ed1b8Smatthias.ringwald  *  - Apple's PacketLogger
47fe1ed1b8Smatthias.ringwald  *  - stdout hexdump
4879662672Smatthias.ringwald  *
4979662672Smatthias.ringwald  */
5079662672Smatthias.ringwald 
517907f069SMatthias Ringwald #include "btstack_config.h"
52a1d7dd1fSmatthias.ringwald 
53359cfe47SMatthias Ringwald // enable POSIX functions (needed for -std=c99)
54359cfe47SMatthias Ringwald #define _POSIX_C_SOURCE 200809
55359cfe47SMatthias Ringwald 
5679662672Smatthias.ringwald #include "hci_dump.h"
5779662672Smatthias.ringwald #include "hci.h"
58c6448b67Smatthias.ringwald #include "hci_transport.h"
5956042629SMatthias Ringwald #include "hci_cmd.h"
6082636622SMatthias Ringwald #include "btstack_run_loop.h"
61198a9e1bS[email protected] #include <stdio.h>
6279662672Smatthias.ringwald 
63eb443d3dSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
64d5ea8924S[email protected] #include <fcntl.h>        // open
6579662672Smatthias.ringwald #include <unistd.h>       // write
668adf0ddaSmatthias.ringwald #include <time.h>
678b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
68c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
6968e27c0fSmatthias.ringwald #endif
7079662672Smatthias.ringwald 
715fa31a99SMatthias Ringwald #ifdef ENABLE_SEGGER_RTT
725fa31a99SMatthias Ringwald #include "SEGGER_RTT.h"
73*8cbbcccdSMatthias Ringwald 
74*8cbbcccdSMatthias Ringwald // allow to configure mode, channel, up buffer size in btstack_config.h for binary HCI formats (PacketLogger/BlueZ)
75*8cbbcccdSMatthias Ringwald 
76*8cbbcccdSMatthias Ringwald #ifndef SEGGER_RTT_PACKETLOG_MODE
77*8cbbcccdSMatthias Ringwald #define SEGGER_RTT_PACKETLOG_MODE SEGGER_RTT_MODE_DEFAULT
78*8cbbcccdSMatthias Ringwald #endif
79*8cbbcccdSMatthias Ringwald #ifndef SEGGER_RTT_PACKETLOG_BUFFER_SIZE
80*8cbbcccdSMatthias Ringwald #define SEGGER_RTT_PACKETLOG_BUFFER_SIZE 1024
81*8cbbcccdSMatthias Ringwald #endif
82*8cbbcccdSMatthias Ringwald #ifndef SEGGER_RTT_PACKETLOG_CHANNEL
83*8cbbcccdSMatthias Ringwald #define SEGGER_RTT_PACKETLOG_CHANNEL 1
84*8cbbcccdSMatthias Ringwald #endif
85*8cbbcccdSMatthias Ringwald 
86*8cbbcccdSMatthias Ringwald static char segger_rtt_packetlog_buffer[SEGGER_RTT_PACKETLOG_BUFFER_SIZE];
875fa31a99SMatthias Ringwald #endif
885fa31a99SMatthias Ringwald 
891a1c8389SMatthias Ringwald // BLUEZ hcidump - struct not used directly, but left here as documentation
908b658ebcSmatthias.ringwald typedef struct {
918b658ebcSmatthias.ringwald     uint16_t    len;
928b658ebcSmatthias.ringwald     uint8_t     in;
938b658ebcSmatthias.ringwald     uint8_t     pad;
948b658ebcSmatthias.ringwald     uint32_t    ts_sec;
958b658ebcSmatthias.ringwald     uint32_t    ts_usec;
968b658ebcSmatthias.ringwald     uint8_t     packet_type;
976c5c6faaSmatthias.ringwald }
986c5c6faaSmatthias.ringwald hcidump_hdr;
99f3e036dcSMatthias Ringwald #define HCIDUMP_HDR_SIZE 13
10079662672Smatthias.ringwald 
1011a1c8389SMatthias Ringwald // APPLE PacketLogger - struct not used directly, but left here as documentation
1028b658ebcSmatthias.ringwald typedef struct {
1038b658ebcSmatthias.ringwald     uint32_t    len;
1048b658ebcSmatthias.ringwald     uint32_t    ts_sec;
1058b658ebcSmatthias.ringwald     uint32_t    ts_usec;
1062df12229Smatthias.ringwald     uint8_t     type;   // 0xfc for note
1076c5c6faaSmatthias.ringwald }
1086c5c6faaSmatthias.ringwald pktlog_hdr;
109f3e036dcSMatthias Ringwald #define PKTLOG_HDR_SIZE 13
1108b658ebcSmatthias.ringwald 
1118b658ebcSmatthias.ringwald static int dump_file = -1;
1128b658ebcSmatthias.ringwald static int dump_format;
1135fa31a99SMatthias Ringwald static union {
1145fa31a99SMatthias Ringwald     uint8_t header_bluez[HCIDUMP_HDR_SIZE];
1155fa31a99SMatthias Ringwald     uint8_t header_packetlogger[PKTLOG_HDR_SIZE];
1165fa31a99SMatthias Ringwald } header;
1175fa31a99SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
1188adf0ddaSmatthias.ringwald static char time_string[40];
1192992c131Smatthias.ringwald static int  max_nr_packets = -1;
1209ae0c346Smatthias.ringwald static int  nr_packets = 0;
1211fb07123SMatthias Ringwald #endif
1221fb07123SMatthias Ringwald 
1231fb07123SMatthias Ringwald #if defined(HAVE_POSIX_FILE_IO) || defined (ENABLE_SEGGER_RTT)
124a1d7dd1fSmatthias.ringwald static char log_message_buffer[256];
12568e27c0fSmatthias.ringwald #endif
1268b658ebcSmatthias.ringwald 
1278a37b10aSMatthias Ringwald // levels: debug, info, error
1288a37b10aSMatthias Ringwald static int log_level_enabled[3] = { 1, 1, 1};
1298a37b10aSMatthias Ringwald 
130a225073eS[email protected] void hci_dump_open(const char *filename, hci_dump_format_t format){
1315fa31a99SMatthias Ringwald 
1328b658ebcSmatthias.ringwald     dump_format = format;
1335fa31a99SMatthias Ringwald 
1345fa31a99SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
1358adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
1368adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
1378adf0ddaSmatthias.ringwald     } else {
138eb443d3dSMatthias Ringwald 
1391e154302SMatthias Ringwald         int oflags = O_WRONLY | O_CREAT | O_TRUNC;
140b52eaea5S[email protected] #ifdef _WIN32
1411e154302SMatthias Ringwald         oflags |= O_BINARY;
142b52eaea5S[email protected] #endif
1431e154302SMatthias Ringwald         dump_file = open(filename, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
1441e154302SMatthias Ringwald         if (dump_file < 0){
1451e154302SMatthias Ringwald             printf("hci_dump_open: failed to open file %s\n", filename);
1461e154302SMatthias Ringwald         }
14779662672Smatthias.ringwald     }
148eb443d3dSMatthias Ringwald #else
1495fa31a99SMatthias Ringwald 
150d0662982SMatthias Ringwald     UNUSED(filename);
1515fa31a99SMatthias Ringwald 
1525fa31a99SMatthias Ringwald #ifdef ENABLE_SEGGER_RTT
1535fa31a99SMatthias Ringwald     switch (dump_format){
1545fa31a99SMatthias Ringwald         case HCI_DUMP_PACKETLOGGER:
1555fa31a99SMatthias Ringwald         case HCI_DUMP_BLUEZ:
156*8cbbcccdSMatthias Ringwald             SEGGER_RTT_ConfigUpBuffer(SEGGER_RTT_PACKETLOG_CHANNEL, "hci_dump", &segger_rtt_packetlog_buffer[0], SEGGER_RTT_PACKETLOG_BUFFER_SIZE, SEGGER_RTT_PACKETLOG_MODE);
1575fa31a99SMatthias Ringwald             break;
1585fa31a99SMatthias Ringwald         default:
1595fa31a99SMatthias Ringwald             break;
1605fa31a99SMatthias Ringwald     }
1615fa31a99SMatthias Ringwald #endif
162d0662982SMatthias Ringwald 
163eb443d3dSMatthias Ringwald     dump_file = 1;
16468e27c0fSmatthias.ringwald #endif
165d9659922Smatthias.ringwald }
16679662672Smatthias.ringwald 
167eb443d3dSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
1682992c131Smatthias.ringwald void hci_dump_set_max_packets(int packets){
1692992c131Smatthias.ringwald     max_nr_packets = packets;
1702992c131Smatthias.ringwald }
1717c5f7483Smatthias.ringwald #endif
1722992c131Smatthias.ringwald 
1735fa31a99SMatthias Ringwald static void hci_dump_packetlogger_setup_header(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len){
1745fa31a99SMatthias Ringwald     big_endian_store_32( buffer, 0, PKTLOG_HDR_SIZE - 4 + len);
1755fa31a99SMatthias Ringwald     big_endian_store_32( buffer, 4, tv_sec);
1765fa31a99SMatthias Ringwald     big_endian_store_32( buffer, 8, tv_us);
1775fa31a99SMatthias Ringwald     uint8_t packet_logger_type = 0;
1785fa31a99SMatthias Ringwald     switch (packet_type){
1795fa31a99SMatthias Ringwald         case HCI_COMMAND_DATA_PACKET:
1805fa31a99SMatthias Ringwald             packet_logger_type = 0x00;
1815fa31a99SMatthias Ringwald             break;
1825fa31a99SMatthias Ringwald         case HCI_ACL_DATA_PACKET:
1835fa31a99SMatthias Ringwald             packet_logger_type = in ? 0x03 : 0x02;
1845fa31a99SMatthias Ringwald             break;
1855fa31a99SMatthias Ringwald         case HCI_SCO_DATA_PACKET:
1865fa31a99SMatthias Ringwald             packet_logger_type = in ? 0x09 : 0x08;
1875fa31a99SMatthias Ringwald             break;
1885fa31a99SMatthias Ringwald         case HCI_EVENT_PACKET:
1895fa31a99SMatthias Ringwald             packet_logger_type = 0x01;
1905fa31a99SMatthias Ringwald             break;
1915fa31a99SMatthias Ringwald         case LOG_MESSAGE_PACKET:
1925fa31a99SMatthias Ringwald             packet_logger_type = 0xfc;
1935fa31a99SMatthias Ringwald             break;
1945fa31a99SMatthias Ringwald         default:
1955fa31a99SMatthias Ringwald             return;
1965fa31a99SMatthias Ringwald     }
1975fa31a99SMatthias Ringwald     buffer[12] = packet_logger_type;
1985fa31a99SMatthias Ringwald }
1995fa31a99SMatthias Ringwald 
2005fa31a99SMatthias Ringwald static void hci_dump_bluez_setup_header(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len){
2015fa31a99SMatthias Ringwald     little_endian_store_16( buffer, 0, 1 + len);
2025fa31a99SMatthias Ringwald     buffer[2] = in;
2035fa31a99SMatthias Ringwald     buffer[3] = 0;
2045fa31a99SMatthias Ringwald     little_endian_store_32( buffer, 4, tv_sec);
2055fa31a99SMatthias Ringwald     little_endian_store_32( buffer, 8, tv_us);
2065fa31a99SMatthias Ringwald     buffer[12] = packet_type;
2075fa31a99SMatthias Ringwald }
2085fa31a99SMatthias Ringwald 
2098a37b10aSMatthias Ringwald static void printf_packet(uint8_t packet_type, uint8_t in, uint8_t * packet, uint16_t len){
210198a9e1bS[email protected]     switch (packet_type){
211198a9e1bS[email protected]         case HCI_COMMAND_DATA_PACKET:
212198a9e1bS[email protected]             printf("CMD => ");
213198a9e1bS[email protected]             break;
214198a9e1bS[email protected]         case HCI_EVENT_PACKET:
215198a9e1bS[email protected]             printf("EVT <= ");
216198a9e1bS[email protected]             break;
217198a9e1bS[email protected]         case HCI_ACL_DATA_PACKET:
218198a9e1bS[email protected]             if (in) {
219198a9e1bS[email protected]                 printf("ACL <= ");
220198a9e1bS[email protected]             } else {
221198a9e1bS[email protected]                 printf("ACL => ");
222198a9e1bS[email protected]             }
223198a9e1bS[email protected]             break;
2241e154302SMatthias Ringwald         case HCI_SCO_DATA_PACKET:
2251e154302SMatthias Ringwald             if (in) {
2261e154302SMatthias Ringwald                 printf("SCO <= ");
2271e154302SMatthias Ringwald             } else {
2281e154302SMatthias Ringwald                 printf("SCO => ");
2291e154302SMatthias Ringwald             }
2301e154302SMatthias Ringwald             break;
231198a9e1bS[email protected]         case LOG_MESSAGE_PACKET:
232198a9e1bS[email protected]             printf("LOG -- %s\n", (char*) packet);
233198a9e1bS[email protected]             return;
234198a9e1bS[email protected]         default:
235198a9e1bS[email protected]             return;
236198a9e1bS[email protected]     }
237198a9e1bS[email protected]     printf_hexdump(packet, len);
238198a9e1bS[email protected] }
239198a9e1bS[email protected] 
240ad6274a7SMatthias Ringwald static void printf_timestamp(void){
2416401061aSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
2426401061aSMatthias Ringwald     struct tm* ptm;
2436401061aSMatthias Ringwald     struct timeval curr_time;
2446401061aSMatthias Ringwald     gettimeofday(&curr_time, NULL);
2456401061aSMatthias Ringwald     time_t curr_time_secs = curr_time.tv_sec;
2466401061aSMatthias Ringwald     /* Obtain the time of day, and convert it to a tm struct. */
2476401061aSMatthias Ringwald     ptm = localtime (&curr_time_secs);
2486401061aSMatthias Ringwald     /* assert localtime was successful */
2496401061aSMatthias Ringwald     if (!ptm) return;
2506401061aSMatthias Ringwald     /* Format the date and time, down to a single second. */
2516401061aSMatthias Ringwald     strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
2526401061aSMatthias Ringwald     /* Compute milliseconds from microseconds. */
2536401061aSMatthias Ringwald     uint16_t milliseconds = curr_time.tv_usec / 1000;
2546401061aSMatthias Ringwald     /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */
2556401061aSMatthias Ringwald     printf ("%s.%03u] ", time_string, milliseconds);
2566401061aSMatthias Ringwald #else
257ad6274a7SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_get_time_ms();
258ad6274a7SMatthias Ringwald     int      seconds = time_ms / 1000;
259ad6274a7SMatthias Ringwald     int      minutes = seconds / 60;
260f04a0c31SMatthias Ringwald     unsigned int hours = minutes / 60;
261ad6274a7SMatthias Ringwald 
262f04a0c31SMatthias Ringwald     uint16_t p_ms      = time_ms - (seconds * 1000);
263f04a0c31SMatthias Ringwald     uint16_t p_seconds = seconds - (minutes * 60);
264f04a0c31SMatthias Ringwald     uint16_t p_minutes = minutes - (hours   * 60);
265ad6274a7SMatthias Ringwald     printf("[%02u:%02u:%02u.%03u] ", hours, p_minutes, p_seconds, p_ms);
266ad6274a7SMatthias Ringwald #endif
2676401061aSMatthias Ringwald }
268ad6274a7SMatthias Ringwald 
26979662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
27068e27c0fSmatthias.ringwald 
2718b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
2728b658ebcSmatthias.ringwald 
273eb443d3dSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
2742992c131Smatthias.ringwald     // don't grow bigger than max_nr_packets
2752992c131Smatthias.ringwald     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
2762992c131Smatthias.ringwald         if (nr_packets >= max_nr_packets){
2772992c131Smatthias.ringwald             lseek(dump_file, 0, SEEK_SET);
278acb15818SMatthias Ringwald             // avoid -Wunused-result
279acb15818SMatthias Ringwald             int res = ftruncate(dump_file, 0);
280acb15818SMatthias Ringwald             UNUSED(res);
2812992c131Smatthias.ringwald             nr_packets = 0;
2822992c131Smatthias.ringwald         }
2832992c131Smatthias.ringwald         nr_packets++;
2842992c131Smatthias.ringwald     }
2855fa31a99SMatthias Ringwald #endif
2862992c131Smatthias.ringwald 
2875fa31a99SMatthias Ringwald     if (dump_format == HCI_DUMP_STDOUT){
2886401061aSMatthias Ringwald         printf_timestamp();
289198a9e1bS[email protected]         printf_packet(packet_type, in, packet, len);
2905fa31a99SMatthias Ringwald         return;
291a9cf4d77S[email protected]     }
2920d79c710Smatthias.ringwald 
2935fa31a99SMatthias Ringwald     uint32_t tv_sec = 0;
2945fa31a99SMatthias Ringwald     uint32_t tv_us  = 0;
2955fa31a99SMatthias Ringwald 
2965fa31a99SMatthias Ringwald     // get time
2975fa31a99SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
2985fa31a99SMatthias Ringwald     struct timeval curr_time;
2995fa31a99SMatthias Ringwald     gettimeofday(&curr_time, NULL);
3005fa31a99SMatthias Ringwald     tv_sec = curr_time.tv_sec;
3015fa31a99SMatthias Ringwald     tv_us  = curr_time.tv_usec;
3025fa31a99SMatthias Ringwald #else
3035fa31a99SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_get_time_ms();
3045fa31a99SMatthias Ringwald     tv_us   = time_ms * 1000;
3055fa31a99SMatthias Ringwald     tv_sec  = 946728000UL + (time_ms / 1000);
3065fa31a99SMatthias Ringwald #endif
3075fa31a99SMatthias Ringwald 
3083b809c72SMatthias Ringwald #ifdef ENABLE_SEGGER_RTT
309*8cbbcccdSMatthias Ringwald #if (SEGGER_RTT_PACKETLOG_MODE == SEGGER_RTT_MODE_NO_BLOCK_SKIP)
3103b809c72SMatthias Ringwald     static const char rtt_warning[] = "RTT buffer full - packet(s) skipped";
3113b809c72SMatthias Ringwald     static bool rtt_packet_skipped = false;
3123b809c72SMatthias Ringwald     if (rtt_packet_skipped){
3133b809c72SMatthias Ringwald         // try to write warning log message
3143b809c72SMatthias Ringwald         rtt_packet_skipped = false;
3153b809c72SMatthias Ringwald         packet_type = LOG_MESSAGE_PACKET;
3163b809c72SMatthias Ringwald         packet      = (uint8_t *) &rtt_warning[0];
3173b809c72SMatthias Ringwald         len         = sizeof(rtt_warning)-1;
3183b809c72SMatthias Ringwald     }
3193b809c72SMatthias Ringwald #endif
3203b809c72SMatthias Ringwald #endif
3213b809c72SMatthias Ringwald 
3225fa31a99SMatthias Ringwald     uint16_t header_len = 0;
3235fa31a99SMatthias Ringwald     switch (dump_format){
3248b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
3255fa31a99SMatthias Ringwald             hci_dump_bluez_setup_header(header.header_bluez, tv_sec, tv_us, packet_type, in, len);
3265fa31a99SMatthias Ringwald             header_len = HCIDUMP_HDR_SIZE;
3278b658ebcSmatthias.ringwald             break;
3288b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
3295fa31a99SMatthias Ringwald             hci_dump_packetlogger_setup_header(header.header_packetlogger, tv_sec, tv_us, packet_type, in, len);
3305fa31a99SMatthias Ringwald             header_len = PKTLOG_HDR_SIZE;
3310d79c710Smatthias.ringwald             break;
3328b658ebcSmatthias.ringwald         default:
3338b658ebcSmatthias.ringwald             return;
3348b658ebcSmatthias.ringwald     }
3355fa31a99SMatthias Ringwald 
3365fa31a99SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
3375fa31a99SMatthias Ringwald     // avoid -Wunused-result
3385fa31a99SMatthias Ringwald     int res = 0;
3395fa31a99SMatthias Ringwald     res = write (dump_file, &header, header_len);
340acb15818SMatthias Ringwald     res = write (dump_file, packet, len );
341acb15818SMatthias Ringwald     UNUSED(res);
34268e27c0fSmatthias.ringwald #endif
3433b809c72SMatthias Ringwald 
3445fa31a99SMatthias Ringwald #ifdef ENABLE_SEGGER_RTT
3453b809c72SMatthias Ringwald 
346*8cbbcccdSMatthias Ringwald #if (SEGGER_RTT_PACKETLOG_MODE == SEGGER_RTT_MODE_NO_BLOCK_SKIP)
3473b809c72SMatthias Ringwald     // check available space in buffer to avoid writing header but not packet
348*8cbbcccdSMatthias Ringwald     unsigned space_free = SEGGER_RTT_GetAvailWriteSpace(SEGGER_RTT_PACKETLOG_CHANNEL);
3493b809c72SMatthias Ringwald     if ((header_len + len) > space_free) {
3503b809c72SMatthias Ringwald         rtt_packet_skipped = true;
3513b809c72SMatthias Ringwald         return;
3523b809c72SMatthias Ringwald     }
3533b809c72SMatthias Ringwald #endif
3543b809c72SMatthias Ringwald 
355*8cbbcccdSMatthias Ringwald     SEGGER_RTT_Write(SEGGER_RTT_PACKETLOG_CHANNEL, &header, header_len);
356*8cbbcccdSMatthias Ringwald     SEGGER_RTT_Write(SEGGER_RTT_PACKETLOG_CHANNEL, packet, len);
3575fa31a99SMatthias Ringwald #endif
3585fa31a99SMatthias Ringwald     UNUSED(header_len);
35979662672Smatthias.ringwald }
36079662672Smatthias.ringwald 
3618a37b10aSMatthias Ringwald static int hci_dump_log_level_active(int log_level){
362fa087deaSMatthias Ringwald     if (log_level < HCI_DUMP_LOG_LEVEL_DEBUG) return 0;
363fa087deaSMatthias Ringwald     if (log_level > HCI_DUMP_LOG_LEVEL_ERROR) return 0;
3648a37b10aSMatthias Ringwald     return log_level_enabled[log_level];
3658a37b10aSMatthias Ringwald }
3668a37b10aSMatthias Ringwald 
36794be1a66SMatthias Ringwald void hci_dump_log_va_arg(int log_level, const char * format, va_list argptr){
3686401061aSMatthias Ringwald     if (!hci_dump_log_level_active(log_level)) return;
3696401061aSMatthias Ringwald 
3701fb07123SMatthias Ringwald #if defined(HAVE_POSIX_FILE_IO) || defined (ENABLE_SEGGER_RTT)
3716401061aSMatthias Ringwald     if (dump_file >= 0){
372eb443d3dSMatthias Ringwald         int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
373eb443d3dSMatthias Ringwald         hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
374b8ae70b4SMatthias Ringwald         return;
3756401061aSMatthias Ringwald     }
3766401061aSMatthias Ringwald #endif
3776401061aSMatthias Ringwald 
378ad6274a7SMatthias Ringwald     printf_timestamp();
3791df3b679S[email protected]     printf("LOG -- ");
3801df3b679S[email protected]     vprintf(format, argptr);
3811fd51e45S[email protected]     printf("\n");
38294be1a66SMatthias Ringwald }
38394be1a66SMatthias Ringwald 
38494be1a66SMatthias Ringwald void hci_dump_log(int log_level, const char * format, ...){
38594be1a66SMatthias Ringwald     va_list argptr;
38694be1a66SMatthias Ringwald     va_start(argptr, format);
38794be1a66SMatthias Ringwald     hci_dump_log_va_arg(log_level, format, argptr);
3881df3b679S[email protected]     va_end(argptr);
389a1d7dd1fSmatthias.ringwald }
390a1d7dd1fSmatthias.ringwald 
39120ea11b9S[email protected] #ifdef __AVR__
3928a37b10aSMatthias Ringwald void hci_dump_log_P(int log_level, PGM_P format, ...){
3938a37b10aSMatthias Ringwald     if (!hci_dump_log_level_active(log_level)) return;
39420ea11b9S[email protected]     va_list argptr;
39520ea11b9S[email protected]     va_start(argptr, format);
39620ea11b9S[email protected]     printf_P(PSTR("LOG -- "));
39720ea11b9S[email protected]     vfprintf_P(stdout, format, argptr);
39820ea11b9S[email protected]     printf_P(PSTR("\n"));
39920ea11b9S[email protected]     va_end(argptr);
40020ea11b9S[email protected] }
40120ea11b9S[email protected] #endif
40220ea11b9S[email protected] 
40371de195eSMatthias Ringwald void hci_dump_close(void){
404eb443d3dSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
40579662672Smatthias.ringwald     close(dump_file);
40668e27c0fSmatthias.ringwald #endif
407eb443d3dSMatthias Ringwald     dump_file = -1;
40879662672Smatthias.ringwald }
40979662672Smatthias.ringwald 
4108a37b10aSMatthias Ringwald void hci_dump_enable_log_level(int log_level, int enable){
411fa087deaSMatthias Ringwald     if (log_level < HCI_DUMP_LOG_LEVEL_DEBUG) return;
412fa087deaSMatthias Ringwald     if (log_level > HCI_DUMP_LOG_LEVEL_ERROR) return;
4138a37b10aSMatthias Ringwald     log_level_enabled[log_level] = enable;
4148a37b10aSMatthias Ringwald }
4158a37b10aSMatthias Ringwald 
416