xref: /btstack/src/hci_dump.c (revision 9ae0c3466aa21c59bc3539810a8bb9e57c0e300d)
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"
47c8901d41Smatthias.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 
598b658ebcSmatthias.ringwald // BLUEZ hcidump
608b658ebcSmatthias.ringwald typedef struct {
618b658ebcSmatthias.ringwald 	uint16_t	len;
628b658ebcSmatthias.ringwald 	uint8_t		in;
638b658ebcSmatthias.ringwald 	uint8_t		pad;
648b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
658b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
668b658ebcSmatthias.ringwald     uint8_t     packet_type;
676c5c6faaSmatthias.ringwald }
686c5c6faaSmatthias.ringwald #ifdef __GNUC__
696c5c6faaSmatthias.ringwald __attribute__ ((packed))
706c5c6faaSmatthias.ringwald #endif
716c5c6faaSmatthias.ringwald hcidump_hdr;
7279662672Smatthias.ringwald 
738b658ebcSmatthias.ringwald // APPLE PacketLogger
748b658ebcSmatthias.ringwald typedef struct {
758b658ebcSmatthias.ringwald 	uint32_t	len;
768b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
778b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
788b658ebcSmatthias.ringwald 	uint8_t		type;
796c5c6faaSmatthias.ringwald }
806c5c6faaSmatthias.ringwald #ifdef __GNUC__
816c5c6faaSmatthias.ringwald __attribute__ ((packed))
826c5c6faaSmatthias.ringwald #endif
836c5c6faaSmatthias.ringwald pktlog_hdr;
848b658ebcSmatthias.ringwald 
8568e27c0fSmatthias.ringwald #ifndef EMBEDDED
868b658ebcSmatthias.ringwald static int dump_file = -1;
878b658ebcSmatthias.ringwald static int dump_format;
888b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
898b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
908adf0ddaSmatthias.ringwald static char time_string[40];
912992c131Smatthias.ringwald static int max_nr_packets = -1;
92*9ae0c346Smatthias.ringwald static int nr_packets = 0;
9368e27c0fSmatthias.ringwald #endif
948b658ebcSmatthias.ringwald 
958b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
9668e27c0fSmatthias.ringwald #ifndef EMBEDDED
978b658ebcSmatthias.ringwald     dump_format = format;
988adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
998adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
1008adf0ddaSmatthias.ringwald     } else {
1018adf0ddaSmatthias.ringwald         dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
10279662672Smatthias.ringwald     }
10368e27c0fSmatthias.ringwald #endif
104d9659922Smatthias.ringwald }
10579662672Smatthias.ringwald 
1067c5f7483Smatthias.ringwald #ifndef EMBEDDED
1072992c131Smatthias.ringwald void hci_dump_set_max_packets(int packets){
1082992c131Smatthias.ringwald     max_nr_packets = packets;
1092992c131Smatthias.ringwald }
1107c5f7483Smatthias.ringwald #endif
1112992c131Smatthias.ringwald 
11279662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
11368e27c0fSmatthias.ringwald #ifndef EMBEDDED
11468e27c0fSmatthias.ringwald 
1158b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
1168b658ebcSmatthias.ringwald 
1172992c131Smatthias.ringwald     // don't grow bigger than max_nr_packets
1182992c131Smatthias.ringwald     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
1192992c131Smatthias.ringwald         if (nr_packets >= max_nr_packets){
1202992c131Smatthias.ringwald             lseek(dump_file, 0, SEEK_SET);
1212992c131Smatthias.ringwald             ftruncate(dump_file, 0);
1222992c131Smatthias.ringwald             nr_packets = 0;
1232992c131Smatthias.ringwald         }
1242992c131Smatthias.ringwald         nr_packets++;
1252992c131Smatthias.ringwald     }
1262992c131Smatthias.ringwald 
1278b658ebcSmatthias.ringwald     // get time
1288b658ebcSmatthias.ringwald     struct timeval curr_time;
1298adf0ddaSmatthias.ringwald     struct tm* ptm;
1308b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
1318b658ebcSmatthias.ringwald 
1328b658ebcSmatthias.ringwald     switch (dump_format){
133a9cf4d77S[email protected]         case HCI_DUMP_STDOUT: {
1348adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
1358adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
1368adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
1378adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
1388adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
1398adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
1408adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
1418adf0ddaSmatthias.ringwald              and the milliseconds. */
1428adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
1438adf0ddaSmatthias.ringwald             switch (packet_type){
1448adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1458adf0ddaSmatthias.ringwald                     printf("CMD => ");
1468adf0ddaSmatthias.ringwald                     break;
1478adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
1488adf0ddaSmatthias.ringwald                     printf("EVT <= ");
1498adf0ddaSmatthias.ringwald                     break;
1508adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1518adf0ddaSmatthias.ringwald                     if (in) {
1528adf0ddaSmatthias.ringwald                         printf("ACL <= ");
1538adf0ddaSmatthias.ringwald                     } else {
1548adf0ddaSmatthias.ringwald                         printf("ACL => ");
1558adf0ddaSmatthias.ringwald                     }
1568adf0ddaSmatthias.ringwald                     break;
1578adf0ddaSmatthias.ringwald             }
1588adf0ddaSmatthias.ringwald             hexdump(packet, len);
1598adf0ddaSmatthias.ringwald             break;
160a9cf4d77S[email protected]         }
1618b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
1628b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
1638b658ebcSmatthias.ringwald             header_bluez.in  = in;
1648b658ebcSmatthias.ringwald             header_bluez.pad = 0;
1658b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1668b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1678b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1688b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
16979662672Smatthias.ringwald             write (dump_file, packet, len );
1708b658ebcSmatthias.ringwald             break;
1718b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1728b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1738b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1748b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1758b658ebcSmatthias.ringwald             switch (packet_type){
1768b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1778b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1788b658ebcSmatthias.ringwald                     break;
1798b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1808b658ebcSmatthias.ringwald                     if (in) {
1818b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1828b658ebcSmatthias.ringwald                     } else {
1838b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1848b658ebcSmatthias.ringwald                     }
1858b658ebcSmatthias.ringwald                     break;
1868b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1878b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1888b658ebcSmatthias.ringwald                     break;
1898b658ebcSmatthias.ringwald                 default:
1908b658ebcSmatthias.ringwald                     return;
1918b658ebcSmatthias.ringwald             }
1928b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1938b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1948b658ebcSmatthias.ringwald     }
19568e27c0fSmatthias.ringwald #endif
19679662672Smatthias.ringwald }
19779662672Smatthias.ringwald 
19879662672Smatthias.ringwald void hci_dump_close(){
19968e27c0fSmatthias.ringwald #ifndef EMBEDDED
20079662672Smatthias.ringwald     close(dump_file);
201d9659922Smatthias.ringwald     dump_file = -1;
20268e27c0fSmatthias.ringwald #endif
20379662672Smatthias.ringwald }
20479662672Smatthias.ringwald 
205