xref: /btstack/src/hci_dump.c (revision 8adf0dda452dfdcc90e999c1581cd0f7e35e07d6)
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*8adf0ddaSmatthias.ringwald #include <time.h>
198b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
20c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
2179662672Smatthias.ringwald 
228b658ebcSmatthias.ringwald // BLUEZ hcidump
238b658ebcSmatthias.ringwald typedef struct {
248b658ebcSmatthias.ringwald 	uint16_t	len;
258b658ebcSmatthias.ringwald 	uint8_t		in;
268b658ebcSmatthias.ringwald 	uint8_t		pad;
278b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
288b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
298b658ebcSmatthias.ringwald     uint8_t     packet_type;
308b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
3179662672Smatthias.ringwald 
328b658ebcSmatthias.ringwald // APPLE PacketLogger
338b658ebcSmatthias.ringwald typedef struct {
348b658ebcSmatthias.ringwald 	uint32_t	len;
358b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
368b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
378b658ebcSmatthias.ringwald 	uint8_t		type;
388b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
398b658ebcSmatthias.ringwald 
408b658ebcSmatthias.ringwald static int dump_file = -1;
418b658ebcSmatthias.ringwald static int dump_format;
428b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
438b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
44*8adf0ddaSmatthias.ringwald static char time_string[40];
458b658ebcSmatthias.ringwald 
468b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
478b658ebcSmatthias.ringwald     dump_format = format;
48*8adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
49*8adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
50*8adf0ddaSmatthias.ringwald     } else {
51*8adf0ddaSmatthias.ringwald         dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
5279662672Smatthias.ringwald     }
53d9659922Smatthias.ringwald }
5479662672Smatthias.ringwald 
55*8adf0ddaSmatthias.ringwald 
5679662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
578b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
588b658ebcSmatthias.ringwald 
598b658ebcSmatthias.ringwald     // get time
608b658ebcSmatthias.ringwald     struct timeval curr_time;
61*8adf0ddaSmatthias.ringwald     struct tm* ptm;
628b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
638b658ebcSmatthias.ringwald 
648b658ebcSmatthias.ringwald     switch (dump_format){
65*8adf0ddaSmatthias.ringwald         case HCI_DUMP_STDOUT:
66*8adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
67*8adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
68*8adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
69*8adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
70*8adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
71*8adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
72*8adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
73*8adf0ddaSmatthias.ringwald              and the milliseconds. */
74*8adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
75*8adf0ddaSmatthias.ringwald             switch (packet_type){
76*8adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
77*8adf0ddaSmatthias.ringwald                     printf("CMD => ");
78*8adf0ddaSmatthias.ringwald                     break;
79*8adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
80*8adf0ddaSmatthias.ringwald                     printf("EVT <= ");
81*8adf0ddaSmatthias.ringwald                     break;
82*8adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
83*8adf0ddaSmatthias.ringwald                     if (in) {
84*8adf0ddaSmatthias.ringwald                         printf("ACL <= ");
85*8adf0ddaSmatthias.ringwald                     } else {
86*8adf0ddaSmatthias.ringwald                         printf("ACL => ");
87*8adf0ddaSmatthias.ringwald                     }
88*8adf0ddaSmatthias.ringwald                     break;
89*8adf0ddaSmatthias.ringwald             }
90*8adf0ddaSmatthias.ringwald             hexdump(packet, len);
91*8adf0ddaSmatthias.ringwald             break;
928b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
938b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
948b658ebcSmatthias.ringwald             header_bluez.in  = in;
958b658ebcSmatthias.ringwald             header_bluez.pad = 0;
968b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
978b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
988b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
998b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
10079662672Smatthias.ringwald             write (dump_file, packet, len );
1018b658ebcSmatthias.ringwald             break;
1028b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1038b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1048b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1058b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1068b658ebcSmatthias.ringwald             switch (packet_type){
1078b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1088b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1098b658ebcSmatthias.ringwald                     break;
1108b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1118b658ebcSmatthias.ringwald                     if (in) {
1128b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1138b658ebcSmatthias.ringwald                     } else {
1148b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1158b658ebcSmatthias.ringwald                     }
1168b658ebcSmatthias.ringwald                     break;
1178b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1188b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1198b658ebcSmatthias.ringwald                     break;
1208b658ebcSmatthias.ringwald                 default:
1218b658ebcSmatthias.ringwald                     return;
1228b658ebcSmatthias.ringwald             }
1238b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1248b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1258b658ebcSmatthias.ringwald     }
12679662672Smatthias.ringwald }
12779662672Smatthias.ringwald 
12879662672Smatthias.ringwald void hci_dump_close(){
12979662672Smatthias.ringwald     close(dump_file);
130d9659922Smatthias.ringwald     dump_file = -1;
13179662672Smatthias.ringwald }
13279662672Smatthias.ringwald 
133