2 * This file is part of hayes-ril.
4 * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
6 * Based on htcgeneric-ril, reference-ril:
7 * Copyright 2006-2011, htcgeneric-ril contributors
8 * Copyright 2006, The Android Open Source Project
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
26 #define LOG_TAG "RIL-AT"
27 #include <utils/Log.h>
29 #include <hayes-ril.h>
31 int at_strings_compare(char *major, char *minor)
33 if(strncmp(major, minor, strlen(major)) == 0)
39 void at_string_clean(char *string, int length)
43 for(i=length-1; i >= 0 ; i--) {
44 if(!isprint(string[i]))
49 int at_line_parse_status(char *data, int length, char **error_p)
51 // TODO: defined rc, fill error_p
55 if(at_strings_compare("OK", data))
58 if(at_strings_compare("CONNECT", data))
61 if(at_strings_compare("ERROR", data))
64 // TODO: Other error codes
66 // TODO: undefined magic
70 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
73 int string_length = 0;
74 int close_your_eyes = 0;
79 for(i=0 ; i < length ; i++) {
80 if(data[i] == ':' && mark == 0) {
84 string_length = i + 1;
85 string = strndup(data, string_length);
87 if(!isprint(string[0])) {
90 *response_command = string;
96 while(isspace(data[i+1])) {
103 if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
104 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
106 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
109 if(data[i] == '\'') {
110 if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
111 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
113 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
116 // Found = or ? outside of any quotes: assume no data
117 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
120 string_length = i + 1;
121 string = strndup(data, string_length);
123 if(!isprint(string[0])) {
126 *response_command = string;
134 if(length - mark > 0) {
135 string_length = length - mark;
136 string = strndup(data + mark, string_length);
139 *response_command = string;
142 *response_data = string;
143 return string_length;
150 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
152 struct at_response **responses = NULL;
154 char *response_command = NULL;
155 char *response_data = NULL;
156 int response_data_length = 0;
157 char *response_error = NULL;
158 int response_status = 0;
160 char **response_previous_data = NULL;
161 int response_data_count = 0;
167 if(responses_p == NULL || data == NULL || length < 0) {
168 LOGE("Failed to process AT response: wrong arguments!");
172 responses = *responses_p;
175 response_status = at_line_parse_status(data, length, &response_error);
177 if(response_status != 0) {
178 if(responses_count > 0 && responses != NULL) {
179 for(i=responses_count-1 ; i >= 0; i--) {
180 if(responses[i]->status == 0) {
181 responses[i]->status = response_status;
182 responses[i]->error = response_error;
184 // Do not alloc a new response
191 // Alloc a new response
193 // Index is the request index in the requests array
194 index = responses_count;
195 // Count is the total count of requests in the array
198 // Alloc the array with the new size
199 *responses_p = malloc(sizeof(struct at_response *) * count);
201 // Copy and free previous data
202 if(responses != NULL) {
203 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
207 responses = *responses_p;
209 // Alloc new structure and copy obtained data
210 responses[index] = calloc(1, sizeof(struct at_response));
211 responses[index]->status = response_status;
212 responses[index]->error = response_error;
215 // Parse command and data
216 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
218 if(response_command == NULL) {
219 LOGE("Failed to parse command!");
220 return responses_count;
223 at_string_clean(response_command, strlen(response_command) + 1);
225 if(responses_count > 0 && responses != NULL) {
226 for(i=responses_count-1 ; i >= 0; i--) {
227 if(responses[i]->command != NULL) {
228 if(strcmp(responses[i]->command, response_command) == 0)
229 // Do not alloc a new response
235 // Alloc a new response
237 // Index is the request index in the requests array
238 index = responses_count;
239 // Count is the total count of requests in the array
242 // Alloc the array with the new size
243 *responses_p = malloc(sizeof(struct at_response *) * count);
245 // Copy and free previous data
246 if(responses != NULL) {
247 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
251 responses = *responses_p;
253 // Alloc new structure and copy obtained data
254 responses[index] = calloc(1, sizeof(struct at_response));
255 responses[index]->command = response_command;
258 if(response_data_length > 0 && response_data != NULL) {
259 at_string_clean(response_data, response_data_length);
261 response_previous_data = responses[index]->data;
263 // Data count is the total count of elements in the request data
264 response_data_count = responses[index]->data_count + 1;
266 // Alloc the array with the new size
267 responses[index]->data = malloc(sizeof(char *) * response_data_count);
269 // Copy and free previous data
270 if(response_previous_data != NULL) {
271 memcpy(responses[index]->data, response_previous_data, sizeof(char *) * responses[index]->data_count);
272 free(response_previous_data);
275 responses[index]->data_count = response_data_count;
276 responses[index]->data[response_data_count - 1] = response_data;
280 return count > responses_count ? count : responses_count;
283 int at_responses_process(struct at_response ***responses_p, char *data, int length)
285 int responses_count = 0;
289 int string_length = 0;
293 if(responses_p == NULL || data == NULL || length < 0) {
294 LOGE("Failed to process AT response: wrong arguments!");
298 for(i=0 ; i < length ; i++) {
299 if(data[i] == '\r' || data[i] == ';') {
303 string_length = i - mark + 1;
304 string = strndup(data + mark, string_length);
306 if(!isprint(string[0])) {
310 count = at_responses_process_line(responses_p, responses_count, string, string_length);
311 if(count > responses_count)
312 responses_count = count;
320 while(isspace(data[i+1])) {
327 if(length - mark > 0) {
328 for(i=mark ; i < length ; i++)
329 if(!isprint(data[i]))
333 string_length = i - mark + 1;
334 string = calloc(1, string_length);
336 memcpy(string, data + mark, string_length - 1);
337 string[string_length - 1] = '\0';
339 count = at_responses_process_line(responses_p, responses_count, string , string_length);
340 if(count > responses_count)
341 responses_count = count;
347 return responses_count;
350 void at_responses_dump(struct at_response **responses, int responses_count)
354 LOGD("== AT RESPONSES DUMP ==\n");
355 for(i=0 ; i < responses_count ; i++) {
356 LOGD("#%d command=%s status=%d error=%s\n", i, responses[i]->command, responses[i]->status, responses[i]->error);
357 if(responses[i]->data_count > 0) {
359 for(j=0 ; j < responses[i]->data_count ; j++) {
360 LOGD(" #%d data='%s'\n", j, responses[i]->data[j]);
366 void at_responses_free(struct at_response **responses, int responses_count)
370 for(i=0 ; i < responses_count ; i++) {
371 if(responses[i]->data_count > 0 && responses[i]->data != NULL) {
372 for(j=0 ; j < responses[i]->data_count ; j++) {
373 if(responses[i]->data[j] != NULL) {
374 free(responses[i]->data[j]);
375 responses[i]->data[j] = NULL;
379 free(responses[i]->data);
380 responses[i]->data_count = 0;
383 if(responses[i]->command != NULL) {
384 free(responses[i]->command);
385 responses[i]->command = NULL;
388 if(responses[i]->error != NULL) {
389 free(responses[i]->error);
390 responses[i]->error = NULL;