1 /******************************************************************************
2 *
3 * Copyright (C) 2009-2018 Realtek Corporation.
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 #define LOG_TAG "rtk_heartbeat"
19 #define RTKBT_RELEASE_NAME "20190717_BT_ANDROID_9.0"
20
21 #include <utils/Log.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <signal.h>
25 #include <termios.h>
26 #include <sys/syscall.h>
27 #include <time.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/eventfd.h>
35 #include <semaphore.h>
36 #include <endian.h>
37 #include <byteswap.h>
38 #include <sys/un.h>
39 #include <stddef.h>
40 #include <sys/socket.h>
41 #include <sys/types.h>
42 #include "bt_hci_bdroid.h"
43 #include "bt_vendor_rtk.h"
44 #include "userial.h"
45 #include "userial_vendor.h"
46 #include "rtk_btservice.h"
47 #include "rtk_poll.h"
48 #include "upio.h"
49
50 #include "bt_vendor_lib.h"
51
52 #define RTKBT_HEARTBEAT_CONF_FILE "/vendor/etc/bluetooth/rtkbt_heartbeat.conf"
53
54 #define HCI_EVT_HEARTBEAT_STATUS_OFFSET (5)
55 #define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L (6)
56 #define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H (7)
57
58 static const uint32_t DEFALUT_HEARTBEAT_TIMEOUT_MS = 1000; // send a per sercond
59 int heartBeatLog = -1;
60 static int heartBeatTimeout = -1;
61 static bool heartbeatFlag = false;
62 static int heartbeatCount = 0;
63 static uint16_t nextSeqNum = 1;
64 static uint16_t cleanupFlag = 0;
65 static pthread_mutex_t heartbeat_mutex;
66
67 #define HCI_CMD_VNDR_HEARTBEAT 0xFC94
68
rtk_trim(char * str)69 static char *rtk_trim(char *str)
70 {
71 char *str_tmp = str;
72 while (isspace(*str_tmp)) {
73 ++str_tmp;
74 }
75
76 if (!*str_tmp) {
77 return str_tmp;
78 }
79
80 char *end_str = str_tmp + strlen(str) - 1;
81 while (end_str > str_tmp && isspace(*end_str)) {
82 --end_str;
83 }
84
85 end_str[1] = '\0';
86 return str_tmp;
87 }
88
load_rtkbt_heartbeat_conf(void)89 static void load_rtkbt_heartbeat_conf(void)
90 {
91 char *split;
92 int ret = -1;
93 char *ret_fgets = 0;
94 FILE *fp = fopen(RTKBT_HEARTBEAT_CONF_FILE, "rt");
95 if (!fp) {
96 HILOGE("%s unable to open file '%s': %s", __func__, RTKBT_HEARTBEAT_CONF_FILE, strerror(errno));
97 return;
98 }
99 int line_num = 0;
100 char line[1024];
101 ret_fgets = fgets(line, sizeof(line), fp);
102 while (ret_fgets > 0) {
103 char *line_ptr = rtk_trim(line);
104 ++line_num;
105
106 // Skip blank and comment lines.
107 if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[') {
108 continue;
109 }
110
111 split = strchr(line_ptr, '=');
112 if (!split) {
113 HILOGE("%s no key/value separator found on line %d.", __func__, line_num);
114 continue;
115 }
116
117 *split = '\0';
118 char *endptr;
119 if (!strcmp(rtk_trim(line_ptr), "HeartBeatTimeOut")) {
120 heartBeatTimeout = strtol(rtk_trim(split + 1), &endptr, 0);
121 } else if (!strcmp(rtk_trim(line_ptr), "HeartBeatLog")) {
122 heartBeatLog = strtol(rtk_trim(split + 1), &endptr, 0);
123 }
124 }
125
126 ret = fclose(fp);
127 if (ret < 0) {
128 HILOGE("");
129 }
130 }
131
rtkbt_heartbeat_send_hw_error(uint8_t status,uint16_t seqnum,uint16_t next_seqnum,int heartbeatCnt)132 static void rtkbt_heartbeat_send_hw_error(uint8_t status, uint16_t seqnum, uint16_t next_seqnum, int heartbeatCnt)
133 {
134 if (!heartbeatFlag) {
135 return;
136 }
137 unsigned char p_buf[100];
138 int length;
139 #define P_BUF_2 2
140 #define P_BUF_3 3
141 #define P_BUF_4 4
142 p_buf[0] = HCIT_TYPE_EVENT; // event
143 p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT; // firmwre event log
144 p_buf[P_BUF_3] = 0x01; // host log opcode
145 length = sprintf_s((char *)&p_buf[P_BUF_4], sizeof(p_buf), "host stack: heartbeat hw error: %d:%d:%d:%d",
146 status, seqnum, next_seqnum, heartbeatCnt);
147 if (length == -1) {
148 }
149 p_buf[P_BUF_2] = length + P_BUF_2; // len
150 length = length + 1 + P_BUF_4;
151 userial_recv_rawdata_hook(p_buf, length);
152
153 length = P_BUF_4;
154 p_buf[0] = HCIT_TYPE_EVENT; // event
155 p_buf[1] = HCI_HARDWARE_ERROR_EVT; // hardware error
156 p_buf[P_BUF_2] = 0x01; // len
157 p_buf[P_BUF_3] = 0xfc; // heartbeat error code
158 userial_recv_rawdata_hook(p_buf, length);
159 }
160
rtkbt_heartbeat_cmpl_cback(HC_BT_HDR * p_params)161 static void rtkbt_heartbeat_cmpl_cback(HC_BT_HDR *p_params)
162 {
163 uint8_t status = 0;
164 uint16_t seqnum = 0;
165 HC_BT_HDR *p_evt_buf = p_params;
166
167 if (!heartbeatFlag) {
168 return;
169 }
170
171 #define BUF_DATA_8 8
172 if (p_params != NULL) {
173 p_evt_buf = (HC_BT_HDR *)p_params;
174 status = p_evt_buf->data[HCI_EVT_HEARTBEAT_STATUS_OFFSET];
175 seqnum = p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H] << BUF_DATA_8 |
176 p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L];
177 }
178
179 if (status == 0 && seqnum == nextSeqNum) {
180 nextSeqNum = (seqnum + 1);
181 pthread_mutex_lock(&heartbeat_mutex);
182 heartbeatCount = 0;
183 pthread_mutex_unlock(&heartbeat_mutex);
184 } else {
185 HILOGE("rtkbt_heartbeat_cmpl_cback: Current SeqNum = %d,should SeqNum=%d, status = %d", seqnum, nextSeqNum,
186 status);
187 HILOGE("heartbeat event missing: restart bluedroid stack\n");
188 #define CBACK_USLEEP_1000 1000
189 usleep(CBACK_USLEEP_1000);
190 rtkbt_heartbeat_send_hw_error(status, seqnum, nextSeqNum, heartbeatCount);
191 }
192 }
193
heartbeat_timed_out(void)194 static void heartbeat_timed_out(void) // (union sigval arg)
195 {
196 Rtk_Service_Data *p_buf;
197 int count;
198
199 if (!heartbeatFlag) {
200 return;
201 }
202 pthread_mutex_lock(&heartbeat_mutex);
203 heartbeatCount++;
204 #define COUNT_3 3
205 if (heartbeatCount >= COUNT_3) {
206 if (cleanupFlag == 1) {
207 HILOGW("Already cleanup, ignore.");
208 pthread_mutex_unlock(&heartbeat_mutex);
209 return;
210 }
211 HILOGE("heartbeat_timed_out: heartbeatCount = %d, expected nextSeqNum = %d", heartbeatCount, nextSeqNum);
212 HILOGE("heartbeat_timed_out,controller may be suspend! Now restart bluedroid stack\n");
213 count = heartbeatCount;
214 pthread_mutex_unlock(&heartbeat_mutex);
215 #define TIME_OUT_USLEEP_1000 1000
216 usleep(TIME_OUT_USLEEP_1000);
217 rtkbt_heartbeat_send_hw_error(0, 0, nextSeqNum, count);
218
219 return;
220 }
221 pthread_mutex_unlock(&heartbeat_mutex);
222 if (heartbeatFlag) {
223 p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
224 if (p_buf == NULL) {
225 HILOGE("p_buf: allocate error");
226 return;
227 }
228 p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
229 p_buf->parameter = NULL;
230 p_buf->parameter_len = 0;
231 p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
232
233 Rtk_Service_Vendorcmd_Hook(p_buf, -1);
234 free(p_buf);
235 poll_timer_flush();
236 }
237 }
238
rtkbt_heartbeat_beginTimer_func(void)239 static void rtkbt_heartbeat_beginTimer_func(void)
240 {
241 Rtk_Service_Data *p_buf;
242
243 if ((heartBeatTimeout != -1) && (heartBeatLog != -1)) {
244 poll_init(heartbeat_timed_out, heartBeatTimeout);
245 } else {
246 heartBeatLog = 0;
247 poll_init(heartbeat_timed_out, DEFALUT_HEARTBEAT_TIMEOUT_MS);
248 }
249 poll_enable(TRUE);
250
251 p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
252 if (p_buf == NULL) {
253 HILOGE("p_buf: allocate error");
254 return;
255 }
256 p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
257 p_buf->parameter = NULL;
258 p_buf->parameter_len = 0;
259 p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
260
261 Rtk_Service_Vendorcmd_Hook(p_buf, -1);
262 free(p_buf);
263
264 poll_timer_flush();
265 }
266
Heartbeat_cleanup(void)267 void Heartbeat_cleanup(void)
268 {
269 if (!heartbeatFlag) {
270 return;
271 }
272 heartbeatFlag = false;
273 nextSeqNum = 1;
274 heartbeatCount = 0;
275 cleanupFlag = 1;
276 poll_enable(FALSE);
277 poll_cleanup();
278 }
279
Heartbeat_init(void)280 void Heartbeat_init(void)
281 {
282 int res;
283 HILOGD("Heartbeat_init start");
284 Heartbeat_cleanup();
285 load_rtkbt_heartbeat_conf();
286 pthread_mutex_init(&heartbeat_mutex, NULL);
287 heartbeatFlag = true;
288 heartbeatCount = 0;
289 cleanupFlag = 0;
290 res = get_heartbeat_from_hardware();
291 HILOGD("Heartbeat_init res = %x", res);
292 if (res == 1) {
293 rtkbt_heartbeat_beginTimer_func();
294 } else {
295 Heartbeat_cleanup();
296 }
297 HILOGD("Heartbeat_init end");
298 }
299