• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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