Merge branch 'gnss_cleanup' into 'master'

Fix various small issues in the gnss assistance data upload code

Closes #20

See merge request mobian1/devices/eg25-manager!29
This commit is contained in:
Arnaud Ferraris
2021-09-29 21:05:08 +00:00

View File

@@ -8,8 +8,13 @@
#include "manager.h" #include "manager.h"
#include "at.h" #include "at.h"
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <errno.h>
#define BUFFER_SIZE 256 #define BUFFER_SIZE 256
#define UPLOAD_DELAY 100000 #define UPLOAD_DELAY_US 10000
#define UPLOAD_TIMEOUT_S 10
#define RESCHEDULE_IN_SECS 30 #define RESCHEDULE_IN_SECS 30
static void gnss_step(struct EG25Manager *manager); static void gnss_step(struct EG25Manager *manager);
@@ -195,71 +200,71 @@ static void state_at_gnss(struct EG25Manager *manager)
static void fetch_assistance_data(struct EG25Manager *manager) static void fetch_assistance_data(struct EG25Manager *manager)
{ {
CURL *curl;
CURLcode response; CURLcode response;
long status_code; curl_off_t downloaded;
gchar *url = NULL; CURL *curl = NULL;
g_autofree gchar *url = NULL;
FILE *tmp_file = NULL; FILE *tmp_file = NULL;
long int size; gchar errbuf[CURL_ERROR_SIZE];
errbuf[0] = 0;
/* Fetch assistance data with curl */ /* Fetch assistance data with curl */
tmp_file = fdopen(manager->gnss_assistance_fd, "wb+"); 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); lseek(manager->gnss_assistance_fd, 0, SEEK_SET);
ftruncate(manager->gnss_assistance_fd, 0); ftruncate(manager->gnss_assistance_fd, 0);
url = g_strconcat(manager->gnss_assistance_url, "/", url = g_strconcat(manager->gnss_assistance_url, "/",
manager->gnss_assistance_file, NULL); manager->gnss_assistance_file, NULL);
curl = curl_easy_init(); curl = curl_easy_init();
if (!curl) if (!curl) {
g_error ("Unable to initialize curl"); g_critical("Unable to initialize curl");
goto bail;
}
curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, tmp_file); 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_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 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);
/* Restart upload on HTTP error status code */ response = curl_easy_perform(curl);
g_message ("Rescheduling upload because of failure in %ds", if (response != CURLE_OK) {
RESCHEDULE_IN_SECS); g_warning("Unable to fetch GNSS assistance data from %s: %s",
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; url, strlen(errbuf) ? errbuf : curl_easy_strerror(response));
g_timeout_add_seconds(RESCHEDULE_IN_SECS, goto bail;
G_SOURCE_FUNC(gnss_upload_assistance_data),
manager);
return;
} }
/* Get file size in bytes */ response = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &downloaded);
size = (long int)lseek(manager->gnss_assistance_fd, 0, SEEK_END); if (response) {
lseek(manager->gnss_assistance_fd, 0, SEEK_SET); g_critical("Unable to get number of downloaded bytes from curl");
goto bail;
if (size <= 0) { } else if (downloaded <= 0) {
g_warning ("GNSS assistance data contains 0 bytes," g_warning("Downloaded empty assistance data file");
"check network connection."); goto bail;
/*
* 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); g_message("Fetching GNSS assistance data from %s was successfull", url);
fflush(tmp_file);
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
g_free(url); g_free(url);
/* Go to the next step */ /* Go to the next step */
manager->gnss_assistance_step++; manager->gnss_assistance_step++;
gnss_step(manager); gnss_step(manager);
return;
bail:
if (curl != NULL)
curl_easy_cleanup(curl);
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
} }
/******************************************************************************/ /******************************************************************************/
@@ -279,18 +284,24 @@ static void init_assistance_data_upload_start(struct EG25Manager *manager,
const char *response) const char *response)
{ {
gchar value[BUFFER_SIZE]; gchar value[BUFFER_SIZE];
long int size; off_t size;
/* Process AT response */ /* Process AT response */
at_process_result(manager, response); at_process_result(manager, response);
/* Get file size in bytes */ /* 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); lseek(manager->gnss_assistance_fd, 0, SEEK_SET);
/* Start upload */ /* Start upload */
g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\",%ld\r\n", g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\",%ld,%d",
manager->gnss_assistance_file, size); manager->gnss_assistance_file, size, UPLOAD_TIMEOUT_S);
g_message("Initiate GNSS assistance data upload: %s", value); g_message("Initiate GNSS assistance data upload: %s", value);
at_append_command(manager, "QFUPL", NULL, value, NULL, at_append_command(manager, "QFUPL", NULL, value, NULL,
init_assistance_data_upload_ready); init_assistance_data_upload_ready);
@@ -310,39 +321,39 @@ static void init_assistance_data_upload(struct EG25Manager *manager)
static void upload_assistance_data(struct EG25Manager *manager) static void upload_assistance_data(struct EG25Manager *manager)
{ {
char buffer[2*BUFFER_SIZE]; gint error;
gint len; glong written_total = 0;
gboolean success = TRUE; gint ret;
struct stat sb;
/* Copy downloaded XTRA assistance data to the modem over serial */ if (fstat(manager->gnss_assistance_fd, &sb) != 0) {
while((len = read(manager->gnss_assistance_fd, buffer, 2*BUFFER_SIZE)) > 0) g_critical("gnss: unable to stat xtra data file: %s", g_strerror(errno));
{
len = write(manager->at_fd, buffer, len); /* Make sure the upload times out and the modem goes back to AT command mode */
if (len < 0) { sleep(UPLOAD_TIMEOUT_S + 1);
success = FALSE; manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
g_error("Writing GNSS assistance data failed: %d", len); return;
break;
}
usleep(UPLOAD_DELAY);
g_message("Uploaded %d bytes", len);
} }
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 */ /* Clear QFUPL AT command and process next */
at_next_command(manager); at_next_command(manager);
/* Go to the next step if successful */ /* 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++; manager->gnss_assistance_step++;
gnss_step(manager); gnss_step(manager);
} } else {
/* Restart upload */ g_critical("Unable to upload xtra data: %s", g_strerror(error));
else {
g_message ("Rescheduling upload because of failure in %ds",
RESCHEDULE_IN_SECS);
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST; manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
g_timeout_add_seconds(RESCHEDULE_IN_SECS,
G_SOURCE_FUNC(gnss_upload_assistance_data),
manager);
} }
} }
@@ -385,9 +396,9 @@ static void finish_assistance_data_upload(struct EG25Manager *manager)
#ifdef HAVE_MMGLIB #ifdef HAVE_MMGLIB
static void enable_mm_gnss(struct EG25Manager *manager) static void enable_mm_gnss(struct EG25Manager *manager)
{ {
MMModemLocationSource sources;
gboolean signal_location;
g_autoptr (GError) error = NULL; 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) if (manager->gnss_sources & EG25_GNSS_SOURCE_UNMANAGED)
sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED; sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
@@ -396,8 +407,6 @@ static void enable_mm_gnss(struct EG25Manager *manager)
if (manager->gnss_sources & EG25_GNSS_SOURCE_RAW) if (manager->gnss_sources & EG25_GNSS_SOURCE_RAW)
sources |= MM_MODEM_LOCATION_SOURCE_GPS_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, mm_modem_location_setup_sync(manager->mm_location, sources,
signal_location, NULL, &error); signal_location, NULL, &error);
if (error != NULL) if (error != NULL)