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 int at_strings_raw_compare(char *major, char *minor)
54 int major_length = strlen(major);
56 // Only consider major length (minor might not have \0)
57 if(strncmp(major, minor, major_length) == 0)
63 // Major is response string, minor is request (reference) string
64 int at_commands_compare(char *major, char *minor)
68 // Assume major is corect
70 if(at_strings_compare(major, minor))
73 // Compare without AT prefix
74 if(at_strings_compare("AT", minor) && !at_strings_compare("AT", major) && strlen(minor) > 2)
75 return at_strings_compare(major, minor + 2);
77 if(at_strings_compare("AT", major) && !at_strings_compare("AT", minor) && strlen(major) > 2)
78 return at_strings_compare(major + 2, minor);
83 void at_string_clean(char *string, int length)
87 for(i=length-1; i >= 0 ; i--) {
88 if(!isprint(string[i]))
93 int at_status_error(int status)
96 case AT_STATUS_CONNECT:
109 int at_line_parse_status(char *data, int length, char **error_p)
111 char *response_command = NULL;
112 char *response_error = NULL;
113 int response_error_length = 0;
117 if(at_strings_compare("OK", data)) {
122 if(at_strings_compare("CONNECT", data)) {
124 return AT_STATUS_CONNECT;
127 if(at_strings_compare("ERROR", data)) {
129 return AT_STATUS_ERROR;
132 if(at_strings_compare("+CME ERROR", data)) {
133 response_error_length = at_line_parse_command_data(data, length, &response_command, &response_error);
134 if(response_error != NULL && response_error_length > 0) {
135 at_string_clean(response_error, strlen(response_error) + 1);
136 *error_p = response_error;
139 if(response_command != NULL)
140 free(response_command);
142 return AT_STATUS_CME_ERROR;
145 return AT_STATUS_UNDEF;
148 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
151 int string_length = 0;
152 int close_your_eyes = 0;
157 for(i=0 ; i < length ; i++) {
158 if(data[i] == ':' && mark == 0) {
162 string_length = i + 1;
163 string = strndup(data, string_length);
165 if(!isprint(string[0])) {
168 *response_command = string;
174 while(isspace(data[i+1])) {
181 if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
182 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
184 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
187 if(data[i] == '\'') {
188 if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
189 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
191 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
194 // Found = or ? outside of any quotes: assume no data
195 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
198 string_length = i + 1;
199 string = strndup(data, string_length);
201 if(!isprint(string[0])) {
204 *response_command = string;
212 if(length - mark > 0) {
213 string_length = length - mark;
214 string = strndup(data + mark, string_length);
217 *response_command = string;
220 *response_data = string;
221 return string_length;
229 * Responses line processor
232 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
234 struct at_response **responses = NULL;
236 char *response_command = NULL;
237 char *response_data = NULL;
238 int response_data_length = 0;
239 char *response_error = NULL;
240 int response_status = 0;
242 char **response_previous_data = NULL;
243 int response_data_count = 0;
249 if(responses_p == NULL || data == NULL || length < 0) {
250 LOGE("Failed to process AT response: wrong arguments!");
254 responses = *responses_p;
257 response_status = at_line_parse_status(data, length, &response_error);
259 if(response_status != AT_STATUS_UNDEF) {
260 if(responses_count > 0 && responses != NULL) {
261 for(i=responses_count-1 ; i >= 0; i--) {
262 if(responses[i]->status == AT_STATUS_UNDEF) {
263 responses[i]->status = response_status;
264 responses[i]->error = response_error;
266 // Do not alloc a new response
273 // Alloc a new response
275 // Index is the request index in the requests array
276 index = responses_count;
277 // Count is the total count of requests in the array
280 // Alloc the array with the new size
281 *responses_p = malloc(sizeof(struct at_response *) * count);
283 // Copy and free previous data
284 if(responses != NULL) {
285 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
289 responses = *responses_p;
291 // Alloc new structure and copy obtained data
292 responses[index] = calloc(1, sizeof(struct at_response));
293 responses[index]->status = response_status;
294 responses[index]->error = response_error;
297 // Parse command and data
298 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
300 if(response_command == NULL) {
301 LOGE("Failed to parse command!");
302 return responses_count;
305 at_string_clean(response_command, strlen(response_command) + 1);
307 if(responses_count > 0 && responses != NULL) {
308 for(i=responses_count-1 ; i >= 0; i--) {
309 if(responses[i]->command != NULL) {
310 if(at_commands_compare(responses[i]->command, response_command))
311 // Do not alloc a new response
317 // Alloc a new response
319 // Index is the request index in the requests array
320 index = responses_count;
321 // Count is the total count of requests in the array
324 // Alloc the array with the new size
325 *responses_p = malloc(sizeof(struct at_response *) * count);
327 // Copy and free previous data
328 if(responses != NULL) {
329 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
333 responses = *responses_p;
335 // Alloc new structure and copy obtained data
336 responses[index] = calloc(1, sizeof(struct at_response));
337 responses[index]->command = response_command;
338 responses[index]->status = AT_STATUS_UNDEF;
341 if(response_data_length > 0 && response_data != NULL) {
342 at_string_clean(response_data, response_data_length);
344 response_previous_data = responses[index]->data;
346 // Data count is the total count of elements in the request data
347 response_data_count = responses[index]->data_count + 1;
349 // Alloc the array with the new size
350 responses[index]->data = malloc(sizeof(char *) * response_data_count);
352 // Copy and free previous data
353 if(response_previous_data != NULL) {
354 memcpy(responses[index]->data, response_previous_data, sizeof(char *) * responses[index]->data_count);
355 free(response_previous_data);
358 responses[index]->data_count = response_data_count;
359 responses[index]->data[response_data_count - 1] = response_data;
363 return count > responses_count ? count : responses_count;
367 * Responses structures processing
370 int at_responses_process(struct at_response ***responses_p, char *data, int length)
372 int responses_count = 0;
376 int string_length = 0;
380 if(responses_p == NULL || data == NULL || length < 0) {
381 LOGE("Failed to process AT response: wrong arguments!");
385 for(i=0 ; i < length ; i++) {
386 if(data[i] == '\r' || data[i] == ';') {
390 string_length = i - mark + 1;
391 string = strndup(data + mark, string_length);
393 if(!isprint(string[0])) {
397 count = at_responses_process_line(responses_p, responses_count, string, string_length);
398 if(count > responses_count)
399 responses_count = count;
407 while(isspace(data[i+1])) {
414 if(length - mark > 0) {
415 for(i=mark ; i < length ; i++)
416 if(!isprint(data[i]))
420 string_length = i - mark + 1;
421 string = calloc(1, string_length);
423 memcpy(string, data + mark, string_length - 1);
424 string[string_length - 1] = '\0';
426 count = at_responses_process_line(responses_p, responses_count, string , string_length);
427 if(count > responses_count)
428 responses_count = count;
434 return responses_count;
437 void at_response_free(struct at_response *response)
441 if(response->data_count > 0 && response->data != NULL) {
442 for(i=0 ; i < response->data_count ; i++) {
443 if(response->data[i] != NULL) {
444 free(response->data[i]);
445 response->data[i] = NULL;
449 free(response->data);
450 response->data_count = 0;
453 if(response->command != NULL) {
454 free(response->command);
455 response->command = NULL;
458 if(response->error != NULL) {
459 free(response->error);
460 response->error = NULL;
464 void at_responses_free(struct at_response **responses, int responses_count)
468 for(i=0 ; i < responses_count ; i++) {
469 at_response_free(responses[i]);
477 void at_responses_handling_init(void)
479 memset(&at_responses_handling, 0, sizeof(struct at_responses_handling));
480 pthread_mutex_init(&(at_responses_handling.sync_mutex), NULL);
484 AT_RESPONSES_QUEUE_LOCK();
487 void at_responses_handling_sync_clean(void)
489 if(at_responses_handling.sync_request != NULL) {
490 at_request_free(at_responses_handling.sync_request);
491 at_responses_handling.sync_request = NULL;
494 if(at_responses_handling.sync_response != NULL) {
495 at_response_free(at_responses_handling.sync_response);
496 at_responses_handling.sync_response = NULL;
504 void at_responses_queue_unlock(void)
506 // Only unlock if there are responses available
507 if(at_responses_handling.responses_queue.responses_count > 0 && at_responses_handling.responses_queue.responses != NULL) {
508 AT_RESPONSES_QUEUE_UNLOCK();
512 int at_response_queue(struct at_response *response)
514 struct at_response **responses = NULL;
518 if(response == NULL) {
524 // Index is the request index in the responses array
525 index = at_responses_handling.responses_queue.responses_count;
526 // Count is the total count of responses in the array
529 // Save the previous data pointer
530 responses = at_responses_handling.responses_queue.responses;
532 // Alloc the array with the new size
533 at_responses_handling.responses_queue.responses = malloc(sizeof(struct at_response *) * count);
535 // Copy and free previous data
536 if(responses != NULL) {
537 memcpy(at_responses_handling.responses_queue.responses, responses, sizeof(struct at_response *) * at_responses_handling.responses_queue.responses_count);
541 responses = at_responses_handling.responses_queue.responses;
543 // Alloc new structure and copy obtained data
544 responses[index] = response;
546 at_responses_handling.responses_queue.responses_count = count;
548 AT_RESPONSES_UNLOCK();
553 struct at_response *at_response_dequeue(void)
555 struct at_response *response = NULL;
556 struct at_response **responses = NULL;
557 int responses_count = 0;
564 responses = at_responses_handling.responses_queue.responses;
565 responses_count = at_responses_handling.responses_queue.responses_count;
567 while(responses_count <= 0 || responses == NULL) {
568 LOGE("No response queued, blocking!");
570 AT_RESPONSES_UNLOCK();
571 AT_RESPONSES_QUEUE_LOCK();
574 responses = at_responses_handling.responses_queue.responses;
575 responses_count = at_responses_handling.responses_queue.responses_count;
577 LOGE("Unblocking: %d new responses queued!", responses_count);
580 for(i=0 ; i < responses_count ; i++) {
581 if(responses[i] != NULL) {
582 response = responses[i];
588 if(response == NULL) {
589 LOGD("Found no valid response, aborting!");
590 AT_RESPONSES_UNLOCK();
594 responses[pos] = NULL;
596 // Move the elements back
597 for(i=pos ; i < responses_count-1 ; i++) {
598 responses[i] = responses[i+1];
601 // Empty the latest element
602 if(pos != responses_count-1) {
603 responses[responses_count-1] = NULL;
606 at_responses_handling.responses_queue.responses_count--;
608 if(at_responses_handling.responses_queue.responses_count == 0) {
610 at_responses_handling.responses_queue.responses = NULL;
613 AT_RESPONSES_UNLOCK();
622 int at_request_expect_to_func_queue(struct at_async_request *request)
624 struct at_async_request **requests = NULL;
625 int requests_count = 0;
632 // Index is the request index in the requests array
633 index = at_responses_handling.async_queue.requests_count;
634 // Count is the total count of requests in the array
637 // Save the previous data pointer
638 requests = at_responses_handling.async_queue.requests;
639 requests_count = at_responses_handling.async_queue.requests_count;
641 // Alloc the array with the new size
642 at_responses_handling.async_queue.requests = malloc(sizeof(struct at_async_request *) * count);
644 // Copy and free previous data
645 if(requests != NULL) {
646 memcpy(at_responses_handling.async_queue.requests, requests, sizeof(struct at_async_request *) * requests_count);
650 requests = at_responses_handling.async_queue.requests;
651 requests[index] = request;
653 at_responses_handling.async_queue.requests_count = count;
655 LOGD("%d elements left in the async queue", at_responses_handling.async_queue.requests_count);
660 void at_request_expect_to_func_dequeue(struct at_async_request *request)
662 struct at_async_request **requests = NULL;
663 int requests_count = 0;
670 requests = at_responses_handling.async_queue.requests;
671 requests_count = at_responses_handling.async_queue.requests_count;
673 for(i=0 ; i < requests_count ; i++) {
674 if(requests[i] == request) {
681 LOGD("Found no matching request, aborting dequeue!");
685 requests[pos] = NULL;
687 // Move the elements back
688 for(i=pos ; i < requests_count-1 ; i++) {
689 requests[i] = requests[i+1];
692 // Empty the latest element
693 if(pos != requests_count-1) {
694 requests[requests_count-1] = NULL;
697 at_responses_handling.async_queue.requests_count--;
699 if(at_responses_handling.async_queue.requests_count == 0) {
701 at_responses_handling.async_queue.requests = NULL;
704 LOGD("%d elements left in the async queue", at_responses_handling.async_queue.requests_count);
707 void at_request_expect_to_func_release(struct at_async_request *request)
712 if(request->command != NULL)
713 free(request->command);
714 if(request->error != NULL)
715 free(request->error);
720 struct at_async_request *at_request_expect_to_func_find_command(char *command)
722 struct at_async_request *request = NULL;
723 struct at_async_request **requests = NULL;
724 int requests_count = 0;
734 requests = at_responses_handling.async_queue.requests;
735 requests_count = at_responses_handling.async_queue.requests_count;
737 if(requests == NULL) {
742 for(i=0 ; i < requests_count ; i++) {
743 if(requests[i] != NULL) {
744 if(requests[i]->command != NULL) {
745 rc = at_commands_compare(command, requests[i]->command);
747 request = requests[i];
759 struct at_async_request *at_request_expect_to_func_find_handled(int handled)
761 struct at_async_request *request = NULL;
762 struct at_async_request **requests = NULL;
763 int requests_count = 0;
770 requests = at_responses_handling.async_queue.requests;
771 requests_count = at_responses_handling.async_queue.requests_count;
773 if(requests == NULL) {
778 for(i=0 ; i < requests_count ; i++) {
779 if(requests[i] != NULL) {
780 if(requests[i]->handled == handled) {
781 request = requests[i];
792 int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
794 struct at_async_request *request = NULL;
797 if(command == NULL || func == NULL) {
803 // Alloc new structure and copy obtained data
804 request = calloc(1, sizeof(struct at_async_request));
805 request->handled = AT_RESPONSE_WAITING;
806 request->status = AT_STATUS_UNDEF;
807 request->error = NULL;
808 request->command = strdup(command);
809 request->data = data;
811 request->func = func;
813 rc = at_request_expect_to_func_queue(request);
815 LOGE("Failed to queue async request, aborting");
816 at_request_expect_to_func_release(request);
819 LOGD("Registered async function for command: %s", command);
826 int at_response_expect_to_func(struct at_response *response)
828 struct at_async_request *request = NULL;
831 if(response == NULL || response->command == NULL)
834 request = at_request_expect_to_func_find_command(response->command);
835 if(request == NULL || request->func == NULL) {
839 LOGD("Found a matching request!");
841 // Use status and error from the request (filled after unhandled because of status)
842 if(response->status == AT_STATUS_UNDEF && request->status != AT_STATUS_UNDEF)
843 response->status = request->status;
844 if(response->error == NULL && request->error != NULL)
845 response->error = request->error;
847 // This prevents sync data not to be reported when the same command is issued in func and previous handled was unhandled for status reason
848 request->handled = AT_RESPONSE_WAITING;
850 at_request_expect_to_func_dequeue(request);
852 // This must run out of any mutex
853 rc = request->func(response, request->data, request->token);
855 // If the request was unhandled, update its status and requeue
856 if(rc == AT_RESPONSE_UNHANDELD_REASON_STATUS) {
857 LOGD("Response not handled (missing status)");
858 request->handled = AT_RESPONSE_UNHANDELD_REASON_STATUS;
859 at_request_expect_to_func_queue(request);
860 } else if(rc == AT_RESPONSE_UNHANDELD_REASON_DATA) {
861 LOGD("Response not handled (missing data)");
862 request->handled = AT_RESPONSE_UNHANDELD_REASON_DATA;
863 at_request_expect_to_func_queue(request);
866 at_request_expect_to_func_release(request);
877 void at_response_expect_status_release(void)
880 at_responses_handling_sync_clean();
884 int at_request_expect_status(struct at_request *request)
886 // Register the request
891 if(at_responses_handling.sync_request != NULL) {
892 LOGE("There is already an AT sync request waiting, aborting!");
896 if(request->command == NULL) {
897 LOGE("No command was given, aborting!");
901 at_responses_handling.sync_request = request;
906 int at_response_expect_status(struct at_response *response)
908 struct at_async_request *request = NULL;
914 // If there is no request waiting for a status
915 if(at_responses_handling.sync_request == NULL && at_request_expect_to_func_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS) == NULL)
918 // If we get an unsol response while we expect a status, there is something going wrong
919 if(response->command != NULL && at_responses_handling.sync_request != NULL && at_responses_handling.sync_request->command != NULL) {
920 rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
922 // Only unlock is there is no async request waiting with this command (if it is unsol)!
923 if(at_request_expect_to_func_find_command(response->command) == NULL) {
931 if(response->status == AT_STATUS_UNDEF && at_responses_handling.sync_request != NULL && at_responses_handling.sync_request->command != NULL) {
932 if((response->data == NULL || response->data_count <= 0) && response->command != NULL) {
933 rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
935 // Command is the one we expect, but there is no status nor data, so just skip it
936 LOGD("Skipping matching request with no status nor data");
937 at_response_free(response);
942 // Only unlock if there is a status and command differs
946 if(response->command == NULL) {
947 // If there is an async response that was unhandled because it lacked status, fill it
948 request = at_request_expect_to_func_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS);
949 if(request != NULL) {
950 LOGD("Found an async function that needs a status!");
952 request->status = response->status;
953 if(response->error != NULL)
954 request->error = strdup(response->error);
955 request->handled = AT_RESPONSE_WAITING;
957 if(request->command != NULL)
958 response->command = strdup(request->command);
964 if(at_responses_handling.sync_request == NULL)
967 at_responses_handling.sync_response = response;
974 int at_expect_status(struct at_request *request)
981 if(at_responses_handling.sync_response == NULL) {
982 LOGD("Blocking for sync response");
984 // Second lock: block until sync_response is there
988 if(at_responses_handling.sync_response == NULL)
991 if(at_responses_handling.sync_response->command != NULL) {
992 rc = at_commands_compare(at_responses_handling.sync_response->command, request->command);
994 LOGE("Obtained command doesn't match, aborting!");
999 LOGD("Found matching sync response");
1001 request->status = at_responses_handling.sync_response->status;
1002 if(at_responses_handling.sync_response->error != NULL)
1003 request->error = strdup(at_responses_handling.sync_response->error);
1012 int at_request_send(struct at_request *request)
1014 char *string = NULL;
1017 int offset_separator_begin = 0;
1018 int length_separator_begin = 0;
1019 int offset_command = 0;
1020 int length_command = 0;
1021 int offset_data_separator = 0;
1022 int length_data_separator = 0;
1023 int offset_data = 0;
1024 int length_data = 0;
1025 int offset_separator_end = 0;
1026 int length_separator_end = 0;
1030 // TODO: Do we send \r\n or only \r, begining/end or just end?
1031 char separator[] = "\r\n";
1032 char data_separator[] = "=";
1034 if(request->command == NULL)
1037 offset_separator_begin = 0;
1038 length_separator_begin = strlen(separator);
1039 length += length_separator_begin;
1041 offset_command = length;
1042 length_command = strlen(request->command);
1043 length += length_command;
1045 if(request->data != NULL) {
1046 offset_data_separator = length;
1047 length_data_separator = strlen(data_separator);
1048 length += length_data_separator;
1050 offset_data = length;
1051 length_data = strlen(request->data);
1052 length += length_data;
1055 offset_separator_end = length;
1056 length_separator_end = strlen(separator);
1057 length += length_separator_end;
1059 // Alloc final string
1060 string = calloc(1, length);
1062 // Copy the data to the string
1063 memcpy(string + offset_separator_begin, separator, length_separator_begin);
1064 memcpy(string + offset_command, request->command, length_command);
1065 if(request->data != NULL) {
1066 memcpy(string + offset_data_separator, data_separator, length_data_separator);
1067 memcpy(string + offset_data, request->data, length_data);
1069 memcpy(string + offset_separator_end, separator, length_separator_end);
1073 ril_data_log(string, length);
1074 ril_send_log(request);
1077 ril_device_send(ril_device, string, length);
1084 struct at_request *at_request_create(char *command, char *data)
1086 struct at_request *request = NULL;
1092 request = calloc(1, sizeof(struct at_request));
1094 asprintf(&(request->command), "%s", command);
1097 asprintf(&(request->data), "%s", data);
1103 void at_request_free(struct at_request *request)
1107 if(request->command != NULL)
1108 free(request->command);
1110 if(request->data != NULL)
1111 free(request->data);
1113 if(request->error != NULL)
1114 free(request->error);
1121 int at_send(char *command, char *data)
1123 struct at_request *request = NULL;
1126 request = at_request_create(command, data);
1127 if(request == NULL) {
1128 LOGE("Unable to create request, aborting!");
1132 rc = at_request_send(request);
1134 LOGE("Unable to send request, aborting!");
1135 at_request_free(request);
1139 at_request_free(request);
1144 int at_send_command(char *command)
1146 return at_send(command, NULL);
1149 int at_send_expect_status(char *command, char *data)
1151 struct at_request *request = NULL;
1160 request = at_request_create(command, data);
1161 if(request == NULL) {
1162 LOGE("Unable to create request, aborting!");
1163 return AT_STATUS_INTERNAL_ERROR;
1166 // Try to register request 5 times, during 5 * 1s
1167 for(i=5 ; i > 0 ; i--) {
1168 rc = at_request_expect_status(request);
1170 LOGE("Unable to request expect status, retrying!");
1177 LOGE("Unable to request expect status, aborting!");
1178 at_request_free(request);
1179 return AT_STATUS_INTERNAL_ERROR;
1182 rc = at_request_send(request);
1184 LOGE("Unable to send request, aborting!");
1185 at_response_expect_status_release();
1186 return AT_STATUS_INTERNAL_ERROR;
1190 rc = at_expect_status(request);
1192 LOGE("Unable to get expected status, aborting!");
1193 at_response_expect_status_release();
1194 return AT_STATUS_INTERNAL_ERROR;
1197 status = request->status;
1199 // Release sync structures and lock the mutex
1200 at_response_expect_status_release();
1205 int at_send_expect_to_func(char *command, char *data, void *pdata, RIL_Token t, at_async_request_cb func)
1207 struct at_request *request = NULL;
1213 request = at_request_create(command, data);
1214 if(request == NULL) {
1215 LOGE("Unable to create request, aborting!");
1219 rc = at_request_expect_to_func(command, pdata, t, func);
1221 LOGE("Unable to request expect to func, aborting!");
1222 at_request_free(request);
1225 rc = at_request_send(request);
1227 LOGE("Unable to send request, aborting!");
1228 at_request_free(request);