Reworked AT queuing, with queues for send, recv, async recv and sync recv
authorPaul Kocialkowski <contact@paulk.fr>
Mon, 30 Jul 2012 11:06:33 +0000 (13:06 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Mon, 30 Jul 2012 11:06:33 +0000 (13:06 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
at.c
at.h
device.c
hayes-ril.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;
 }
diff --git a/at.h b/at.h
index 9b04057..8651340 100644 (file)
--- a/at.h
+++ b/at.h
  * Defines
  */
 
-#define AT_SYNC_LOCK() pthread_mutex_lock(&(at_responses_handling.sync_mutex));
-#define AT_SYNC_UNLOCK() pthread_mutex_unlock(&(at_responses_handling.sync_mutex));
-#define AT_ASYNC_LOCK() pthread_mutex_lock(&(at_responses_handling.async_mutex));
-#define AT_ASYNC_UNLOCK() pthread_mutex_unlock(&(at_responses_handling.async_mutex));
-#define AT_RESPONSES_LOCK() pthread_mutex_lock(&(at_responses_handling.responses_mutex));
-#define AT_RESPONSES_UNLOCK() pthread_mutex_unlock(&(at_responses_handling.responses_mutex));
-#define AT_RESPONSES_QUEUE_LOCK() pthread_mutex_lock(&(at_responses_handling.responses_queue_mutex));
-#define AT_RESPONSES_QUEUE_UNLOCK() pthread_mutex_unlock(&(at_responses_handling.responses_queue_mutex));
+#define AT_RESPONSES_QUEUE_LOCK() pthread_mutex_lock(&(at_handling.responses_queue.queue_mutex));
+#define AT_RESPONSES_QUEUE_UNLOCK() pthread_mutex_unlock(&(at_handling.responses_queue.queue_mutex));
+#define AT_RESPONSES_LOCK() pthread_mutex_lock(&(at_handling.responses_queue.mutex));
+#define AT_RESPONSES_UNLOCK() pthread_mutex_unlock(&(at_handling.responses_queue.mutex));
+#define AT_REQUESTS_LOCK() pthread_mutex_lock(&(at_handling.requests_queue.mutex));
+#define AT_REQUESTS_UNLOCK() pthread_mutex_unlock(&(at_handling.requests_queue.mutex));
+#define AT_SYNC_QUEUE_LOCK() pthread_mutex_lock(&(at_handling.sync_requests_queue.queue_mutex));
+#define AT_SYNC_QUEUE_UNLOCK() pthread_mutex_unlock(&(at_handling.sync_requests_queue.queue_mutex));
+#define AT_SYNC_LOCK() pthread_mutex_lock(&(at_handling.sync_requests_queue.mutex));
+#define AT_SYNC_UNLOCK() pthread_mutex_unlock(&(at_handling.sync_requests_queue.mutex));
+#define AT_ASYNC_LOCK() pthread_mutex_lock(&(at_handling.async_requests_queue.mutex));
+#define AT_ASYNC_UNLOCK() pthread_mutex_unlock(&(at_handling.async_requests_queue.mutex));
 
 #define AT_PARSE_SINGLE_QUOTE  (1 << 0)
 #define AT_PARSE_DOUBLE_QUOTE  (1 << 1)
@@ -137,47 +141,73 @@ enum {
 
 enum {
        AT_RESPONSE_WAITING,
+       AT_RESPONSE_SENT,
        AT_RESPONSE_UNHANDELD_REASON_DATA,
        AT_RESPONSE_UNHANDELD_REASON_STATUS,
        AT_RESPONSE_HANDLED_OK,
        AT_RESPONSE_HANDLED_ERROR,
-};
-
-struct at_responses_queue {
-       struct at_response **responses;
-       int responses_count;
+       AT_RESPONSE_GARBAGE,
 };
 
 typedef int (*at_async_request_cb)(struct at_response *response, void *data, RIL_Token t);
 
+struct at_sync_request {
+       int handled;
+
+       struct at_request *request;
+       struct at_response *response;
+
+       char *command;
+};
+
 struct at_async_request {
        int handled;
-       int status;
-       char *error;
+
+       struct at_request *request;
+       struct at_response *response;
 
        char *command;
        void *data;
        RIL_Token token;
-
        at_async_request_cb func;
 };
 
-struct at_async_queue {
-       struct at_async_request **requests;
+struct at_responses_queue {
+       struct at_response **responses;
+       int responses_count;
+
+       pthread_mutex_t queue_mutex;
+       pthread_mutex_t mutex;
+};
+
+struct at_requests_queue {
+       struct at_request **requests;
        int requests_count;
+
+       pthread_mutex_t mutex;
 };
 
-struct at_responses_handling {
-       pthread_mutex_t responses_queue_mutex;
-       struct at_responses_queue responses_queue;
-       pthread_mutex_t responses_mutex;
+struct at_sync_requests_queue {
+       struct at_sync_request **sync_requests;
+       int sync_requests_count;
+
+       pthread_mutex_t queue_mutex;
+       pthread_mutex_t mutex;
+};
+
+struct at_async_requests_queue {
+       struct at_async_request **async_requests;
+       int async_requests_count;
 
-       struct at_async_queue async_queue;
-       pthread_mutex_t async_mutex;
+       pthread_mutex_t mutex;
+};
+
+struct at_handling {
+       struct at_responses_queue responses_queue;
+       struct at_requests_queue requests_queue;
 
-       struct at_request *sync_request;
-       struct at_response *sync_response;
-       pthread_mutex_t sync_mutex;
+       struct at_sync_requests_queue sync_requests_queue;
+       struct at_async_requests_queue async_requests_queue;
 };
 
 /*
@@ -193,23 +223,20 @@ int at_status_error(int status);
 // Responses structures processing
 int at_responses_process(struct at_response ***responses_p, char *data, int length);
 void at_response_free(struct at_response *response);
-void at_responses_free(struct at_response **responses, int responses_count);
 
-// Responses handling
-void at_responses_handling_init(void);
+// Handling
+void at_handling_init(void);
 
 // Responses queue
+void at_responses_queue_unlock(void);
 int at_response_queue(struct at_response *response);
 struct at_response *at_response_dequeue(void);
 
-// Expect to func
-int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func);
-int at_response_expect_to_func(struct at_response *response);
+// Async
+int at_async_response_dequeue(struct at_response *response);
 
-// Expect status
-int at_request_expect_status(struct at_request *request);
-int at_response_expect_status(struct at_response *response);
-int at_expect_status(struct at_request *request);
+// Sync
+int at_sync_response_dequeue(struct at_response *response);
 
 // Request
 int at_request_send(struct at_request *request);
@@ -217,9 +244,12 @@ struct at_request *at_request_create(char *command, char *data);
 void at_request_free(struct at_request *request);
 
 // Send
-int at_send(char *command, char *data);
-int at_send_command(char *command);
+int at_send_async(struct at_request *request, void *data, RIL_Token token, at_async_request_cb func);
+struct at_response *at_send_sync(struct at_request *request);
+int at_send_expect_to_func(char *command, char *data, void *async_data, RIL_Token token, at_async_request_cb func);
 int at_send_expect_status(char *command, char *data);
-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_response *at_send_command(char *command);
+struct at_response *at_send(char *command, char *data);
 
 #endif
index f9a55d7..c974f26 100644 (file)
--- a/device.c
+++ b/device.c
@@ -412,7 +412,8 @@ int ril_device_recv_loop(struct ril_device *ril_device_p)
                                ril_recv_log(responses[j]);
                                RIL_LOG_UNLOCK();
 
-                               rc = at_response_expect_status(responses[j]);
+                               // Handle sync
+                               rc = at_sync_response_dequeue(responses[j]);
                                if(rc < 0) {
                                        rc = at_response_queue(responses[j]);
                                        if(rc < 0) {
index ff36106..4617cda 100644 (file)
@@ -96,17 +96,19 @@ void *ril_dispatch(void *data)
                        if(response == NULL)
                                break;
 
-                       if(response->command == NULL) {
-                               at_response_free(response);
-                               continue;
-                       }
-
                        // Dequeue works now
                        if(i != 5)
                                i = 5;
 
-                       rc = at_response_expect_to_func(response);
+                       // Handle async
+                       rc = at_async_response_dequeue(response);
                        if(rc < 0) {
+                               // Handle UNSOL
+                               if(response->command == NULL) {
+                                       at_response_free(response);
+                                       continue;
+                               }
+
                                for(j=0 ; j < ril_globals.dispatch_unsol_count ; j++) {
                                        if(at_commands_compare(response->command, ril_globals.dispatch_unsol[j].command) && ril_globals.dispatch_unsol[j].func != NULL) {
                                                ril_globals.dispatch_unsol[j].func(response);
@@ -152,7 +154,7 @@ void ril_globals_init(void)
 
        ril_globals.radio_state = RADIO_STATE_OFF;
 
-       at_responses_handling_init();
+       at_handling_init();
 }
 
 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)