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>
27 int at_strings_compare(char *major, char *minor)
29 if(strncmp(major, minor, strlen(major)) == 0)
35 void at_string_clean(char *string, int length)
39 for(i=length-1; i >= 0 ; i--) {
40 if(!isprint(string[i]))
45 int at_line_parse_status(char *data, int length, char **error_p)
47 // TODO: defined rc, fill error_p
51 if(at_strings_compare("OK", data))
54 if(at_strings_compare("CONNECT", data))
57 if(at_strings_compare("ERROR", data))
60 // TODO: Other error codes
62 // TODO: undefined magic
66 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
69 int string_length = 0;
70 int close_your_eyes = 0;
75 for(i=0 ; i < length ; i++) {
76 if(data[i] == ':' && mark == 0) {
80 string_length = i + 1;
81 string = strndup(data, string_length);
83 if(!isprint(string[0])) {
86 *response_command = string;
92 while(isspace(data[i+1])) {
99 if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
100 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
102 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
105 if(data[i] == '\'') {
106 if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
107 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
109 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
112 // Found = or ? outside of any quotes: assume no data
113 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
116 string_length = i + 1;
117 string = strndup(data, string_length);
119 if(!isprint(string[0])) {
122 *response_command = string;
130 if(length - mark > 0) {
131 string_length = length - mark;
132 string = strndup(data + mark, string_length);
135 *response_command = string;
138 *response_data = string;
139 return string_length;
146 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
148 struct at_response **responses = NULL;
150 char *response_command = NULL;
151 char *response_data = NULL;
152 int response_data_length = 0;
153 char *response_error = NULL;
154 int response_status = 0;
156 char **response_previous_data = NULL;
157 int response_data_count = 0;
163 if(responses_p == NULL || data == NULL || length < 0) {
164 LOGE("Failed to process AT response: wrong arguments!");
168 responses = *responses_p;
171 response_status = at_line_parse_status(data, length, &response_error);
173 if(response_status != 0) {
174 if(responses_count > 0 && responses != NULL) {
175 for(i=responses_count-1 ; i >= 0; i--) {
176 if(responses[i]->status == 0) {
177 responses[i]->status = response_status;
178 responses[i]->error = response_error;
180 // Do not alloc a new response
187 // Alloc a new response
189 // Index is the request index in the requests array
190 index = responses_count;
191 // Count is the total count of requests in the array
194 // Alloc the array with the new size
195 *responses_p = malloc(sizeof(struct at_response *) * count);
197 // Copy and free previous data
198 if(responses != NULL) {
199 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
203 responses = *responses_p;
205 // Alloc new structure and copy obtained data
206 responses[index] = calloc(1, sizeof(struct at_response));
207 responses[index]->status = response_status;
208 responses[index]->error = response_error;
211 // Parse command and data
212 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
214 if(response_command == NULL) {
215 LOGE("Failed to parse command!");
216 return responses_count;
219 at_string_clean(response_command, strlen(response_command) + 1);
221 if(responses_count > 0 && responses != NULL) {
222 for(i=responses_count-1 ; i >= 0; i--) {
223 if(responses[i]->command != NULL) {
224 if(strcmp(responses[i]->command, response_command) == 0)
225 // Do not alloc a new response
231 // Alloc a new response
233 // Index is the request index in the requests array
234 index = responses_count;
235 // Count is the total count of requests in the array
238 // Alloc the array with the new size
239 *responses_p = malloc(sizeof(struct at_response *) * count);
241 // Copy and free previous data
242 if(responses != NULL) {
243 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
247 responses = *responses_p;
249 // Alloc new structure and copy obtained data
250 responses[index] = calloc(1, sizeof(struct at_response));
251 responses[index]->command = response_command;
254 if(response_data_length > 0 && response_data != NULL) {
255 at_string_clean(response_data, response_data_length);
257 response_previous_data = responses[index]->data;
259 // Data count is the total count of elements in the request data
260 response_data_count = responses[index]->data_count + 1;
262 // Alloc the array with the new size
263 responses[index]->data = malloc(sizeof(char *) * response_data_count);
265 // Copy and free previous data
266 if(response_previous_data != NULL) {
267 memcpy(responses[index]->data, response_previous_data, sizeof(char *) * responses[index]->data_count);
268 free(response_previous_data);
271 responses[index]->data_count = response_data_count;
272 responses[index]->data[response_data_count - 1] = response_data;
276 return count > responses_count ? count : responses_count;
279 int at_responses_process(struct at_response ***responses_p, char *data, int length)
281 int responses_count = 0;
285 int string_length = 0;
289 if(responses_p == NULL || data == NULL || length < 0) {
290 LOGE("Failed to process AT response: wrong arguments!");
294 for(i=0 ; i < length ; i++) {
295 if(data[i] == '\r' || data[i] == ';') {
299 string_length = i - mark + 1;
300 string = strndup(data + mark, string_length);
302 if(!isprint(string[0])) {
306 count = at_responses_process_line(responses_p, responses_count, string, string_length);
307 if(count > responses_count)
308 responses_count = count;
316 while(isspace(data[i+1])) {
323 if(length - mark > 0) {
324 for(i=mark ; i < length ; i++)
325 if(!isprint(data[i]))
329 string_length = i - mark + 1;
330 string = calloc(1, string_length);
332 memcpy(string, data + mark, string_length - 1);
333 string[string_length - 1] = '\0';
335 count = at_responses_process_line(responses_p, responses_count, string , string_length);
336 if(count > responses_count)
337 responses_count = count;
343 return responses_count;
346 void at_responses_dump(struct at_response **responses, int responses_count)
350 LOGD("== AT RESPONSES DUMP ==\n");
351 for(i=0 ; i < responses_count ; i++) {
352 LOGD("#%d command=%s status=%d error=%s\n", i, responses[i]->command, responses[i]->status, responses[i]->error);
353 if(responses[i]->data_count > 0) {
355 for(j=0 ; j < responses[i]->data_count ; j++) {
356 LOGD(" #%d data='%s'\n", j, responses[i]->data[j]);
362 void at_responses_free(struct at_response **responses, int responses_count)
366 for(i=0 ; i < responses_count ; i++) {
367 if(responses[i]->data_count > 0 && responses[i]->data != NULL) {
368 for(j=0 ; j < responses[i]->data_count ; j++) {
369 if(responses[i]->data[j] != NULL) {
370 free(responses[i]->data[j]);
371 responses[i]->data[j] = NULL;
375 free(responses[i]->data);
376 responses[i]->data_count = 0;
379 if(responses[i]->command != NULL) {
380 free(responses[i]->command);
381 responses[i]->command = NULL;
384 if(responses[i]->error != NULL) {
385 free(responses[i]->error);
386 responses[i]->error = NULL;