From 750c41cbb535fcd12493f18e94f775df4cb42e53 Mon Sep 17 00:00:00 2001 From: ArenM Date: Tue, 7 Sep 2021 19:44:14 -0400 Subject: [PATCH 1/7] gnss: rearrange enable_mm_gnss so it doesn't noop --- src/gnss.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 2116c18..64fcbcf 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -372,9 +372,9 @@ static void finish_assistance_data_upload(struct EG25Manager *manager) #ifdef HAVE_MMGLIB static void enable_mm_gnss(struct EG25Manager *manager) { - MMModemLocationSource sources; - gboolean signal_location; g_autoptr (GError) error = NULL; + MMModemLocationSource sources = mm_modem_location_get_enabled(manager->mm_location); + gboolean signal_location = mm_modem_location_signals_location(manager->mm_location); if (manager->gnss_sources & EG25_GNSS_SOURCE_UNMANAGED) sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED; @@ -383,8 +383,6 @@ static void enable_mm_gnss(struct EG25Manager *manager) if (manager->gnss_sources & EG25_GNSS_SOURCE_RAW) sources |= MM_MODEM_LOCATION_SOURCE_GPS_RAW; - sources = mm_modem_location_get_enabled(manager->mm_location); - signal_location = mm_modem_location_signals_location(manager->mm_location); mm_modem_location_setup_sync(manager->mm_location, sources, signal_location, NULL, &error); if (error != NULL) From 6177c7167cdd6dbc103f42a4797d153abf01f6d0 Mon Sep 17 00:00:00 2001 From: ArenM Date: Tue, 7 Sep 2021 19:48:40 -0400 Subject: [PATCH 2/7] gnss: use sendfile to upload xtra data This should make the data upload much faster because it handles incomplete writes better, and because it the kernel copies the data between the files directly, and it doesn't get sent to userspace and back. --- src/gnss.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 64fcbcf..2a1b38a 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -8,8 +8,12 @@ #include "manager.h" #include "at.h" +#include +#include +#include + #define BUFFER_SIZE 256 -#define UPLOAD_DELAY 100000 +#define UPLOAD_DELAY_US 10000 #define RESCHEDULE_IN_SECS 30 static void gnss_step(struct EG25Manager *manager); @@ -297,39 +301,34 @@ static void init_assistance_data_upload(struct EG25Manager *manager) static void upload_assistance_data(struct EG25Manager *manager) { - char buffer[2*BUFFER_SIZE]; - gint len; - gboolean success = TRUE; + gint error; + glong written_total = 0; + gint ret; + struct stat sb; - /* Copy downloaded XTRA assistance data to the modem over serial */ - while((len = read(manager->gnss_assistance_fd, buffer, 2*BUFFER_SIZE)) > 0) - { - len = write(manager->at_fd, buffer, len); - if (len < 0) { - success = FALSE; - g_error("Writing GNSS assistance data failed: %d", len); - break; - } - usleep(UPLOAD_DELAY); - g_message("Uploaded %d bytes", len); + if (fstat(manager->gnss_assistance_fd, &sb) != 0) { + g_error("Unable to upload xtra data: %s", g_strerror(errno)); } + do { + errno = 0; + /* Copy downloaded XTRA assistance data to the modem over serial */ + ret = sendfile(manager->at_fd, manager->gnss_assistance_fd, &written_total, sb.st_size); + error = errno; + usleep(UPLOAD_DELAY_US); + } while ((!error && written_total < sb.st_size) || (ret == -1 && error == EAGAIN)); + /* Clear QFUPL AT command and process next */ at_next_command(manager); /* Go to the next step if successful */ - if (success) { + if (!error) { + g_message("Successfully uploaded %ld bytes to the modem", written_total); manager->gnss_assistance_step++; gnss_step(manager); - } - /* Restart upload */ - else { - g_message ("Rescheduling upload because of failure in %ds", - RESCHEDULE_IN_SECS); + } else { + g_critical("Unable to upload xtra data: %s", g_strerror(error)); manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; - g_timeout_add_seconds(RESCHEDULE_IN_SECS, - G_SOURCE_FUNC(gnss_upload_assistance_data), - manager); } } From ad1d6e5d3e73ebba95d2ff014f6242345983d64b Mon Sep 17 00:00:00 2001 From: ArenM Date: Sat, 11 Sep 2021 13:42:59 -0400 Subject: [PATCH 3/7] gnss: increase upload timeout to 10 seconds The timeout for QFUPL defaults to 5 seconds which is about how long it takes to upload data under ideal circumstances. I'm not sure if this will actually have an effect, the docs say " The time waiting for data to be inputted to USB/UART. The default value is 5. Unit: s." which could be the time before the first byte is received. --- src/gnss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 2a1b38a..0145606 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -14,6 +14,7 @@ #define BUFFER_SIZE 256 #define UPLOAD_DELAY_US 10000 +#define UPLOAD_TIMEOUT_S 10 #define RESCHEDULE_IN_SECS 30 static void gnss_step(struct EG25Manager *manager); @@ -280,8 +281,8 @@ static void init_assistance_data_upload_start(struct EG25Manager *manager, lseek(manager->gnss_assistance_fd, 0, SEEK_SET); /* Start upload */ - g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\",%ld\r\n", - manager->gnss_assistance_file, size); + g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\",%ld,%d", + manager->gnss_assistance_file, size, UPLOAD_TIMEOUT_S); g_message("Initiate GNSS assistance data upload: %s", value); at_append_command(manager, "QFUPL", NULL, value, NULL, init_assistance_data_upload_ready); From 593db8aa674821f9687c86c4be684e3a162e2f04 Mon Sep 17 00:00:00 2001 From: ArenM Date: Sun, 12 Sep 2021 12:46:28 -0400 Subject: [PATCH 4/7] gnss: include error messages directly from curl This will print the error message from curl instead of just the http status code if downloading gpsOneXtra data fails. This also removes the need to check to check the size of the file curl downloaded. --- src/gnss.c | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 0145606..16b79a1 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -189,10 +189,10 @@ static void fetch_assistance_data(struct EG25Manager *manager) { CURL *curl; CURLcode response; - long status_code; gchar *url = NULL; FILE *tmp_file = NULL; - long int size; + gchar errbuf[CURL_ERROR_SIZE]; + errbuf[0] = 0; /* Fetch assistance data with curl */ tmp_file = fdopen(manager->gnss_assistance_fd, "wb+"); @@ -203,17 +203,19 @@ static void fetch_assistance_data(struct EG25Manager *manager) curl = curl_easy_init(); if (!curl) g_error ("Unable to initialize curl"); + curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEDATA, tmp_file); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + response = curl_easy_perform(curl); - if (response == CURLE_HTTP_RETURNED_ERROR) { - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code); - curl_easy_cleanup(curl); - g_warning ("Unable to fetch GNSS assistance data from %s (HTTP %ld)", - url, status_code); + curl_easy_cleanup(curl); + if (response != CURLE_OK) { + g_warning ("Unable to fetch GNSS assistance data from %s: %s", + url, strlen(errbuf) ? errbuf : curl_easy_strerror(response)); /* Restart upload on HTTP error status code */ g_message ("Rescheduling upload because of failure in %ds", @@ -225,28 +227,7 @@ static void fetch_assistance_data(struct EG25Manager *manager) return; } - /* Get file size in bytes */ - size = (long int)lseek(manager->gnss_assistance_fd, 0, SEEK_END); - lseek(manager->gnss_assistance_fd, 0, SEEK_SET); - - if (size <= 0) { - g_warning ("GNSS assistance data contains 0 bytes," - "check network connection."); - /* - * Restart upload when file does not contain any data, - * mostly because of no network connection. - */ - g_message ("Rescheduling upload because of failure in %ds", - RESCHEDULE_IN_SECS); - manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; - g_timeout_add_seconds(RESCHEDULE_IN_SECS, - G_SOURCE_FUNC(gnss_upload_assistance_data), - manager); - return; - } - g_message("Fetching GNSS assistance data from %s was successfull", url); - curl_easy_cleanup(curl); g_free(url); /* Go to the next step */ From 2fcb5852aea267f7b6f532738ffb8edba71d951b Mon Sep 17 00:00:00 2001 From: ArenM Date: Wed, 29 Sep 2021 14:28:59 -0400 Subject: [PATCH 5/7] gnss: better error handling and messages when fetching data This will print the error message from curl instead of just the http status code if downloading gpsOneXtra data fails. It also adds checks for other errors that are likely to occur. --- src/gnss.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 16b79a1..898c0da 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -187,22 +187,32 @@ static void state_at_gnss(struct EG25Manager *manager) static void fetch_assistance_data(struct EG25Manager *manager) { - CURL *curl; CURLcode response; - gchar *url = NULL; + curl_off_t downloaded; + CURL *curl = NULL; + g_autofree gchar *url = NULL; FILE *tmp_file = NULL; gchar errbuf[CURL_ERROR_SIZE]; errbuf[0] = 0; /* Fetch assistance data with curl */ tmp_file = fdopen(manager->gnss_assistance_fd, "wb+"); + if (tmp_file == NULL) { + g_critical("Unable to open file to save assistance data: %s", + g_strerror(errno)); + goto bail; + } + lseek(manager->gnss_assistance_fd, 0, SEEK_SET); ftruncate(manager->gnss_assistance_fd, 0); url = g_strconcat(manager->gnss_assistance_url, "/", manager->gnss_assistance_file, NULL); + curl = curl_easy_init(); - if (!curl) - g_error ("Unable to initialize curl"); + if (!curl) { + g_critical("Unable to initialize curl"); + goto bail; + } curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); @@ -212,27 +222,33 @@ static void fetch_assistance_data(struct EG25Manager *manager) curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); response = curl_easy_perform(curl); - curl_easy_cleanup(curl); if (response != CURLE_OK) { - g_warning ("Unable to fetch GNSS assistance data from %s: %s", - url, strlen(errbuf) ? errbuf : curl_easy_strerror(response)); + g_warning("Unable to fetch GNSS assistance data from %s: %s", + url, strlen(errbuf) ? errbuf : curl_easy_strerror(response)); + goto bail; + } - /* Restart upload on HTTP error status code */ - g_message ("Rescheduling upload because of failure in %ds", - RESCHEDULE_IN_SECS); - manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; - g_timeout_add_seconds(RESCHEDULE_IN_SECS, - G_SOURCE_FUNC(gnss_upload_assistance_data), - manager); - return; + response = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &downloaded); + if (response) { + g_critical("Unable to get number of downloaded bytes from curl"); + goto bail; + } else if (downloaded <= 0) { + g_warning("Downloaded empty assistance data file"); + goto bail; } g_message("Fetching GNSS assistance data from %s was successfull", url); - g_free(url); + curl_easy_cleanup(curl); /* Go to the next step */ manager->gnss_assistance_step++; gnss_step(manager); + return; + +bail: + if (curl != NULL) + curl_easy_cleanup(curl); + manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; } /******************************************************************************/ From ee10cafa00d519f9533d161a9f3a220f9fe5f511 Mon Sep 17 00:00:00 2001 From: ArenM Date: Sun, 12 Sep 2021 16:03:45 -0400 Subject: [PATCH 6/7] gnss: flush tmp_file after downloading gpsOneXtra data --- src/gnss.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gnss.c b/src/gnss.c index 898c0da..741caa9 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -238,7 +238,10 @@ static void fetch_assistance_data(struct EG25Manager *manager) } g_message("Fetching GNSS assistance data from %s was successfull", url); + + fflush(tmp_file); curl_easy_cleanup(curl); + g_free(url); /* Go to the next step */ manager->gnss_assistance_step++; From 36ac57b627d0ee87214112527e22dc2fc86ac2ca Mon Sep 17 00:00:00 2001 From: ArenM Date: Tue, 28 Sep 2021 14:30:31 -0400 Subject: [PATCH 7/7] gnss: Gracefully handle failure to access xtra data file --- src/gnss.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/gnss.c b/src/gnss.c index 741caa9..5b15b8d 100644 --- a/src/gnss.c +++ b/src/gnss.c @@ -271,13 +271,19 @@ static void init_assistance_data_upload_start(struct EG25Manager *manager, const char *response) { gchar value[BUFFER_SIZE]; - long int size; + off_t size; /* Process AT response */ at_process_result(manager, response); /* Get file size in bytes */ - size = (long int)lseek(manager->gnss_assistance_fd, 0, SEEK_END); + size = lseek(manager->gnss_assistance_fd, 0, SEEK_END); + if (size == -1) { + g_critical("gnss: unable to read size of xtra data file: %s", g_strerror(errno)); + + manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; + return; + } lseek(manager->gnss_assistance_fd, 0, SEEK_SET); /* Start upload */ @@ -308,7 +314,12 @@ static void upload_assistance_data(struct EG25Manager *manager) struct stat sb; if (fstat(manager->gnss_assistance_fd, &sb) != 0) { - g_error("Unable to upload xtra data: %s", g_strerror(errno)); + g_critical("gnss: unable to stat xtra data file: %s", g_strerror(errno)); + + /* Make sure the upload times out and the modem goes back to AT command mode */ + sleep(UPLOAD_TIMEOUT_S + 1); + manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; + return; } do {