1/****************************************************************************** 2 * 3 * Copyright (C) 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 "btcore/include/bdaddr.h" 24#include "btif/include/btif_debug.h" 25#include "btif/include/btif_debug_conn.h" 26 27#define NUM_CONNECTION_EVENTS 16 28#define TEMP_BUFFER_SIZE 30 29 30typedef struct conn_event_t { 31 uint64_t ts; 32 btif_debug_conn_state_t state; 33 bt_bdaddr_t bda; 34 tGATT_DISCONN_REASON disconnect_reason; 35} conn_event_t; 36 37static conn_event_t connection_events[NUM_CONNECTION_EVENTS]; 38static uint8_t current_event = 0; 39 40static char *format_ts(const uint64_t ts, char *buffer, int len) { 41 const uint64_t ms = ts / 1000; 42 const time_t secs = ms / 1000; 43 struct tm *ptm = localtime(&secs); 44 45 char tempbuff[20]; 46 strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm); 47 snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000)); 48 49 return buffer; 50} 51 52static char *format_state(const btif_debug_conn_state_t state) { 53 switch (state) { 54 case BTIF_DEBUG_CONNECTED: 55 return "CONNECTED "; 56 case BTIF_DEBUG_DISCONNECTED: 57 return "DISCONNECTED"; 58 } 59 return "UNKNOWN"; 60} 61 62static void next_event() { 63 ++current_event; 64 if (current_event == NUM_CONNECTION_EVENTS) 65 current_event = 0; 66} 67 68void btif_debug_conn_state(const bt_bdaddr_t bda, const btif_debug_conn_state_t state, 69 const tGATT_DISCONN_REASON disconnect_reason) { 70 next_event(); 71 72 conn_event_t *evt = &connection_events[current_event]; 73 evt->ts = btif_debug_ts(); 74 evt->state = state; 75 evt->disconnect_reason = disconnect_reason; 76 memcpy(&evt->bda, &bda, sizeof(bt_bdaddr_t)); 77} 78 79void btif_debug_conn_dump(int fd) { 80 const uint8_t current_event_local = current_event; // Cache to avoid threading issues 81 uint8_t dump_event = current_event_local; 82 char ts_buffer[TEMP_BUFFER_SIZE] = {0}; 83 char name_buffer[TEMP_BUFFER_SIZE] = {0}; 84 85 dprintf(fd, "\nConnection Events:\n"); 86 if (connection_events[dump_event].ts == 0) 87 dprintf(fd, " None\n"); 88 89 while (connection_events[dump_event].ts) { 90 conn_event_t *evt = &connection_events[dump_event]; 91 dprintf(fd, " %s %s %s", 92 format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)), 93 format_state(evt->state), 94 bdaddr_to_string(&evt->bda, name_buffer, sizeof(name_buffer)) 95 ); 96 if (evt->state == BTIF_DEBUG_DISCONNECTED) 97 dprintf(fd, " reason=%d", evt->disconnect_reason); 98 dprintf(fd,"\n"); 99 100 // Go to previous event; wrap if needed 101 if (dump_event > 0) 102 --dump_event; 103 else 104 dump_event = NUM_CONNECTION_EVENTS - 1; 105 106 // Check if we dumped all events 107 if (dump_event == current_event_local) 108 break; 109 } 110} 111