• 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     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