xref: /btstack/src/hci_dump.c (revision 8adf0dda452dfdcc90e999c1581cd0f7e35e07d6)
1 /*
2  *  hci_dump.c
3  *
4  *  Dump HCI trace in BlueZ's hcidump format
5  *
6  *  Created by Matthias Ringwald on 5/26/09.
7  */
8 
9 #include "hci_dump.h"
10 #include "hci.h"
11 #include "hci_transport_h4.h"
12 
13 #include <fcntl.h>        // open
14 #include <arpa/inet.h>    // hton..
15 #include <strings.h>      // bzero
16 #include <unistd.h>       // write
17 #include <stdio.h>
18 #include <time.h>
19 #include <sys/time.h>     // for timestamps
20 #include <sys/stat.h>     // for mode flags
21 
22 // BLUEZ hcidump
23 typedef struct {
24 	uint16_t	len;
25 	uint8_t		in;
26 	uint8_t		pad;
27 	uint32_t	ts_sec;
28 	uint32_t	ts_usec;
29     uint8_t     packet_type;
30 } __attribute__ ((packed)) hcidump_hdr;
31 
32 // APPLE PacketLogger
33 typedef struct {
34 	uint32_t	len;
35 	uint32_t	ts_sec;
36 	uint32_t	ts_usec;
37 	uint8_t		type;
38 } __attribute__ ((packed)) pktlog_hdr;
39 
40 static int dump_file = -1;
41 static int dump_format;
42 static hcidump_hdr header_bluez;
43 static pktlog_hdr  header_packetlogger;
44 static char time_string[40];
45 
46 void hci_dump_open(char *filename, hci_dump_format_t format){
47     dump_format = format;
48     if (dump_format == HCI_DUMP_STDOUT) {
49         dump_file = fileno(stdout);
50     } else {
51         dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
52     }
53 }
54 
55 
56 void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
57     if (dump_file < 0) return; // not activated yet
58 
59     // get time
60     struct timeval curr_time;
61     struct tm* ptm;
62     gettimeofday(&curr_time, NULL);
63 
64     switch (dump_format){
65         case HCI_DUMP_STDOUT:
66             /* Obtain the time of day, and convert it to a tm struct. */
67             ptm = localtime (&curr_time.tv_sec);
68             /* Format the date and time, down to a single second. */
69             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
70             /* Compute milliseconds from microseconds. */
71             uint16_t milliseconds = curr_time.tv_usec / 1000;
72             /* Print the formatted time, in seconds, followed by a decimal point
73              and the milliseconds. */
74             printf ("%s.%03u] ", time_string, milliseconds);
75             switch (packet_type){
76                 case HCI_COMMAND_DATA_PACKET:
77                     printf("CMD => ");
78                     break;
79                 case HCI_EVENT_PACKET:
80                     printf("EVT <= ");
81                     break;
82                 case HCI_ACL_DATA_PACKET:
83                     if (in) {
84                         printf("ACL <= ");
85                     } else {
86                         printf("ACL => ");
87                     }
88                     break;
89             }
90             hexdump(packet, len);
91             break;
92         case HCI_DUMP_BLUEZ:
93             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
94             header_bluez.in  = in;
95             header_bluez.pad = 0;
96             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
97             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
98             header_bluez.packet_type = packet_type;
99             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
100             write (dump_file, packet, len );
101             break;
102         case HCI_DUMP_PACKETLOGGER:
103             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
104             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
105             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
106             switch (packet_type){
107                 case HCI_COMMAND_DATA_PACKET:
108                     header_packetlogger.type = 0x00;
109                     break;
110                 case HCI_ACL_DATA_PACKET:
111                     if (in) {
112                         header_packetlogger.type = 0x03;
113                     } else {
114                         header_packetlogger.type = 0x02;
115                     }
116                     break;
117                 case HCI_EVENT_PACKET:
118                     header_packetlogger.type = 0x01;
119                     break;
120                 default:
121                     return;
122             }
123             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
124             write (dump_file, packet, len );
125     }
126 }
127 
128 void hci_dump_close(){
129     close(dump_file);
130     dump_file = -1;
131 }
132 
133