2 * This file is part of hayes-ril.
4 * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #define LOG_TAG "RIL-AT"
23 #include <utils/Log.h>
25 #include <hayes-ril.h>
31 struct at_responses_handling at_responses_handling;
37 int at_strings_compare(char *major, char *minor)
39 int major_length = strlen(major);
40 int minor_length = strlen(minor);
42 // We can't check against the whole major string
43 if(major_length > minor_length)
46 if(strncmp(major, minor, major_length) == 0)
52 // Major is response string, minor is request (reference) string
53 int at_commands_compare(char *major, char *minor)
57 // Assume major is corect
59 if(at_strings_compare(major, minor))
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);
66 if(at_strings_compare("AT", major) && !at_strings_compare("AT", minor) && strlen(major) > 2)
67 return at_strings_compare(major + 2, minor);
72 void at_string_clean(char *string, int length)
76 for(i=length-1; i >= 0 ; i--) {
77 if(!isprint(string[i]))
82 int at_status_error(int status)
85 case AT_STATUS_CONNECT:
98 int at_line_parse_status(char *data, int length, char **error_p)
100 char *response_command = NULL;
101 char *response_error = NULL;
102 int response_error_length = 0;
106 if(at_strings_compare("OK", data)) {
111 if(at_strings_compare("CONNECT", data)) {
113 return AT_STATUS_CONNECT;
116 if(at_strings_compare("ERROR", data)) {
118 return AT_STATUS_ERROR;
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;
128 if(response_command != NULL)
129 free(response_command);
131 return AT_STATUS_CME_ERROR;
134 return AT_STATUS_UNDEF;
137 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
140 int string_length = 0;
141 int close_your_eyes = 0;
146 for(i=0 ; i < length ; i++) {
147 if(data[i] == ':' && mark == 0) {
151 string_length = i + 1;
152 string = strndup(data, string_length);
154 if(!isprint(string[0])) {
157 *response_command = string;
163 while(isspace(data[i+1])) {
170 if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
171 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
173 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
176 if(data[i] == '\'') {
177 if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
178 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
180 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
183 // Found = or ? outside of any quotes: assume no data
184 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
187 string_length = i + 1;
188 string = strndup(data, string_length);
190 if(!isprint(string[0])) {
193 *response_command = string;
201 if(length - mark > 0) {
202 string_length = length - mark;
203 string = strndup(data + mark, string_length);
206 *response_command = string;
209 *response_data = string;
210 return string_length;
218 * Responses line processor
221 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
223 struct at_response **responses = NULL;
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;
231 char **response_previous_data = NULL;
232 int response_data_count = 0;
238 if(responses_p == NULL || data == NULL || length < 0) {
239 LOGE("Failed to process AT response: wrong arguments!");
243 responses = *responses_p;
246 response_status = at_line_parse_status(data, length, &response_error);
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;
255 // Do not alloc a new response
262 // Alloc a new response
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
269 // Alloc the array with the new size
270 *responses_p = malloc(sizeof(struct at_response *) * count);
272 // Copy and free previous data
273 if(responses != NULL) {
274 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
278 responses = *responses_p;
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;
286 // Parse command and data
287 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
289 if(response_command == NULL) {
290 LOGE("Failed to parse command!");
291 return responses_count;
294 at_string_clean(response_command, strlen(response_command) + 1);
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
306 // Alloc a new response
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
313 // Alloc the array with the new size
314 *responses_p = malloc(sizeof(struct at_response *) * count);
316 // Copy and free previous data
317 if(responses != NULL) {
318 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
322 responses = *responses_p;
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;
330 if(response_data_length > 0 && response_data != NULL) {
331 at_string_clean(response_data, response_data_length);
333 response_previous_data = responses[index]->data;
335 // Data count is the total count of elements in the request data
336 response_data_count = responses[index]->data_count + 1;
338 // Alloc the array with the new size
339 responses[index]->data = malloc(sizeof(char *) * response_data_count);
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);
347 responses[index]->data_count = response_data_count;
348 responses[index]->data[response_data_count - 1] = response_data;
352 return count > responses_count ? count : responses_count;
356 * Responses structures processing
359 int at_responses_process(struct at_response ***responses_p, char *data, int length)
361 int responses_count = 0;
365 int string_length = 0;
369 if(responses_p == NULL || data == NULL || length < 0) {
370 LOGE("Failed to process AT response: wrong arguments!");
374 for(i=0 ; i < length ; i++) {
375 if(data[i] == '\r' || data[i] == ';') {
379 string_length = i - mark + 1;
380 string = strndup(data + mark, string_length);
382 if(!isprint(string[0])) {
386 count = at_responses_process_line(responses_p, responses_count, string, string_length);
387 if(count > responses_count)
388 responses_count = count;
396 while(isspace(data[i+1])) {
403 if(length - mark > 0) {
404 for(i=mark ; i < length ; i++)
405 if(!isprint(data[i]))
409 string_length = i - mark + 1;
410 string = calloc(1, string_length);
412 memcpy(string, data + mark, string_length - 1);
413 string[string_length - 1] = '\0';
415 count = at_responses_process_line(responses_p, responses_count, string , string_length);
416 if(count > responses_count)
417 responses_count = count;
423 return responses_count;
426 void at_response_free(struct at_response *response)
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;
438 free(response->data);
439 response->data_count = 0;
442 if(response->command != NULL) {
443 free(response->command);
444 response->command = NULL;
447 if(response->error != NULL) {
448 free(response->error);
449 response->error = NULL;
453 void at_responses_free(struct at_response **responses, int responses_count)
457 for(i=0 ; i < responses_count ; i++) {
458 at_response_free(responses[i]);
466 void at_responses_handling_init(void)
468 memset(&at_responses_handling, 0, sizeof(struct at_responses_handling));
469 pthread_mutex_init(&(at_responses_handling.sync_mutex), NULL);
473 AT_RESPONSES_QUEUE_LOCK();
476 void at_responses_handling_sync_clean(void)
478 if(at_responses_handling.sync_request != NULL) {
479 at_request_free(at_responses_handling.sync_request);
480 at_responses_handling.sync_request = NULL;
483 if(at_responses_handling.sync_response != NULL) {
484 at_response_free(at_responses_handling.sync_response);
485 at_responses_handling.sync_response = NULL;
493 int at_response_queue(struct at_response *response)
495 struct at_response **responses = NULL;
499 if(response == NULL) {
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
510 // Save the previous data pointer
511 responses = at_responses_handling.responses_queue.responses;
513 // Alloc the array with the new size
514 at_responses_handling.responses_queue.responses = malloc(sizeof(struct at_response *) * count);
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);
522 responses = at_responses_handling.responses_queue.responses;
524 // Alloc new structure and copy obtained data
525 responses[index] = response;
527 at_responses_handling.responses_queue.responses_count = count;
529 AT_RESPONSES_UNLOCK();
531 AT_RESPONSES_QUEUE_UNLOCK();
536 struct at_response *at_response_dequeue(void)
538 struct at_response *response = NULL;
539 struct at_response **responses = NULL;
540 int responses_count = 0;
547 responses = at_responses_handling.responses_queue.responses;
548 responses_count = at_responses_handling.responses_queue.responses_count;
550 if(responses_count <= 0 && responses == NULL) {
551 LOGE("No response queued, blocking!");
553 AT_RESPONSES_UNLOCK();
554 AT_RESPONSES_QUEUE_LOCK();
557 responses = at_responses_handling.responses_queue.responses;
558 responses_count = at_responses_handling.responses_queue.responses_count;
561 for(i=0 ; i < responses_count ; i++) {
562 if(responses[i] != NULL) {
563 response = responses[i];
569 if(response == NULL) {
570 LOGD("Found no valid response, aborting!");
571 AT_RESPONSES_UNLOCK();
575 responses[pos] = NULL;
577 // Move the elements back
578 for(i=pos ; i < responses_count-1 ; i--) {
579 responses[i] = responses[i+1];
582 // Empty the latest element
583 if(pos != responses_count-1) {
584 responses[responses_count-1] = NULL;
587 at_responses_handling.responses_queue.responses_count--;
589 if(at_responses_handling.responses_queue.responses_count == 0) {
591 at_responses_handling.responses_queue.responses = NULL;
594 AT_RESPONSES_UNLOCK();
603 void at_request_expect_to_func_release(struct at_async_request *request)
605 struct at_async_request **requests = NULL;
606 int requests_count = 0;
613 requests = at_responses_handling.async_queue.requests;
614 requests_count = at_responses_handling.async_queue.requests_count;
616 for(i=0 ; i < requests_count ; i++) {
617 if(requests[i] == request) {
624 LOGD("Found no matching request, aborting release!");
628 if(requests[pos]->command != NULL)
629 free(requests[pos]->command);
632 requests[pos] = NULL;
634 // Move the elements back
635 for(i=pos ; i < requests_count-1 ; i--) {
636 requests[i] = requests[i+1];
639 // Empty the latest element
640 if(pos != requests_count-1) {
641 requests[requests_count-1] = NULL;
644 at_responses_handling.async_queue.requests_count--;
646 if(at_responses_handling.async_queue.requests_count == 0) {
648 at_responses_handling.async_queue.requests = NULL;
652 int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
654 struct at_async_request **requests = NULL;
658 if(command == NULL || func == NULL) {
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
669 // Save the previous data pointer
670 requests = at_responses_handling.async_queue.requests;
672 // Alloc the array with the new size
673 at_responses_handling.async_queue.requests = malloc(sizeof(struct at_async_request *) * count);
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);
681 requests = at_responses_handling.async_queue.requests;
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;
690 at_responses_handling.async_queue.requests_count = count;
692 LOGD("Registered async function for command: %s", command);
699 struct at_async_request *at_request_expect_to_func_find(char *command)
701 struct at_async_request *request = NULL;
702 struct at_async_request **requests = NULL;
703 int requests_count = 0;
713 requests = at_responses_handling.async_queue.requests;
714 requests_count = at_responses_handling.async_queue.requests_count;
716 if(requests == NULL) {
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);
726 request = requests[i];
738 int at_response_expect_to_func(struct at_response *response)
740 struct at_async_request *request = NULL;
743 if(response == NULL || response->command == NULL)
746 request = at_request_expect_to_func_find(response->command);
747 if(request == NULL || request->func == NULL) {
750 LOGD("Found a matching request!");
753 // This must run out of any mutex
754 rc = request->func(response, request->data, request->token);
756 if(rc != AT_RESPONSE_UNHANDELD) {
758 at_request_expect_to_func_release(request);
769 void at_response_expect_status_release(void)
772 at_responses_handling_sync_clean();
776 int at_request_expect_status(struct at_request *request)
778 // Register the request
783 if(at_responses_handling.sync_request != NULL) {
784 LOGE("There is already an AT sync request waiting, aborting!");
788 if(request->command == NULL) {
789 LOGE("No command was given, aborting!");
793 at_responses_handling.sync_request = request;
798 int at_response_expect_status(struct at_response *response)
805 if(at_responses_handling.sync_request == NULL) {
809 if(response->status == AT_STATUS_UNDEF) {
810 // Only unlock if there is a status and command differs
814 if(response->command != NULL) {
815 rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
817 // Only unlock is there is no async request waiting with this command!
818 if(at_request_expect_to_func_find(response->command) == NULL) {
826 at_responses_handling.sync_response = response;
833 int at_expect_status(struct at_request *request)
840 // Second lock: block until sync_response is there
843 if(at_responses_handling.sync_response == NULL)
846 if(at_responses_handling.sync_response->command != NULL) {
847 rc = at_commands_compare(at_responses_handling.sync_response->command, request->command);
849 LOGE("Obtained command doesn't match, aborting!");
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);
865 int at_request_send(struct at_request *request)
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;
878 int offset_separator_end = 0;
879 int length_separator_end = 0;
883 // TODO: Do we send \r\n or only \r, begining/end or just end?
884 char separator[] = "\r\n";
885 char data_separator[] = "=";
887 if(request->command == NULL)
890 offset_separator_begin = 0;
891 length_separator_begin = strlen(separator);
892 length += length_separator_begin;
894 offset_command = length;
895 length_command = strlen(request->command);
896 length += length_command;
898 if(request->data != NULL) {
899 offset_data_separator = length;
900 length_data_separator = strlen(data_separator);
901 length += length_data_separator;
903 offset_data = length;
904 length_data = strlen(request->data);
905 length += length_data;
908 offset_separator_end = length;
909 length_separator_end = strlen(separator);
910 length += length_separator_end;
912 // Alloc final string
913 string = calloc(1, length);
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);
922 memcpy(string + offset_separator_end, separator, length_separator_end);
926 ril_data_log(string, length);
927 ril_send_log(request);
930 ril_device_send(ril_device, string, length);
937 struct at_request *at_request_create(char *command, char *data)
939 struct at_request *request = NULL;
945 request = calloc(1, sizeof(struct at_request));
947 asprintf(&(request->command), "%s", command);
950 asprintf(&(request->data), "%s", data);
956 void at_request_free(struct at_request *request)
960 if(request->command != NULL)
961 free(request->command);
963 if(request->data != NULL)
966 if(request->error != NULL)
967 free(request->error);
974 int at_send(char *command, char *data)
976 struct at_request *request = NULL;
979 request = at_request_create(command, data);
980 if(request == NULL) {
981 LOGE("Unable to create request, aborting!");
985 rc = at_request_send(request);
987 LOGE("Unable to send request, aborting!");
988 at_request_free(request);
992 at_request_free(request);
997 int at_send_command(char *command)
999 return at_send(command, NULL);
1002 int at_send_expect_status(char *command, char *data)
1004 struct at_request *request = NULL;
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;
1018 rc = at_request_send(request);
1020 LOGE("Unable to send request, aborting!");
1021 at_response_expect_status_release();
1022 return AT_STATUS_INTERNAL_ERROR;
1025 rc = at_request_expect_status(request);
1027 LOGE("Unable to request expect status, aborting!");
1028 at_response_expect_status_release();
1029 return AT_STATUS_INTERNAL_ERROR;
1033 rc = at_expect_status(request);
1035 LOGE("Unable to get expected status, aborting!");
1036 at_response_expect_status_release();
1037 return AT_STATUS_INTERNAL_ERROR;
1040 status = request->status;
1042 // Release sync structures and lock the mutex
1043 at_response_expect_status_release();
1048 int at_send_expect_to_func(char *command, char *data, void *pdata, RIL_Token t, at_async_request_cb func)
1050 struct at_request *request = NULL;
1056 request = at_request_create(command, data);
1057 if(request == NULL) {
1058 LOGE("Unable to create request, aborting!");
1062 rc = at_request_expect_to_func(command, pdata, t, func);
1064 LOGE("Unable to request expect to func, aborting!");
1065 at_request_free(request);
1068 rc = at_request_send(request);
1070 LOGE("Unable to send request, aborting!");
1071 at_request_free(request);