Reworked AT queuing, with queues for send, recv, async recv and sync recv
[hayes-ril.git] / at.c
diff --git a/at.c b/at.c
index b1d7b58..e8cf821 100644 (file)
--- a/at.c
+++ b/at.c
@@ -28,7 +28,7 @@
  * Globals
  */
 
-struct at_responses_handling at_responses_handling;
+struct at_handling at_handling;
 
 /*
  * Utilities
@@ -450,119 +450,112 @@ void at_response_free(struct at_response *response)
                response->data_count = 0;
        }
 
-       if(response->command != NULL) {
+       if(response->command != NULL)
                free(response->command);
-               response->command = NULL;
-       }
 
-       if(response->error != NULL) {
+       if(response->error != NULL)
                free(response->error);
-               response->error = NULL;
-       }
-}
 
-void at_responses_free(struct at_response **responses, int responses_count)
-{
-       int i;
+       memset(response, 0, sizeof(struct at_response));
 
-       for(i=0 ; i < responses_count ; i++) {
-               at_response_free(responses[i]);
-       }
 }
 
 /*
- * Responses handling
+ * Handling
  */
 
-void at_responses_handling_init(void)
+void at_handling_init(void)
 {
-       memset(&at_responses_handling, 0, sizeof(struct at_responses_handling));
-       pthread_mutex_init(&(at_responses_handling.sync_mutex), NULL);
+       memset(&at_handling, 0, sizeof(struct at_handling));
 
-       // First lock
-       AT_SYNC_LOCK();
-       AT_RESPONSES_QUEUE_LOCK();
-}
+       pthread_mutex_init(&(at_handling.responses_queue.queue_mutex), NULL);
+       pthread_mutex_init(&(at_handling.responses_queue.mutex), NULL);
+       pthread_mutex_init(&(at_handling.requests_queue.mutex), NULL);
+       pthread_mutex_init(&(at_handling.sync_requests_queue.queue_mutex), NULL);
+       pthread_mutex_init(&(at_handling.sync_requests_queue.mutex), NULL);
+       pthread_mutex_init(&(at_handling.async_requests_queue.mutex), NULL);
 
-void at_responses_handling_sync_clean(void)
-{
-       if(at_responses_handling.sync_request != NULL) {
-               at_request_free(at_responses_handling.sync_request);
-               at_responses_handling.sync_request = NULL;
-       }
-
-       if(at_responses_handling.sync_response != NULL) {
-               at_response_free(at_responses_handling.sync_response);
-               at_responses_handling.sync_response = NULL;
-       }
+       // First lock to the queues mutexes
+       AT_RESPONSES_QUEUE_LOCK();
+       AT_SYNC_QUEUE_LOCK();
 }
 
 /*
  * Responses queue
  */
 
+// Unlock the responses queue after queuing all the available requests
 void at_responses_queue_unlock(void)
 {
-       // Only unlock if there are responses available
-       if(at_responses_handling.responses_queue.responses_count > 0 && at_responses_handling.responses_queue.responses != NULL) {
-               AT_RESPONSES_QUEUE_UNLOCK();
-       }
+       if(at_handling.responses_queue.responses_count <= 0 || at_handling.responses_queue.responses == NULL)
+               return;
+
+       AT_RESPONSES_QUEUE_UNLOCK();
 }
 
+// Queue one response to the responses queue
 int at_response_queue(struct at_response *response)
 {
        struct at_response **responses = NULL;
+       int responses_count = 0;
        int index;
        int count;
 
-       if(response == NULL) {
+       if(response == NULL)
                return -1;
-       }
 
        AT_RESPONSES_LOCK();
 
-       // Index is the request index in the responses array
-       index = at_responses_handling.responses_queue.responses_count;
+       // Save the previous data pointer and count
+       responses = at_handling.responses_queue.responses;
+       responses_count = at_handling.responses_queue.responses_count;
+
+       if(responses_count < 0)
+               responses_count = 0;
+
+       // Index is the response index in the responses array
+       index = responses_count;
        // Count is the total count of responses in the array
        count = index + 1;
 
-       // Save the previous data pointer
-       responses = at_responses_handling.responses_queue.responses;
-
        // Alloc the array with the new size
-       at_responses_handling.responses_queue.responses = malloc(sizeof(struct at_response *) * count);
+       at_handling.responses_queue.responses = malloc(sizeof(struct at_response *) * count);
+       at_handling.responses_queue.responses_count = count;
 
        // Copy and free previous data
-       if(responses != NULL) {
-               memcpy(at_responses_handling.responses_queue.responses, responses, sizeof(struct at_response *) * at_responses_handling.responses_queue.responses_count);
+       if(responses != NULL && responses_count > 0) {
+               memcpy(at_handling.responses_queue.responses, responses, sizeof(struct at_response *) * at_handling.responses_queue.responses_count);
                free(responses);
        }
 
-       responses = at_responses_handling.responses_queue.responses;
+       // Get the new data pointer and count
+       responses = at_handling.responses_queue.responses;
+       responses_count = at_handling.responses_queue.responses_count;
 
-       // Alloc new structure and copy obtained data
+       // Put the response in the queue
        responses[index] = response;
 
-       at_responses_handling.responses_queue.responses_count = count;
+       LOGD("%d elements in the responses queue", responses_count);
 
        AT_RESPONSES_UNLOCK();
 
        return 0;
 }
 
+// Unqueue the oldest response in the queue
 struct at_response *at_response_dequeue(void)
 {
        struct at_response *response = NULL;
        struct at_response **responses = NULL;
        int responses_count = 0;
-       int pos;
+       int pos = -1;
        int i;
 
        AT_RESPONSES_LOCK();
 
-       response = NULL;
-       responses = at_responses_handling.responses_queue.responses;
-       responses_count = at_responses_handling.responses_queue.responses_count;
+       // Save the previous data pointer and count
+       responses = at_handling.responses_queue.responses;
+       responses_count = at_handling.responses_queue.responses_count;
 
        while(responses_count <= 0 || responses == NULL) {
                LOGE("No response queued, blocking!");
@@ -571,8 +564,9 @@ struct at_response *at_response_dequeue(void)
                AT_RESPONSES_QUEUE_LOCK();
                AT_RESPONSES_LOCK();
 
-               responses = at_responses_handling.responses_queue.responses;
-               responses_count = at_responses_handling.responses_queue.responses_count;
+               // Get the new data pointer and count
+               responses = at_handling.responses_queue.responses;
+               responses_count = at_handling.responses_queue.responses_count;
 
                LOGE("Unblocking: %d new responses queued!", responses_count);
        }
@@ -585,12 +579,14 @@ struct at_response *at_response_dequeue(void)
                }
        }
 
-       if(response == NULL) {
+       if(response == NULL || pos < 0) {
                LOGD("Found no valid response, aborting!");
+
                AT_RESPONSES_UNLOCK();
                return NULL;
        }
 
+       // Empty the found position in the responses array
        responses[pos] = NULL;
 
        // Move the elements back
@@ -603,25 +599,30 @@ struct at_response *at_response_dequeue(void)
                responses[responses_count-1] = NULL;
        }
 
-       at_responses_handling.responses_queue.responses_count--;
+       responses_count--;
 
-       if(at_responses_handling.responses_queue.responses_count == 0) {
+       if(responses_count == 0) {
                free(responses);
-               at_responses_handling.responses_queue.responses = NULL;
+               at_handling.responses_queue.responses = NULL;
        }
 
+       at_handling.responses_queue.responses_count = responses_count;
+
+       LOGD("%d elements in the responses queue", responses_count);
+
        AT_RESPONSES_UNLOCK();
 
        return response;
 }
 
 /*
- * Expect to func
+ * Requests queue
  */
 
-int at_request_expect_to_func_queue(struct at_async_request *request)
+// Queue one request to the requests queue
+int at_request_queue(struct at_request *request)
 {
-       struct at_async_request **requests = NULL;
+       struct at_request **requests = NULL;
        int requests_count = 0;
        int index;
        int count;
@@ -629,59 +630,82 @@ int at_request_expect_to_func_queue(struct at_async_request *request)
        if(request == NULL)
                return -1;
 
+       AT_REQUESTS_LOCK();
+
+       // Save the previous data pointer and count
+       requests = at_handling.requests_queue.requests;
+       requests_count = at_handling.requests_queue.requests_count;
+
+       if(requests_count < 0)
+               requests_count = 0;
+
        // Index is the request index in the requests array
-       index = at_responses_handling.async_queue.requests_count;
+       index = requests_count;
        // Count is the total count of requests in the array
        count = index + 1;
 
-       // Save the previous data pointer
-       requests = at_responses_handling.async_queue.requests;
-       requests_count = at_responses_handling.async_queue.requests_count;
-
        // Alloc the array with the new size
-       at_responses_handling.async_queue.requests = malloc(sizeof(struct at_async_request *) * count);
+       at_handling.requests_queue.requests = malloc(sizeof(struct at_request *) * count);
+       at_handling.requests_queue.requests_count = count;
 
        // Copy and free previous data
-       if(requests != NULL) {
-               memcpy(at_responses_handling.async_queue.requests, requests, sizeof(struct at_async_request *) * requests_count);
+       if(requests != NULL && requests_count > 0) {
+               memcpy(at_handling.requests_queue.requests, requests, sizeof(struct at_request *) * at_handling.requests_queue.requests_count);
                free(requests);
        }
 
-       requests = at_responses_handling.async_queue.requests;
+       // Get the new data pointer and count
+       requests = at_handling.requests_queue.requests;
+       requests_count = at_handling.requests_queue.requests_count;
+
+       // Put the request in the queue
        requests[index] = request;
 
-       at_responses_handling.async_queue.requests_count = count;
+       LOGD("%d elements in the requests queue", requests_count);
 
-       LOGD("%d elements left in the async queue", at_responses_handling.async_queue.requests_count);
+       AT_REQUESTS_UNLOCK();
 
        return 0;
 }
 
-void at_request_expect_to_func_dequeue(struct at_async_request *request)
+// Unqueue the oldest request in the queue
+struct at_request *at_request_dequeue(void)
 {
-       struct at_async_request **requests = NULL;
+       struct at_request *request = NULL;
+       struct at_request **requests = NULL;
        int requests_count = 0;
        int pos = -1;
        int i;
 
-       if(request == NULL)
-               return;
+       AT_REQUESTS_LOCK();
+
+       // Save the previous data pointer and count
+       requests = at_handling.requests_queue.requests;
+       requests_count = at_handling.requests_queue.requests_count;
 
-       requests = at_responses_handling.async_queue.requests;
-       requests_count = at_responses_handling.async_queue.requests_count;
+       if(requests_count <= 0 || requests == NULL) {
+               LOGE("No requests queued!");
+
+               AT_REQUESTS_UNLOCK();
+               return NULL;
+       }
 
        for(i=0 ; i < requests_count ; i++) {
-               if(requests[i] == request) {
+               if(requests[i] != NULL) {
+                       request = requests[i];
                        pos = i;
                        break;
                }
        }
 
-       if(pos == -1) {
-               LOGD("Found no matching request, aborting dequeue!");
-               return;
+       if(requests == NULL || pos < 0) {
+               LOGD("Found no valid request, aborting!");
+
+               AT_REQUESTS_UNLOCK();
+               return NULL;
        }
 
+       // Empty the found position in the requests array
        requests[pos] = NULL;
 
        // Move the elements back
@@ -694,35 +718,45 @@ void at_request_expect_to_func_dequeue(struct at_async_request *request)
                requests[requests_count-1] = NULL;
        }
 
-       at_responses_handling.async_queue.requests_count--;
+       requests_count--;
 
-       if(at_responses_handling.async_queue.requests_count == 0) {
+       if(requests_count == 0) {
                free(requests);
-               at_responses_handling.async_queue.requests = NULL;
+               at_handling.requests_queue.requests = NULL;
        }
 
-       LOGD("%d elements left in the async queue", at_responses_handling.async_queue.requests_count);
+       at_handling.requests_queue.requests_count = requests_count;
+
+       LOGD("%d elements in the requests queue", requests_count);
+
+       AT_REQUESTS_UNLOCK();
+
+       return request;
 }
 
-void at_request_expect_to_func_release(struct at_async_request *request)
+/*
+ * Async requests queue
+ */
+
+// Free the async request
+void at_async_request_free(struct at_async_request *async_request)
 {
-       if(request == NULL)
+       if(async_request == NULL)
                return;
 
-       if(request->command != NULL)
-               free(request->command);
-       if(request->error != NULL)
-               free(request->error);
+       if(async_request->command)
+               free(async_request->command);
 
-       free(request);
+       memset(async_request, 0, sizeof(struct at_async_request));
+       async_request->handled = AT_RESPONSE_GARBAGE;
 }
 
-struct at_async_request *at_request_expect_to_func_find_command(char *command)
+// Find an async request from its command
+struct at_async_request *at_async_request_find_command(char *command)
 {
-       struct at_async_request *request = NULL;
-       struct at_async_request **requests = NULL;
-       int requests_count = 0;
-       int rc;
+       struct at_async_request *async_request = NULL;
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
        int i;
 
        if(command == NULL)
@@ -730,55 +764,52 @@ struct at_async_request *at_request_expect_to_func_find_command(char *command)
 
        AT_ASYNC_LOCK();
 
-       request = NULL;
-       requests = at_responses_handling.async_queue.requests;
-       requests_count = at_responses_handling.async_queue.requests_count;
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
 
-       if(requests == NULL) {
+       if(async_requests_count <= 0 || async_requests == NULL) {
                AT_ASYNC_UNLOCK();
                return NULL;
        }
 
-       for(i=0 ; i < requests_count ; i++) {
-               if(requests[i] != NULL) {
-                       if(requests[i]->command != NULL) {
-                               rc = at_commands_compare(command, requests[i]->command);
-                               if(rc) {
-                                       request = requests[i];
-                                       break;
-                               }
+       for(i=0 ; i < async_requests_count ; i++) {
+               if(async_requests[i] != NULL && async_requests[i]->command != NULL) {
+                       if(at_commands_compare(command, async_requests[i]->command)) {
+                               async_request = async_requests[i];
+                               break;
                        }
                }
        }
 
        AT_ASYNC_UNLOCK();
 
-       return request;
+       return async_request;
 }
 
-struct at_async_request *at_request_expect_to_func_find_handled(int handled)
+// Find an async request from its handled status
+struct at_async_request *at_async_request_find_handled(int handled)
 {
-       struct at_async_request *request = NULL;
-       struct at_async_request **requests = NULL;
-       int requests_count = 0;
-       int rc;
+       struct at_async_request *async_request = NULL;
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
        int i;
 
        AT_ASYNC_LOCK();
 
-       request = NULL;
-       requests = at_responses_handling.async_queue.requests;
-       requests_count = at_responses_handling.async_queue.requests_count;
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
 
-       if(requests == NULL) {
+       if(async_requests_count <= 0 || async_requests == NULL) {
                AT_ASYNC_UNLOCK();
                return NULL;
        }
 
-       for(i=0 ; i < requests_count ; i++) {
-               if(requests[i] != NULL) {
-                       if(requests[i]->handled == handled) {
-                               request = requests[i];
+       for(i=0 ; i < async_requests_count ; i++) {
+               if(async_requests[i] != NULL) {
+                       if(async_requests[i]->handled == handled) {
+                               async_request = async_requests[i];
                                break;
                        }
                }
@@ -786,221 +817,609 @@ struct at_async_request *at_request_expect_to_func_find_handled(int handled)
 
        AT_ASYNC_UNLOCK();
 
-       return request;
+       return async_request;
 }
 
-int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
+// Find an async request from its request pointer
+struct at_async_request *at_async_request_find_request(struct at_request *request)
 {
-       struct at_async_request *request = NULL;
-       int rc;
+       struct at_async_request *async_request = NULL;
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
+       int i;
 
-       if(command == NULL || func == NULL) {
-               return -1;
+       if(request == NULL)
+               return NULL;
+
+       AT_ASYNC_LOCK();
+
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
+
+       if(async_requests_count <= 0 || async_requests == NULL) {
+               AT_ASYNC_UNLOCK();
+               return NULL;
        }
 
+       for(i=0 ; i < async_requests_count ; i++) {
+               if(async_requests[i] != NULL) {
+                       if(async_requests[i]->request == request) {
+                               async_request = async_requests[i];
+                               break;
+                       }
+               }
+       }
+
+       AT_ASYNC_UNLOCK();
+
+       return async_request;
+}
+
+// Find an async request from its response pointer
+struct at_async_request *at_async_request_find_response(struct at_response *response)
+{
+       struct at_async_request *async_request = NULL;
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
+       int i;
+
+       if(response == NULL)
+               return NULL;
+
        AT_ASYNC_LOCK();
 
-       // Alloc new structure and copy obtained data
-       request = calloc(1, sizeof(struct at_async_request));
-       request->handled = AT_RESPONSE_WAITING;
-       request->status = AT_STATUS_UNDEF;
-       request->error = NULL;
-       request->command = strdup(command);
-       request->data = data;
-       request->token = t;
-       request->func = func;
-
-       rc = at_request_expect_to_func_queue(request);
-       if(rc < 0) {
-               LOGE("Failed to queue async request, aborting");
-               at_request_expect_to_func_release(request);
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
+
+       if(async_requests_count <= 0 || async_requests == NULL) {
+               AT_ASYNC_UNLOCK();
+               return NULL;
+       }
+
+       for(i=0 ; i < async_requests_count ; i++) {
+               if(async_requests[i] != NULL && async_requests[i]->response != NULL) {
+                       if(async_requests[i]->response == response) {
+                               async_request = async_requests[i];
+                               break;
+                       }
+               }
+       }
+
+       AT_ASYNC_UNLOCK();
+
+       return async_request;
+}
+
+// Queue one request to the async requests queue
+int at_async_request_queue(struct at_async_request *async_request)
+{
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
+       int index;
+       int count;
+
+       if(async_request == NULL)
+               return -1;
+
+       AT_ASYNC_LOCK();
+
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
+
+       if(async_requests_count < 0)
+               async_requests_count = 0;
+
+       // Index is the sync request index in the sync requests array
+       index = async_requests_count;
+       // Count is the total count of sync requests in the array
+       count = index + 1;
+
+       // Alloc the array with the new size
+       at_handling.async_requests_queue.async_requests = malloc(sizeof(struct at_async_request *) * count);
+       at_handling.async_requests_queue.async_requests_count = count;
+
+       // Copy and free previous data
+       if(async_requests != NULL && async_requests_count > 0) {
+               memcpy(at_handling.async_requests_queue.async_requests, async_requests, sizeof(struct at_async_request *) * at_handling.async_requests_queue.async_requests_count);
+               free(async_requests);
        }
 
-       LOGD("Registered async function for command: %s", command);
+       // Get the new data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
+
+       // Put the sync request in the queue
+       async_requests[index] = async_request;
+
+       LOGD("%d elements in the async requests queue", async_requests_count);
 
        AT_ASYNC_UNLOCK();
 
        return 0;
 }
 
-int at_response_expect_to_func(struct at_response *response)
+int at_async_response_dequeue(struct at_response *response)
 {
-       struct at_async_request *request = NULL;
+       struct at_async_request *async_request = NULL;
        int rc;
 
-       if(response == NULL || response->command == NULL)
+       if(response == NULL)
                return -1;
 
-       request = at_request_expect_to_func_find_command(response->command);
-       if(request == NULL || request->func == NULL) {
-               return -1;
-       }
+       // First, try to grab the async request from the response, if it was already filled by sync dequeue
+       async_request = at_async_request_find_response(response);
+       if(async_request == NULL || async_request->func == NULL) {
+               // Grab the async request from the command
+
+               async_request = at_async_request_find_command(response->command);
+               if(async_request == NULL || async_request->func == NULL) {
+                       return -1;
+               }
+
+               // FIXME: What if there is already a response with valid data?
 
-       LOGD("Found a matching request!");
+               async_request->response = response;
+       }
 
-       // Use status and error from the request (filled after unhandled because of status)
-       if(response->status == AT_STATUS_UNDEF && request->status != AT_STATUS_UNDEF)
-               response->status = request->status;
-       if(response->error == NULL && request->error != NULL)
-               response->error = request->error;
+       LOGD("Found a matching request for %s!", async_request->command);
 
        // This prevents sync data not to be reported when the same command is issued in func and previous handled was unhandled for status reason
-       request->handled = AT_RESPONSE_WAITING;
+       async_request->handled = AT_RESPONSE_SENT;
 
-       at_request_expect_to_func_dequeue(request);
+       at_async_request_dequeue(async_request);
 
-       // This must run out of any mutex
-       rc = request->func(response, request->data, request->token);
+       rc = async_request->func(response, async_request->data, async_request->token);
 
        // If the request was unhandled, update its status and requeue
        if(rc == AT_RESPONSE_UNHANDELD_REASON_STATUS) {
                LOGD("Response not handled (missing status)");
-               request->handled = AT_RESPONSE_UNHANDELD_REASON_STATUS;
-               at_request_expect_to_func_queue(request);
+               async_request->handled = AT_RESPONSE_UNHANDELD_REASON_STATUS;
+               at_async_request_queue(async_request);
        } else if(rc == AT_RESPONSE_UNHANDELD_REASON_DATA) {
                LOGD("Response not handled (missing data)");
-               request->handled = AT_RESPONSE_UNHANDELD_REASON_DATA;
-               at_request_expect_to_func_queue(request);
+               async_request->handled = AT_RESPONSE_UNHANDELD_REASON_DATA;
+               at_async_request_queue(async_request);
        } else {
-               AT_ASYNC_LOCK();
-               at_request_expect_to_func_release(request);
+               // We can free the request
+               at_async_request_free(async_request);
+
+               // Send the next request in the queue
+               at_send_next_request();
+       }
+
+       return 0;
+}
+
+// Dequeue one async request (only remove from the queue)
+int at_async_request_dequeue(struct at_async_request *async_request)
+{
+       struct at_async_request **async_requests = NULL;
+       int async_requests_count = 0;
+       int pos = -1;
+       int i;
+
+       if(async_request == NULL)
+               return -1;
+
+       AT_ASYNC_LOCK();
+
+       // Save the previous data pointer and count
+       async_requests = at_handling.async_requests_queue.async_requests;
+       async_requests_count = at_handling.async_requests_queue.async_requests_count;
+
+       if(async_requests_count <= 0 || async_requests == NULL) {
+               LOGE("No async requests queued, aborting dequeue!");
+
+               AT_ASYNC_UNLOCK();
+               return -1;
+       }
+
+       for(i=0 ; i < async_requests_count ; i++) {
+               if(async_requests[i] == async_request) {
+                       pos = i;
+                       break;
+               }
+       }
+
+       if(pos < 0) {
+               LOGD("Found no matching async request, aborting dequeue!");
+
                AT_ASYNC_UNLOCK();
+               return -1;
        }
 
-       return rc;
+       // Empty the found position in the async requests array
+       async_requests[pos] = NULL;
+
+       // Move the elements back
+       for(i=pos ; i < async_requests_count-1 ; i++) {
+               async_requests[i] = async_requests[i+1];
+       }
+
+       // Empty the latest element
+       if(pos != async_requests_count-1) {
+               async_requests[async_requests_count-1] = NULL;
+       }
+
+       async_requests_count--;
+
+       if(async_requests_count == 0) {
+               free(async_requests);
+               at_handling.async_requests_queue.async_requests = NULL;
+       }
+
+       at_handling.async_requests_queue.async_requests_count = async_requests_count;
+
+       LOGD("%d elements in the async requests queue", async_requests_count);
+
+       AT_ASYNC_UNLOCK();
+
+       return 0;
 }
 
 /*
- * Expect status
+ * Sync requests queue
  */
 
-void at_response_expect_status_release(void)
+// Lock the sync requests queue
+void at_sync_requests_queue_lock(void)
+{
+       AT_SYNC_QUEUE_LOCK();
+}
+
+// Unlock the sync requests queue
+void at_sync_requests_queue_unlock(void)
+{
+       AT_SYNC_QUEUE_UNLOCK();
+}
+
+// Free the sync request
+void at_sync_request_free(struct at_sync_request *sync_request)
+{
+       if(sync_request == NULL)
+               return;
+
+       if(sync_request->command)
+               free(sync_request->command);
+
+       memset(sync_request, 0, sizeof(struct at_sync_request));
+       sync_request->handled = AT_RESPONSE_GARBAGE;
+}
+
+// Whether the sync queue is empty
+int at_sync_queue_empty(void)
 {
+       struct at_sync_request *sync_request = NULL;
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count;
+
+       int empty = 1;
+
+       AT_SYNC_LOCK();
+
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       if(sync_requests_count <= 0 || sync_requests == NULL)
+               empty = 1;
+       else
+               empty = 0;
+
        AT_SYNC_UNLOCK();
-       at_responses_handling_sync_clean();
+
+       return empty;
+}
+
+// Find a sync request from its command
+struct at_sync_request *at_sync_request_find_command(char *command)
+{
+       struct at_sync_request *sync_request = NULL;
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count = 0;
+       int i;
+
+       if(command == NULL)
+               return NULL;
+
        AT_SYNC_LOCK();
+
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       if(sync_requests_count <= 0 || sync_requests == NULL) {
+               AT_SYNC_UNLOCK();
+               return NULL;
+       }
+
+       for(i=0 ; i < sync_requests_count ; i++) {
+               if(sync_requests[i] != NULL && sync_requests[i]->command != NULL) {
+                       if(at_commands_compare(command, sync_requests[i]->command)) {
+                               sync_request = sync_requests[i];
+                               break;
+                       }
+               }
+       }
+
+       AT_SYNC_UNLOCK();
+
+       return sync_request;
 }
 
-int at_request_expect_status(struct at_request *request)
+// Find a sync request from its handled status
+struct at_sync_request *at_sync_request_find_handled(int handled)
 {
-       // Register the request
+       struct at_sync_request *sync_request = NULL;
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count = 0;
+       int i;
+
+       AT_SYNC_LOCK();
+
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       if(sync_requests_count <= 0 || sync_requests == NULL) {
+               AT_SYNC_UNLOCK();
+               return NULL;
+       }
+
+       for(i=0 ; i < sync_requests_count ; i++) {
+               if(sync_requests[i] != NULL) {
+                       if(sync_requests[i]->handled == handled) {
+                               sync_request = sync_requests[i];
+                               break;
+                       }
+               }
+       }
+
+       AT_SYNC_UNLOCK();
+
+       return sync_request;
+}
+
+// Find a sync request from its request pointer
+struct at_sync_request *at_sync_request_find_request(struct at_request *request)
+{
+       struct at_sync_request *sync_request = NULL;
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count = 0;
+       int i;
 
        if(request == NULL)
-               return -1;
+               return NULL;
 
-       if(at_responses_handling.sync_request != NULL) {
-               LOGE("There is already an AT sync request waiting, aborting!");
-               return -1;
+       AT_SYNC_LOCK();
+
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       if(sync_requests_count <= 0 || sync_requests == NULL) {
+               AT_SYNC_UNLOCK();
+               return NULL;
        }
 
-       if(request->command == NULL) {
-               LOGE("No command was given, aborting!");
+       for(i=0 ; i < sync_requests_count ; i++) {
+               if(sync_requests[i] != NULL) {
+                       if(sync_requests[i]->request == request) {
+                               sync_request = sync_requests[i];
+                               break;
+                       }
+               }
+       }
+
+       AT_SYNC_UNLOCK();
+
+       return sync_request;
+}
+
+// Queue one request to the sync requests queue
+int at_sync_request_queue(struct at_sync_request *sync_request)
+{
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count = 0;
+       int index;
+       int count;
+
+       if(sync_request == NULL)
                return -1;
+
+       AT_SYNC_LOCK();
+
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       if(sync_requests_count < 0)
+               sync_requests_count = 0;
+
+       // Index is the sync request index in the sync requests array
+       index = sync_requests_count;
+       // Count is the total count of sync requests in the array
+       count = index + 1;
+
+       // Alloc the array with the new size
+       at_handling.sync_requests_queue.sync_requests = malloc(sizeof(struct at_sync_request *) * count);
+       at_handling.sync_requests_queue.sync_requests_count = count;
+
+       // Copy and free previous data
+       if(sync_requests != NULL && sync_requests_count > 0) {
+               memcpy(at_handling.sync_requests_queue.sync_requests, sync_requests, sizeof(struct at_sync_request *) * at_handling.sync_requests_queue.sync_requests_count);
+               free(sync_requests);
        }
 
-       at_responses_handling.sync_request = request;
+       // Get the new data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
+
+       // Put the sync request in the queue
+       sync_requests[index] = sync_request;
+
+       LOGD("%d elements in the sync requests queue", sync_requests_count);
+
+       AT_SYNC_UNLOCK();
 
        return 0;
 }
 
-int at_response_expect_status(struct at_response *response)
+// Dequeue one response (that will or not be assigned to a sync request)
+int at_sync_response_dequeue(struct at_response *response)
 {
-       struct at_async_request *request = NULL;
+       struct at_sync_request *sync_request = NULL;
+       struct at_async_request *async_request = NULL;
        int rc;
 
        if(response == NULL)
                return -1;
 
-       // If there is no request waiting for a status
-       if(at_responses_handling.sync_request == NULL && at_request_expect_to_func_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS) == NULL)
-               return -1;
+       if(response->command != NULL && !at_sync_queue_empty()) {
+               if(response->status == AT_STATUS_UNDEF && (response->data == NULL || response->data_count <= 0)) {
+                       // Check if this is a part of a queued sync command
 
-       // If we get an unsol response while we expect a status, there is something going wrong
-       if(response->command != NULL && at_responses_handling.sync_request != NULL && at_responses_handling.sync_request->command != NULL) {
-               rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
-               if(!rc) {
-                       // Only unlock is there is no async request waiting with this command (if it is unsol)!
-                       if(at_request_expect_to_func_find_command(response->command) == NULL) {
-                               AT_SYNC_UNLOCK();
-                       }
+                       sync_request = at_sync_request_find_command(response->command);
+                       if(sync_request != NULL && sync_request->handled == AT_RESPONSE_SENT) {
+                               // This will make this sync request the next one to get a status
 
-                       return -1;
-               }
-       }
+                               sync_request->handled = AT_RESPONSE_UNHANDELD_REASON_STATUS;
 
-       if(response->status == AT_STATUS_UNDEF && at_responses_handling.sync_request != NULL && at_responses_handling.sync_request->command != NULL) {
-               if((response->data == NULL || response->data_count <= 0) && response->command != NULL) {
-                       rc = at_commands_compare(response->command, at_responses_handling.sync_request->command);
-                       if(rc) {
-                               // Command is the one we expect, but there is no status nor data, so just skip it
-                               LOGD("Skipping matching request with no status nor data");
+                               LOGD("Skipping matching request with no status nor data!");
                                at_response_free(response);
                                return 0;
                        }
                }
 
-               // Only unlock if there is a status and command differs
+               // FIXME: What if we get some data for the sync request here, but not with the status yet => set response already => next time if there is already a response, grab its data
+
+               sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT);
+               if(sync_request != NULL && sync_request->command != NULL) {
+                       // If we catch an unsol or a response for another request, there is something wrong
+
+                       rc = at_commands_compare(response->command, sync_request->command);
+                       if(!rc) {
+                               // We don't need to check on the async queue as requests are sent one at a time
+
+                               LOGE("Got a response for another request, aborting!");
+                               AT_SYNC_QUEUE_UNLOCK();
+                               return -1;
+                       }
+               } else {
+                       // There is a command but we didn't send any sync request, so don't deal with it
+
+                       return -1;
+               }
+       }
+
+       // If we have no status at this point, we have no use of the response
+       if(response->status == AT_STATUS_UNDEF) {
                return -1;
        }
 
+       // Have no command but a status
        if(response->command == NULL) {
-               // If there is an async response that was unhandled because it lacked status, fill it
-               request = at_request_expect_to_func_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS);
-               if(request != NULL) {
-                       LOGD("Found an async function that needs a status!");
+               async_request = at_async_request_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS);
+               if(async_request != NULL) {
+                       // FIXME: What if there was already a response with data but no status? We would override data => make a mix of both and free one
 
-                       request->status = response->status;
-                       if(response->error != NULL)
-                               request->error = strdup(response->error);
-                       request->handled = AT_RESPONSE_WAITING;
+                       async_request->response = response;
+                       async_request->handled = AT_RESPONSE_SENT;
 
-                       if(request->command != NULL)
-                               response->command = strdup(request->command);
+                       LOGD("Found a status for a previous async request!");
 
                        return -1;
                }
+
+               sync_request = at_sync_request_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS);
+               if(sync_request != NULL) {
+                       sync_request->handled = AT_RESPONSE_SENT;
+               }
+
        }
 
-       if(at_responses_handling.sync_request == NULL)
-               return -1;
+       if(sync_request == NULL) {
+               sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT);
+               if(sync_request == NULL) {
+                       LOGE("Got a status but no request waiting for it at all, this should never happend!");
+                       return -1;
+               }
+       }
 
-       at_responses_handling.sync_response = response;
+       sync_request->response = response;
+       LOGD("Found a response for a sync request!");
 
-       AT_SYNC_UNLOCK();
+       AT_SYNC_QUEUE_UNLOCK();
 
        return 0;
 }
 
-int at_expect_status(struct at_request *request)
+// Dequeue one sync request (only remove from the queue)
+int at_sync_request_dequeue(struct at_sync_request *sync_request)
 {
-       int rc;
+       struct at_sync_request **sync_requests = NULL;
+       int sync_requests_count = 0;
+       int pos = -1;
+       int i;
 
-       if(request == NULL)
+       if(sync_request == NULL)
                return -1;
 
-       if(at_responses_handling.sync_response == NULL) {
-               LOGD("Blocking for sync response");
+       AT_SYNC_LOCK();
 
-               // Second lock: block until sync_response is there
-               AT_SYNC_LOCK();
-       }
+       // Save the previous data pointer and count
+       sync_requests = at_handling.sync_requests_queue.sync_requests;
+       sync_requests_count = at_handling.sync_requests_queue.sync_requests_count;
 
-       if(at_responses_handling.sync_response == NULL)
+       if(sync_requests_count <= 0 || sync_requests == NULL) {
+               LOGE("No sync requests queued, aborting dequeue!");
+
+               AT_SYNC_UNLOCK();
                return -1;
+       }
 
-       if(at_responses_handling.sync_response->command != NULL) {
-               rc = at_commands_compare(at_responses_handling.sync_response->command, request->command);
-               if(!rc) {
-                       LOGE("Obtained command doesn't match, aborting!");
-                       return -1;
+       for(i=0 ; i < sync_requests_count ; i++) {
+               if(sync_requests[i] == sync_request) {
+                       pos = i;
+                       break;
                }
        }
 
-       LOGD("Found matching sync response");
+       if(pos < 0) {
+               LOGD("Found no matching sync request, aborting dequeue!");
 
-       request->status = at_responses_handling.sync_response->status;
-       if(at_responses_handling.sync_response->error != NULL)
-               request->error = strdup(at_responses_handling.sync_response->error);
+               AT_SYNC_UNLOCK();
+               return -1;
+       }
+
+       // Empty the found position in the sync requests array
+       sync_requests[pos] = NULL;
+
+       // Move the elements back
+       for(i=pos ; i < sync_requests_count-1 ; i++) {
+               sync_requests[i] = sync_requests[i+1];
+       }
+
+       // Empty the latest element
+       if(pos != sync_requests_count-1) {
+               sync_requests[sync_requests_count-1] = NULL;
+       }
+
+       sync_requests_count--;
+
+       if(sync_requests_count == 0) {
+               free(sync_requests);
+               at_handling.sync_requests_queue.sync_requests = NULL;
+       }
+
+       at_handling.sync_requests_queue.sync_requests_count = sync_requests_count;
+
+       LOGD("%d elements in the sync requests queue", sync_requests_count);
+
+       AT_SYNC_UNLOCK();
 
        return 0;
 }
@@ -1102,9 +1521,7 @@ struct at_request *at_request_create(char *command, char *data)
 
 void at_request_free(struct at_request *request)
 {
-       int i;
-
-       if(request->command != NULL)
+       if(request->command != NULL) 
                free(request->command);
 
        if(request->data != NULL)
@@ -1112,20 +1529,32 @@ void at_request_free(struct at_request *request)
 
        if(request->error != NULL)
                free(request->error);
+
+       memset(request, 0, sizeof(struct at_request *));
 }
 
 /*
  * Send
  */
 
-int at_send(char *command, char *data)
+int at_send_next_request(void)
 {
+       struct at_sync_request *sync_request = NULL;
+       struct at_async_request *async_request = NULL;
        struct at_request *request = NULL;
        int rc;
 
-       request = at_request_create(command, data);
+       sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT);
+       async_request = at_async_request_find_handled(AT_RESPONSE_SENT);
+
+       if(sync_request != NULL || async_request != NULL) {
+               LOGE("There are still unanswered requests!");
+               return -1;
+       }
+
+       request = at_request_dequeue();
        if(request == NULL) {
-               LOGE("Unable to create request, aborting!");
+               LOGD("Nothing left to send!");
                return -1;
        }
 
@@ -1136,79 +1565,199 @@ int at_send(char *command, char *data)
                return -1;
        }
 
+       sync_request = at_sync_request_find_request(request);
+       if(sync_request != NULL) {
+               sync_request->handled = AT_RESPONSE_SENT;
+               sync_request->request = NULL;
+       }
+
+       async_request = at_async_request_find_request(request);
+       if(async_request != NULL) {
+               async_request->handled = AT_RESPONSE_SENT;
+               async_request->request = NULL;
+       }
+
        at_request_free(request);
 
        return 0;
 }
 
-int at_send_command(char *command)
+int at_send_async(struct at_request *request, void *data, RIL_Token token, at_async_request_cb func)
 {
-       return at_send(command, NULL);
+       struct at_async_request *async_request = NULL;
+       int rc;
+       int i;
+
+       if(request->command == NULL || func == NULL)
+               return -1;
+
+       async_request = calloc(1, sizeof(struct at_async_request));
+       async_request->handled = AT_RESPONSE_WAITING;
+       async_request->request = request;
+       async_request->command = strdup(request->command);
+       async_request->data = data;
+       async_request->token = token;
+       async_request->func = func;
+
+       rc = at_async_request_queue(async_request);
+       if(rc < 0) {
+               LOGE("Unable to queue async request");
+
+               at_async_request_free(async_request);
+               return -1;
+       }
+
+       rc = at_request_queue(request);
+       if(rc < 0) {
+               LOGE("Unable to queue request");
+
+               // Better trying to dequeue too
+               at_async_request_dequeue(async_request);
+               at_async_request_free(async_request);
+               return NULL;
+       }
+
+       // Try to send it now, don't fail if it can't
+       at_send_next_request();
+
+       return 0;
 }
 
-int at_send_expect_status(char *command, char *data)
+struct at_response *at_send_sync(struct at_request *request)
 {
-       struct at_request *request = NULL;
-       int tries;
-       int status;
+       struct at_sync_request *sync_request = NULL;
+       struct at_response *response = NULL;
        int rc;
        int i;
 
-       if(command == NULL)
-               return -1;
+       if(request->command == NULL)
+               return NULL;
+
+       sync_request = calloc(1, sizeof(struct at_sync_request));
+       sync_request->handled = AT_RESPONSE_WAITING;
+       sync_request->request = request;
+       sync_request->command = strdup(request->command);
+
+       rc = at_sync_request_queue(sync_request);
+       if(rc < 0) {
+               LOGE("Unable to queue sync request");
+
+               at_sync_request_free(sync_request);
+               return NULL;
+       }
+
+       rc = at_request_queue(request);
+       if(rc < 0) {
+               LOGE("Unable to queue request");
+
+               // Better trying to dequeue too
+               at_sync_request_dequeue(sync_request);
+               at_sync_request_free(sync_request);
+               return NULL;
+       }
+
+       // Try to send it now, don't fail if it can't
+       at_send_next_request();
+
+       // Block until there is a response available
+       at_sync_requests_queue_lock();
+
+       if(sync_request->response == NULL) {
+               LOGE("Sync queue was unlocked but there is no response, aborting");
+
+               // Better trying to dequeue too
+               at_sync_request_dequeue(sync_request);
+               at_sync_request_free(sync_request);
+
+               // Send the next request in the queue
+               at_send_next_request();
+
+               return NULL;
+       }
+
+       response = sync_request->response;
+
+       at_sync_request_free(sync_request);
+
+       // Send the next request in the queue
+       at_send_next_request();
+
+       return response;
+}
+
+int at_send_expect_to_func(char *command, char *data, void *async_data, RIL_Token token, at_async_request_cb func)
+{
+       struct at_request *request = NULL;
+       int rc;
 
        request = at_request_create(command, data);
        if(request == NULL) {
-               LOGE("Unable to create request, aborting!");
-               return AT_STATUS_INTERNAL_ERROR;
+               LOGE("Unable to create request, aborting");
+               return -1;
        }
 
-       // Try to register request 5 times, during 5 * 1s
-       for(i=5 ; i > 0 ; i--) {
-               rc = at_request_expect_status(request);
-               if(rc < 0) {
-                       LOGE("Unable to request expect status, retrying!");
-                       sleep(1);
-               } else {
-                       break;
-               }
-       }
+       rc = at_send_async(request, async_data, token, func);
        if(rc < 0) {
-               LOGE("Unable to request expect status, aborting!");
+               LOGE("Unable to send async request, aborting");
+
                at_request_free(request);
-               return AT_STATUS_INTERNAL_ERROR;
+               return -1;
        }
 
-       rc = at_request_send(request);
-       if(rc < 0) {
-               LOGE("Unable to send request, aborting!");
-               at_response_expect_status_release();
-               return AT_STATUS_INTERNAL_ERROR;
+       return 0;
+}
+
+int at_send_expect_status(char *command, char *data)
+{
+       struct at_request *request = NULL;
+       struct at_response *response = NULL;
+       int status;
+
+       request = at_request_create(command, data);
+       if(request == NULL) {
+               LOGE("Unable to create request, aborting");
+               return -1;
        }
 
-       // Block here
-       rc = at_expect_status(request);
-       if(rc < 0) {
-               LOGE("Unable to get expected status, aborting!");
-               at_response_expect_status_release();
-               return AT_STATUS_INTERNAL_ERROR;
+       response = at_send_sync(request);
+       if(response == NULL) {
+               LOGE("Unable to get sync response, aborting");
+
+               at_request_free(request);
+               return -1;
        }
 
-       status = request->status;
+       status = response->status;
 
-       // Release sync structures and lock the mutex
-       at_response_expect_status_release();
+       at_request_free(request);
+       at_response_free(response);
 
        return status;
 }
 
-int at_send_expect_to_func(char *command, char *data, void *pdata, RIL_Token t, at_async_request_cb func)
+int at_send_noresp(char *command, char *data)
 {
-       struct at_request *request = NULL;
-       int rc;
+       struct at_response *response;
 
-       if(command == NULL)
+       response = at_send(command, data);
+       if(response != NULL) {
+               at_response_free(response);
+               return 0;
+       } else {
                return -1;
+       }
+}
+
+struct at_response *at_send_command(char *command)
+{
+       return at_send(command, NULL);
+}
+
+struct at_response *at_send(char *command, char *data)
+{
+       struct at_request *request = NULL;
+       struct at_response *response = NULL;
+       int rc;
 
        request = at_request_create(command, data);
        if(request == NULL) {
@@ -1216,18 +1765,13 @@ int at_send_expect_to_func(char *command, char *data, void *pdata, RIL_Token t,
                return -1;
        }
 
-       rc = at_request_expect_to_func(command, pdata, t, func);
-       if(rc < 0) {
-               LOGE("Unable to request expect to func, aborting!");
-               at_request_free(request);
-       }
+       response = at_send_sync(request);
+       if(response == NULL) {
+               LOGE("Unable to get sync response, aborting");
 
-       rc = at_request_send(request);
-       if(rc < 0) {
-               LOGE("Unable to send request, aborting!");
                at_request_free(request);
                return -1;
        }
 
-       return 0;
+       return response;
 }