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