1 /****************************************************************************** 2 * 3 * Copyright 2015 Google Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #include <stdio.h> 20 #include <string.h> 21 #include <time.h> 22 23 #include "btif/include/btif_debug_conn.h" 24 #include "osi/include/time.h" 25 26 #define NUM_CONNECTION_EVENTS 16 27 #define TEMP_BUFFER_SIZE 30 28 29 typedef struct conn_event_t { 30 uint64_t ts; 31 btif_debug_conn_state_t state; 32 RawAddress bda; 33 tGATT_DISCONN_REASON disconnect_reason; 34 } conn_event_t; 35 36 static conn_event_t connection_events[NUM_CONNECTION_EVENTS]; 37 static uint8_t current_event = 0; 38 39 static char* format_ts(const uint64_t ts, char* buffer, int len) { 40 const uint64_t ms = ts / 1000; 41 const time_t secs = ms / 1000; 42 struct tm* ptm = localtime(&secs); 43 44 char tempbuff[20]; 45 strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm); 46 snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000)); 47 48 return buffer; 49 } 50 51 static const char* format_state(const btif_debug_conn_state_t state) { 52 switch (state) { 53 case BTIF_DEBUG_CONNECTED: 54 return "CONNECTED "; 55 case BTIF_DEBUG_DISCONNECTED: 56 return "DISCONNECTED"; 57 } 58 return "UNKNOWN"; 59 } 60 61 static void next_event() { 62 ++current_event; 63 if (current_event == NUM_CONNECTION_EVENTS) current_event = 0; 64 } 65 66 void btif_debug_conn_state(const RawAddress& bda, 67 const btif_debug_conn_state_t state, 68 const tGATT_DISCONN_REASON disconnect_reason) { 69 next_event(); 70 71 conn_event_t* evt = &connection_events[current_event]; 72 evt->ts = time_gettimeofday_us(); 73 evt->state = state; 74 evt->disconnect_reason = disconnect_reason; 75 evt->bda = bda; 76 } 77 78 void btif_debug_conn_dump(int fd) { 79 const uint8_t current_event_local = 80 current_event; // Cache to avoid threading issues 81 uint8_t dump_event = current_event_local; 82 char ts_buffer[TEMP_BUFFER_SIZE] = {0}; 83 84 dprintf(fd, "\nConnection Events:\n"); 85 if (connection_events[dump_event].ts == 0) dprintf(fd, " None\n"); 86 87 while (connection_events[dump_event].ts) { 88 conn_event_t* evt = &connection_events[dump_event]; 89 dprintf(fd, " %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)), 90 format_state(evt->state), evt->bda.ToString().c_str()); 91 if (evt->state == BTIF_DEBUG_DISCONNECTED) 92 dprintf(fd, " reason=%d", evt->disconnect_reason); 93 dprintf(fd, "\n"); 94 95 // Go to previous event; wrap if needed 96 if (dump_event > 0) 97 --dump_event; 98 else 99 dump_event = NUM_CONNECTION_EVENTS - 1; 100 101 // Check if we dumped all events 102 if (dump_event == current_event_local) break; 103 } 104 } 105