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