hci_dump.c (acb15818d50b860e14489f68a6237686091b95b9) | hci_dump.c (5fa31a9940804989b94f828b5982860dcb81c77d) |
---|---|
1/* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright --- 32 unchanged lines hidden (view full) --- 41 * hci_dump.c 42 * 43 * Dump HCI trace in various formats: 44 * 45 * - BlueZ's hcidump format 46 * - Apple's PacketLogger 47 * - stdout hexdump 48 * | 1/* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright --- 32 unchanged lines hidden (view full) --- 41 * hci_dump.c 42 * 43 * Dump HCI trace in various formats: 44 * 45 * - BlueZ's hcidump format 46 * - Apple's PacketLogger 47 * - stdout hexdump 48 * |
49 * Created by Matthias Ringwald on 5/26/09. | |
50 */ 51 52#include "btstack_config.h" 53 54// enable POSIX functions (needed for -std=c99) 55#define _POSIX_C_SOURCE 200809 56 57#include "hci_dump.h" --- 6 unchanged lines hidden (view full) --- 64#ifdef HAVE_POSIX_FILE_IO 65#include <fcntl.h> // open 66#include <unistd.h> // write 67#include <time.h> 68#include <sys/time.h> // for timestamps 69#include <sys/stat.h> // for mode flags 70#endif 71 | 49 */ 50 51#include "btstack_config.h" 52 53// enable POSIX functions (needed for -std=c99) 54#define _POSIX_C_SOURCE 200809 55 56#include "hci_dump.h" --- 6 unchanged lines hidden (view full) --- 63#ifdef HAVE_POSIX_FILE_IO 64#include <fcntl.h> // open 65#include <unistd.h> // write 66#include <time.h> 67#include <sys/time.h> // for timestamps 68#include <sys/stat.h> // for mode flags 69#endif 70 |
71#ifdef ENABLE_SEGGER_RTT 72#include "SEGGER_RTT.h" 73static char channel1_out[1024]; 74#endif 75 |
|
72// BLUEZ hcidump - struct not used directly, but left here as documentation 73typedef struct { 74 uint16_t len; 75 uint8_t in; 76 uint8_t pad; 77 uint32_t ts_sec; 78 uint32_t ts_usec; 79 uint8_t packet_type; --- 7 unchanged lines hidden (view full) --- 87 uint32_t ts_sec; 88 uint32_t ts_usec; 89 uint8_t type; // 0xfc for note 90} 91pktlog_hdr; 92#define PKTLOG_HDR_SIZE 13 93 94static int dump_file = -1; | 76// BLUEZ hcidump - struct not used directly, but left here as documentation 77typedef struct { 78 uint16_t len; 79 uint8_t in; 80 uint8_t pad; 81 uint32_t ts_sec; 82 uint32_t ts_usec; 83 uint8_t packet_type; --- 7 unchanged lines hidden (view full) --- 91 uint32_t ts_sec; 92 uint32_t ts_usec; 93 uint8_t type; // 0xfc for note 94} 95pktlog_hdr; 96#define PKTLOG_HDR_SIZE 13 97 98static int dump_file = -1; |
95#ifdef HAVE_POSIX_FILE_IO | |
96static int dump_format; | 99static int dump_format; |
97static uint8_t header_bluez[HCIDUMP_HDR_SIZE]; 98static uint8_t header_packetlogger[PKTLOG_HDR_SIZE]; | 100static union { 101 uint8_t header_bluez[HCIDUMP_HDR_SIZE]; 102 uint8_t header_packetlogger[PKTLOG_HDR_SIZE]; 103} header; 104#ifdef HAVE_POSIX_FILE_IO |
99static char time_string[40]; 100static int max_nr_packets = -1; 101static int nr_packets = 0; 102static char log_message_buffer[256]; 103#endif 104 105// levels: debug, info, error 106static int log_level_enabled[3] = { 1, 1, 1}; 107 108void hci_dump_open(const char *filename, hci_dump_format_t format){ | 105static char time_string[40]; 106static int max_nr_packets = -1; 107static int nr_packets = 0; 108static char log_message_buffer[256]; 109#endif 110 111// levels: debug, info, error 112static int log_level_enabled[3] = { 1, 1, 1}; 113 114void hci_dump_open(const char *filename, hci_dump_format_t format){ |
109#ifdef HAVE_POSIX_FILE_IO | 115 |
110 dump_format = format; | 116 dump_format = format; |
117 118#ifdef HAVE_POSIX_FILE_IO |
|
111 if (dump_format == HCI_DUMP_STDOUT) { 112 dump_file = fileno(stdout); 113 } else { 114 115 int oflags = O_WRONLY | O_CREAT | O_TRUNC; 116#ifdef _WIN32 117 oflags |= O_BINARY; 118#endif | 119 if (dump_format == HCI_DUMP_STDOUT) { 120 dump_file = fileno(stdout); 121 } else { 122 123 int oflags = O_WRONLY | O_CREAT | O_TRUNC; 124#ifdef _WIN32 125 oflags |= O_BINARY; 126#endif |
119 | |
120 dump_file = open(filename, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); 121 if (dump_file < 0){ 122 printf("hci_dump_open: failed to open file %s\n", filename); 123 } 124 } 125#else | 127 dump_file = open(filename, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); 128 if (dump_file < 0){ 129 printf("hci_dump_open: failed to open file %s\n", filename); 130 } 131 } 132#else |
133 |
|
126 UNUSED(filename); | 134 UNUSED(filename); |
127 UNUSED(format); | 135 136#ifdef ENABLE_SEGGER_RTT 137 switch (dump_format){ 138 case HCI_DUMP_PACKETLOGGER: 139 case HCI_DUMP_BLUEZ: 140 // Configure up channel 1, options: 141 // - SEGGER_RTT_MODE_NO_BLOCK_SKIP 142 // - SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL 143 // Note: with SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL, firwmware will hang if RTT not supported/debug probe not connected 144 // Note: with SEGGER_RTT_MODE_NO_BLOCK_SKIP, there's a chance for log file corruption if second write (packet) is skipped 145 SEGGER_RTT_ConfigUpBuffer(1, "hci_dump", &channel1_out[0], sizeof(channel1_out), SEGGER_RTT_MODE_NO_BLOCK_SKIP) ;; 146 break; 147 default: 148 break; 149 } 150#endif |
128 129 dump_file = 1; 130#endif 131} 132 133#ifdef HAVE_POSIX_FILE_IO 134void hci_dump_set_max_packets(int packets){ 135 max_nr_packets = packets; 136} 137#endif 138 | 151 152 dump_file = 1; 153#endif 154} 155 156#ifdef HAVE_POSIX_FILE_IO 157void hci_dump_set_max_packets(int packets){ 158 max_nr_packets = packets; 159} 160#endif 161 |
162static void hci_dump_packetlogger_setup_header(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len){ 163 big_endian_store_32( buffer, 0, PKTLOG_HDR_SIZE - 4 + len); 164 big_endian_store_32( buffer, 4, tv_sec); 165 big_endian_store_32( buffer, 8, tv_us); 166 uint8_t packet_logger_type = 0; 167 switch (packet_type){ 168 case HCI_COMMAND_DATA_PACKET: 169 packet_logger_type = 0x00; 170 break; 171 case HCI_ACL_DATA_PACKET: 172 packet_logger_type = in ? 0x03 : 0x02; 173 break; 174 case HCI_SCO_DATA_PACKET: 175 packet_logger_type = in ? 0x09 : 0x08; 176 break; 177 case HCI_EVENT_PACKET: 178 packet_logger_type = 0x01; 179 break; 180 case LOG_MESSAGE_PACKET: 181 packet_logger_type = 0xfc; 182 break; 183 default: 184 return; 185 } 186 buffer[12] = packet_logger_type; 187} 188 189static void hci_dump_bluez_setup_header(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len){ 190 little_endian_store_16( buffer, 0, 1 + len); 191 buffer[2] = in; 192 buffer[3] = 0; 193 little_endian_store_32( buffer, 4, tv_sec); 194 little_endian_store_32( buffer, 8, tv_us); 195 buffer[12] = packet_type; 196} 197 |
|
139static void printf_packet(uint8_t packet_type, uint8_t in, uint8_t * packet, uint16_t len){ 140 switch (packet_type){ 141 case HCI_COMMAND_DATA_PACKET: 142 printf("CMD => "); 143 break; 144 case HCI_EVENT_PACKET: 145 printf("EVT <= "); 146 break; --- 35 unchanged lines hidden (view full) --- 182 /* Compute milliseconds from microseconds. */ 183 uint16_t milliseconds = curr_time.tv_usec / 1000; 184 /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */ 185 printf ("%s.%03u] ", time_string, milliseconds); 186#else 187 uint32_t time_ms = btstack_run_loop_get_time_ms(); 188 int seconds = time_ms / 1000; 189 int minutes = seconds / 60; | 198static void printf_packet(uint8_t packet_type, uint8_t in, uint8_t * packet, uint16_t len){ 199 switch (packet_type){ 200 case HCI_COMMAND_DATA_PACKET: 201 printf("CMD => "); 202 break; 203 case HCI_EVENT_PACKET: 204 printf("EVT <= "); 205 break; --- 35 unchanged lines hidden (view full) --- 241 /* Compute milliseconds from microseconds. */ 242 uint16_t milliseconds = curr_time.tv_usec / 1000; 243 /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */ 244 printf ("%s.%03u] ", time_string, milliseconds); 245#else 246 uint32_t time_ms = btstack_run_loop_get_time_ms(); 247 int seconds = time_ms / 1000; 248 int minutes = seconds / 60; |
190 unsigned int hours = minutes / 60; | 249 unsigned int hours = minutes / 60; |
191 192 uint16_t p_ms = time_ms - (seconds * 1000); 193 uint16_t p_seconds = seconds - (minutes * 60); 194 uint16_t p_minutes = minutes - (hours * 60); 195 printf("[%02u:%02u:%02u.%03u] ", hours, p_minutes, p_seconds, p_ms); 196#endif 197} 198 199void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 200 201 if (dump_file < 0) return; // not activated yet 202 203#ifdef HAVE_POSIX_FILE_IO | 250 251 uint16_t p_ms = time_ms - (seconds * 1000); 252 uint16_t p_seconds = seconds - (minutes * 60); 253 uint16_t p_minutes = minutes - (hours * 60); 254 printf("[%02u:%02u:%02u.%03u] ", hours, p_minutes, p_seconds, p_ms); 255#endif 256} 257 258void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 259 260 if (dump_file < 0) return; // not activated yet 261 262#ifdef HAVE_POSIX_FILE_IO |
204 | |
205 // don't grow bigger than max_nr_packets 206 if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){ 207 if (nr_packets >= max_nr_packets){ 208 lseek(dump_file, 0, SEEK_SET); 209 // avoid -Wunused-result 210 int res = ftruncate(dump_file, 0); 211 UNUSED(res); 212 nr_packets = 0; 213 } 214 nr_packets++; 215 } | 263 // don't grow bigger than max_nr_packets 264 if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){ 265 if (nr_packets >= max_nr_packets){ 266 lseek(dump_file, 0, SEEK_SET); 267 // avoid -Wunused-result 268 int res = ftruncate(dump_file, 0); 269 UNUSED(res); 270 nr_packets = 0; 271 } 272 nr_packets++; 273 } |
216 | 274#endif 275 276 if (dump_format == HCI_DUMP_STDOUT){ 277 printf_timestamp(); 278 printf_packet(packet_type, in, packet, len); 279 return; 280 } 281 282 uint32_t tv_sec = 0; 283 uint32_t tv_us = 0; 284 |
217 // get time | 285 // get time |
286#ifdef HAVE_POSIX_FILE_IO |
|
218 struct timeval curr_time; 219 gettimeofday(&curr_time, NULL); | 287 struct timeval curr_time; 288 gettimeofday(&curr_time, NULL); |
289 tv_sec = curr_time.tv_sec; 290 tv_us = curr_time.tv_usec; 291#else 292 uint32_t time_ms = btstack_run_loop_get_time_ms(); 293 tv_us = time_ms * 1000; 294 tv_sec = 946728000UL + (time_ms / 1000); 295#endif |
|
220 | 296 |
221 // avoid -Wunused-result 222 int res = 0; | 297 uint16_t header_len = 0; |
223 switch (dump_format){ | 298 switch (dump_format){ |
224 case HCI_DUMP_STDOUT: { 225 printf_timestamp(); 226 printf_packet(packet_type, in, packet, len); 227 break; 228 } 229 | |
230 case HCI_DUMP_BLUEZ: | 299 case HCI_DUMP_BLUEZ: |
231 little_endian_store_16( header_bluez, 0, 1 + len); 232 header_bluez[2] = in; 233 header_bluez[3] = 0; 234 little_endian_store_32( header_bluez, 4, (uint32_t) curr_time.tv_sec); 235 little_endian_store_32( header_bluez, 8, curr_time.tv_usec); 236 header_bluez[12] = packet_type; 237 res = write (dump_file, header_bluez, HCIDUMP_HDR_SIZE); 238 res = write (dump_file, packet, len ); | 300 hci_dump_bluez_setup_header(header.header_bluez, tv_sec, tv_us, packet_type, in, len); 301 header_len = HCIDUMP_HDR_SIZE; |
239 break; | 302 break; |
240 | |
241 case HCI_DUMP_PACKETLOGGER: | 303 case HCI_DUMP_PACKETLOGGER: |
242 big_endian_store_32( header_packetlogger, 0, PKTLOG_HDR_SIZE - 4 + len); 243 big_endian_store_32( header_packetlogger, 4, (uint32_t) curr_time.tv_sec); 244 big_endian_store_32( header_packetlogger, 8, curr_time.tv_usec); 245 switch (packet_type){ 246 case HCI_COMMAND_DATA_PACKET: 247 header_packetlogger[12] = 0x00; 248 break; 249 case HCI_ACL_DATA_PACKET: 250 if (in) { 251 header_packetlogger[12] = 0x03; 252 } else { 253 header_packetlogger[12] = 0x02; 254 } 255 break; 256 case HCI_SCO_DATA_PACKET: 257 if (in) { 258 header_packetlogger[12] = 0x09; 259 } else { 260 header_packetlogger[12] = 0x08; 261 } 262 break; 263 case HCI_EVENT_PACKET: 264 header_packetlogger[12] = 0x01; 265 break; 266 case LOG_MESSAGE_PACKET: 267 header_packetlogger[12] = 0xfc; 268 break; 269 default: 270 return; 271 } 272 res = write (dump_file, &header_packetlogger, PKTLOG_HDR_SIZE); 273 res = write (dump_file, packet, len ); | 304 hci_dump_packetlogger_setup_header(header.header_packetlogger, tv_sec, tv_us, packet_type, in, len); 305 header_len = PKTLOG_HDR_SIZE; |
274 break; | 306 break; |
275 | |
276 default: | 307 default: |
277 break; | 308 return; |
278 } | 309 } |
279 UNUSED(res); 280#else | |
281 | 310 |
282 printf_timestamp(); 283 printf_packet(packet_type, in, packet, len); 284 | 311#ifdef HAVE_POSIX_FILE_IO 312 // avoid -Wunused-result 313 int res = 0; 314 res = write (dump_file, &header, header_len); 315 res = write (dump_file, packet, len ); 316 UNUSED(res); |
285#endif | 317#endif |
318#ifdef ENABLE_SEGGER_RTT 319 SEGGER_RTT_Write(1, &header, header_len); 320 SEGGER_RTT_Write(1, packet, len); 321#endif 322 UNUSED(header_len); |
|
286} 287 288static int hci_dump_log_level_active(int log_level){ 289 if (log_level < HCI_DUMP_LOG_LEVEL_DEBUG) return 0; 290 if (log_level > HCI_DUMP_LOG_LEVEL_ERROR) return 0; 291 return log_level_enabled[log_level]; 292} 293 --- 49 unchanged lines hidden --- | 323} 324 325static int hci_dump_log_level_active(int log_level){ 326 if (log_level < HCI_DUMP_LOG_LEVEL_DEBUG) return 0; 327 if (log_level > HCI_DUMP_LOG_LEVEL_ERROR) return 0; 328 return log_level_enabled[log_level]; 329} 330 --- 49 unchanged lines hidden --- |