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
30 typedef 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
37 static conn_event_t connection_events[NUM_CONNECTION_EVENTS];
38 static uint8_t current_event = 0;
39
format_ts(const uint64_t ts,char * buffer,int len)40 static 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 strftime(buffer, len, "%m-%d %H:%M:%S.%%03u", ptm);
46 snprintf(buffer, len, buffer, (uint16_t)(ms % 1000));
47
48 return buffer;
49 }
50
format_state(const btif_debug_conn_state_t state)51 static 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
next_event()61 static void next_event() {
62 ++current_event;
63 if (current_event == NUM_CONNECTION_EVENTS)
64 current_event = 0;
65 }
66
btif_debug_conn_state(const bt_bdaddr_t bda,const btif_debug_conn_state_t state,const tGATT_DISCONN_REASON disconnect_reason)67 void btif_debug_conn_state(const bt_bdaddr_t bda, 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 = btif_debug_ts();
73 evt->state = state;
74 evt->disconnect_reason = disconnect_reason;
75 memcpy(&evt->bda, &bda, sizeof(bt_bdaddr_t));
76 }
77
btif_debug_conn_dump(int fd)78 void btif_debug_conn_dump(int fd) {
79 const uint8_t current_event_local = current_event; // Cache to avoid threading issues
80 uint8_t dump_event = current_event_local;
81 char ts_buffer[TEMP_BUFFER_SIZE] = {0};
82 char name_buffer[TEMP_BUFFER_SIZE] = {0};
83
84 dprintf(fd, "\nConnection Events:\n");
85 if (connection_events[dump_event].ts == 0)
86 dprintf(fd, " None\n");
87
88 while (connection_events[dump_event].ts) {
89 conn_event_t *evt = &connection_events[dump_event];
90 dprintf(fd, " %s %s %s",
91 format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
92 format_state(evt->state),
93 bdaddr_to_string(&evt->bda, name_buffer, sizeof(name_buffer))
94 );
95 if (evt->state == BTIF_DEBUG_DISCONNECTED)
96 dprintf(fd, " reason=%d", evt->disconnect_reason);
97 dprintf(fd,"\n");
98
99 // Go to previous event; wrap if needed
100 if (dump_event > 0)
101 --dump_event;
102 else
103 dump_event = NUM_CONNECTION_EVENTS - 1;
104
105 // Check if we dumped all events
106 if (dump_event == current_event_local)
107 break;
108 }
109 }
110