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