BTstack Bluetooth stack

Dependencies:   mbed USBHost

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hci_dump.c Source File

hci_dump.c

00001 /*
00002  * Copyright (C) 2009-2012 by Matthias Ringwald
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  * 4. Any redistribution, use, or modification is done solely for
00017  *    personal benefit and not for any commercial purpose or for
00018  *    monetary gain.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
00024  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * Please inquire about commercial licensing options at btstack@ringwald.ch
00034  *
00035  */
00036 
00037 /*
00038  *  hci_dump.c
00039  *
00040  *  Dump HCI trace in various formats:
00041  *
00042  *  - BlueZ's hcidump format
00043  *  - Apple's PacketLogger
00044  *  - stdout hexdump
00045  *
00046  *  Created by Matthias Ringwald on 5/26/09.
00047  */
00048 
00049 #include "config.h"
00050 
00051 #include "hci_dump.h"
00052 #include "hci.h"
00053 #include "hci_transport.h"
00054 #include <btstack/hci_cmds.h>
00055 
00056 #ifndef EMBEDDED
00057 #include <fcntl.h>        // open
00058 #include <arpa/inet.h>    // hton..
00059 #include <unistd.h>       // write 
00060 #include <stdio.h>
00061 #include <time.h>
00062 #include <sys/time.h>     // for timestamps
00063 #include <sys/stat.h>     // for mode flags
00064 #include <stdarg.h>       // for va_list
00065 #endif
00066 
00067 // BLUEZ hcidump
00068 typedef struct {
00069     uint16_t    len;
00070     uint8_t     in;
00071     uint8_t     pad;
00072     uint32_t    ts_sec;
00073     uint32_t    ts_usec;
00074     uint8_t     packet_type;
00075 }
00076 #ifdef __GNUC__
00077 __attribute__ ((packed))
00078 #endif 
00079 hcidump_hdr;
00080 
00081 // APPLE PacketLogger
00082 typedef struct {
00083     uint32_t    len;
00084     uint32_t    ts_sec;
00085     uint32_t    ts_usec;
00086     uint8_t     type;   // 0xfc for note
00087 }
00088 #ifdef __GNUC__
00089 __attribute__ ((packed))
00090 #endif
00091 pktlog_hdr;
00092 
00093 #ifndef EMBEDDED
00094 static int dump_file = -1;
00095 static int dump_format;
00096 static hcidump_hdr header_bluez;
00097 static pktlog_hdr  header_packetlogger;
00098 static char time_string[40];
00099 static int  max_nr_packets = -1;
00100 static int  nr_packets = 0;
00101 static char log_message_buffer[256];
00102 #endif
00103 
00104 void hci_dump_open(char *filename, hci_dump_format_t format){
00105 #ifndef EMBEDDED
00106     dump_format = format;
00107     if (dump_format == HCI_DUMP_STDOUT) {
00108         dump_file = fileno(stdout);
00109     } else {
00110         dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00111     }
00112 #endif
00113 }
00114 
00115 #ifndef EMBEDDED
00116 void hci_dump_set_max_packets(int packets){
00117     max_nr_packets = packets;
00118 }
00119 #endif
00120 
00121 void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
00122 #ifndef EMBEDDED
00123 
00124     if (dump_file < 0) return; // not activated yet
00125 
00126     // don't grow bigger than max_nr_packets
00127     if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
00128         if (nr_packets >= max_nr_packets){
00129             lseek(dump_file, 0, SEEK_SET);
00130             ftruncate(dump_file, 0);
00131             nr_packets = 0;
00132         }
00133         nr_packets++;
00134     }
00135     
00136     // get time
00137     struct timeval curr_time;
00138     struct tm* ptm;
00139     gettimeofday(&curr_time, NULL);
00140     
00141     switch (dump_format){
00142         case HCI_DUMP_STDOUT: {
00143             /* Obtain the time of day, and convert it to a tm struct. */
00144             ptm = localtime (&curr_time.tv_sec);
00145             /* Format the date and time, down to a single second. */
00146             strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
00147             /* Compute milliseconds from microseconds. */
00148             uint16_t milliseconds = curr_time.tv_usec / 1000;
00149             /* Print the formatted time, in seconds, followed by a decimal point
00150              and the milliseconds. */
00151             printf ("%s.%03u] ", time_string, milliseconds);
00152             switch (packet_type){
00153                 case HCI_COMMAND_DATA_PACKET:
00154                     printf("CMD => ");
00155                     break;
00156                 case HCI_EVENT_PACKET:
00157                     printf("EVT <= ");
00158                     break;
00159                 case HCI_ACL_DATA_PACKET:
00160                     if (in) {
00161                         printf("ACL <= ");
00162                     } else {
00163                         printf("ACL => ");
00164                     }
00165                     break;
00166                 case LOG_MESSAGE_PACKET:
00167                     // assume buffer is big enough
00168                     packet[len] = 0;
00169                     printf("LOG -- %s\n", (char*) packet);
00170                     return;
00171                 default:
00172                     return;
00173             }
00174             hexdump(packet, len);
00175             break;
00176         }
00177             
00178         case HCI_DUMP_BLUEZ:
00179             bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
00180             header_bluez.in  = in;
00181             header_bluez.pad = 0;
00182             bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
00183             bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
00184             header_bluez.packet_type = packet_type;
00185             write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
00186             write (dump_file, packet, len );
00187             break;
00188             
00189         case HCI_DUMP_PACKETLOGGER:
00190             header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
00191             header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
00192             header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
00193             switch (packet_type){
00194                 case HCI_COMMAND_DATA_PACKET:
00195                     header_packetlogger.type = 0x00;
00196                     break;
00197                 case HCI_ACL_DATA_PACKET:
00198                     if (in) {
00199                         header_packetlogger.type = 0x03;
00200                     } else {
00201                         header_packetlogger.type = 0x02;
00202                     }
00203                     break;
00204                 case HCI_EVENT_PACKET:
00205                     header_packetlogger.type = 0x01;
00206                     break;
00207                 case LOG_MESSAGE_PACKET:
00208                     header_packetlogger.type = 0xfc;
00209                     break;
00210                 default:
00211                     return;
00212             }
00213             write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
00214             write (dump_file, packet, len );
00215             break;
00216             
00217         default:
00218             break;
00219     }
00220 #endif
00221 }
00222 
00223 void hci_dump_log(const char * format, ...){
00224 #ifndef EMBEDDED
00225     va_list argptr;
00226     va_start(argptr, format);
00227     int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
00228     hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
00229     va_end(argptr);
00230 #endif    
00231 }
00232 
00233 void hci_dump_close(){
00234 #ifndef EMBEDDED
00235     close(dump_file);
00236     dump_file = -1;
00237 #endif
00238 }
00239