xref: /btstack/src/hci_dump.c (revision 1713bcea3a49b492b9437ccc3270646a8b9d602e)
179662672Smatthias.ringwald /*
2*1713bceaSmatthias.ringwald  * Copyright (C) 2009 by Matthias Ringwald
3*1713bceaSmatthias.ringwald  *
4*1713bceaSmatthias.ringwald  * Redistribution and use in source and binary forms, with or without
5*1713bceaSmatthias.ringwald  * modification, are permitted provided that the following conditions
6*1713bceaSmatthias.ringwald  * are met:
7*1713bceaSmatthias.ringwald  *
8*1713bceaSmatthias.ringwald  * 1. Redistributions of source code must retain the above copyright
9*1713bceaSmatthias.ringwald  *    notice, this list of conditions and the following disclaimer.
10*1713bceaSmatthias.ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*1713bceaSmatthias.ringwald  *    notice, this list of conditions and the following disclaimer in the
12*1713bceaSmatthias.ringwald  *    documentation and/or other materials provided with the distribution.
13*1713bceaSmatthias.ringwald  * 3. Neither the name of the copyright holders nor the names of
14*1713bceaSmatthias.ringwald  *    contributors may be used to endorse or promote products derived
15*1713bceaSmatthias.ringwald  *    from this software without specific prior written permission.
16*1713bceaSmatthias.ringwald  *
17*1713bceaSmatthias.ringwald  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
18*1713bceaSmatthias.ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*1713bceaSmatthias.ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20*1713bceaSmatthias.ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
21*1713bceaSmatthias.ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22*1713bceaSmatthias.ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23*1713bceaSmatthias.ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24*1713bceaSmatthias.ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25*1713bceaSmatthias.ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26*1713bceaSmatthias.ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27*1713bceaSmatthias.ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*1713bceaSmatthias.ringwald  * SUCH DAMAGE.
29*1713bceaSmatthias.ringwald  *
30*1713bceaSmatthias.ringwald  */
31*1713bceaSmatthias.ringwald 
32*1713bceaSmatthias.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"
4679662672Smatthias.ringwald #include "hci_transport_h4.h"
4779662672Smatthias.ringwald 
4879662672Smatthias.ringwald #include <fcntl.h>        // open
4979662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
5079662672Smatthias.ringwald #include <strings.h>      // bzero
5179662672Smatthias.ringwald #include <unistd.h>       // write
5279662672Smatthias.ringwald #include <stdio.h>
538adf0ddaSmatthias.ringwald #include <time.h>
548b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
55c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
5679662672Smatthias.ringwald 
578b658ebcSmatthias.ringwald // BLUEZ hcidump
588b658ebcSmatthias.ringwald typedef struct {
598b658ebcSmatthias.ringwald 	uint16_t	len;
608b658ebcSmatthias.ringwald 	uint8_t		in;
618b658ebcSmatthias.ringwald 	uint8_t		pad;
628b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
638b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
648b658ebcSmatthias.ringwald     uint8_t     packet_type;
658b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
6679662672Smatthias.ringwald 
678b658ebcSmatthias.ringwald // APPLE PacketLogger
688b658ebcSmatthias.ringwald typedef struct {
698b658ebcSmatthias.ringwald 	uint32_t	len;
708b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
718b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
728b658ebcSmatthias.ringwald 	uint8_t		type;
738b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
748b658ebcSmatthias.ringwald 
758b658ebcSmatthias.ringwald static int dump_file = -1;
768b658ebcSmatthias.ringwald static int dump_format;
778b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
788b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
798adf0ddaSmatthias.ringwald static char time_string[40];
808b658ebcSmatthias.ringwald 
818b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
828b658ebcSmatthias.ringwald     dump_format = format;
838adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
848adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
858adf0ddaSmatthias.ringwald     } else {
868adf0ddaSmatthias.ringwald         dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
8779662672Smatthias.ringwald     }
88d9659922Smatthias.ringwald }
8979662672Smatthias.ringwald 
9079662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
918b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
928b658ebcSmatthias.ringwald 
938b658ebcSmatthias.ringwald     // get time
948b658ebcSmatthias.ringwald     struct timeval curr_time;
958adf0ddaSmatthias.ringwald     struct tm* ptm;
968b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
978b658ebcSmatthias.ringwald 
988b658ebcSmatthias.ringwald     switch (dump_format){
998adf0ddaSmatthias.ringwald         case HCI_DUMP_STDOUT:
1008adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
1018adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
1028adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
1038adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
1048adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
1058adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
1068adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
1078adf0ddaSmatthias.ringwald              and the milliseconds. */
1088adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
1098adf0ddaSmatthias.ringwald             switch (packet_type){
1108adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1118adf0ddaSmatthias.ringwald                     printf("CMD => ");
1128adf0ddaSmatthias.ringwald                     break;
1138adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
1148adf0ddaSmatthias.ringwald                     printf("EVT <= ");
1158adf0ddaSmatthias.ringwald                     break;
1168adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1178adf0ddaSmatthias.ringwald                     if (in) {
1188adf0ddaSmatthias.ringwald                         printf("ACL <= ");
1198adf0ddaSmatthias.ringwald                     } else {
1208adf0ddaSmatthias.ringwald                         printf("ACL => ");
1218adf0ddaSmatthias.ringwald                     }
1228adf0ddaSmatthias.ringwald                     break;
1238adf0ddaSmatthias.ringwald             }
1248adf0ddaSmatthias.ringwald             hexdump(packet, len);
1258adf0ddaSmatthias.ringwald             break;
1268b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
1278b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
1288b658ebcSmatthias.ringwald             header_bluez.in  = in;
1298b658ebcSmatthias.ringwald             header_bluez.pad = 0;
1308b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1318b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1328b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1338b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
13479662672Smatthias.ringwald             write (dump_file, packet, len );
1358b658ebcSmatthias.ringwald             break;
1368b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1378b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1388b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1398b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1408b658ebcSmatthias.ringwald             switch (packet_type){
1418b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1428b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1438b658ebcSmatthias.ringwald                     break;
1448b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1458b658ebcSmatthias.ringwald                     if (in) {
1468b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1478b658ebcSmatthias.ringwald                     } else {
1488b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1498b658ebcSmatthias.ringwald                     }
1508b658ebcSmatthias.ringwald                     break;
1518b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1528b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1538b658ebcSmatthias.ringwald                     break;
1548b658ebcSmatthias.ringwald                 default:
1558b658ebcSmatthias.ringwald                     return;
1568b658ebcSmatthias.ringwald             }
1578b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1588b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1598b658ebcSmatthias.ringwald     }
16079662672Smatthias.ringwald }
16179662672Smatthias.ringwald 
16279662672Smatthias.ringwald void hci_dump_close(){
16379662672Smatthias.ringwald     close(dump_file);
164d9659922Smatthias.ringwald     dump_file = -1;
16579662672Smatthias.ringwald }
16679662672Smatthias.ringwald 
167