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