xref: /btstack/src/hci_dump.c (revision fe1ed1b8b680d23b4d9fe8dd47c59beebcb72020)
179662672Smatthias.ringwald /*
279662672Smatthias.ringwald  *  hci_dump.c
379662672Smatthias.ringwald  *
4*fe1ed1b8Smatthias.ringwald  *  Dump HCI trace in various formats:
5*fe1ed1b8Smatthias.ringwald  *
6*fe1ed1b8Smatthias.ringwald  *  - BlueZ's hcidump format
7*fe1ed1b8Smatthias.ringwald  *  - Apple's PacketLogger
8*fe1ed1b8Smatthias.ringwald  *  - stdout hexdump
979662672Smatthias.ringwald  *
1079662672Smatthias.ringwald  *  Created by Matthias Ringwald on 5/26/09.
1179662672Smatthias.ringwald  */
1279662672Smatthias.ringwald 
1379662672Smatthias.ringwald #include "hci_dump.h"
1479662672Smatthias.ringwald #include "hci.h"
1579662672Smatthias.ringwald #include "hci_transport_h4.h"
1679662672Smatthias.ringwald 
1779662672Smatthias.ringwald #include <fcntl.h>        // open
1879662672Smatthias.ringwald #include <arpa/inet.h>    // hton..
1979662672Smatthias.ringwald #include <strings.h>      // bzero
2079662672Smatthias.ringwald #include <unistd.h>       // write
2179662672Smatthias.ringwald #include <stdio.h>
228adf0ddaSmatthias.ringwald #include <time.h>
238b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
24c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
2579662672Smatthias.ringwald 
268b658ebcSmatthias.ringwald // BLUEZ hcidump
278b658ebcSmatthias.ringwald typedef struct {
288b658ebcSmatthias.ringwald 	uint16_t	len;
298b658ebcSmatthias.ringwald 	uint8_t		in;
308b658ebcSmatthias.ringwald 	uint8_t		pad;
318b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
328b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
338b658ebcSmatthias.ringwald     uint8_t     packet_type;
348b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
3579662672Smatthias.ringwald 
368b658ebcSmatthias.ringwald // APPLE PacketLogger
378b658ebcSmatthias.ringwald typedef struct {
388b658ebcSmatthias.ringwald 	uint32_t	len;
398b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
408b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
418b658ebcSmatthias.ringwald 	uint8_t		type;
428b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
438b658ebcSmatthias.ringwald 
448b658ebcSmatthias.ringwald static int dump_file = -1;
458b658ebcSmatthias.ringwald static int dump_format;
468b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
478b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
488adf0ddaSmatthias.ringwald static char time_string[40];
498b658ebcSmatthias.ringwald 
508b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
518b658ebcSmatthias.ringwald     dump_format = format;
528adf0ddaSmatthias.ringwald     if (dump_format == HCI_DUMP_STDOUT) {
538adf0ddaSmatthias.ringwald         dump_file = fileno(stdout);
548adf0ddaSmatthias.ringwald     } else {
558adf0ddaSmatthias.ringwald         dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
5679662672Smatthias.ringwald     }
57d9659922Smatthias.ringwald }
5879662672Smatthias.ringwald 
5979662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
608b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
618b658ebcSmatthias.ringwald 
628b658ebcSmatthias.ringwald     // get time
638b658ebcSmatthias.ringwald     struct timeval curr_time;
648adf0ddaSmatthias.ringwald     struct tm* ptm;
658b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
668b658ebcSmatthias.ringwald 
678b658ebcSmatthias.ringwald     switch (dump_format){
688adf0ddaSmatthias.ringwald         case HCI_DUMP_STDOUT:
698adf0ddaSmatthias.ringwald             /* Obtain the time of day, and convert it to a tm struct. */
708adf0ddaSmatthias.ringwald             ptm = localtime (&curr_time.tv_sec);
718adf0ddaSmatthias.ringwald             /* Format the date and time, down to a single second. */
728adf0ddaSmatthias.ringwald             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
738adf0ddaSmatthias.ringwald             /* Compute milliseconds from microseconds. */
748adf0ddaSmatthias.ringwald             uint16_t milliseconds = curr_time.tv_usec / 1000;
758adf0ddaSmatthias.ringwald             /* Print the formatted time, in seconds, followed by a decimal point
768adf0ddaSmatthias.ringwald              and the milliseconds. */
778adf0ddaSmatthias.ringwald             printf ("%s.%03u] ", time_string, milliseconds);
788adf0ddaSmatthias.ringwald             switch (packet_type){
798adf0ddaSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
808adf0ddaSmatthias.ringwald                     printf("CMD => ");
818adf0ddaSmatthias.ringwald                     break;
828adf0ddaSmatthias.ringwald                 case HCI_EVENT_PACKET:
838adf0ddaSmatthias.ringwald                     printf("EVT <= ");
848adf0ddaSmatthias.ringwald                     break;
858adf0ddaSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
868adf0ddaSmatthias.ringwald                     if (in) {
878adf0ddaSmatthias.ringwald                         printf("ACL <= ");
888adf0ddaSmatthias.ringwald                     } else {
898adf0ddaSmatthias.ringwald                         printf("ACL => ");
908adf0ddaSmatthias.ringwald                     }
918adf0ddaSmatthias.ringwald                     break;
928adf0ddaSmatthias.ringwald             }
938adf0ddaSmatthias.ringwald             hexdump(packet, len);
948adf0ddaSmatthias.ringwald             break;
958b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
968b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
978b658ebcSmatthias.ringwald             header_bluez.in  = in;
988b658ebcSmatthias.ringwald             header_bluez.pad = 0;
998b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
1008b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
1018b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
1028b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
10379662672Smatthias.ringwald             write (dump_file, packet, len );
1048b658ebcSmatthias.ringwald             break;
1058b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
1068b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
1078b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
1088b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
1098b658ebcSmatthias.ringwald             switch (packet_type){
1108b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
1118b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
1128b658ebcSmatthias.ringwald                     break;
1138b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
1148b658ebcSmatthias.ringwald                     if (in) {
1158b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
1168b658ebcSmatthias.ringwald                     } else {
1178b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
1188b658ebcSmatthias.ringwald                     }
1198b658ebcSmatthias.ringwald                     break;
1208b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
1218b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
1228b658ebcSmatthias.ringwald                     break;
1238b658ebcSmatthias.ringwald                 default:
1248b658ebcSmatthias.ringwald                     return;
1258b658ebcSmatthias.ringwald             }
1268b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
1278b658ebcSmatthias.ringwald             write (dump_file, packet, len );
1288b658ebcSmatthias.ringwald     }
12979662672Smatthias.ringwald }
13079662672Smatthias.ringwald 
13179662672Smatthias.ringwald void hci_dump_close(){
13279662672Smatthias.ringwald     close(dump_file);
133d9659922Smatthias.ringwald     dump_file = -1;
13479662672Smatthias.ringwald }
13579662672Smatthias.ringwald 
136