xref: /btstack/src/hci_dump.c (revision c7b9c5599dc1af8ebdb23db5e9b2996f16c70ab2)
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>
188b658ebcSmatthias.ringwald #include <sys/time.h>     // for timestamps
19*c7b9c559Smatthias.ringwald #include <sys/stat.h>     // for mode flags
2079662672Smatthias.ringwald 
218b658ebcSmatthias.ringwald // BLUEZ hcidump
228b658ebcSmatthias.ringwald typedef struct {
238b658ebcSmatthias.ringwald 	uint16_t	len;
248b658ebcSmatthias.ringwald 	uint8_t		in;
258b658ebcSmatthias.ringwald 	uint8_t		pad;
268b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
278b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
288b658ebcSmatthias.ringwald     uint8_t     packet_type;
298b658ebcSmatthias.ringwald } __attribute__ ((packed)) hcidump_hdr;
3079662672Smatthias.ringwald 
318b658ebcSmatthias.ringwald // APPLE PacketLogger
328b658ebcSmatthias.ringwald typedef struct {
338b658ebcSmatthias.ringwald 	uint32_t	len;
348b658ebcSmatthias.ringwald 	uint32_t	ts_sec;
358b658ebcSmatthias.ringwald 	uint32_t	ts_usec;
368b658ebcSmatthias.ringwald 	uint8_t		type;
378b658ebcSmatthias.ringwald } __attribute__ ((packed)) pktlog_hdr;
388b658ebcSmatthias.ringwald 
398b658ebcSmatthias.ringwald static int dump_file = -1;
408b658ebcSmatthias.ringwald static int dump_format;
418b658ebcSmatthias.ringwald static hcidump_hdr header_bluez;
428b658ebcSmatthias.ringwald static pktlog_hdr  header_packetlogger;
438b658ebcSmatthias.ringwald 
448b658ebcSmatthias.ringwald void hci_dump_open(char *filename, hci_dump_format_t format){
45d9659922Smatthias.ringwald     if (dump_file < 0) {
465e0fa50dSmatthias.ringwald         dump_file =  open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
478b658ebcSmatthias.ringwald         dump_format = format;
4879662672Smatthias.ringwald     }
49d9659922Smatthias.ringwald }
5079662672Smatthias.ringwald 
5179662672Smatthias.ringwald void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
528b658ebcSmatthias.ringwald     if (dump_file < 0) return; // not activated yet
538b658ebcSmatthias.ringwald 
548b658ebcSmatthias.ringwald     // get time
558b658ebcSmatthias.ringwald     struct timeval curr_time;
568b658ebcSmatthias.ringwald     gettimeofday(&curr_time, NULL);
578b658ebcSmatthias.ringwald 
588b658ebcSmatthias.ringwald     switch (dump_format){
598b658ebcSmatthias.ringwald         case HCI_DUMP_BLUEZ:
608b658ebcSmatthias.ringwald             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
618b658ebcSmatthias.ringwald             header_bluez.in  = in;
628b658ebcSmatthias.ringwald             header_bluez.pad = 0;
638b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
648b658ebcSmatthias.ringwald             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
658b658ebcSmatthias.ringwald             header_bluez.packet_type = packet_type;
668b658ebcSmatthias.ringwald             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
6779662672Smatthias.ringwald             write (dump_file, packet, len );
688b658ebcSmatthias.ringwald             break;
698b658ebcSmatthias.ringwald         case HCI_DUMP_PACKETLOGGER:
708b658ebcSmatthias.ringwald             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
718b658ebcSmatthias.ringwald             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
728b658ebcSmatthias.ringwald             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
738b658ebcSmatthias.ringwald             switch (packet_type){
748b658ebcSmatthias.ringwald                 case HCI_COMMAND_DATA_PACKET:
758b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x00;
768b658ebcSmatthias.ringwald                     break;
778b658ebcSmatthias.ringwald                 case HCI_ACL_DATA_PACKET:
788b658ebcSmatthias.ringwald                     if (in) {
798b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x03;
808b658ebcSmatthias.ringwald                     } else {
818b658ebcSmatthias.ringwald                         header_packetlogger.type = 0x02;
828b658ebcSmatthias.ringwald                     }
838b658ebcSmatthias.ringwald                     break;
848b658ebcSmatthias.ringwald                 case HCI_EVENT_PACKET:
858b658ebcSmatthias.ringwald                     header_packetlogger.type = 0x01;
868b658ebcSmatthias.ringwald                     break;
878b658ebcSmatthias.ringwald                 default:
888b658ebcSmatthias.ringwald                     return;
898b658ebcSmatthias.ringwald             }
908b658ebcSmatthias.ringwald             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
918b658ebcSmatthias.ringwald             write (dump_file, packet, len );
928b658ebcSmatthias.ringwald     }
9379662672Smatthias.ringwald }
9479662672Smatthias.ringwald 
9579662672Smatthias.ringwald void hci_dump_close(){
9679662672Smatthias.ringwald     close(dump_file);
97d9659922Smatthias.ringwald     dump_file = -1;
9879662672Smatthias.ringwald }
9979662672Smatthias.ringwald 
100