xref: /btstack/src/hci_dump.c (revision 6c5c6faa6031e447c92e61d6c9c182aa9ce7b079)
179662672Smatthias.ringwald /*
21713bceaSmatthias.ringwald  * Copyright (C) 2009 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.
161713bceaSmatthias.ringwald  *
171713bceaSmatthias.ringwald  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
181713bceaSmatthias.ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
191713bceaSmatthias.ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
201713bceaSmatthias.ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
211713bceaSmatthias.ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
221713bceaSmatthias.ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
231713bceaSmatthias.ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
241713bceaSmatthias.ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
251713bceaSmatthias.ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
261713bceaSmatthias.ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
271713bceaSmatthias.ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281713bceaSmatthias.ringwald  * SUCH DAMAGE.
291713bceaSmatthias.ringwald  *
301713bceaSmatthias.ringwald  */
311713bceaSmatthias.ringwald 
321713bceaSmatthias.ringwald /*
3379662672Smatthias.ringwald  *  hci_dump.c
3479662672Smatthias.ringwald  *
35fe1ed1b8Smatthias.ringwald  *  Dump HCI trace in various formats:
36fe1ed1b8Smatthias.ringwald  *
37fe1ed1b8Smatthias.ringwald  *  - BlueZ's hcidump format
38fe1ed1b8Smatthias.ringwald  *  - Apple's PacketLogger
39fe1ed1b8Smatthias.ringwald  *  - stdout hexdump
4079662672Smatthias.ringwald  *
4179662672Smatthias.ringwald  *  Created by Matthias Ringwald on 5/26/09.
4279662672Smatthias.ringwald  */
4379662672Smatthias.ringwald 
4479662672Smatthias.ringwald #include "hci_dump.h"
4579662672Smatthias.ringwald #include "hci.h"
46c6448b67Smatthias.ringwald #include "hci_transport.h"
477c5f7483Smatthias.ringwald #include "../config.h"
4879662672Smatthias.ringwald 
4968e27c0fSmatthias.ringwald #ifndef EMBEDDED
5079662672Smatthias.ringwald #include <fcntl.h>        // open
5179662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
5279662672Smatthias.ringwald #include <unistd.h>       // write
5379662672Smatthias.ringwald #include <stdio.h>
548adf0ddaSmatthias.ringwald #include <time.h>
558b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
56c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
5768e27c0fSmatthias.ringwald #endif
5879662672Smatthias.ringwald 
59be936759Smatthias.ringwald // #define HCI_DUMP_FULL_LOG
60be936759Smatthias.ringwald 
618b658ebcSmatthias.ringwald // BLUEZ hcidump
628b658ebcSmatthias.ringwald typedef struct {
638b658ebcSmatthias.ringwald 	uint16_t	len;
648b658ebcSmatthias.ringwald 	uint8_t		in;
658b658ebcSmatthias.ringwald 	uint8_t		pad;
668b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
678b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
688b658ebcSmatthias.ringwald     uint8_t     packet_type;
69*6c5c6faaSmatthias.ringwald }
70*6c5c6faaSmatthias.ringwald #ifdef __GNUC__
71*6c5c6faaSmatthias.ringwald __attribute__ ((packed))
72*6c5c6faaSmatthias.ringwald #endif
73*6c5c6faaSmatthias.ringwald hcidump_hdr;
7479662672Smatthias.ringwald 
758b658ebcSmatthias.ringwald // APPLE PacketLogger
768b658ebcSmatthias.ringwald typedef struct {
778b658ebcSmatthias.ringwald 	uint32_t	len;
788b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
798b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
808b658ebcSmatthias.ringwald 	uint8_t		type;
81*6c5c6faaSmatthias.ringwald }
82*6c5c6faaSmatthias.ringwald #ifdef __GNUC__
83*6c5c6faaSmatthias.ringwald __attribute__ ((packed))
84*6c5c6faaSmatthias.ringwald #endif
85*6c5c6faaSmatthias.ringwald pktlog_hdr;
868b658ebcSmatthias.ringwald 
8768e27c0fSmatthias.ringwald #ifndef EMBEDDED
888b658ebcSmatthias.ringwald static int dump_file = -1;
898b658ebcSmatthias.ringwald static int dump_format;
908b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
918b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
928adf0ddaSmatthias.ringwald static char time_string[40];
932992c131Smatthias.ringwald static int max_nr_packets = -1;
942992c131Smatthias.ringwald static int nr_packets = 0;
9568e27c0fSmatthias.ringwald #endif
968b658ebcSmatthias.ringwald 
978b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
9868e27c0fSmatthias.ringwald #ifndef EMBEDDED
998b658ebcSmatthias.ringwald     dump_format = format;
1008adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
1018adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
1028adf0ddaSmatthias.ringwald     } else {
1038adf0ddaSmatthias.ringwald         dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
10479662672Smatthias.ringwald     }
10568e27c0fSmatthias.ringwald #endif
106d9659922Smatthias.ringwald }
10779662672Smatthias.ringwald 
1087c5f7483Smatthias.ringwald #ifndef EMBEDDED
1092992c131Smatthias.ringwald void hci_dump_set_max_packets(int packets){
1102992c131Smatthias.ringwald     max_nr_packets = packets;
1112992c131Smatthias.ringwald }
1127c5f7483Smatthias.ringwald #endif
1132992c131Smatthias.ringwald 
11479662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
11568e27c0fSmatthias.ringwald #ifndef EMBEDDED
11668e27c0fSmatthias.ringwald 
1178b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
1188b658ebcSmatthias.ringwald 
119be936759Smatthias.ringwald #ifndef HCI_DUMP_FULL_LOG
1202992c131Smatthias.ringwald     // don't grow bigger than max_nr_packets
1212992c131Smatthias.ringwald     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
1222992c131Smatthias.ringwald         if (nr_packets >= max_nr_packets){
1232992c131Smatthias.ringwald             lseek(dump_file, 0, SEEK_SET);
1242992c131Smatthias.ringwald             ftruncate(dump_file, 0);
1252992c131Smatthias.ringwald             nr_packets = 0;
1262992c131Smatthias.ringwald         }
1272992c131Smatthias.ringwald         nr_packets++;
1282992c131Smatthias.ringwald     }
129be936759Smatthias.ringwald #endif
1302992c131Smatthias.ringwald 
1318b658ebcSmatthias.ringwald     // get time
1328b658ebcSmatthias.ringwald     struct timeval curr_time;
1338adf0ddaSmatthias.ringwald     struct tm* ptm;
1348b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
1358b658ebcSmatthias.ringwald 
1368b658ebcSmatthias.ringwald     switch (dump_format){
1378adf0ddaSmatthias.ringwald         case HCI_DUMP_STDOUT:
1388adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
1398adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
1408adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
1418adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
1428adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
1438adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
1448adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
1458adf0ddaSmatthias.ringwald              and the milliseconds. */
1468adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
1478adf0ddaSmatthias.ringwald             switch (packet_type){
1488adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1498adf0ddaSmatthias.ringwald                     printf("CMD => ");
1508adf0ddaSmatthias.ringwald                     break;
1518adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
1528adf0ddaSmatthias.ringwald                     printf("EVT <= ");
1538adf0ddaSmatthias.ringwald                     break;
1548adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1558adf0ddaSmatthias.ringwald                     if (in) {
1568adf0ddaSmatthias.ringwald                         printf("ACL <= ");
1578adf0ddaSmatthias.ringwald                     } else {
1588adf0ddaSmatthias.ringwald                         printf("ACL => ");
1598adf0ddaSmatthias.ringwald                     }
1608adf0ddaSmatthias.ringwald                     break;
1618adf0ddaSmatthias.ringwald             }
1628adf0ddaSmatthias.ringwald             hexdump(packet, len);
1638adf0ddaSmatthias.ringwald             break;
1648b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
1658b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
1668b658ebcSmatthias.ringwald             header_bluez.in  = in;
1678b658ebcSmatthias.ringwald             header_bluez.pad = 0;
1688b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1698b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1708b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1718b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
17279662672Smatthias.ringwald             write (dump_file, packet, len );
1738b658ebcSmatthias.ringwald             break;
1748b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1758b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1768b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1778b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1788b658ebcSmatthias.ringwald             switch (packet_type){
1798b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1808b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1818b658ebcSmatthias.ringwald                     break;
1828b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1838b658ebcSmatthias.ringwald                     if (in) {
1848b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1858b658ebcSmatthias.ringwald                     } else {
1868b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1878b658ebcSmatthias.ringwald                     }
1888b658ebcSmatthias.ringwald                     break;
1898b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1908b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1918b658ebcSmatthias.ringwald                     break;
1928b658ebcSmatthias.ringwald                 default:
1938b658ebcSmatthias.ringwald                     return;
1948b658ebcSmatthias.ringwald             }
1958b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1968b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1978b658ebcSmatthias.ringwald     }
19868e27c0fSmatthias.ringwald #endif
19979662672Smatthias.ringwald }
20079662672Smatthias.ringwald 
20179662672Smatthias.ringwald void hci_dump_close(){
20268e27c0fSmatthias.ringwald #ifndef EMBEDDED
20379662672Smatthias.ringwald     close(dump_file);
204d9659922Smatthias.ringwald     dump_file = -1;
20568e27c0fSmatthias.ringwald #endif
20679662672Smatthias.ringwald }
20779662672Smatthias.ringwald 
208