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, NULL);
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 pthread_mutex_unlock(g_commandmutex);
149 if (g_onNotifyFunc != NULL) {
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 if (outResponse != NULL && *outResponse != NULL) {
242 FreeResponseInfo((ResponseInfo *)*outResponse);
243 *outResponse = NULL;
244 }
245 }
246 g_prefix = prefix;
247 err = SendCommandNoLock(command, timeout, outResponse);
248 pthread_mutex_unlock(&g_commandmutex);
249 TELEPHONY_LOGI("err = %{public}d", err);
250 // when timeout to process
251 if (err == AT_ERR_TIMEOUT && g_onTimeout != NULL) {
252 g_onTimeout();
253 } else if (err == AT_ERR_GENERIC) {
254 TELEPHONY_LOGI("OnReaderClosed() err = %{public}d", err);
255 OnReaderClosed();
256 }
257 return err;
258 }
259
SendCommandNetWorksLock(const char * command,const char * prefix,long long timeout,ResponseInfo ** outResponse)260 int32_t SendCommandNetWorksLock(const char *command, const char *prefix, long long timeout, ResponseInfo **outResponse)
261 {
262 int32_t err;
263 if (pthread_equal(g_reader, pthread_self()) != 0) {
264 TELEPHONY_LOGE("The read thread prohibits sending commands.");
265 return AT_ERR_INVALID_THREAD;
266 }
267 pthread_mutex_lock(&g_commandmutex);
268 g_isNeedATPause = true;
269 g_prefix = prefix;
270 err = SendCommandNoLock(command, timeout, outResponse);
271 pthread_mutex_unlock(&g_commandmutex);
272 TELEPHONY_LOGD("err = %{public}d", err);
273 // when timeout to process
274 if (err == AT_ERR_TIMEOUT) {
275 err = AT_ERR_WAITING;
276 }
277 return err;
278 }
279
SendCommandSmsLock(const char * command,const char * smsPdu,const char * prefix,long long timeout,ResponseInfo ** outResponse)280 int32_t SendCommandSmsLock(
281 const char *command, const char *smsPdu, const char *prefix, long long timeout, ResponseInfo **outResponse)
282 {
283 int32_t err;
284 if (pthread_equal(g_reader, pthread_self()) != 0) {
285 TELEPHONY_LOGE("The read thread prohibits sending commands.");
286 return AT_ERR_INVALID_THREAD;
287 }
288 pthread_mutex_lock(&g_commandmutex);
289 g_prefix = prefix;
290 g_smsPdu = smsPdu;
291 err = SendCommandNoLock(command, timeout, outResponse);
292 pthread_mutex_unlock(&g_commandmutex);
293 TELEPHONY_LOGD("err = %{public}d", err);
294 g_smsPdu = NULL;
295 // when timeout to process
296 if (err == AT_ERR_TIMEOUT && g_onTimeout != NULL) {
297 g_onTimeout();
298 }
299 return err;
300 }
301
NewResponseInfo(void)302 static int32_t NewResponseInfo(void)
303 {
304 int32_t err = VENDOR_SUCCESS;
305 if (g_response != NULL) {
306 err = AT_ERR_COMMAND_PENDING;
307 TELEPHONY_LOGE("g_response is not null, so the command cannot be sent.");
308 return err;
309 }
310 g_response = (ResponseInfo *)calloc(1, sizeof(ResponseInfo));
311 if (g_response == NULL) {
312 err = AT_ERR_GENERIC;
313 TELEPHONY_LOGE("g_response calloc is fail, err:%{public}d.", err);
314 ClearCurCommand();
315 return err;
316 }
317 return err;
318 }
319
SendCommandNoLock(const char * command,long long timeout,ResponseInfo ** outResponse)320 int32_t SendCommandNoLock(const char *command, long long timeout, ResponseInfo **outResponse)
321 {
322 long long defaultTimeOut = DEFAULT_LONG_TIMEOUT;
323 int32_t err = 0;
324 struct timespec time;
325
326 err = NewResponseInfo();
327 if (err != VENDOR_SUCCESS) {
328 TELEPHONY_LOGE("New responseInfo is fail, err:%{public}d.", err);
329 return err;
330 }
331 err = WriteATCommand(command, 0, g_atFd);
332 if (err != VENDOR_SUCCESS) {
333 TELEPHONY_LOGE("send AT cmd is fail, err:%{public}d.", err);
334 ClearCurCommand();
335 return err;
336 }
337 SetWaitTimeout(&time, (timeout != 0) ? timeout : defaultTimeOut);
338 while (g_response != NULL && g_response->result == NULL && g_readerClosed == 0) {
339 err = pthread_cond_timedwait(&g_commandcond, &g_commandmutex, &time);
340 if (err == ETIMEDOUT) {
341 err = AT_ERR_TIMEOUT;
342 TELEPHONY_LOGE("pthread cond timedwait is timeout, err:%{public}d.", err);
343 ClearCurCommand();
344 return err;
345 }
346 }
347 if (outResponse == NULL) {
348 FreeResponseInfo((ResponseInfo *)g_response);
349 } else {
350 *outResponse = (ResponseInfo *)g_response;
351 }
352 g_response = NULL;
353 if (g_readerClosed > 0) {
354 err = AT_ERR_CHANNEL_CLOSED;
355 TELEPHONY_LOGE("g_readerClosed is closed, err:%{public}d.", err);
356 ClearCurCommand();
357 return err;
358 }
359 err = 0;
360 return err;
361 }
362
ClearCurCommand(void)363 void ClearCurCommand(void)
364 {
365 if (g_response != NULL) {
366 FreeResponseInfo((ResponseInfo *)g_response);
367 }
368 g_response = NULL;
369 g_prefix = NULL;
370 }
371
SetWatchFunction(void (* watchFun)(void))372 void SetWatchFunction(void (*watchFun)(void))
373 {
374 g_atWatch = watchFun;
375 }
376
SetAtPauseFlag(bool isNeedPause)377 void SetAtPauseFlag(bool isNeedPause)
378 {
379 pthread_mutex_lock(&g_atPauseFlagMutex);
380 g_isNeedATPause = isNeedPause;
381 pthread_mutex_unlock(&g_atPauseFlagMutex);
382 }
383
GetAtPauseFlag(void)384 bool GetAtPauseFlag(void)
385 {
386 bool isNeedPause = FALSE;
387 pthread_mutex_lock(&g_atPauseFlagMutex);
388 isNeedPause = g_isNeedATPause;
389 pthread_mutex_unlock(&g_atPauseFlagMutex);
390 return isNeedPause;
391 }
392