2c0605b4c845faf7652ad992619b8b4e59ae0549
[hayes-ril.git] / at.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <string.h>
20 #include <ctype.h>
21
22 #define LOG_TAG "RIL-AT"
23 #include <utils/Log.h>
24
25 #include <hayes-ril.h>
26
27 /*
28  * Globals
29  */
30
31 struct at_responses_handling at_responses_handling;
32
33 /*
34  * Utilities
35  */
36
37 int at_strings_compare(char *major, char *minor)
38 {
39         int major_length = strlen(major);
40         int minor_length = strlen(minor);
41
42         // We can't check against the whole major string
43         if(major_length > minor_length)
44                 return 0;
45
46         if(strncmp(major, minor, major_length) == 0)
47                 return 1;
48         else
49                 return 0;
50 }
51
52 // Major is response string, minor is request (reference) string
53 int at_commands_compare(char *major, char *minor)
54 {
55         int rc;
56
57         // Assume major is corect
58
59         if(at_strings_compare(major, minor))
60                 return 1;
61
62         // Compare without AT prefix
63         if(at_strings_compare("AT", minor) && !at_strings_compare("AT", major) && strlen(minor) > 2)
64                 return at_strings_compare(major, minor + 2);
65
66         if(at_strings_compare("AT", major) && !at_strings_compare("AT", minor) && strlen(major) > 2)
67                 return at_strings_compare(major + 2, minor);
68
69         return 0;
70 }
71
72 void at_string_clean(char *string, int length)
73 {
74         int i=0;
75
76         for(i=length-1; i >= 0 ; i--) {
77                 if(!isprint(string[i]))
78                         string[i] = '\0';
79         }
80 }
81
82 int at_status_error(int status)
83 {
84         switch(status) {
85                 case AT_STATUS_CONNECT:
86                         return 0;
87                 case AT_STATUS_OK:
88                         return 0;
89                 default:
90                         return 1;
91         }
92 }
93
94 /*
95  * Line parsers
96  */
97
98 int at_line_parse_status(char *data, int length, char **error_p)
99 {
100         char *response_command = NULL;
101         char *response_error = NULL;
102         int response_error_length = 0;
103
104         *error_p = NULL;
105
106         if(at_strings_compare("OK", data)) {
107                 *error_p = NULL;
108                 return AT_STATUS_OK;
109         }
110
111         if(at_strings_compare("CONNECT", data)) {
112                 *error_p = NULL;
113                 return AT_STATUS_CONNECT;
114         }
115
116         if(at_strings_compare("ERROR", data)) {
117                 *error_p = NULL;
118                 return AT_STATUS_ERROR;
119         }
120
121         if(at_strings_compare("+CME ERROR", data)) {
122                 response_error_length = at_line_parse_command_data(data, length, &response_command, &response_error);
123                 if(response_error != NULL && response_error_length > 0) {
124                         at_string_clean(response_error, strlen(response_error) + 1);
125                         *error_p = response_error;
126                 }
127
128                 if(response_command != NULL)
129                         free(response_command);
130
131                 return AT_STATUS_CME_ERROR;
132         }
133
134         return AT_STATUS_UNDEF;
135 }
136
137 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
138 {
139         char *string = NULL;
140         int string_length = 0;
141         int close_your_eyes = 0;
142         int mark = 0;
143         int i;
144
145
146         for(i=0 ; i < length ; i++) {
147                 if(data[i] == ':' && mark == 0) {
148                         if(i > 0) {
149                                 data[i] = '\0';
150
151                                 string_length = i + 1;
152                                 string = strndup(data, string_length);
153
154                                 if(!isprint(string[0])) {
155                                         free(string);
156                                 } else {
157                                         *response_command = string;
158                                 }
159
160                                 mark = i + 1;
161                         }
162
163                         while(isspace(data[i+1])) {
164                                 mark = i + 2;
165                                 i++;
166                         }
167                 }
168
169                 if(data[i] == '"') {
170                         if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
171                                 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
172                         else
173                                 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
174                 }
175
176                 if(data[i] == '\'') {
177                         if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
178                                 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
179                         else
180                                 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
181                 }
182
183                 // Found = or ? outside of any quotes: assume no data
184                 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
185                         data[i] = '\0';
186
187                         string_length = i + 1;
188                         string = strndup(data, string_length);
189
190                         if(!isprint(string[0])) {
191                                 free(string);
192                         } else {
193                                 *response_command = string;
194                         }
195
196                         return 0;
197                 }
198         }
199
200
201         if(length - mark > 0) {
202                 string_length = length - mark;
203                 string = strndup(data + mark, string_length);
204
205                 if(mark == 0) {
206                         *response_command = string;
207                         return 0;
208                 } else {
209                         *response_data = string;
210                         return string_length;
211                 }
212         }
213
214         return 0;
215 }
216
217 /*
218  * Responses line processor
219  */
220
221 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
222 {
223         struct at_response **responses = NULL;
224
225         char *response_command = NULL;
226         char *response_data = NULL;
227         int response_data_length = 0;
228         char *response_error = NULL;
229         int response_status = 0;
230
231         char **response_previous_data = NULL;
232         int response_data_count = 0;
233
234         int index = -1;
235         int count = 0;
236         int i;
237
238         if(responses_p == NULL || data == NULL || length < 0) {
239                 LOGE("Failed to process AT response: wrong arguments!");
240                 return 0;
241         }
242
243         responses = *responses_p;
244
245         // Parse status
246         response_status = at_line_parse_status(data, length, &response_error);
247
248         if(response_status != AT_STATUS_UNDEF) {
249                 if(responses_count > 0 && responses != NULL) {
250                         for(i=responses_count-1 ; i >= 0; i--) {
251                                 if(responses[i]->status == AT_STATUS_UNDEF) {
252                                         responses[i]->status = response_status;
253                                         responses[i]->error = response_error;
254
255                                         // Do not alloc a new response
256                                         if(index == -1)
257                                                 index = i;
258                                 }
259                         }
260                 }
261
262                 // Alloc a new response
263                 if(index == -1) {
264                         // Index is the request index in the requests array
265                         index = responses_count;
266                         // Count is the total count of requests in the array
267                         count = index + 1;
268
269                         // Alloc the array with the new size
270                         *responses_p = malloc(sizeof(struct at_response *) * count);
271
272                         // Copy and free previous data
273                         if(responses != NULL) {
274                                 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
275                                 free(responses);
276                         }
277
278                         responses = *responses_p;
279
280                         // Alloc new structure and copy obtained data
281                         responses[index] = calloc(1, sizeof(struct at_response));
282                         responses[index]->status = response_status;
283                         responses[index]->error = response_error;
284                 }
285         } else {
286                 // Parse command and data
287                 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
288
289                 if(response_command == NULL) {
290                         LOGE("Failed to parse command!");
291                         return responses_count;
292                 }
293
294                 at_string_clean(response_command, strlen(response_command) + 1);
295
296                 if(responses_count > 0 && responses != NULL) {
297                         for(i=responses_count-1 ; i >= 0; i--) {
298                                 if(responses[i]->command != NULL) {
299                                         if(at_commands_compare(responses[i]->command, response_command))
300                                                 // Do not alloc a new response
301                                                 index = i;
302                                 }
303                         }
304                 }
305
306                 // Alloc a new response
307                 if(index == -1) {
308                         // Index is the request index in the requests array
309                         index = responses_count;
310                         // Count is the total count of requests in the array
311                         count = index + 1;
312
313                         // Alloc the array with the new size
314                         *responses_p = malloc(sizeof(struct at_response *) * count);
315
316                         // Copy and free previous data
317                         if(responses != NULL) {
318                                 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
319                                 free(responses);
320                         }
321
322                         responses = *responses_p;
323
324                         // Alloc new structure and copy obtained data
325                         responses[index] = calloc(1, sizeof(struct at_response));
326                         responses[index]->command = response_command;
327                         responses[index]->status = AT_STATUS_UNDEF;
328                 }
329
330                 if(response_data_length > 0 && response_data != NULL) {
331                         at_string_clean(response_data, response_data_length);
332
333                         response_previous_data = responses[index]->data;
334
335                         // Data count is the total count of elements in the request data
336                         response_data_count = responses[index]->data_count + 1;
337
338                         // Alloc the array with the new size
339                         responses[index]->data = malloc(sizeof(char *) * response_data_count);
340
341                         // Copy and free previous data
342                         if(response_previous_data != NULL) {
343                                 memcpy(responses[index]->data, response_previous_data, sizeof(char *) * responses[index]->data_count);
344                                 free(response_previous_data);
345                         }
346
347                         responses[index]->data_count = response_data_count;
348                         responses[index]->data[response_data_count - 1] = response_data;
349                 }
350         }
351
352         return count > responses_count ? count : responses_count;
353 }
354
355 /*
356  * Responses structures processing
357  */
358
359 int at_responses_process(struct at_response ***responses_p, char *data, int length)
360 {
361         int responses_count = 0;
362         int count = 0;
363
364         char *string = NULL;
365         int string_length = 0;
366         int mark = 0;
367         int i;
368
369         if(responses_p == NULL || data == NULL || length < 0) {
370                 LOGE("Failed to process AT response: wrong arguments!");
371                 return 0;
372         }
373
374         for(i=0 ; i < length ; i++) {
375                 if(data[i] == '\r' || data[i] == ';') {
376                         if(i - mark > 0) {
377                                 data[i] = '\0';
378
379                                 string_length = i - mark + 1;
380                                 string = strndup(data + mark, string_length);
381
382                                 if(!isprint(string[0])) {
383                                         free(string);
384                                 }
385                                 else {
386                                         count = at_responses_process_line(responses_p, responses_count, string, string_length);
387                                         if(count > responses_count)
388                                                 responses_count = count;
389
390                                         free(string);
391                                 }
392
393                                 mark = i + 1;
394                         }
395
396                         while(isspace(data[i+1])) {
397                                 mark = i + 2;
398                                 i++;
399                         }
400                 }
401         }
402
403         if(length - mark > 0) {
404                 for(i=mark ; i < length ; i++)
405                         if(!isprint(data[i]))
406                                 break;
407
408                 if(i - mark > 0) {
409                         string_length = i - mark + 1;
410                         string = calloc(1, string_length);
411
412                         memcpy(string, data + mark, string_length - 1);
413                         string[string_length - 1] = '\0';
414
415                         count = at_responses_process_line(responses_p, responses_count, string , string_length);
416                         if(count > responses_count)
417                                 responses_count = count;
418
419                         free(string);
420                 }
421         }
422
423         return responses_count;
424 }
425
426 void at_response_free(struct at_response *response)
427 {
428         int i;
429
430         if(response->data_count > 0 && response->data != NULL) {
431                 for(i=0 ; i < response->data_count ; i++) {
432                         if(response->data[i] != NULL) {
433                                 free(response->data[i]);
434                                 response->data[i] = NULL;
435                         }
436                 }
437
438                 free(response->data);
439                 response->data_count = 0;
440         }
441
442         if(response->command != NULL) {
443                 free(response->command);
444                 response->command = NULL;
445         }
446
447         if(response->error != NULL) {
448                 free(response->error);
449                 response->error = NULL;
450         }
451 }
452
453 void at_responses_free(struct at_response **responses, int responses_count)
454 {
455         int i;
456
457         for(i=0 ; i < responses_count ; i++) {
458                 at_response_free(responses[i]);
459         }
460 }
461
462 /*
463  * Responses handling
464  */
465
466 void at_responses_handling_init(void)
467 {
468         memset(&at_responses_handling, 0, sizeof(struct at_responses_handling));
469         pthread_mutex_init(&(at_responses_handling.sync_mutex), NULL);
470
471         // First lock
472         AT_SYNC_LOCK();
473         AT_RESPONSES_QUEUE_LOCK();
474 }
475
476 void at_responses_handling_sync_clean(void)
477 {
478         if(at_responses_handling.sync_request != NULL) {
479                 at_request_free(at_responses_handling.sync_request);
480                 at_responses_handling.sync_request = NULL;
481         }
482
483         if(at_responses_handling.sync_response != NULL) {
484                 at_response_free(at_responses_handling.sync_response);
485                 at_responses_handling.sync_response = NULL;
486         }
487 }
488
489 /*
490  * Responses queue
491  */
492
493 int at_response_queue(struct at_response *response)
494 {
495         struct at_response **responses = NULL;
496         int index;
497         int count;
498
499         if(response == NULL) {
500                 return -1;
501         }
502
503         AT_RESPONSES_LOCK();
504
505         // Index is the request index in the responses array
506         index = at_responses_handling.responses_queue.responses_count;
507         // Count is the total count of responses in the array
508         count = index + 1;
509
510         // Save the previous data pointer
511         responses = at_responses_handling.responses_queue.responses;
512
513         // Alloc the array with the new size
514         at_responses_handling.responses_queue.responses = malloc(sizeof(struct at_response *) * count);
515
516         // Copy and free previous data
517         if(responses != NULL) {
518                 memcpy(at_responses_handling.responses_queue.responses, responses, sizeof(struct at_response *) * at_responses_handling.responses_queue.responses_count);
519                 free(responses);
520         }
521
522         responses = at_responses_handling.responses_queue.responses;
523
524         // Alloc new structure and copy obtained data
525         responses[index] = response;
526
527         at_responses_handling.responses_queue.responses_count = count;
528
529         AT_RESPONSES_UNLOCK();
530
531         AT_RESPONSES_QUEUE_UNLOCK();
532
533         return 0;
534 }
535
536 struct at_response *at_response_dequeue(void)
537 {
538         struct at_response *response = NULL;
539         struct at_response **responses = NULL;
540         int responses_count = 0;
541         int pos;
542         int i;
543
544         AT_RESPONSES_LOCK();
545
546         response = NULL;
547         responses = at_responses_handling.responses_queue.responses;
548         responses_count = at_responses_handling.responses_queue.responses_count;
549
550         if(responses_count <= 0 && responses == NULL) {
551                 LOGE("No response queued, blocking!");
552
553                 AT_RESPONSES_UNLOCK();
554                 AT_RESPONSES_QUEUE_LOCK();
555                 AT_RESPONSES_LOCK();
556
557                 responses = at_responses_handling.responses_queue.responses;
558                 responses_count = at_responses_handling.responses_queue.responses_count;
559         }
560
561         for(i=0 ; i < responses_count ; i++) {
562                 if(responses[i] != NULL) {
563                         response = responses[i];
564                         pos = i;
565                         break;
566                 }
567         }
568
569         if(response == NULL) {
570                 LOGD("Found no valid response, aborting!");
571                 AT_RESPONSES_UNLOCK();
572                 return NULL;
573         }
574
575         responses[pos] = NULL;
576
577         // Move the elements back
578         for(i=pos ; i < responses_count-1 ; i--) {
579                 responses[i] = responses[i+1];
580         }
581
582         // Empty the latest element
583         if(pos != responses_count-1) {
584                 responses[responses_count-1] = NULL;
585         }
586
587         at_responses_handling.responses_queue.responses_count--;
588
589         if(at_responses_handling.responses_queue.responses_count == 0) {
590                 free(responses);
591                 at_responses_handling.responses_queue.responses = NULL;
592         }
593
594         AT_RESPONSES_UNLOCK();
595
596         return response;
597 }
598
599 /*
600  * Expect to func
601  */
602
603 void at_request_expect_to_func_release(struct at_async_request *request)
604 {
605         struct at_async_request **requests = NULL;
606         int requests_count = 0;
607         int pos = -1;
608         int i;
609
610         if(request == NULL)
611                 return;
612
613         requests = at_responses_handling.async_queue.requests;
614         requests_count = at_responses_handling.async_queue.requests_count;
615
616         for(i=0 ; i < requests_count ; i++) {
617                 if(requests[i] == request) {
618                         pos = i;
619                         break;
620                 }
621         }
622
623         if(pos == -1) {
624                 LOGD("Found no matching request, aborting release!");
625                 return;
626         }
627
628         if(requests[pos]->command != NULL)
629                 free(requests[pos]->command);
630
631         free(requests[pos]);
632         requests[pos] = NULL;
633
634         // Move the elements back
635         for(i=pos ; i < requests_count-1 ; i--) {
636                 requests[i] = requests[i+1];
637         }
638
639         // Empty the latest element
640         if(pos != requests_count-1) {
641                 requests[requests_count-1] = NULL;
642         }
643
644         at_responses_handling.async_queue.requests_count--;
645
646         if(at_responses_handling.async_queue.requests_count == 0) {
647                 free(requests);
648                 at_responses_handling.async_queue.requests = NULL;
649         }
650 }
651
652 int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
653 {
654         struct at_async_request **requests = NULL;
655         int index;
656         int count;
657
658         if(command == NULL || func == NULL) {
659                 return -1;
660         }
661
662         AT_ASYNC_LOCK();
663
664         // Index is the request index in the requests array
665         index = at_responses_handling.async_queue.requests_count;
666         // Count is the total count of requests in the array
667         count = index + 1;
668
669         // Save the previous data pointer
670         requests = at_responses_handling.async_queue.requests;
671
672         // Alloc the array with the new size
673         at_responses_handling.async_queue.requests = malloc(sizeof(struct at_async_request *) * count);
674
675         // Copy and free previous data
676         if(requests != NULL) {
677                 memcpy(at_responses_handling.async_queue.requests, requests, sizeof(struct at_async_request *) * at_responses_handling.async_queue.requests_count);
678                 free(requests);
679         }
680
681         requests = at_responses_handling.async_queue.requests;
682
683         // Alloc new structure and copy obtained data
684         requests[index] = calloc(1, sizeof(struct at_async_request));
685         requests[index]->command = strdup(command);
686         requests[index]->data = data;
687         requests[index]->token = t;
688         requests[index]->func = func;
689
690         at_responses_handling.async_queue.requests_count = count;
691
692         LOGD("Registered async function for command: %s", command);
693
694         AT_ASYNC_UNLOCK();
695
696         return 0;
697 }
698
699 struct at_async_request *at_request_expect_to_func_find(char *command)
700 {
701         struct at_async_request *request = NULL;
702         struct at_async_request **requests = NULL;
703         int requests_count = 0;
704         int rc;
705         int i;
706
707         if(command == NULL)
708                 return NULL;
709
710         AT_ASYNC_LOCK();
711
712         request = NULL;
713         requests = at_responses_handling.async_queue.requests;
714         requests_count = at_responses_handling.async_queue.requests_count;
715
716         if(requests == NULL) {
717                 AT_ASYNC_UNLOCK();
718                 return NULL;
719         }
720
721         for(i=0 ; i < requests_count ; i++) {
722                 if(requests[i] != NULL) {
723                         if(requests[i]->command != NULL) {
724                                 rc = at_commands_compare(command, requests[i]->command);
725                                 if(rc) {
726                                         request = requests[i];
727                                         break;
728                                 }
729                         }
730                 }
731         }
732
733         AT_ASYNC_UNLOCK();
734
735         return request;
736 }
737
738 int at_response_expect_to_func(struct at_response *response)
739 {
740         struct at_async_request *request = NULL;
741         int rc;
742
743         if(response == NULL || response->command == NULL)
744                 return -1;
745
746         request = at_request_expect_to_func_find(response->command);
747         if(request == NULL || request->func == NULL) {
748                 return -1;
749         } else {
750                 LOGD("Found a matching request!");
751         }
752
753         // This must run out of any mutex
754         rc = request->func(response, request->data, request->token);
755
756         if(rc != AT_RESPONSE_UNHANDELD) {
757                 AT_ASYNC_LOCK();
758                 at_request_expect_to_func_release(request);
759                 AT_ASYNC_UNLOCK();
760         }
761
762         return rc;
763 }
764
765 /*
766  * Expect status
767  */
768
769 void at_response_expect_status_release(void)
770 {
771         AT_SYNC_UNLOCK();
772         at_responses_handling_sync_clean();
773         AT_SYNC_LOCK();
774 }
775
776 int at_request_expect_status(struct at_request *request)
777 {
778         // Register the request
779
780         if(request == NULL)
781                 return -1;
782
783         if(at_responses_handling.sync_request != NULL) {
784                 LOGE("There is already an AT sync request waiting, aborting!");
785                 return -1;
786         }
787
788         if(request->command == NULL) {
789                 LOGE("No command was given, aborting!");
790                 return -1;
791         }
792
793         at_responses_handling.sync_request = request;
794
795         return 0;
796 }
797
798 int at_response_expect_status(struct at_response *response)
799 {
800         int rc;
801
802         if(response == NULL)
803                 return -1;
804
805         if(at_responses_handling.sync_request == NULL) {
806                 return -1;
807         }
808
809         if(response->status == AT_STATUS_UNDEF) {
810                 // Only unlock if there is a status and command differs
811                 return -1;
812         }
813
814         if(response->command != NULL) {
815                 rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
816                 if(!rc) {
817                         // Only unlock is there is no async request waiting with this command!
818                         if(at_request_expect_to_func_find(response->command) == NULL) {
819                                 AT_SYNC_UNLOCK();
820                         }
821
822                         return -1;
823                 }
824         }
825
826         at_responses_handling.sync_response = response;
827
828         AT_SYNC_UNLOCK();
829
830         return 0;
831 }
832
833 int at_expect_status(struct at_request *request)
834 {
835         int rc;
836
837         if(request == NULL)
838                 return -1;
839
840         // Second lock: block until sync_response is there
841         AT_SYNC_LOCK();
842
843         if(at_responses_handling.sync_response == NULL)
844                 return -1;
845
846         if(at_responses_handling.sync_response->command != NULL) {
847                 rc = at_commands_compare(at_responses_handling.sync_response->command, request->command);
848                 if(!rc) {
849                         LOGE("Obtained command doesn't match, aborting!");
850                         return -1;
851                 }
852         }
853
854         request->status = at_responses_handling.sync_response->status;
855         if(at_responses_handling.sync_response->error != NULL)
856                 request->error = strdup(at_responses_handling.sync_response->error);
857
858         return 0;
859 }
860
861 /*
862  * Request
863  */
864
865 int at_request_send(struct at_request *request)
866 {
867         char *string = NULL;
868         int length = 0;
869
870         int offset_separator_begin = 0;
871         int length_separator_begin = 0;
872         int offset_command = 0;
873         int length_command = 0;
874         int offset_data_separator = 0;
875         int length_data_separator = 0;
876         int offset_data = 0;
877         int length_data = 0;
878         int offset_separator_end = 0;
879         int length_separator_end = 0;
880
881         int i, p;
882
883         // TODO: Do we send \r\n or only \r, begining/end or just end?
884         char separator[] = "\r\n";
885         char data_separator[] = "=";
886
887         if(request->command == NULL)
888                 return -1;
889
890         offset_separator_begin = 0;
891         length_separator_begin = strlen(separator);
892         length += length_separator_begin;
893
894         offset_command = length;
895         length_command = strlen(request->command);
896         length += length_command;
897
898         if(request->data != NULL) {
899                 offset_data_separator = length;
900                 length_data_separator = strlen(data_separator);
901                 length += length_data_separator;
902
903                 offset_data = length;
904                 length_data = strlen(request->data);
905                 length += length_data;
906         }
907
908         offset_separator_end = length;
909         length_separator_end = strlen(separator);
910         length += length_separator_end;
911
912         // Alloc final string
913         string = calloc(1, length);
914
915         // Copy the data to the string
916         memcpy(string + offset_separator_begin, separator, length_separator_begin);
917         memcpy(string + offset_command, request->command, length_command);
918         if(request->data != NULL) {
919                 memcpy(string + offset_data_separator, data_separator, length_data_separator);
920                 memcpy(string + offset_data, request->data, length_data);
921         }
922         memcpy(string + offset_separator_end, separator, length_separator_end);
923
924         // Log request
925         RIL_LOG_LOCK();
926         ril_data_log(string, length);
927         ril_send_log(request);
928         RIL_LOG_UNLOCK();
929
930         ril_device_send(ril_device, string, length);
931
932         free(string);
933
934         return 0;
935 }
936
937 struct at_request *at_request_create(char *command, char *data)
938 {
939         struct at_request *request = NULL;
940         int i;
941
942         if(command == NULL)
943                 return NULL;
944
945         request = calloc(1, sizeof(struct at_request));
946
947         asprintf(&(request->command), "%s", command);
948
949         if(data != NULL) {
950                 asprintf(&(request->data), "%s", data);
951         }
952
953         return request;
954 }
955
956 void at_request_free(struct at_request *request)
957 {
958         int i;
959
960         if(request->command != NULL)
961                 free(request->command);
962
963         if(request->data != NULL)
964                 free(request->data);
965
966         if(request->error != NULL)
967                 free(request->error);
968 }
969
970 /*
971  * Send
972  */
973
974 int at_send(char *command, char *data)
975 {
976         struct at_request *request = NULL;
977         int rc;
978
979         request = at_request_create(command, data);
980         if(request == NULL) {
981                 LOGE("Unable to create request, aborting!");
982                 return -1;
983         }
984
985         rc = at_request_send(request);
986         if(rc < 0) {
987                 LOGE("Unable to send request, aborting!");
988                 at_request_free(request);
989                 return -1;
990         }
991
992         at_request_free(request);
993
994         return 0;
995 }
996
997 int at_send_command(char *command)
998 {
999         return at_send(command, NULL);
1000 }
1001
1002 int at_send_expect_status(char *command, char *data)
1003 {
1004         struct at_request *request = NULL;
1005         int status;
1006         int rc;
1007
1008         if(command == NULL)
1009                 return -1;
1010
1011         request = at_request_create(command, data);
1012         if(request == NULL) {
1013                 LOGE("Unable to create request, aborting!");
1014                 at_response_expect_status_release();
1015                 return AT_STATUS_INTERNAL_ERROR;
1016         }
1017
1018         rc = at_request_send(request);
1019         if(rc < 0) {
1020                 LOGE("Unable to send request, aborting!");
1021                 at_response_expect_status_release();
1022                 return AT_STATUS_INTERNAL_ERROR;
1023         }
1024
1025         rc = at_request_expect_status(request);
1026         if(rc < 0) {
1027                 LOGE("Unable to request expect status, aborting!");
1028                 at_response_expect_status_release();
1029                 return AT_STATUS_INTERNAL_ERROR;
1030         }
1031
1032         // Block here
1033         rc = at_expect_status(request);
1034         if(rc < 0) {
1035                 LOGE("Unable to get expected status, aborting!");
1036                 at_response_expect_status_release();
1037                 return AT_STATUS_INTERNAL_ERROR;
1038         }
1039
1040         status = request->status;
1041
1042         // Release sync structures and lock the mutex
1043         at_response_expect_status_release();
1044
1045         return status;
1046 }
1047
1048 int at_send_expect_to_func(char *command, char *data, void *pdata, RIL_Token t, at_async_request_cb func)
1049 {
1050         struct at_request *request = NULL;
1051         int rc;
1052
1053         if(command == NULL)
1054                 return -1;
1055
1056         request = at_request_create(command, data);
1057         if(request == NULL) {
1058                 LOGE("Unable to create request, aborting!");
1059                 return -1;
1060         }
1061
1062         rc = at_request_expect_to_func(command, pdata, t, func);
1063         if(rc < 0) {
1064                 LOGE("Unable to request expect to func, aborting!");
1065                 at_request_free(request);
1066         }
1067
1068         rc = at_request_send(request);
1069         if(rc < 0) {
1070                 LOGE("Unable to send request, aborting!");
1071                 at_request_free(request);
1072                 return -1;
1073         }
1074
1075         return 0;
1076 }