* Globals
*/
-struct at_responses_handling at_responses_handling;
+struct at_handling at_handling;
/*
* Utilities
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!");
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);
}
}
}
- 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
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;
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
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)
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;
}
}
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;
}
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)
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;
}
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) {
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;
}