1 /******************************************************************************
2 *
3 * Copyright (C) 2016 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 <stdint.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include "btcore/include/bdaddr.h"
25 #include "btif/include/btif_debug.h"
26 #include "btif/include/btif_debug_l2c.h"
27
28 #define NUM_UPDATE_REQUESTS 5
29 #define NUM_UPDATE_RESPONSES 5
30
31 #define INTERVAL_1_25_MS_MULTIPLIER 1.25f
32 #define TIMEOUT_10_MS_MULTIPLIER 10
33
34 typedef enum {
35 BTIF_DEBUG_CONNECTION_UPDATE_REQUEST,
36 BTIF_DEBUG_CONNECTION_UPDATE_RESPONSE,
37 } btif_debug_ble_conn_update_t;
38
39 /* Shared Connection update record for both request and response. */
40 typedef struct ble_conn_update_t {
41 uint64_t timestamp_ms;
42 bt_bdaddr_t bda;
43 btif_debug_ble_conn_update_t type;
44 uint8_t status; /* Not populated for request. */
45 uint16_t min_interval; /* Not populated for response. */
46 uint16_t max_interval;
47 uint16_t latency;
48 uint16_t timeout;
49 } ble_conn_update_t;
50
51 static int update_request_index;
52 static int update_response_index;
53 static ble_conn_update_t last_ble_conn_update_requests[NUM_UPDATE_REQUESTS];
54 static ble_conn_update_t last_ble_conn_update_responses[NUM_UPDATE_RESPONSES];
55
dump_connection_update(int fd,const ble_conn_update_t * update)56 static int dump_connection_update(int fd, const ble_conn_update_t *update) {
57 if (!update || update->timestamp_ms == 0) {
58 return -1;
59 }
60
61 /* Format timestamp */
62 const uint64_t msecs = update->timestamp_ms / 1000;
63 const time_t secs = msecs / 1000;
64 struct tm *ptm = localtime(&secs);
65 char time_buf[20] = {0};
66 strftime(time_buf, sizeof(time_buf), "%m-%d %H:%M:%S", ptm);
67 snprintf(time_buf, sizeof(time_buf), "%s.%03u", time_buf,
68 (uint16_t)(msecs % 1000));
69
70 /* Format address */
71 char addr_buf[18] = {0};
72 bdaddr_to_string(&update->bda, addr_buf, sizeof(addr_buf));
73
74 if (update->type == BTIF_DEBUG_CONNECTION_UPDATE_REQUEST) {
75 dprintf(fd,
76 " %s %s min interval=%d (%.2fms) max interval=%d (%.2fms) "
77 "latency parameter=%d timeout multiplier=%d (%dms)\n",
78 time_buf, addr_buf, update->min_interval,
79 (float)update->min_interval * INTERVAL_1_25_MS_MULTIPLIER,
80 update->max_interval,
81 (float)update->max_interval * INTERVAL_1_25_MS_MULTIPLIER,
82 update->latency, update->timeout,
83 update->timeout * TIMEOUT_10_MS_MULTIPLIER);
84 } else {
85 dprintf(fd,
86 " %s %s status=%d interval=%d (%.2fms) latency parameter=%d "
87 "timeout multiplier=%d (%dms)\n", time_buf,
88 addr_buf, update->status, update->max_interval,
89 (float)update->max_interval * INTERVAL_1_25_MS_MULTIPLIER,
90 update->latency, update->timeout,
91 update->timeout * TIMEOUT_10_MS_MULTIPLIER);
92 }
93
94 return 0;
95 }
96
record_connection_update(bt_bdaddr_t bda,uint8_t status,uint16_t min_interval,uint16_t max_interval,uint16_t latency,uint16_t timeout,btif_debug_ble_conn_update_t type,ble_conn_update_t * update)97 static void record_connection_update(bt_bdaddr_t bda, uint8_t status,
98 uint16_t min_interval, uint16_t max_interval, uint16_t latency,
99 uint16_t timeout, btif_debug_ble_conn_update_t type,
100 ble_conn_update_t* update) {
101
102 memcpy(&update->bda, &bda, sizeof(bt_bdaddr_t));
103 update->type = type;
104 update->timestamp_ms = btif_debug_ts();
105 update->min_interval = min_interval;
106 update->max_interval = max_interval;
107 update->latency = latency;
108 update->timeout = timeout;
109 update->status = 0;
110 }
111
btif_debug_ble_connection_update_request(bt_bdaddr_t bda,uint16_t min_interval,uint16_t max_interval,uint16_t slave_latency_param,uint16_t timeout_multiplier)112 void btif_debug_ble_connection_update_request(bt_bdaddr_t bda,
113 uint16_t min_interval, uint16_t max_interval, uint16_t slave_latency_param,
114 uint16_t timeout_multiplier) {
115 ble_conn_update_t *request =
116 &last_ble_conn_update_requests[update_request_index];
117
118 record_connection_update(bda, 0, min_interval, max_interval, slave_latency_param,
119 timeout_multiplier, BTIF_DEBUG_CONNECTION_UPDATE_REQUEST, request);
120
121 update_request_index = (update_request_index == NUM_UPDATE_REQUESTS - 1) ?
122 0 : update_request_index + 1;
123 }
124
btif_debug_ble_connection_update_response(bt_bdaddr_t bda,uint8_t status,uint16_t interval,uint16_t slave_latency_param,uint16_t timeout_multiplier)125 void btif_debug_ble_connection_update_response(bt_bdaddr_t bda, uint8_t status,
126 uint16_t interval, uint16_t slave_latency_param,
127 uint16_t timeout_multiplier) {
128 ble_conn_update_t *response =
129 &last_ble_conn_update_responses[update_response_index];
130
131 record_connection_update(bda, status, 0, interval, slave_latency_param,
132 timeout_multiplier, BTIF_DEBUG_CONNECTION_UPDATE_RESPONSE, response);
133
134 update_response_index = (update_response_index == NUM_UPDATE_RESPONSES - 1) ?
135 0 : update_response_index + 1;
136 }
137
btif_debug_l2c_dump(int fd)138 void btif_debug_l2c_dump(int fd) {
139 dprintf(fd, "\nLE Connection Parameter Updates:\n");
140
141 int i;
142 dprintf(fd, " Last %d Request(s):\n", NUM_UPDATE_REQUESTS);
143 for (i = 0; i < NUM_UPDATE_REQUESTS; ++i) {
144 if (dump_connection_update(fd, &last_ble_conn_update_requests[i]) < 0 &&
145 i == 0) {
146 dprintf(fd, " None\n");
147 break;
148 }
149 }
150
151 dprintf(fd, "\n Last %d Response(s):\n", NUM_UPDATE_RESPONSES);
152 for (i = 0; i < NUM_UPDATE_RESPONSES; ++i) {
153 if (dump_connection_update(fd, &last_ble_conn_update_responses[i]) < 0 &&
154 i == 0) {
155 dprintf(fd, " None\n");
156 break;
157 }
158 }
159 }
160