• 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 <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