xref: /btstack/src/hci_dump.c (revision be9367593573ba34661b802718fb52a119287ba1)
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"
4779662672Smatthias.ringwald 
4868e27c0fSmatthias.ringwald #ifndef EMBEDDED
4979662672Smatthias.ringwald #include <fcntl.h>        // open
5079662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
5179662672Smatthias.ringwald #include <strings.h>      // bzero
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 
59*be936759Smatthias.ringwald // #define HCI_DUMP_FULL_LOG
60*be936759Smatthias.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;
698b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
7079662672Smatthias.ringwald 
718b658ebcSmatthias.ringwald // APPLE PacketLogger
728b658ebcSmatthias.ringwald typedef struct {
738b658ebcSmatthias.ringwald 	uint32_t	len;
748b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
758b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
768b658ebcSmatthias.ringwald 	uint8_t		type;
778b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
788b658ebcSmatthias.ringwald 
7968e27c0fSmatthias.ringwald #ifndef EMBEDDED
808b658ebcSmatthias.ringwald static int dump_file = -1;
818b658ebcSmatthias.ringwald static int dump_format;
828b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
838b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
848adf0ddaSmatthias.ringwald static char time_string[40];
852992c131Smatthias.ringwald static int max_nr_packets = -1;
862992c131Smatthias.ringwald static int nr_packets = 0;
8768e27c0fSmatthias.ringwald #endif
888b658ebcSmatthias.ringwald 
898b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
9068e27c0fSmatthias.ringwald #ifndef EMBEDDED
918b658ebcSmatthias.ringwald     dump_format = format;
928adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
938adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
948adf0ddaSmatthias.ringwald     } else {
958adf0ddaSmatthias.ringwald         dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
9679662672Smatthias.ringwald     }
9768e27c0fSmatthias.ringwald #endif
98d9659922Smatthias.ringwald }
9979662672Smatthias.ringwald 
1002992c131Smatthias.ringwald void hci_dump_set_max_packets(int packets){
1012992c131Smatthias.ringwald     max_nr_packets = packets;
1022992c131Smatthias.ringwald }
1032992c131Smatthias.ringwald 
10479662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
10568e27c0fSmatthias.ringwald #ifndef EMBEDDED
10668e27c0fSmatthias.ringwald 
1078b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
1088b658ebcSmatthias.ringwald 
109*be936759Smatthias.ringwald #ifndef HCI_DUMP_FULL_LOG
1102992c131Smatthias.ringwald     // don't grow bigger than max_nr_packets
1112992c131Smatthias.ringwald     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
1122992c131Smatthias.ringwald         if (nr_packets >= max_nr_packets){
1132992c131Smatthias.ringwald             lseek(dump_file, 0, SEEK_SET);
1142992c131Smatthias.ringwald             ftruncate(dump_file, 0);
1152992c131Smatthias.ringwald             nr_packets = 0;
1162992c131Smatthias.ringwald         }
1172992c131Smatthias.ringwald         nr_packets++;
1182992c131Smatthias.ringwald     }
119*be936759Smatthias.ringwald #endif
1202992c131Smatthias.ringwald 
1218b658ebcSmatthias.ringwald     // get time
1228b658ebcSmatthias.ringwald     struct timeval curr_time;
1238adf0ddaSmatthias.ringwald     struct tm* ptm;
1248b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
1258b658ebcSmatthias.ringwald 
1268b658ebcSmatthias.ringwald     switch (dump_format){
1278adf0ddaSmatthias.ringwald         case HCI_DUMP_STDOUT:
1288adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
1298adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
1308adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
1318adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
1328adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
1338adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
1348adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
1358adf0ddaSmatthias.ringwald              and the milliseconds. */
1368adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
1378adf0ddaSmatthias.ringwald             switch (packet_type){
1388adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1398adf0ddaSmatthias.ringwald                     printf("CMD => ");
1408adf0ddaSmatthias.ringwald                     break;
1418adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
1428adf0ddaSmatthias.ringwald                     printf("EVT <= ");
1438adf0ddaSmatthias.ringwald                     break;
1448adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1458adf0ddaSmatthias.ringwald                     if (in) {
1468adf0ddaSmatthias.ringwald                         printf("ACL <= ");
1478adf0ddaSmatthias.ringwald                     } else {
1488adf0ddaSmatthias.ringwald                         printf("ACL => ");
1498adf0ddaSmatthias.ringwald                     }
1508adf0ddaSmatthias.ringwald                     break;
1518adf0ddaSmatthias.ringwald             }
1528adf0ddaSmatthias.ringwald             hexdump(packet, len);
1538adf0ddaSmatthias.ringwald             break;
1548b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
1558b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
1568b658ebcSmatthias.ringwald             header_bluez.in  = in;
1578b658ebcSmatthias.ringwald             header_bluez.pad = 0;
1588b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1598b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1608b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1618b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
16279662672Smatthias.ringwald             write (dump_file, packet, len );
1638b658ebcSmatthias.ringwald             break;
1648b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1658b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1668b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1678b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1688b658ebcSmatthias.ringwald             switch (packet_type){
1698b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1708b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1718b658ebcSmatthias.ringwald                     break;
1728b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1738b658ebcSmatthias.ringwald                     if (in) {
1748b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1758b658ebcSmatthias.ringwald                     } else {
1768b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1778b658ebcSmatthias.ringwald                     }
1788b658ebcSmatthias.ringwald                     break;
1798b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1808b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1818b658ebcSmatthias.ringwald                     break;
1828b658ebcSmatthias.ringwald                 default:
1838b658ebcSmatthias.ringwald                     return;
1848b658ebcSmatthias.ringwald             }
1858b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1868b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1878b658ebcSmatthias.ringwald     }
18868e27c0fSmatthias.ringwald #endif
18979662672Smatthias.ringwald }
19079662672Smatthias.ringwald 
19179662672Smatthias.ringwald void hci_dump_close(){
19268e27c0fSmatthias.ringwald #ifndef EMBEDDED
19379662672Smatthias.ringwald     close(dump_file);
194d9659922Smatthias.ringwald     dump_file = -1;
19568e27c0fSmatthias.ringwald #endif
19679662672Smatthias.ringwald }
19779662672Smatthias.ringwald 
198