xref: /btstack/src/hci_dump.c (revision 6b64433e6a17b046d431031fa3995f31c29aa188)
179662672Smatthias.ringwald /*
2*6b64433eSmatthias.ringwald  * Copyright (C) 2009-2012 by Matthias Ringwald
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.
16*6b64433eSmatthias.ringwald  * 4. Any redistribution, use, or modification is done solely for
17*6b64433eSmatthias.ringwald  *    personal benefit and not for any commercial purpose or for
18*6b64433eSmatthias.ringwald  *    monetary gain.
191713bceaSmatthias.ringwald  *
201713bceaSmatthias.ringwald  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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  *
33*6b64433eSmatthias.ringwald  * Please inquire about commercial licensing options at [email protected]
34*6b64433eSmatthias.ringwald  *
351713bceaSmatthias.ringwald  */
361713bceaSmatthias.ringwald 
371713bceaSmatthias.ringwald /*
3879662672Smatthias.ringwald  *  hci_dump.c
3979662672Smatthias.ringwald  *
40fe1ed1b8Smatthias.ringwald  *  Dump HCI trace in various formats:
41fe1ed1b8Smatthias.ringwald  *
42fe1ed1b8Smatthias.ringwald  *  - BlueZ's hcidump format
43fe1ed1b8Smatthias.ringwald  *  - Apple's PacketLogger
44fe1ed1b8Smatthias.ringwald  *  - stdout hexdump
4579662672Smatthias.ringwald  *
4679662672Smatthias.ringwald  *  Created by Matthias Ringwald on 5/26/09.
4779662672Smatthias.ringwald  */
4879662672Smatthias.ringwald 
49a1d7dd1fSmatthias.ringwald #include "config.h"
50a1d7dd1fSmatthias.ringwald 
5179662672Smatthias.ringwald #include "hci_dump.h"
5279662672Smatthias.ringwald #include "hci.h"
53c6448b67Smatthias.ringwald #include "hci_transport.h"
54a1d7dd1fSmatthias.ringwald #include <btstack/hci_cmds.h>
5579662672Smatthias.ringwald 
5668e27c0fSmatthias.ringwald #ifndef EMBEDDED
5779662672Smatthias.ringwald #include <fcntl.h>        // open
5879662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
5979662672Smatthias.ringwald #include <unistd.h>       // write
6079662672Smatthias.ringwald #include <stdio.h>
618adf0ddaSmatthias.ringwald #include <time.h>
628b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
63c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
64a1d7dd1fSmatthias.ringwald #include <stdarg.h>       // for va_list
6568e27c0fSmatthias.ringwald #endif
6679662672Smatthias.ringwald 
678b658ebcSmatthias.ringwald // BLUEZ hcidump
688b658ebcSmatthias.ringwald typedef struct {
698b658ebcSmatthias.ringwald 	uint16_t	len;
708b658ebcSmatthias.ringwald 	uint8_t		in;
718b658ebcSmatthias.ringwald 	uint8_t		pad;
728b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
738b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
748b658ebcSmatthias.ringwald     uint8_t     packet_type;
756c5c6faaSmatthias.ringwald }
766c5c6faaSmatthias.ringwald #ifdef __GNUC__
776c5c6faaSmatthias.ringwald __attribute__ ((packed))
786c5c6faaSmatthias.ringwald #endif
796c5c6faaSmatthias.ringwald hcidump_hdr;
8079662672Smatthias.ringwald 
818b658ebcSmatthias.ringwald // APPLE PacketLogger
828b658ebcSmatthias.ringwald typedef struct {
838b658ebcSmatthias.ringwald 	uint32_t	len;
848b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
858b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
862df12229Smatthias.ringwald 	uint8_t		type;   // 0xfc for note
876c5c6faaSmatthias.ringwald }
886c5c6faaSmatthias.ringwald #ifdef __GNUC__
896c5c6faaSmatthias.ringwald __attribute__ ((packed))
906c5c6faaSmatthias.ringwald #endif
916c5c6faaSmatthias.ringwald pktlog_hdr;
928b658ebcSmatthias.ringwald 
9368e27c0fSmatthias.ringwald #ifndef EMBEDDED
948b658ebcSmatthias.ringwald static int dump_file = -1;
958b658ebcSmatthias.ringwald static int dump_format;
968b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
978b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
988adf0ddaSmatthias.ringwald static char time_string[40];
992992c131Smatthias.ringwald static int  max_nr_packets = -1;
1009ae0c346Smatthias.ringwald static int  nr_packets = 0;
101a1d7dd1fSmatthias.ringwald static char log_message_buffer[256];
10268e27c0fSmatthias.ringwald #endif
1038b658ebcSmatthias.ringwald 
1048b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
10568e27c0fSmatthias.ringwald #ifndef EMBEDDED
1068b658ebcSmatthias.ringwald     dump_format = format;
1078adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
1088adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
1098adf0ddaSmatthias.ringwald     } else {
1108adf0ddaSmatthias.ringwald         dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
11179662672Smatthias.ringwald     }
11268e27c0fSmatthias.ringwald #endif
113d9659922Smatthias.ringwald }
11479662672Smatthias.ringwald 
1157c5f7483Smatthias.ringwald #ifndef EMBEDDED
1162992c131Smatthias.ringwald void hci_dump_set_max_packets(int packets){
1172992c131Smatthias.ringwald     max_nr_packets = packets;
1182992c131Smatthias.ringwald }
1197c5f7483Smatthias.ringwald #endif
1202992c131Smatthias.ringwald 
12179662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
12268e27c0fSmatthias.ringwald #ifndef EMBEDDED
12368e27c0fSmatthias.ringwald 
1248b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
1258b658ebcSmatthias.ringwald 
1262992c131Smatthias.ringwald     // don't grow bigger than max_nr_packets
1272992c131Smatthias.ringwald     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
1282992c131Smatthias.ringwald         if (nr_packets >= max_nr_packets){
1292992c131Smatthias.ringwald             lseek(dump_file, 0, SEEK_SET);
1302992c131Smatthias.ringwald             ftruncate(dump_file, 0);
1312992c131Smatthias.ringwald             nr_packets = 0;
1322992c131Smatthias.ringwald         }
1332992c131Smatthias.ringwald         nr_packets++;
1342992c131Smatthias.ringwald     }
1352992c131Smatthias.ringwald 
1368b658ebcSmatthias.ringwald     // get time
1378b658ebcSmatthias.ringwald     struct timeval curr_time;
1388adf0ddaSmatthias.ringwald     struct tm* ptm;
1398b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
1408b658ebcSmatthias.ringwald 
1418b658ebcSmatthias.ringwald     switch (dump_format){
142a9cf4d77S[email protected]         case HCI_DUMP_STDOUT: {
1438adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
1448adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
1458adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
1468adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
1478adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
1488adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
1498adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
1508adf0ddaSmatthias.ringwald              and the milliseconds. */
1518adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
1528adf0ddaSmatthias.ringwald             switch (packet_type){
1538adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1548adf0ddaSmatthias.ringwald                     printf("CMD => ");
1558adf0ddaSmatthias.ringwald                     break;
1568adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
1578adf0ddaSmatthias.ringwald                     printf("EVT <= ");
1588adf0ddaSmatthias.ringwald                     break;
1598adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1608adf0ddaSmatthias.ringwald                     if (in) {
1618adf0ddaSmatthias.ringwald                         printf("ACL <= ");
1628adf0ddaSmatthias.ringwald                     } else {
1638adf0ddaSmatthias.ringwald                         printf("ACL => ");
1648adf0ddaSmatthias.ringwald                     }
1658adf0ddaSmatthias.ringwald                     break;
1660d79c710Smatthias.ringwald                 case LOG_MESSAGE_PACKET:
1670d79c710Smatthias.ringwald                     // assume buffer is big enough
1680d79c710Smatthias.ringwald                     packet[len] = 0;
1690d79c710Smatthias.ringwald                     printf("LOG -- %s\n", (char*) packet);
1700d79c710Smatthias.ringwald                     return;
1710d79c710Smatthias.ringwald                 default:
1720d79c710Smatthias.ringwald                     return;
1738adf0ddaSmatthias.ringwald             }
1748adf0ddaSmatthias.ringwald             hexdump(packet, len);
1758adf0ddaSmatthias.ringwald             break;
176a9cf4d77S[email protected]         }
1770d79c710Smatthias.ringwald 
1788b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
1798b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
1808b658ebcSmatthias.ringwald             header_bluez.in  = in;
1818b658ebcSmatthias.ringwald             header_bluez.pad = 0;
1828b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1838b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1848b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1858b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
18679662672Smatthias.ringwald             write (dump_file, packet, len );
1878b658ebcSmatthias.ringwald             break;
1880d79c710Smatthias.ringwald 
1898b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1908b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1918b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1928b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1938b658ebcSmatthias.ringwald             switch (packet_type){
1948b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1958b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1968b658ebcSmatthias.ringwald                     break;
1978b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1988b658ebcSmatthias.ringwald                     if (in) {
1998b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
2008b658ebcSmatthias.ringwald                     } else {
2018b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
2028b658ebcSmatthias.ringwald                     }
2038b658ebcSmatthias.ringwald                     break;
2048b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
2058b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
2068b658ebcSmatthias.ringwald                     break;
2070d79c710Smatthias.ringwald                 case LOG_MESSAGE_PACKET:
2080d79c710Smatthias.ringwald                     header_packetlogger.type = 0xfc;
2090d79c710Smatthias.ringwald                     break;
2108b658ebcSmatthias.ringwald                 default:
2118b658ebcSmatthias.ringwald                     return;
2128b658ebcSmatthias.ringwald             }
2138b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
2148b658ebcSmatthias.ringwald             write (dump_file, packet, len );
2150d79c710Smatthias.ringwald             break;
2160d79c710Smatthias.ringwald 
2170d79c710Smatthias.ringwald         default:
2180d79c710Smatthias.ringwald             break;
2198b658ebcSmatthias.ringwald     }
22068e27c0fSmatthias.ringwald #endif
22179662672Smatthias.ringwald }
22279662672Smatthias.ringwald 
223a1d7dd1fSmatthias.ringwald void hci_dump_log(const char * format, ...){
224a1d7dd1fSmatthias.ringwald #ifndef EMBEDDED
225a1d7dd1fSmatthias.ringwald     va_list argptr;
226a1d7dd1fSmatthias.ringwald     va_start(argptr, format);
227a1d7dd1fSmatthias.ringwald     int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
228a1d7dd1fSmatthias.ringwald     hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
229a1d7dd1fSmatthias.ringwald     va_end(argptr);
230a1d7dd1fSmatthias.ringwald #endif
231a1d7dd1fSmatthias.ringwald }
232a1d7dd1fSmatthias.ringwald 
23379662672Smatthias.ringwald void hci_dump_close(){
23468e27c0fSmatthias.ringwald #ifndef EMBEDDED
23579662672Smatthias.ringwald     close(dump_file);
236d9659922Smatthias.ringwald     dump_file = -1;
23768e27c0fSmatthias.ringwald #endif
23879662672Smatthias.ringwald }
23979662672Smatthias.ringwald 
240