xref: /btstack/src/hci_dump.c (revision 8b658ebcf868c8176b3f7e17042b1385b71e098d)
179662672Smatthias.ringwald /*
279662672Smatthias.ringwald  *  hci_dump.c
379662672Smatthias.ringwald  *
479662672Smatthias.ringwald  *  Dump HCI trace in BlueZ's hcidump format
579662672Smatthias.ringwald  *
679662672Smatthias.ringwald  *  Created by Matthias Ringwald on 5/26/09.
779662672Smatthias.ringwald  */
879662672Smatthias.ringwald 
979662672Smatthias.ringwald #include "hci_dump.h"
1079662672Smatthias.ringwald #include "hci.h"
1179662672Smatthias.ringwald #include "hci_transport_h4.h"
1279662672Smatthias.ringwald 
1379662672Smatthias.ringwald #include <fcntl.h>        // open
1479662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
1579662672Smatthias.ringwald #include <strings.h>      // bzero
1679662672Smatthias.ringwald #include <unistd.h>       // write
1779662672Smatthias.ringwald #include <stdio.h>
18*8b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
1979662672Smatthias.ringwald 
20*8b658ebcSmatthias.ringwald // BLUEZ hcidump
21*8b658ebcSmatthias.ringwald typedef struct {
22*8b658ebcSmatthias.ringwald 	uint16_t	len;
23*8b658ebcSmatthias.ringwald 	uint8_t		in;
24*8b658ebcSmatthias.ringwald 	uint8_t		pad;
25*8b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
26*8b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
27*8b658ebcSmatthias.ringwald     uint8_t     packet_type;
28*8b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
2979662672Smatthias.ringwald 
30*8b658ebcSmatthias.ringwald // APPLE PacketLogger
31*8b658ebcSmatthias.ringwald typedef struct {
32*8b658ebcSmatthias.ringwald 	uint32_t	len;
33*8b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
34*8b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
35*8b658ebcSmatthias.ringwald 	uint8_t		type;
36*8b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
37*8b658ebcSmatthias.ringwald 
38*8b658ebcSmatthias.ringwald static int dump_file = -1;
39*8b658ebcSmatthias.ringwald static int dump_format;
40*8b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
41*8b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
42*8b658ebcSmatthias.ringwald 
43*8b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
4479662672Smatthias.ringwald     dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
45*8b658ebcSmatthias.ringwald     dump_format = format;
4679662672Smatthias.ringwald }
4779662672Smatthias.ringwald 
4879662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
49*8b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
50*8b658ebcSmatthias.ringwald 
51*8b658ebcSmatthias.ringwald     // get time
52*8b658ebcSmatthias.ringwald     struct timeval curr_time;
53*8b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
54*8b658ebcSmatthias.ringwald 
55*8b658ebcSmatthias.ringwald     switch (dump_format){
56*8b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
57*8b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
58*8b658ebcSmatthias.ringwald             header_bluez.in  = in;
59*8b658ebcSmatthias.ringwald             header_bluez.pad = 0;
60*8b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
61*8b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
62*8b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
63*8b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
6479662672Smatthias.ringwald             write (dump_file, packet, len );
65*8b658ebcSmatthias.ringwald             break;
66*8b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
67*8b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
68*8b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
69*8b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
70*8b658ebcSmatthias.ringwald             switch (packet_type){
71*8b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
72*8b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
73*8b658ebcSmatthias.ringwald                     break;
74*8b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
75*8b658ebcSmatthias.ringwald                     if (in) {
76*8b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
77*8b658ebcSmatthias.ringwald                     } else {
78*8b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
79*8b658ebcSmatthias.ringwald                     }
80*8b658ebcSmatthias.ringwald                     break;
81*8b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
82*8b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
83*8b658ebcSmatthias.ringwald                     break;
84*8b658ebcSmatthias.ringwald                 default:
85*8b658ebcSmatthias.ringwald                     return;
86*8b658ebcSmatthias.ringwald             }
87*8b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
88*8b658ebcSmatthias.ringwald             write (dump_file, packet, len );
89*8b658ebcSmatthias.ringwald     }
9079662672Smatthias.ringwald }
9179662672Smatthias.ringwald 
9279662672Smatthias.ringwald void hci_dump_close(){
9379662672Smatthias.ringwald     close(dump_file);
9479662672Smatthias.ringwald }
9579662672Smatthias.ringwald 
96