temp/eg25-manager: build master branch, drop merged patches (MR 2443)

I believe everything here has been merged in master, so let's build that
for now (since it includes at least 1 additional fix not in the patches
that were dropped here)
This commit is contained in:
Clayton Craft 2021-08-16 10:50:10 -07:00
parent 2283190a93
commit c4fc7c9ed0
No known key found for this signature in database
GPG key ID: 0BF4C1B5988C50D8
9 changed files with 6 additions and 1439 deletions

View file

@ -1,28 +0,0 @@
From 705950bb399781a291a3998014f916fc1effce16 Mon Sep 17 00:00:00 2001
From: Bhushan Shah <bhush94@gmail.com>
Date: Thu, 15 Apr 2021 09:29:36 +0530
Subject: [PATCH 1/8] mm-iface: clean out modem_iface if mm disappears
otherwise we will be stuck in state where restarting of mm will not
reset the modem_iface and it will loop through hard resetting modem
---
src/mm-iface.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/mm-iface.c b/src/mm-iface.c
index d6a74f8..0409236 100644
--- a/src/mm-iface.c
+++ b/src/mm-iface.c
@@ -183,6 +183,9 @@ static void mm_iface_clean(struct EG25Manager *manager)
g_free(manager->modem_usb_id);
manager->modem_usb_id = NULL;
}
+ if (manager->modem_iface == MODEM_IFACE_MODEMMANAGER) {
+ manager->modem_iface = MODEM_IFACE_NONE;
+ }
}
static void mm_vanished_cb(GDBusConnection *connection,
--
2.31.1

View file

@ -1,97 +0,0 @@
From a046b539418958eeb2ee26ec5ef273835c98d0d2 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Thu, 15 Apr 2021 20:11:03 +0200
Subject: [PATCH 2/8] config: synchronize with modem-power
We cannot assume default factory values if other drivers change them
---
data/pine64,pinephone-1.0.toml | 13 +++++++++++--
data/pine64,pinephone-1.1.toml | 13 +++++++++++--
data/pine64,pinephone-1.2.toml | 12 ++++++++++++
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/data/pine64,pinephone-1.0.toml b/data/pine64,pinephone-1.0.toml
index e1f5b24..6e21bda 100644
--- a/data/pine64,pinephone-1.0.toml
+++ b/data/pine64,pinephone-1.0.toml
@@ -39,12 +39,21 @@ configure = [
{ cmd = "QCFG", subcmd = "risignaltype", expect = "\"physical\"" },
{ cmd = "QCFG", subcmd = "ims", expect = "1" },
{ cmd = "QCFG", subcmd = "urc/ri/ring", expect = "\"pulse\",2000,1000,5000,\"off\",1" },
- { cmd = "QCFG", subcmd = "urc/ri/smsincoming", expect = "\"pulse\",2000" },
- { cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1" },
+ { cmd = "QCFG", subcmd = "urc/ri/smsincoming", expect = "\"pulse\",2000,1" },
+ { cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
{ cmd = "QCFG", subcmd = "urc/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
+# Reset modem-power configurations to what we expect
+ { cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
+ { cmd = "QCFG", subcmd = "fast/poweroff", expect = "1" },
+ { cmd = "QCFG", subcmd = "apready", expect = "0,0,500" },
+ { cmd = "QCFG", subcmd = "sleepind/level", expect = "0" },
+ { cmd = "QCFG", subcmd = "wakeupin/level", expect = "0,0" },
+ { cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
]
suspend = [
{ cmd = "QGPSEND" },
diff --git a/data/pine64,pinephone-1.1.toml b/data/pine64,pinephone-1.1.toml
index e1f5b24..6e21bda 100644
--- a/data/pine64,pinephone-1.1.toml
+++ b/data/pine64,pinephone-1.1.toml
@@ -39,12 +39,21 @@ configure = [
{ cmd = "QCFG", subcmd = "risignaltype", expect = "\"physical\"" },
{ cmd = "QCFG", subcmd = "ims", expect = "1" },
{ cmd = "QCFG", subcmd = "urc/ri/ring", expect = "\"pulse\",2000,1000,5000,\"off\",1" },
- { cmd = "QCFG", subcmd = "urc/ri/smsincoming", expect = "\"pulse\",2000" },
- { cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1" },
+ { cmd = "QCFG", subcmd = "urc/ri/smsincoming", expect = "\"pulse\",2000,1" },
+ { cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
{ cmd = "QCFG", subcmd = "urc/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
+# Reset modem-power configurations to what we expect
+ { cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
+ { cmd = "QCFG", subcmd = "fast/poweroff", expect = "1" },
+ { cmd = "QCFG", subcmd = "apready", expect = "0,0,500" },
+ { cmd = "QCFG", subcmd = "sleepind/level", expect = "0" },
+ { cmd = "QCFG", subcmd = "wakeupin/level", expect = "0,0" },
+ { cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
]
suspend = [
{ cmd = "QGPSEND" },
diff --git a/data/pine64,pinephone-1.2.toml b/data/pine64,pinephone-1.2.toml
index 4ca1274..598ebaf 100644
--- a/data/pine64,pinephone-1.2.toml
+++ b/data/pine64,pinephone-1.2.toml
@@ -36,9 +36,21 @@ configure = [
{ cmd = "QCFG", subcmd = "risignaltype", expect = "\"physical\"" },
{ cmd = "QCFG", subcmd = "ims", expect = "1" },
{ cmd = "QCFG", subcmd = "apready", expect = "1,0,500" },
+ { cmd = "QCFG", subcmd = "urc/ri/ring", expect = "\"pulse\",120,1000,5000,\"off\",1" },
+ { cmd = "QCFG", subcmd = "urc/ri/smsincoming", expect = "\"pulse\",120,1" },
+ { cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
+ { cmd = "QCFG", subcmd = "urc/delay", expect = "0" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
+# Reset modem-power configurations to what we expect
+ { cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
+ { cmd = "QCFG", subcmd = "fast/poweroff", expect = "1" },
+ { cmd = "QCFG", subcmd = "sleepind/level", expect = "0" },
+ { cmd = "QCFG", subcmd = "wakeupin/level", expect = "0,0" },
+ { cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
+ { cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
]
suspend = [
{ cmd = "QGPSEND" },
--
2.31.1

View file

@ -1,31 +0,0 @@
From 0094dea49d8bc5a60c044da1e01417c29397c7b0 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Sat, 17 Apr 2021 15:50:07 +0200
Subject: [PATCH 3/8] at: fast/poweroff is only available in newer firmware
versions
Do not retry the AT command of the fast/poweroff setting as it may not be supported by the firmware
---
src/at.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/at.c b/src/at.c
index a34025f..4469d26 100644
--- a/src/at.c
+++ b/src/at.c
@@ -215,7 +215,11 @@ static gboolean modem_response(gint fd,
suspend_inhibit(manager, TRUE, TRUE);
manager->modem_state = EG25_STATE_STARTED;
}
- else if (strstr(response, "ERROR"))
+ /*
+ * QCFG="fast/poweroff" configuration is only available in
+ * newer firmware versions
+ */
+ else if (strstr(response, "ERROR") && !strstr(response, "fast/poweroff"))
retry_at_command(manager);
else if (strstr(response, "OK"))
process_at_result(manager, response);
--
2.31.1

View file

@ -1,46 +0,0 @@
From a74d2c58babd2e85a4d1920e0144b5c7ee2231d0 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Wed, 12 May 2021 16:41:48 +0200
Subject: [PATCH 4/8] at: g_free doesn't require NULL checking
From the docs: If mem is NULL it simply returns, so there is no need to check mem against NULL before calling this function.
---
src/at.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/src/at.c b/src/at.c
index 4469d26..3ccc5d6 100644
--- a/src/at.c
+++ b/src/at.c
@@ -104,14 +104,10 @@ static void next_at_command(struct EG25Manager *manager)
if (!at_cmd)
return;
- if (at_cmd->cmd)
- g_free(at_cmd->cmd);
- if (at_cmd->subcmd)
- g_free(at_cmd->subcmd);
- if (at_cmd->value)
- g_free(at_cmd->value);
- if (at_cmd->expected)
- g_free(at_cmd->expected);
+ g_free(at_cmd->cmd);
+ g_free(at_cmd->subcmd);
+ g_free(at_cmd->value);
+ g_free(at_cmd->expected);
g_free(at_cmd);
manager->at_cmds = g_list_remove(manager->at_cmds, at_cmd);
@@ -142,8 +138,7 @@ static void process_at_result(struct EG25Manager *manager, char *response)
return;
if (at_cmd->expected && !strstr(response, at_cmd->expected)) {
- if (at_cmd->value)
- g_free(at_cmd->value);
+ g_free(at_cmd->value);
at_cmd->value = at_cmd->expected;
at_cmd->expected = NULL;
g_message("Got a different result than expected, changing value...");
--
2.31.1

View file

@ -1,176 +0,0 @@
From 3a205f7e9baf702dccc572ae2342990052c23155 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Wed, 12 May 2021 18:21:29 +0200
Subject: [PATCH 5/8] at: make next_at_command, send_at_command,
process_at_result, and append_at_command public methods
Allows other modules to send AT commands as well
---
src/at.c | 47 ++++++++++++++++++++++++-----------------------
src/at.h | 22 ++++++++++++++++------
2 files changed, 40 insertions(+), 29 deletions(-)
diff --git a/src/at.c b/src/at.c
index 3ccc5d6..1e605a1 100644
--- a/src/at.c
+++ b/src/at.c
@@ -52,7 +52,7 @@ static int configure_serial(const char *tty)
return fd;
}
-static gboolean send_at_command(struct EG25Manager *manager)
+gboolean at_send_command(struct EG25Manager *manager)
{
char command[256];
struct AtCommand *at_cmd = manager->at_cmds ? g_list_nth_data(manager->at_cmds, 0) : NULL;
@@ -97,7 +97,7 @@ static gboolean send_at_command(struct EG25Manager *manager)
return FALSE;
}
-static void next_at_command(struct EG25Manager *manager)
+void at_next_command(struct EG25Manager *manager)
{
struct AtCommand *at_cmd = manager->at_cmds ? g_list_nth_data(manager->at_cmds, 0) : NULL;
@@ -111,7 +111,7 @@ static void next_at_command(struct EG25Manager *manager)
g_free(at_cmd);
manager->at_cmds = g_list_remove(manager->at_cmds, at_cmd);
- send_at_command(manager);
+ at_send_command(manager);
}
static void retry_at_command(struct EG25Manager *manager)
@@ -124,13 +124,14 @@ static void retry_at_command(struct EG25Manager *manager)
at_cmd->retries++;
if (at_cmd->retries > 3) {
g_critical("Command %s retried %d times, aborting...", at_cmd->cmd, at_cmd->retries);
- next_at_command(manager);
+ at_next_command(manager);
} else {
- g_timeout_add(500, G_SOURCE_FUNC(send_at_command), manager);
+ g_timeout_add(500, G_SOURCE_FUNC(at_send_command), manager);
}
}
-static void process_at_result(struct EG25Manager *manager, char *response)
+void at_process_result(struct EG25Manager *manager,
+ const char *response)
{
struct AtCommand *at_cmd = manager->at_cmds ? g_list_nth_data(manager->at_cmds, 0) : NULL;
@@ -143,17 +144,17 @@ static void process_at_result(struct EG25Manager *manager, char *response)
at_cmd->expected = NULL;
g_message("Got a different result than expected, changing value...");
g_message("\t%s\n\t%s", at_cmd->expected, response);
- send_at_command(manager);
+ at_send_command(manager);
} else {
- next_at_command(manager);
+ at_next_command(manager);
}
}
-static int append_at_command(struct EG25Manager *manager,
- const char *cmd,
- const char *subcmd,
- const char *value,
- const char *expected)
+int at_append_command(struct EG25Manager *manager,
+ const char *cmd,
+ const char *subcmd,
+ const char *value,
+ const char *expected)
{
struct AtCommand *at_cmd = calloc(1, sizeof(struct AtCommand));
@@ -217,10 +218,10 @@ static gboolean modem_response(gint fd,
else if (strstr(response, "ERROR") && !strstr(response, "fast/poweroff"))
retry_at_command(manager);
else if (strstr(response, "OK"))
- process_at_result(manager, response);
+ at_process_result(manager, response);
else
// Not a recognized response, try running next command, just in case
- next_at_command(manager);
+ at_next_command(manager);
}
return TRUE;
@@ -325,34 +326,34 @@ void at_sequence_configure(struct EG25Manager *manager)
{
for (guint i = 0; i < configure_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(configure_commands, struct AtCommand, i);
- append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
}
- send_at_command(manager);
+ at_send_command(manager);
}
void at_sequence_suspend(struct EG25Manager *manager)
{
for (guint i = 0; i < suspend_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(suspend_commands, struct AtCommand, i);
- append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
}
- send_at_command(manager);
+ at_send_command(manager);
}
void at_sequence_resume(struct EG25Manager *manager)
{
for (guint i = 0; i < resume_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(resume_commands, struct AtCommand, i);
- append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
}
- send_at_command(manager);
+ at_send_command(manager);
}
void at_sequence_reset(struct EG25Manager *manager)
{
for (guint i = 0; i < reset_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(reset_commands, struct AtCommand, i);
- append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
}
- send_at_command(manager);
+ at_send_command(manager);
}
diff --git a/src/at.h b/src/at.h
index ba294a4..e0445af 100644
--- a/src/at.h
+++ b/src/at.h
@@ -8,10 +8,20 @@
#include "manager.h"
-int at_init(struct EG25Manager *data, toml_table_t *config);
-void at_destroy(struct EG25Manager *data);
+int at_init(struct EG25Manager *manager, toml_table_t *config);
+void at_destroy(struct EG25Manager *manager);
-void at_sequence_configure(struct EG25Manager *data);
-void at_sequence_suspend(struct EG25Manager *data);
-void at_sequence_resume(struct EG25Manager *data);
-void at_sequence_reset(struct EG25Manager *data);
+void at_process_result(struct EG25Manager *manager,
+ const char *response);
+void at_next_command(struct EG25Manager *manager);
+gboolean at_send_command(struct EG25Manager *manager);
+int at_append_command(struct EG25Manager *manager,
+ const char *cmd,
+ const char *subcmd,
+ const char *value,
+ const char *expected);
+
+void at_sequence_configure(struct EG25Manager *manager);
+void at_sequence_suspend(struct EG25Manager *manager);
+void at_sequence_resume(struct EG25Manager *manager);
+void at_sequence_reset(struct EG25Manager *manager);
--
2.31.1

View file

@ -1,29 +0,0 @@
From 47a7069c143c0f6a1219a1cef78a51d0f31f0710 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Wed, 12 May 2021 18:25:40 +0200
Subject: [PATCH 6/8] at: log expected result before setting it to NULL
Otherwise the log contains NULL instead of the expected value, making it hard to debug
---
src/at.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/at.c b/src/at.c
index 1e605a1..533ed1c 100644
--- a/src/at.c
+++ b/src/at.c
@@ -141,9 +141,9 @@ void at_process_result(struct EG25Manager *manager,
if (at_cmd->expected && !strstr(response, at_cmd->expected)) {
g_free(at_cmd->value);
at_cmd->value = at_cmd->expected;
- at_cmd->expected = NULL;
g_message("Got a different result than expected, changing value...");
- g_message("\t%s\n\t%s", at_cmd->expected, response);
+ g_message("Expected: [%s]\nResponse: [%s]", at_cmd->expected, response);
+ at_cmd->expected = NULL;
at_send_command(manager);
} else {
at_next_command(manager);
--
2.31.1

View file

@ -1,158 +0,0 @@
From 427944b75e0a4abc4cc2af2f16858739a8833e6e Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Wed, 12 May 2021 18:34:03 +0200
Subject: [PATCH 7/8] at: allow custom callbacks for AT command response
processing
---
src/at.c | 32 +++++++++++++++++---------------
src/at.h | 14 +++++++++++++-
src/manager.h | 1 +
3 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/src/at.c b/src/at.c
index 533ed1c..35b7042 100644
--- a/src/at.c
+++ b/src/at.c
@@ -16,14 +16,6 @@
#include <glib-unix.h>
-struct AtCommand {
- char *cmd;
- char *subcmd;
- char *value;
- char *expected;
- int retries;
-};
-
static GArray *configure_commands = NULL;
static GArray *suspend_commands = NULL;
static GArray *resume_commands = NULL;
@@ -69,6 +61,7 @@ gboolean at_send_command(struct EG25Manager *manager)
len = sprintf(command, "AT+%s=\"%s\"\r\n", at_cmd->cmd, at_cmd->subcmd);
else if (at_cmd->subcmd && at_cmd->value)
len = sprintf(command, "AT+%s=\"%s\",%s\r\n", at_cmd->cmd, at_cmd->subcmd, at_cmd->value);
+ manager->at_callback = at_cmd->callback;
ret = write(manager->at_fd, command, len);
if (ret < len)
@@ -154,7 +147,10 @@ int at_append_command(struct EG25Manager *manager,
const char *cmd,
const char *subcmd,
const char *value,
- const char *expected)
+ const char *expected,
+ void (*callback)
+ (struct EG25Manager *manager,
+ const char *response))
{
struct AtCommand *at_cmd = calloc(1, sizeof(struct AtCommand));
@@ -168,6 +164,8 @@ int at_append_command(struct EG25Manager *manager,
at_cmd->value = g_strdup(value);
if (expected)
at_cmd->expected = g_strdup(expected);
+ if (callback)
+ at_cmd->callback = callback;
manager->at_cmds = g_list_append(manager->at_cmds, at_cmd);
@@ -217,8 +215,12 @@ static gboolean modem_response(gint fd,
*/
else if (strstr(response, "ERROR") && !strstr(response, "fast/poweroff"))
retry_at_command(manager);
- else if (strstr(response, "OK"))
- at_process_result(manager, response);
+ else if (strstr(response, "OK")) {
+ if (manager->at_callback != NULL)
+ manager->at_callback(manager, response);
+ else
+ g_warning("AT command succesfull but no callback registered");
+ }
else
// Not a recognized response, try running next command, just in case
at_next_command(manager);
@@ -326,7 +328,7 @@ void at_sequence_configure(struct EG25Manager *manager)
{
for (guint i = 0; i < configure_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(configure_commands, struct AtCommand, i);
- at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected, at_process_result);
}
at_send_command(manager);
}
@@ -335,7 +337,7 @@ void at_sequence_suspend(struct EG25Manager *manager)
{
for (guint i = 0; i < suspend_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(suspend_commands, struct AtCommand, i);
- at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected, at_process_result);
}
at_send_command(manager);
}
@@ -344,7 +346,7 @@ void at_sequence_resume(struct EG25Manager *manager)
{
for (guint i = 0; i < resume_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(resume_commands, struct AtCommand, i);
- at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected, at_process_result);
}
at_send_command(manager);
}
@@ -353,7 +355,7 @@ void at_sequence_reset(struct EG25Manager *manager)
{
for (guint i = 0; i < reset_commands->len; i++) {
struct AtCommand *cmd = &g_array_index(reset_commands, struct AtCommand, i);
- at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected);
+ at_append_command(manager, cmd->cmd, cmd->subcmd, cmd->value, cmd->expected, at_process_result);
}
at_send_command(manager);
}
diff --git a/src/at.h b/src/at.h
index e0445af..0364e2c 100644
--- a/src/at.h
+++ b/src/at.h
@@ -8,6 +8,15 @@
#include "manager.h"
+typedef struct AtCommand {
+ char *cmd;
+ char *subcmd;
+ char *value;
+ char *expected;
+ void (*callback)(struct EG25Manager *manager, const char *response);
+ int retries;
+} AtCommand;
+
int at_init(struct EG25Manager *manager, toml_table_t *config);
void at_destroy(struct EG25Manager *manager);
@@ -19,7 +28,10 @@ int at_append_command(struct EG25Manager *manager,
const char *cmd,
const char *subcmd,
const char *value,
- const char *expected);
+ const char *expected,
+ void (*callback)
+ (struct EG25Manager *manager,
+ const char *response));
void at_sequence_configure(struct EG25Manager *manager);
void at_sequence_suspend(struct EG25Manager *manager);
diff --git a/src/manager.h b/src/manager.h
index 30028e6..3cc0118 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -47,6 +47,7 @@ struct EG25Manager {
int at_fd;
guint at_source;
GList *at_cmds;
+ void (*at_callback)(struct EG25Manager *manager, const char *response);
enum EG25State modem_state;
gchar *modem_usb_id;
--
2.31.1

View file

@ -1,852 +0,0 @@
From b5578250c1f2c00972e8c7215458160b04871c5e Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Wed, 12 May 2021 19:37:21 +0200
Subject: [PATCH 8/8] gnss: add GNSS assistance support
Automatically fetch the GNSS assistance data from the Web
to heavily reduce the time to acquire a GNSS lock by uploading
the assistance data to the modem.
This feature is optional and can be disabled in the configuration
as people may prefer to not download the assistance data from
the Quectel/Qualcomm servers.
Also configure the GNSS engine to optimize the performance
and power consumption.
---
data/pine64,pinephone-1.0.toml | 26 +-
data/pine64,pinephone-1.1.toml | 26 +-
data/pine64,pinephone-1.2.toml | 26 +-
meson.build | 1 +
src/at.c | 22 +-
src/gnss.c | 478 +++++++++++++++++++++++++++++++++
src/gnss.h | 16 ++
src/manager.c | 2 +
src/manager.h | 34 +++
src/meson.build | 1 +
src/mm-iface.c | 5 +-
11 files changed, 625 insertions(+), 12 deletions(-)
create mode 100644 src/gnss.c
create mode 100644 src/gnss.h
diff --git a/data/pine64,pinephone-1.0.toml b/data/pine64,pinephone-1.0.toml
index 6e21bda..c2ee8bd 100644
--- a/data/pine64,pinephone-1.0.toml
+++ b/data/pine64,pinephone-1.0.toml
@@ -43,7 +43,6 @@ configure = [
{ cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
{ cmd = "QCFG", subcmd = "urc/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
- { cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
# Reset modem-power configurations to what we expect
{ cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
@@ -54,11 +53,32 @@ configure = [
{ cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
+# GNSS configuration:
+# * Enable A-GPS data upload support (XTRA)
+# * Disable On-Demand-Positioning (ODP) mode
+# to avoid running the GNSS system in the background, even when not enabled.
+# * Enable Dynamic Power Optimizations (DPO) mode to turn off GNSS RF radios
+# when they are not in use.
+# * Only enable GPS and GLONASS, disable other GNSS systems.
+# A-GPS data upload doesn't work for Galileo anyway.
+# * Avoid turning on GNSS support automatically when the modem boots.
+ { cmd = "QGPSXTRA", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gnssconfig", expect = "4" },
+ { cmd = "QGPSCFG", subcmd = "odpcontrol", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "dpoenable", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gpsnmeatype", expect = "31" },
+ { cmd = "QGPSCFG", subcmd = "glonassnmeatype", expect = "7" },
+ { cmd = "QGPSCFG", subcmd = "galileonmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "beidounmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "autogps", expect = "0" },
]
suspend = [
- { cmd = "QGPSEND" },
]
resume = [
- { cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]
+
+[gnss]
+enabled = true
+url = "https://proxy.postmarketos.org"
+file = "xtra2.bin"
diff --git a/data/pine64,pinephone-1.1.toml b/data/pine64,pinephone-1.1.toml
index 6e21bda..c2ee8bd 100644
--- a/data/pine64,pinephone-1.1.toml
+++ b/data/pine64,pinephone-1.1.toml
@@ -43,7 +43,6 @@ configure = [
{ cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
{ cmd = "QCFG", subcmd = "urc/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
- { cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
# Reset modem-power configurations to what we expect
{ cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
@@ -54,11 +53,32 @@ configure = [
{ cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
+# GNSS configuration:
+# * Enable A-GPS data upload support (XTRA)
+# * Disable On-Demand-Positioning (ODP) mode
+# to avoid running the GNSS system in the background, even when not enabled.
+# * Enable Dynamic Power Optimizations (DPO) mode to turn off GNSS RF radios
+# when they are not in use.
+# * Only enable GPS and GLONASS, disable other GNSS systems.
+# A-GPS data upload doesn't work for Galileo anyway.
+# * Avoid turning on GNSS support automatically when the modem boots.
+ { cmd = "QGPSXTRA", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gnssconfig", expect = "4" },
+ { cmd = "QGPSCFG", subcmd = "odpcontrol", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "dpoenable", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gpsnmeatype", expect = "31" },
+ { cmd = "QGPSCFG", subcmd = "glonassnmeatype", expect = "7" },
+ { cmd = "QGPSCFG", subcmd = "galileonmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "beidounmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "autogps", expect = "0" },
]
suspend = [
- { cmd = "QGPSEND" },
]
resume = [
- { cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]
+
+[gnss]
+enabled = true
+url = "https://proxy.postmarketos.org"
+file = "xtra2.bin"
diff --git a/data/pine64,pinephone-1.2.toml b/data/pine64,pinephone-1.2.toml
index 598ebaf..a45c7ec 100644
--- a/data/pine64,pinephone-1.2.toml
+++ b/data/pine64,pinephone-1.2.toml
@@ -41,7 +41,6 @@ configure = [
{ cmd = "QCFG", subcmd = "urc/ri/other", expect = "\"off\",1,1" },
{ cmd = "QCFG", subcmd = "urc/delay", expect = "0" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"all\"" },
- { cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
# Reset modem-power configurations to what we expect
{ cmd = "QCFG", subcmd = "urc/cache", expect = "0" },
@@ -51,11 +50,32 @@ configure = [
{ cmd = "QCFG", subcmd = "ApRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "ModemRstLevel", expect = "0" },
{ cmd = "QCFG", subcmd = "urc/ri/pin", expect = "uart_ri" },
+# GNSS configuration:
+# * Enable A-GPS data upload support (XTRA)
+# * Disable On-Demand-Positioning (ODP) mode
+# to avoid running the GNSS system in the background, even when not enabled.
+# * Enable Dynamic Power Optimizations (DPO) mode to turn off GNSS RF radios
+# when they are not in use.
+# * Only enable GPS and GLONASS, disable other GNSS systems.
+# A-GPS data upload doesn't work for Galileo anyway.
+# * Avoid turning on GNSS support automatically when the modem boots.
+ { cmd = "QGPSXTRA", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gnssconfig", expect = "4" },
+ { cmd = "QGPSCFG", subcmd = "odpcontrol", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "dpoenable", expect = "1" },
+ { cmd = "QGPSCFG", subcmd = "gpsnmeatype", expect = "31" },
+ { cmd = "QGPSCFG", subcmd = "glonassnmeatype", expect = "7" },
+ { cmd = "QGPSCFG", subcmd = "galileonmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "beidounmeatype", expect = "0" },
+ { cmd = "QGPSCFG", subcmd = "autogps", expect = "0" },
]
suspend = [
- { cmd = "QGPSEND" },
]
resume = [
- { cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]
+
+[gnss]
+enabled = true
+url = "https://proxy.postmarketos.org"
+file = "xtra2.bin"
diff --git a/meson.build b/meson.build
index d57d2cb..2852778 100644
--- a/meson.build
+++ b/meson.build
@@ -58,6 +58,7 @@ mgr_deps = [
dependency('gudev-1.0'),
dependency('libgpiod'),
dependency('libusb-1.0'),
+ dependency('libcurl'),
mmglib_dep,
]
diff --git a/src/at.c b/src/at.c
index 35b7042..3e0f531 100644
--- a/src/at.c
+++ b/src/at.c
@@ -6,6 +6,7 @@
#include "at.h"
#include "suspend.h"
+#include "gnss.h"
#include <fcntl.h>
#include <stdio.h>
@@ -205,24 +206,41 @@ static gboolean modem_response(gint fd,
g_message("Response: [%s]", response);
+ /*
+ * When the modem is started, it outputs 'RDY' to indicate that
+ * it is ready to receive AT commands.
+ */
if (strcmp(response, "RDY") == 0) {
suspend_inhibit(manager, TRUE, TRUE);
manager->modem_state = EG25_STATE_STARTED;
}
+ /*
+ * Search for 'QGPSURC: "xtradataexpire"' in response to detect
+ * if GNSS assistance data must be re-uploaded.
+ * If that's the case, check if no AT commands are being processed
+ * to avoid deadlocks and start upload.
+ */
+ else if (strstr(response, "QGPSURC: \"xtradataexpire\"") && manager->at_cmds == NULL)
+ gnss_upload_assistance_data(manager);
/*
+ * AT command failed, retry
* QCFG="fast/poweroff" configuration is only available in
* newer firmware versions
*/
else if (strstr(response, "ERROR") && !strstr(response, "fast/poweroff"))
retry_at_command(manager);
- else if (strstr(response, "OK")) {
+ /*
+ * Successfull AT responses contain 'OK', except for AT+QFUPL which also
+ * returns 'CONNECT' when the modem is ready to receive data over serial
+ */
+ else if (strstr(response, "OK") || strstr(response, "CONNECT")) {
if (manager->at_callback != NULL)
manager->at_callback(manager, response);
else
g_warning("AT command succesfull but no callback registered");
}
+ /* Not a recognized response, try running next command, just in case */
else
- // Not a recognized response, try running next command, just in case
at_next_command(manager);
}
diff --git a/src/gnss.c b/src/gnss.c
new file mode 100644
index 0000000..15814e9
--- /dev/null
+++ b/src/gnss.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2021 Dylan Van Assche <me@dylanvanassche.be>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "gnss.h"
+#include "manager.h"
+#include "at.h"
+
+#define BUFFER_SIZE 256
+#define UPLOAD_DELAY 100000
+#define RESCHEDULE_IN_SECS 30
+
+static void gnss_step(struct EG25Manager *manager);
+
+void gnss_upload_assistance_data(struct EG25Manager *manager)
+{
+ if (!manager->gnss_assistance_enabled) {
+ g_message("GNSS assistance is disabled!");
+ return;
+ }
+
+ if (manager->gnss_assistance_step < EG25_GNSS_STEP_LAST) {
+ g_warning("GNSS assistance data upload already in process (%d/%d)",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ return;
+ }
+ manager->gnss_assistance_step = EG25_GNSS_STEP_FIRST;
+ gnss_step(manager);
+}
+
+void gnss_init(struct EG25Manager *manager, toml_table_t *config)
+{
+ toml_datum_t enabled;
+ toml_datum_t url;
+ toml_datum_t file;
+ g_autoptr (GError) error = NULL;
+
+ /*
+ * GNSS assistance is an optional feature, you can disable it
+ * if you want in the configuration file.
+ * In case the configuration is missing, we assume GNSS assistance
+ * to be disabled.
+ */
+ enabled = toml_bool_in(config, "enabled");
+ manager->gnss_assistance_enabled = FALSE;
+ if (enabled.ok)
+ manager->gnss_assistance_enabled = enabled.u.b;
+
+ if (!manager->gnss_assistance_enabled) {
+ g_message("GNSS assistance is disabled!");
+ return;
+ }
+
+ url = toml_string_in(config, "url");
+ if (url.ok)
+ manager->gnss_assistance_url = url.u.s;
+ else
+ g_error("GNSS assistance server URL is missing from config file");
+ file = toml_string_in(config, "file");
+ if (file.ok)
+ manager->gnss_assistance_file = file.u.s;
+ else
+ g_error("GNSS assistance file name is missing from config file");
+
+ /* Create temporary file to store assistance data */
+ manager->gnss_assistance_fd = g_file_open_tmp(NULL, NULL, &error);
+ if (error != NULL)
+ g_error ("Unable to create temporary file: %s", error->message);
+
+ /* Initialize state and schedule upload */
+ manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
+ g_timeout_add_seconds(RESCHEDULE_IN_SECS,
+ G_SOURCE_FUNC(gnss_upload_assistance_data), manager);
+}
+
+void gnss_destroy(struct EG25Manager *manager)
+{
+ close(manager->gnss_assistance_fd);
+}
+
+/******************************************************************************/
+
+#ifdef HAVE_MMGLIB
+static void disable_mm_gnss(struct EG25Manager *manager)
+{
+ MMModemLocationSource sources;
+ gboolean signals_location;
+ g_autoptr (GError) error = NULL;
+
+ sources = mm_modem_location_get_enabled(manager->mm_location);
+ signals_location = mm_modem_location_signals_location(manager->mm_location);
+ manager->gnss_sources = EG25_GNSS_SOURCE_NONE;
+
+ /* Save GNSS engine state */
+ if (sources & MM_MODEM_LOCATION_SOURCE_GPS_NMEA)
+ manager->gnss_sources |= EG25_GNSS_SOURCE_NMEA;
+ else
+ manager->gnss_sources &= ~EG25_GNSS_SOURCE_NMEA;
+
+ if (sources & MM_MODEM_LOCATION_SOURCE_GPS_RAW)
+ manager->gnss_sources |= EG25_GNSS_SOURCE_RAW;
+ else
+ manager->gnss_sources &= ~EG25_GNSS_SOURCE_RAW;
+
+ if (sources & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)
+ manager->gnss_sources |= EG25_GNSS_SOURCE_UNMANAGED;
+ else
+ manager->gnss_sources &= ~EG25_GNSS_SOURCE_UNMANAGED;
+
+ /* Disable GNSS engine */
+ sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_RAW;
+ sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_NMEA;
+ sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
+ mm_modem_location_setup_sync(manager->mm_location, sources,
+ signals_location, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to disable GNSS engine through ModemManager: %s",
+ error->message);
+ }
+}
+#endif
+
+static void disable_at_gnss_cb(struct EG25Manager *manager,
+ const char *response)
+{
+ /* Clear QGPSEND AT command and process next */
+ at_next_command(manager);
+
+ /* Go to the next step */
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+}
+
+static void state_at_gnss_cb(struct EG25Manager *manager, const char *response)
+{
+ struct AtCommand *at_cmd = manager->at_cmds ? g_list_nth_data(manager->at_cmds, 0) : NULL;
+
+ if (!at_cmd)
+ return;
+
+ /* Parse GNSS engine status and disable it if needed */
+ if (strstr(response, "QGPS: 1")) {
+ manager->gnss_sources |= EG25_GNSS_SOURCE_QGPS;
+ g_free(at_cmd->value);
+ g_free(at_cmd->cmd);
+ at_cmd->expected = NULL;
+ at_cmd->subcmd = NULL;
+ at_cmd->value = NULL;
+ at_cmd->cmd = g_strdup("QGPSEND");
+ at_cmd->callback = disable_at_gnss_cb;
+ at_send_command(manager);
+ }
+ /* QGPS is already disabled, move on to next step */
+ else {
+ at_next_command(manager);
+ manager->gnss_sources &= ~EG25_GNSS_SOURCE_QGPS;
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+ }
+}
+
+static void state_at_gnss(struct EG25Manager *manager)
+{
+ /* Asynchronously send AT command to query status of GNSS engine */
+ at_append_command(manager, "QGPS?", NULL, NULL, NULL, state_at_gnss_cb);
+ at_send_command(manager);
+}
+
+/******************************************************************************/
+
+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;
+
+ /* Fetch assistance data with curl */
+ tmp_file = fdopen(manager->gnss_assistance_fd, "wb");
+ url = g_strconcat(manager->gnss_assistance_url, "/",
+ manager->gnss_assistance_file, NULL);
+ 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_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);
+
+ /* 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;
+ }
+
+ /* 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 */
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+}
+
+/******************************************************************************/
+
+static void init_assistance_data_upload_step2(struct EG25Manager *manager,
+ const char *response)
+{
+ /* Search for 'CONNECT' in response to start upload */
+ if (strstr(response, "CONNECT")) {
+ g_message("Modem ready for GNSS assistance data upload");
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+ }
+}
+
+static void init_assistance_data_upload_step1(struct EG25Manager *manager,
+ const char *response)
+{
+ gchar value[BUFFER_SIZE];
+ long int 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);
+ 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_message("Initiate GNSS assistance data upload: %s", value);
+ at_append_command(manager, "QFUPL", NULL, value, NULL,
+ init_assistance_data_upload_step2);
+ at_send_command(manager);
+}
+
+static void init_assistance_data_upload(struct EG25Manager *manager)
+{
+ /*
+ * Delete all previous GNSS assistance data files in RAM
+ * and start uploading the latest one to RAM.
+ */
+ at_append_command(manager, "QFDEL", NULL, "\"RAM:*\"\r\n",
+ NULL, init_assistance_data_upload_step1);
+ at_send_command(manager);
+}
+
+static void upload_assistance_data(struct EG25Manager *manager)
+{
+ char buffer[2*BUFFER_SIZE];
+ gint len;
+ gboolean success = TRUE;
+
+ /* 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);
+ }
+
+ /* Clear QFUPL AT command and process next */
+ at_next_command(manager);
+
+ /* Go to the next step if successful */
+ if (success) {
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+ }
+ /* Restart upload */
+ else {
+ 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);
+ }
+}
+
+static void finish_assistance_data_upload_cb(struct EG25Manager *manager,
+ const char *response)
+{
+ /* Process response */
+ at_process_result(manager, response);
+ g_message("GNSS assistance data upload finished");
+
+ /* Go to the next step */
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+}
+
+static void finish_assistance_data_upload(struct EG25Manager *manager)
+{
+ gchar value[BUFFER_SIZE];
+ GDateTime *datetime;
+ gchar *timestring;
+
+ /* Configure GNSS assistance clock to current system time (UTC) */
+ datetime = g_date_time_new_now_utc();
+ timestring = g_date_time_format(datetime, "0,\"%Y/%m/%d,%H:%M:%S\"\r\n");
+ g_message("Setting GNSS assistance UTC clock to: %s", timestring);
+ at_append_command(manager, "QGPSXTRATIME", NULL, timestring, NULL,
+ at_process_result);
+
+ /* Configure GNSS engine to use uploaded GNSS assistance data */
+ g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\"\r\n",
+ manager->gnss_assistance_file);
+ g_message("Setting GNSS assistance file to: %s", value);
+ at_append_command(manager, "QGPSXTRADATA", NULL, value, NULL,
+ finish_assistance_data_upload_cb);
+ at_send_command(manager);
+}
+
+/******************************************************************************/
+
+#ifdef HAVE_MMGLIB
+static void enable_mm_gnss(struct EG25Manager *manager)
+{
+ MMModemLocationSource sources;
+ gboolean signal_location;
+ g_autoptr (GError) error = NULL;
+
+ if (manager->gnss_sources & EG25_GNSS_SOURCE_UNMANAGED)
+ sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
+ if (manager->gnss_sources & EG25_GNSS_SOURCE_NMEA)
+ sources |= MM_MODEM_LOCATION_SOURCE_GPS_NMEA;
+ 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)
+ g_warning("Unable to enable GNSS engine through ModemManager: %s",
+ error->message);
+}
+#endif
+
+static void enable_at_gnss_cb(struct EG25Manager *manager, const char *response)
+{
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+}
+
+static void enable_at_gnss(struct EG25Manager *manager)
+{
+ if (manager->gnss_sources & EG25_GNSS_SOURCE_QGPS) {
+ at_append_command(manager, "QGPS", NULL, "1", NULL,
+ enable_at_gnss_cb);
+ at_send_command(manager);
+ return;
+ }
+ manager->gnss_assistance_step++;
+ gnss_step(manager);
+}
+
+/******************************************************************************/
+
+void gnss_step(struct EG25Manager *manager)
+{
+ switch(manager->gnss_assistance_step) {
+ case EG25_GNSS_STEP_FIRST:
+ manager->gnss_assistance_step++;
+ g_message("GNSS assistance upload started...");
+ /* fall-through */
+
+#ifdef HAVE_MMGLIB
+ case EG25_GNSS_STEP_MM_GNSS_DISABLE:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "disabling GNSS engine through ModemManager",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ disable_mm_gnss(manager);
+ manager->gnss_assistance_step++;
+ /* fall-through */
+#endif
+
+ case EG25_GNSS_STEP_AT_GNSS_DISABLE:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "disabling GNSS engine through AT+QGPS",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ state_at_gnss(manager);
+ break;
+
+ case EG25_GNSS_STEP_FETCH_ASSISTANCE_DATA:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "fetching assistance data",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ fetch_assistance_data(manager);
+ break;
+
+ case EG25_GNSS_STEP_INIT_UPLOAD:
+ g_message("GNSS assistance upload step (%d/%d): initiating upload",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ init_assistance_data_upload(manager);
+ break;
+
+ case EG25_GNSS_STEP_UPLOAD:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "uploading assistance data",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ upload_assistance_data(manager);
+ break;
+
+ case EG25_GNSS_STEP_FINISH_UPLOAD:
+ g_message("GNSS assistance upload step (%d/%d): finishing upload",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ finish_assistance_data_upload(manager);
+ break;
+
+#ifdef HAVE_MMGLIB
+ case EG25_GNSS_STEP_MM_GNSS_ENABLE:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "re-enabling GNSS through ModemManager",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ enable_mm_gnss(manager);
+ manager->gnss_assistance_step++;
+ /* fall-through */
+#endif
+
+ case EG25_GNSS_STEP_AT_QGPS_ENABLE:
+ g_message("GNSS assistance upload step (%d/%d): "
+ "re-enabling GNSS through AT+QGPS",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ enable_at_gnss(manager);
+ break;
+
+ case EG25_GNSS_STEP_LAST:
+ g_message("GNSS assistance upload step (%d/%d): finished",
+ manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
+ break;
+ }
+}
+
diff --git a/src/gnss.h b/src/gnss.h
new file mode 100644
index 0000000..931ab8b
--- /dev/null
+++ b/src/gnss.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2021 Dylan Van Assche <me@dylanvanassche.be>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <time.h>
+#include <curl/curl.h>
+
+#include "manager.h"
+
+void gnss_init(struct EG25Manager *manager, toml_table_t *config);
+void gnss_destroy(struct EG25Manager *manager);
+void gnss_upload_assistance_data(struct EG25Manager *manager);
diff --git a/src/manager.c b/src/manager.c
index c0b8a43..d13a2a0 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -15,6 +15,7 @@
#include "ofono-iface.h"
#include "suspend.h"
#include "udev.h"
+#include "gnss.h"
#include <fcntl.h>
#include <signal.h>
@@ -342,6 +343,7 @@ int main(int argc, char *argv[])
ofono_iface_init(&manager);
suspend_init(&manager, toml_table_in(toml_config, "suspend"));
udev_init(&manager, toml_table_in(toml_config, "udev"));
+ gnss_init(&manager, toml_table_in(toml_config, "gnss"));
g_idle_add(G_SOURCE_FUNC(modem_start), &manager);
diff --git a/src/manager.h b/src/manager.h
index 3cc0118..3e097b3 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -16,6 +16,32 @@
#include "toml.h"
+typedef enum {
+ EG25_GNSS_STEP_FIRST = 0,
+#ifdef HAVE_MMGLIB
+ EG25_GNSS_STEP_MM_GNSS_DISABLE,
+#endif
+ EG25_GNSS_STEP_AT_GNSS_DISABLE,
+ EG25_GNSS_STEP_FETCH_ASSISTANCE_DATA,
+ EG25_GNSS_STEP_INIT_UPLOAD,
+ EG25_GNSS_STEP_UPLOAD,
+ EG25_GNSS_STEP_FINISH_UPLOAD,
+#ifdef HAVE_MMGLIB
+ EG25_GNSS_STEP_MM_GNSS_ENABLE,
+#endif
+ EG25_GNSS_STEP_AT_QGPS_ENABLE,
+ EG25_GNSS_STEP_LAST,
+} EG25GNSSStep;
+
+typedef enum {
+ EG25_GNSS_SOURCE_NONE = 0,
+ EG25_GNSS_SOURCE_NMEA = 1 << 0,
+ EG25_GNSS_SOURCE_RAW = 1 << 1,
+ EG25_GNSS_SOURCE_UNMANAGED = 1 << 2,
+ EG25_GNSS_SOURCE_QGPS = 1 << 3,
+} EG25GNSSSource;
+
+
enum EG25State {
EG25_STATE_INIT = 0,
EG25_STATE_POWERED, // Power-on sequence has been executed, but the modem isn't on yet
@@ -52,11 +78,19 @@ struct EG25Manager {
enum EG25State modem_state;
gchar *modem_usb_id;
+ gboolean gnss_assistance_enabled;
+ EG25GNSSSource gnss_sources;
+ EG25GNSSStep gnss_assistance_step;
+ gint gnss_assistance_fd;
+ gchar *gnss_assistance_url;
+ gchar *gnss_assistance_file;
+
enum ModemIface modem_iface;
guint mm_watch;
#ifdef HAVE_MMGLIB
MMManager *mm_manager;
MMModem *mm_modem;
+ MMModemLocation *mm_location;
#endif
guint ofono_watch;
GDBOManager *ofono_manager;
diff --git a/src/meson.build b/src/meson.build
index f9eb27f..d1127dc 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,7 @@ src = [
'suspend.c', 'suspend.h',
'toml.c', 'toml.h',
'udev.c', 'udev.h',
+ 'gnss.c', 'gnss.h',
]
if mmglib_dep.found()
diff --git a/src/mm-iface.c b/src/mm-iface.c
index 0409236..2bbdfe5 100644
--- a/src/mm-iface.c
+++ b/src/mm-iface.c
@@ -32,7 +32,10 @@ static void add_modem(struct EG25Manager *manager, GDBusObject *object)
g_assert(MM_IS_OBJECT (object));
manager->mm_modem = mm_object_get_modem(MM_OBJECT(object));
- g_assert(manager->mm_modem != NULL);
+ manager->mm_location = mm_object_get_modem_location(MM_OBJECT(object));
+ g_assert_nonnull(manager->mm_modem);
+ g_assert_nonnull(manager->mm_location);
+
if (manager->modem_state == EG25_STATE_RESUMING) {
if (manager->modem_recovery_timer) {
--
2.31.1

View file

@ -1,13 +1,12 @@
# Forked from Alpine to upgrade to current git master, which has # Forked from Alpine to upgrade to current git master, which has
# Ofono compatibility fixes needed for Plasma Mobile # Ofono compatibility fixes needed for Plasma Mobile
pkgname=eg25-manager pkgname=eg25-manager
pkgver=0.3.0_git20210522 pkgver=0.3.0_git20210812
_commit="73e16f76994b1d3c587796a35766cc668e30c0cd"
pkgrel=0 pkgrel=0
pkgdesc="Daemon for managing the Quectel EG25 modem" pkgdesc="Daemon for managing the Quectel EG25 modem"
url="https://gitlab.com/mobian1/devices/eg25-manager" url="https://gitlab.com/mobian1/devices/eg25-manager"
arch="all !s390x !mips64" # no modemmanager # s390x, mips64 and riscv64 blocked by polkit -> modemmanager
arch="all !s390x !mips64 !riscv64"
license="GPL-3.0-or-later" license="GPL-3.0-or-later"
makedepends=" makedepends="
glib-dev glib-dev
@ -18,22 +17,15 @@ makedepends="
modemmanager-dev modemmanager-dev
curl-dev curl-dev
" "
_commit="e6df81778e812ef73aa55156bea5ede2937f9a4c"
source=" source="
https://gitlab.com/mobian1/devices/eg25-manager/-/archive/$_commit/eg25-manager-$_commit.tar.gz https://gitlab.com/mobian1/devices/eg25-manager/-/archive/$_commit/eg25-manager-$_commit.tar.gz
eg25-manager.confd eg25-manager.confd
eg25-manager.initd eg25-manager.initd
0001-mm-iface-clean-out-modem_iface-if-mm-disappears.patch
0002-config-synchronize-with-modem-power.patch
0003-at-fast-poweroff-is-only-available-in-newer-firmware.patch
0004-at-g_free-doesn-t-require-NULL-checking.patch
0005-at-make-next_at_command-send_at_command-process_at_r.patch
0006-at-log-expected-result-before-setting-it-to-NULL.patch
0007-at-allow-custom-callbacks-for-AT-command-response-pr.patch
0008-gnss-add-GNSS-assistance-support.patch
" "
options="!check" # no tests options="!check" # no tests
subpackages="$pkgname-openrc" subpackages="$pkgname-openrc"
builddir="$srcdir/eg25-manager-$_commit" builddir="$srcdir/$pkgname-$_commit"
build() { build() {
abuild-meson . output abuild-meson . output
@ -54,15 +46,7 @@ package() {
} }
sha512sums=" sha512sums="
2b0d706c893744529e035e8dc70b381362e39ddd2be705e346f0fd88e4907093e59b30800ad5ecb90638338b25bb51308349fb26de2c786197aeed8c1fa9c68a eg25-manager-73e16f76994b1d3c587796a35766cc668e30c0cd.tar.gz 72846ea696ee9d7ec433d5dd932881931d9f1fde2a8edc23e7a8f0d9cd74f41df054ffe15a826d48224b5d1f24ce59a607a93b0da62490ffa06dd8beef2b074c eg25-manager-e6df81778e812ef73aa55156bea5ede2937f9a4c.tar.gz
55936830afad2968a214fb39cfe1a9db50421dc2ff4f67d04f08f6bd2b094c3ab46799cfc7743bbc5032682d98d1216203adf5264353a05134bea58524ac070b eg25-manager.confd 55936830afad2968a214fb39cfe1a9db50421dc2ff4f67d04f08f6bd2b094c3ab46799cfc7743bbc5032682d98d1216203adf5264353a05134bea58524ac070b eg25-manager.confd
0dd866ce18bac37c3832a463205402f5b34a520e1a57cc37658fb37e21a173fbba2cfab223111c68af768be1d3feeb23e41dbaf6d8dc14a2b2c0c088cf3df041 eg25-manager.initd 0dd866ce18bac37c3832a463205402f5b34a520e1a57cc37658fb37e21a173fbba2cfab223111c68af768be1d3feeb23e41dbaf6d8dc14a2b2c0c088cf3df041 eg25-manager.initd
029dce7e7d6e79faab2a63acde2fe76109e5e269bf38d72617d00ffbb89001f75b604e79290d449db7a6f960f9872eb41c2d0ab4a6d82d7563b66e954cd4ffa8 0001-mm-iface-clean-out-modem_iface-if-mm-disappears.patch
fe6c37c79ea6e89b6bcce78d015a3770347384181595e2c2ff2d42a76baa626cf430125fcefe7679570da268718039f1cce0aef90fe1a5c5ca123425006bbd03 0002-config-synchronize-with-modem-power.patch
ff263d8ce700e910d895496dc5ad0e8e75da17aaac9357b5c3a7632728daab28d2fe4700e2d7c7ba8d45d83742c60dbb581882f95847f0b22cbb09d0ae4c30a6 0003-at-fast-poweroff-is-only-available-in-newer-firmware.patch
2e6e3acde664a77dbcb67ad348e622779be1a50b8ef1b7a175fd6377e0e02511ff120b8c6e9670e914e74d9d176f6194e87bbf7742c60b4cfaf69dd26ed90f49 0004-at-g_free-doesn-t-require-NULL-checking.patch
a59cb10bf14500daaac70a4dd238133a3dfffbb365c871dc039258ee1b3f89a8a7a81f85d5b9ad8a7428b3a927cff282351a8323dfcfb1556333d04bdae14934 0005-at-make-next_at_command-send_at_command-process_at_r.patch
4726f8a8e3cb011d4f4694fc104a289340b8f04a813df9784f823aa773bcfa401fa683de0b8e3837e78b202def3c23a4946dbae31b602659add97a6a585415f2 0006-at-log-expected-result-before-setting-it-to-NULL.patch
cce1e5439783e2a88aeb88bad837d7cf09c18065f6516fb0936cb6fb9cac95034b67c87f8a42545a3e82393f2c07f9694ea668237165ec0ab566fd4159894d54 0007-at-allow-custom-callbacks-for-AT-command-response-pr.patch
7e798b4547493d6b5f7eeb848682d7e0b4d2b0c066696079e99ee777d82c5ffa04d25f15f4ef6f9197cb5187a6c9c286ffcf0cbad87122d1c36e0f67aa0ca651 0008-gnss-add-GNSS-assistance-support.patch
" "