1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "at_support.h"
17 #include "vendor_channel.h"
18 #include "vendor_util.h"
19
20 static int32_t g_atFd = -1;
21 static OnNotify g_onNotifyFunc = NULL;
22
23 static volatile ResponseInfo *g_response = NULL;
24 static volatile const char *g_smsPdu = NULL;
25 static volatile bool g_isNeedATPause = false;
26 static volatile const char *g_prefix = NULL;
27 static pthread_mutex_t g_commandmutex = PTHREAD_MUTEX_INITIALIZER;
28 static pthread_cond_t g_commandcond = PTHREAD_COND_INITIALIZER;
29 static volatile int32_t g_readerClosed = 0;
30 static pthread_t g_reader;
31 static void (*g_onTimeout)(void) = NULL;
32 static void (*g_atnUnusual)(void) = NULL;
33 static void (*g_atWatch)(void) = NULL;
34
35 // reader close
36 static void OnReaderClosed(void);
37 // process response
38 static void ProcessResponse(const char *responseLine, const char *pdu);
39 // add item to list
40 static void AddLinkListNode(const char *responseLine);
41 // thread function: readLoop
42 static void ReaderLoop(void);
43 // clear command memory
44 static void ClearCurCommand(void);
45
AtSetOnUnusual(void (* onAtUnusual)(void))46 void AtSetOnUnusual(void (*onAtUnusual)(void))
47 {
48 g_atnUnusual = onAtUnusual;
49 }
50
ATStartReadLoop(int32_t fd,OnNotify func)51 int32_t ATStartReadLoop(int32_t fd, OnNotify func)
52 {
53 int32_t ret = 0;
54 g_atFd = fd;
55 g_onNotifyFunc = func;
56 pthread_attr_t t;
57 pthread_attr_init(&t);
58 pthread_attr_setdetachstate(&t, PTHREAD_CREATE_DETACHED);
59 ret = pthread_create(&g_reader, &t, (void *(*)(void *))ReaderLoop, &t);
60 if (ret < 0) {
61 TELEPHONY_LOGE("create pthread error code: %{public}d", ret);
62 return VENDOR_ERR_PROCESS;
63 }
64 return VENDOR_SUCCESS;
65 }
66
OnReaderClosed(void)67 void OnReaderClosed(void)
68 {
69 if (g_atnUnusual != NULL && g_readerClosed == 0) {
70 g_atnUnusual();
71 }
72 }
73
ATCloseReadLoop(void)74 void ATCloseReadLoop(void)
75 {
76 pthread_mutex_lock(&g_commandmutex);
77 if (g_atFd >= 0) {
78 close(g_atFd);
79 }
80 g_atFd = -1;
81 g_readerClosed = 1;
82 pthread_cond_signal(&g_commandcond);
83 pthread_mutex_unlock(&g_commandmutex);
84 }
85
FreeResponseInfo(ResponseInfo * resp)86 void FreeResponseInfo(ResponseInfo *resp)
87 {
88 Line *p = NULL;
89 if (resp == NULL) {
90 TELEPHONY_LOGE("enter resp is null");
91 return;
92 }
93 p = resp->head;
94 if (p == NULL && resp->result != NULL) {
95 free(resp->result);
96 resp->result = NULL;
97 return;
98 }
99 while (p != NULL) {
100 Line *t = NULL;
101 t = p;
102 p = p->next;
103 if (t->data != NULL) {
104 free(t->data);
105 t->data = NULL;
106 }
107 free(t);
108 t = NULL;
109 }
110 if (resp->result != NULL) {
111 free(resp->result);
112 resp->result = NULL;
113 }
114 free(resp);
115 resp = NULL;
116 }
117
ReaderLoop(void)118 void ReaderLoop(void)
119 {
120 TELEPHONY_LOGD("%{public}s enter", __func__);
121 g_readerClosed = 0;
122 while (1) {
123 const char *str = NULL;
124 const char *pdu = NULL;
125 str = ReadResponse(g_atFd);
126 if (str == NULL) {
127 TELEPHONY_LOGE("str is null");
128 break;
129 }
130 if (IsSmsNotify(str)) {
131 TELEPHONY_LOGI("new sms notify :%{public}s", str);
132 pdu = ReadResponse(g_atFd);
133 }
134 ProcessResponse(str, pdu);
135 }
136 OnReaderClosed();
137 }
138
IsResponseOtherCases(const OnNotify g_onNotifyFunc,pthread_mutex_t * g_commandmutex,const char * responseLine,const char * pdu)139 static void IsResponseOtherCases(
140 const OnNotify g_onNotifyFunc, pthread_mutex_t *g_commandmutex, const char *responseLine, const char *pdu)
141 {
142 if (g_commandmutex == NULL) {
143 TELEPHONY_LOGE("g_commandmutex is null");
144 return;
145 }
146 if (g_onNotifyFunc != NULL) {
147 pthread_mutex_unlock(g_commandmutex);
148 g_onNotifyFunc(responseLine, pdu);
149 }
150 }
151
ProcessResponse(const char * responseLine,const char * pdu)152 void ProcessResponse(const char *responseLine, const char *pdu)
153 {
154 if (responseLine == NULL) {
155 TELEPHONY_LOGE("responseLine is null");
156 return;
157 }
158
159 TELEPHONY_LOGI("processLine line = %{public}s", responseLine);
160 int32_t isPrefix = ReportStrWith(responseLine, (const char *)g_prefix);
161 pthread_mutex_lock(&g_commandmutex);
162 if (g_response == NULL) {
163 if (g_onNotifyFunc != NULL) {
164 pthread_mutex_unlock(&g_commandmutex);
165 g_onNotifyFunc(responseLine, pdu);
166 return;
167 }
168 } else if (IsResponseError(responseLine)) {
169 if (g_response != NULL) {
170 g_response->success = 0;
171 g_response->result = strdup(responseLine);
172 }
173 pthread_cond_signal(&g_commandcond);
174 } else if (IsResponseSuccess(responseLine)) {
175 if (g_response != NULL) {
176 g_response->success = 1;
177 g_response->result = strdup(responseLine);
178 }
179 pthread_cond_signal(&g_commandcond);
180 } else if (IsSms(responseLine) && g_smsPdu != NULL) {
181 if (g_response != NULL) {
182 g_response->result = strdup(responseLine);
183 WriteATCommand((const char *)g_smsPdu, 1, g_atFd);
184 }
185 } else {
186 if (((isdigit(responseLine[0]) || isPrefix) && g_smsPdu == NULL) || (g_smsPdu != NULL && isPrefix)) {
187 AddLinkListNode(responseLine);
188 } else {
189 IsResponseOtherCases(g_onNotifyFunc, &g_commandmutex, responseLine, pdu);
190 return;
191 }
192 }
193 pthread_mutex_unlock(&g_commandmutex);
194 }
195
AddLinkListNode(const char * responseLine)196 void AddLinkListNode(const char *responseLine)
197 {
198 if (g_response == NULL || responseLine == NULL) {
199 TELEPHONY_LOGE("response is null");
200 return;
201 }
202
203 Line *line = (Line *)malloc(sizeof(Line));
204 if (line == NULL) {
205 TELEPHONY_LOGE("malloc memory error");
206 return;
207 }
208 line->data = strdup(responseLine);
209 line->next = NULL;
210 if (g_response->last != NULL) {
211 g_response->last->next = line;
212 } else {
213 g_response->head = line;
214 }
215 g_response->last = line;
216 }
217
SendCommandLock(const char * command,const char * prefix,long long timeout,ResponseInfo ** outResponse)218 int32_t SendCommandLock(const char *command, const char *prefix, long long timeout, ResponseInfo **outResponse)
219 {
220 const char *atCmd = "AT";
221 int32_t err;
222 if (pthread_equal(g_reader, pthread_self()) != 0) {
223 TELEPHONY_LOGE("The read thread prohibits sending commands.");
224 return AT_ERR_INVALID_THREAD;
225 }
226
227 pthread_mutex_lock(&g_commandmutex);
228 if (g_isNeedATPause) {
229 pthread_cond_signal(&g_commandcond);
230 err = SendCommandNoLock(atCmd, timeout, outResponse);
231 if (err != 0) {
232 TELEPHONY_LOGI("NeedATPause err = %{public}d", err);
233 }
234 if (g_atWatch != NULL) {
235 g_atWatch();
236 }
237 g_isNeedATPause = false;
238 alarm(0);
239 }
240 g_prefix = prefix;
241 err = SendCommandNoLock(command, timeout, outResponse);
242 pthread_mutex_unlock(&g_commandmutex);
243 TELEPHONY_LOGI("err = %{public}d", err);
244 // when timeout to process
245 if (err == AT_ERR_TIMEOUT && g_onTimeout != NULL) {
246 g_onTimeout();
247 } else if (err == AT_ERR_GENERIC) {
248 TELEPHONY_LOGI("OnReaderClosed() err = %{public}d", err);
249 OnReaderClosed();
250 }
251 return err;
252 }
253
SendCommandNetWorksLock(const char * command,const char * prefix,long long timeout,ResponseInfo ** outResponse)254 int32_t SendCommandNetWorksLock(const char *command, const char *prefix, long long timeout, ResponseInfo **outResponse)
255 {
256 int32_t err;
257 if (pthread_equal(g_reader, pthread_self()) != 0) {
258 TELEPHONY_LOGE("The read thread prohibits sending commands.");
259 return AT_ERR_INVALID_THREAD;
260 }
261 pthread_mutex_lock(&g_commandmutex);
262 g_isNeedATPause = true;
263 g_prefix = prefix;
264 err = SendCommandNoLock(command, timeout, outResponse);
265 pthread_mutex_unlock(&g_commandmutex);
266 TELEPHONY_LOGD("err = %{public}d", err);
267 // when timeout to process
268 if (err == AT_ERR_TIMEOUT) {
269 err = AT_ERR_WAITING;
270 }
271 return err;
272 }
273
SendCommandSmsLock(const char * command,const char * smsPdu,const char * prefix,long long timeout,ResponseInfo ** outResponse)274 int32_t SendCommandSmsLock(
275 const char *command, const char *smsPdu, const char *prefix, long long timeout, ResponseInfo **outResponse)
276 {
277 int32_t err;
278 if (pthread_equal(g_reader, pthread_self()) != 0) {
279 TELEPHONY_LOGE("The read thread prohibits sending commands.");
280 return AT_ERR_INVALID_THREAD;
281 }
282 pthread_mutex_lock(&g_commandmutex);
283 g_prefix = prefix;
284 g_smsPdu = smsPdu;
285 err = SendCommandNoLock(command, timeout, outResponse);
286 pthread_mutex_unlock(&g_commandmutex);
287 TELEPHONY_LOGD("err = %{public}d", err);
288 // when timeout to process
289 if (err == AT_ERR_TIMEOUT && g_onTimeout != NULL) {
290 g_onTimeout();
291 }
292 return err;
293 }
294
NewResponseInfo(void)295 static int32_t NewResponseInfo(void)
296 {
297 int32_t err = VENDOR_SUCCESS;
298 if (g_response != NULL) {
299 err = AT_ERR_COMMAND_PENDING;
300 TELEPHONY_LOGE("g_response is not null, so the command cannot be sent.");
301 ClearCurCommand();
302 return err;
303 }
304 g_response = (ResponseInfo *)calloc(1, sizeof(ResponseInfo));
305 if (g_response == NULL) {
306 err = AT_ERR_GENERIC;
307 TELEPHONY_LOGE("g_response calloc is fail, err:%{public}d.", err);
308 ClearCurCommand();
309 return err;
310 }
311 return err;
312 }
313
SendCommandNoLock(const char * command,long long timeout,ResponseInfo ** outResponse)314 int32_t SendCommandNoLock(const char *command, long long timeout, ResponseInfo **outResponse)
315 {
316 long long defaultTimeOut = DEFAULT_LONG_TIMEOUT;
317 int32_t err = 0;
318 struct timespec time;
319
320 err = NewResponseInfo();
321 if (err != VENDOR_SUCCESS) {
322 TELEPHONY_LOGE("New responseInfo is fail, err:%{public}d.", err);
323 return err;
324 }
325 err = WriteATCommand(command, 0, g_atFd);
326 if (err != VENDOR_SUCCESS) {
327 TELEPHONY_LOGE("send AT cmd is fail, err:%{public}d.", err);
328 ClearCurCommand();
329 return err;
330 }
331 SetWaitTimeout(&time, (timeout != 0) ? timeout : defaultTimeOut);
332 while (g_response != NULL && g_response->result == NULL && g_readerClosed == 0) {
333 err = pthread_cond_timedwait(&g_commandcond, &g_commandmutex, &time);
334 if (err == ETIMEDOUT) {
335 err = AT_ERR_TIMEOUT;
336 TELEPHONY_LOGE("pthread cond timedwait is timeout, err:%{public}d.", err);
337 ClearCurCommand();
338 return err;
339 }
340 }
341 if (outResponse == NULL) {
342 FreeResponseInfo((ResponseInfo *)g_response);
343 } else {
344 *outResponse = (ResponseInfo *)g_response;
345 }
346 g_response = NULL;
347 if (g_readerClosed > 0) {
348 err = AT_ERR_CHANNEL_CLOSED;
349 TELEPHONY_LOGE("g_readerClosed is closed, err:%{public}d.", err);
350 ClearCurCommand();
351 return err;
352 }
353 err = 0;
354 return err;
355 }
356
ClearCurCommand(void)357 void ClearCurCommand(void)
358 {
359 if (g_response != NULL) {
360 FreeResponseInfo((ResponseInfo *)g_response);
361 }
362 g_response = NULL;
363 g_prefix = NULL;
364 }
365
SetWatchFunction(void (* watchFun)(void))366 void SetWatchFunction(void (*watchFun)(void))
367 {
368 g_atWatch = watchFun;
369 }
370
SetAtPauseFlag(bool isNeedPause)371 void SetAtPauseFlag(bool isNeedPause)
372 {
373 g_isNeedATPause = isNeedPause;
374 }
375
GetAtPauseFlag(void)376 bool GetAtPauseFlag(void)
377 {
378 return g_isNeedATPause;
379 }
380