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