AT: Various code fixes, new async handled code, spare status/error handling
authorPaul Kocialkowski <contact@paulk.fr>
Thu, 26 Jul 2012 14:12:35 +0000 (16:12 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Thu, 26 Jul 2012 14:12:35 +0000 (16:12 +0200)
This following changes were introduced with this commit:
* Added handled code for async
* New function to get async request by handled code
* Spare status/error handling for unhandled async responses (with no status)
* Split some expect_to_func functions to queue, dequeue and release
* Try 5 times (with delay) to register sync requests before aborting
* Unqueue async request before calling func and release next

Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
at.c
at.h

diff --git a/at.c b/at.c
index 2c0605b..500c740 100644 (file)
--- a/at.c
+++ b/at.c
@@ -547,7 +547,7 @@ struct at_response *at_response_dequeue(void)
        responses = at_responses_handling.responses_queue.responses;
        responses_count = at_responses_handling.responses_queue.responses_count;
 
-       if(responses_count <= 0 && responses == NULL) {
+       if(responses_count <= 0 || responses == NULL) {
                LOGE("No response queued, blocking!");
 
                AT_RESPONSES_UNLOCK();
@@ -600,7 +600,43 @@ struct at_response *at_response_dequeue(void)
  * Expect to func
  */
 
-void at_request_expect_to_func_release(struct at_async_request *request)
+int at_request_expect_to_func_queue(struct at_async_request *request)
+{
+       struct at_async_request **requests = NULL;
+       int requests_count = 0;
+       int index;
+       int count;
+
+       if(request == NULL)
+               return -1;
+
+       // Index is the request index in the requests array
+       index = at_responses_handling.async_queue.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);
+
+       // Copy and free previous data
+       if(requests != NULL) {
+               memcpy(at_responses_handling.async_queue.requests, requests, sizeof(struct at_async_request *) * requests_count);
+               free(requests);
+       }
+
+       requests = at_responses_handling.async_queue.requests;
+       requests[index] = request;
+
+       at_responses_handling.async_queue.requests_count = count;
+
+       return 0;
+}
+
+void at_request_expect_to_func_dequeue(struct at_async_request *request)
 {
        struct at_async_request **requests = NULL;
        int requests_count = 0;
@@ -621,14 +657,10 @@ void at_request_expect_to_func_release(struct at_async_request *request)
        }
 
        if(pos == -1) {
-               LOGD("Found no matching request, aborting release!");
+               LOGD("Found no matching request, aborting dequeue!");
                return;
        }
 
-       if(requests[pos]->command != NULL)
-               free(requests[pos]->command);
-
-       free(requests[pos]);
        requests[pos] = NULL;
 
        // Move the elements back
@@ -647,56 +679,63 @@ void at_request_expect_to_func_release(struct at_async_request *request)
                free(requests);
                at_responses_handling.async_queue.requests = NULL;
        }
+
+       LOGD("%d elements left in the async queue", at_responses_handling.async_queue.requests_count);
 }
 
-int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
+void at_request_expect_to_func_release(struct at_async_request *request)
 {
-       struct at_async_request **requests = NULL;
-       int index;
-       int count;
-
-       if(command == NULL || func == NULL) {
-               return -1;
-       }
+       if(request == NULL)
+               return;
 
-       AT_ASYNC_LOCK();
+       if(request->command != NULL)
+               free(request->command);
+       if(request->error != NULL)
+               free(request->error);
 
-       // Index is the request index in the requests array
-       index = at_responses_handling.async_queue.requests_count;
-       // Count is the total count of requests in the array
-       count = index + 1;
+       free(request);
+}
 
-       // Save the previous data pointer
-       requests = at_responses_handling.async_queue.requests;
+struct at_async_request *at_request_expect_to_func_find_command(char *command)
+{
+       struct at_async_request *request = NULL;
+       struct at_async_request **requests = NULL;
+       int requests_count = 0;
+       int rc;
+       int i;
 
-       // Alloc the array with the new size
-       at_responses_handling.async_queue.requests = malloc(sizeof(struct at_async_request *) * count);
+       if(command == NULL)
+               return NULL;
 
-       // Copy and free previous data
-       if(requests != NULL) {
-               memcpy(at_responses_handling.async_queue.requests, requests, sizeof(struct at_async_request *) * at_responses_handling.async_queue.requests_count);
-               free(requests);
-       }
+       AT_ASYNC_LOCK();
 
+       request = NULL;
        requests = at_responses_handling.async_queue.requests;
+       requests_count = at_responses_handling.async_queue.requests_count;
 
-       // Alloc new structure and copy obtained data
-       requests[index] = calloc(1, sizeof(struct at_async_request));
-       requests[index]->command = strdup(command);
-       requests[index]->data = data;
-       requests[index]->token = t;
-       requests[index]->func = func;
-
-       at_responses_handling.async_queue.requests_count = count;
+       if(requests == NULL) {
+               AT_ASYNC_UNLOCK();
+               return NULL;
+       }
 
-       LOGD("Registered async function for command: %s", command);
+       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;
+                               }
+                       }
+               }
+       }
 
        AT_ASYNC_UNLOCK();
 
-       return 0;
+       return request;
 }
 
-struct at_async_request *at_request_expect_to_func_find(char *command)
+struct at_async_request *at_request_expect_to_func_find_handled(int handled)
 {
        struct at_async_request *request = NULL;
        struct at_async_request **requests = NULL;
@@ -704,9 +743,6 @@ struct at_async_request *at_request_expect_to_func_find(char *command)
        int rc;
        int i;
 
-       if(command == NULL)
-               return NULL;
-
        AT_ASYNC_LOCK();
 
        request = NULL;
@@ -720,12 +756,9 @@ struct at_async_request *at_request_expect_to_func_find(char *command)
 
        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;
-                               }
+                       if(requests[i]->handled == handled) {
+                               request = requests[i];
+                               break;
                        }
                }
        }
@@ -735,6 +768,40 @@ struct at_async_request *at_request_expect_to_func_find(char *command)
        return request;
 }
 
+int at_request_expect_to_func(char *command, void *data, RIL_Token t, at_async_request_cb func)
+{
+       struct at_async_request *request = NULL;
+       int rc;
+
+       if(command == NULL || func == NULL) {
+               return -1;
+       }
+
+       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);
+       }
+
+       LOGD("Registered async function for command: %s", command);
+
+       AT_ASYNC_UNLOCK();
+
+       return 0;
+}
+
 int at_response_expect_to_func(struct at_response *response)
 {
        struct at_async_request *request = NULL;
@@ -743,17 +810,37 @@ int at_response_expect_to_func(struct at_response *response)
        if(response == NULL || response->command == NULL)
                return -1;
 
-       request = at_request_expect_to_func_find(response->command);
+       request = at_request_expect_to_func_find_command(response->command);
        if(request == NULL || request->func == NULL) {
                return -1;
-       } else {
-               LOGD("Found a matching request!");
        }
 
+       LOGD("Found a matching request!");
+
+       // 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;
+
+       // 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;
+
+       at_request_expect_to_func_dequeue(request);
+
        // This must run out of any mutex
        rc = request->func(response, request->data, request->token);
 
-       if(rc != AT_RESPONSE_UNHANDELD) {
+       // 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);
+       } 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);
+       } else {
                AT_ASYNC_LOCK();
                at_request_expect_to_func_release(request);
                AT_ASYNC_UNLOCK();
@@ -797,6 +884,7 @@ int at_request_expect_status(struct at_request *request)
 
 int at_response_expect_status(struct at_response *response)
 {
+       struct at_async_request *request = NULL;
        int rc;
 
        if(response == NULL)
@@ -806,16 +894,12 @@ int at_response_expect_status(struct at_response *response)
                return -1;
        }
 
-       if(response->status == AT_STATUS_UNDEF) {
-               // Only unlock if there is a status and command differs
-               return -1;
-       }
-
+       // If we get an unsol response while we expect a status, there is something going wrong
        if(response->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(at_request_expect_to_func_find(response->command) == NULL) {
+                       // 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();
                        }
 
@@ -823,6 +907,36 @@ int at_response_expect_status(struct at_response *response)
                }
        }
 
+
+       if(response->status == AT_STATUS_UNDEF) {
+               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");
+                               at_response_free(response);
+                               return 0;
+                       }
+               }
+
+               // Only unlock if there is a status and command differs
+               return -1;
+       }
+
+       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) {
+                       request->status = response->status;
+                       if(response->error != NULL)
+                               request->error = strdup(response->error);
+                       request->handled = AT_RESPONSE_WAITING;
+
+                       at_response_free(response);
+                       return 0;
+               }
+       }
+
        at_responses_handling.sync_response = response;
 
        AT_SYNC_UNLOCK();
@@ -837,8 +951,12 @@ int at_expect_status(struct at_request *request)
        if(request == NULL)
                return -1;
 
-       // Second lock: block until sync_response is there
-       AT_SYNC_LOCK();
+       if(at_responses_handling.sync_response == NULL) {
+               LOGD("Blocking for sync response");
+
+               // Second lock: block until sync_response is there
+               AT_SYNC_LOCK();
+       }
 
        if(at_responses_handling.sync_response == NULL)
                return -1;
@@ -851,6 +969,8 @@ int at_expect_status(struct at_request *request)
                }
        }
 
+       LOGD("Found matching sync response");
+
        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);
@@ -1002,8 +1122,10 @@ int at_send_command(char *command)
 int at_send_expect_status(char *command, char *data)
 {
        struct at_request *request = NULL;
+       int tries;
        int status;
        int rc;
+       int i;
 
        if(command == NULL)
                return -1;
@@ -1011,20 +1133,28 @@ int at_send_expect_status(char *command, char *data)
        request = at_request_create(command, data);
        if(request == NULL) {
                LOGE("Unable to create request, aborting!");
-               at_response_expect_status_release();
                return AT_STATUS_INTERNAL_ERROR;
        }
 
-       rc = at_request_send(request);
+       // 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;
+               }
+       }
        if(rc < 0) {
-               LOGE("Unable to send request, aborting!");
-               at_response_expect_status_release();
+               LOGE("Unable to request expect status, aborting!");
+               at_request_free(request);
                return AT_STATUS_INTERNAL_ERROR;
        }
 
-       rc = at_request_expect_status(request);
+       rc = at_request_send(request);
        if(rc < 0) {
-               LOGE("Unable to request expect status, aborting!");
+               LOGE("Unable to send request, aborting!");
                at_response_expect_status_release();
                return AT_STATUS_INTERNAL_ERROR;
        }
diff --git a/at.h b/at.h
index abd4d90..869b100 100644 (file)
--- a/at.h
+++ b/at.h
@@ -69,7 +69,9 @@ enum {
 };
 
 enum {
-       AT_RESPONSE_UNHANDELD,
+       AT_RESPONSE_WAITING,
+       AT_RESPONSE_UNHANDELD_REASON_DATA,
+       AT_RESPONSE_UNHANDELD_REASON_STATUS,
        AT_RESPONSE_HANDLED_OK,
        AT_RESPONSE_HANDLED_ERROR,
 };
@@ -82,6 +84,10 @@ struct at_responses_queue {
 typedef int (*at_async_request_cb)(struct at_response *response, void *data, RIL_Token t);
 
 struct at_async_request {
+       int handled;
+       int status;
+       char *error;
+
        char *command;
        void *data;
        RIL_Token token;