9 Commits
0.0.3 ... 0.0.5

Author SHA1 Message Date
Arnaud Ferraris
a9725243ec meson.build: bump version 2020-12-11 13:37:40 +01:00
Arnaud Ferraris
75b0920e9d Revert "manager: split modem_suspend() into _pre() and _post() functions"
This reverts commit ff9b26b831.
2020-12-11 13:36:28 +01:00
Arnaud Ferraris
9713af7ca8 at: fix GPS disabling on suspend 2020-12-11 13:31:11 +01:00
Arnaud Ferraris
664f82d570 at: add default handling for unrecognized responses 2020-12-11 13:31:11 +01:00
Arnaud Ferraris
f386d851fa at: make sure we read the full response before processing it 2020-12-11 12:49:31 +01:00
Arnaud Ferraris
5bc8443c38 at: be less strict when checking for error
The response can include the command and an error number, so we want to 
only check it contains ERROR, even if it's replying more than just the 
'ERROR' string.
2020-12-11 12:49:31 +01:00
Arnaud Ferraris
aabe4df41c at: fix suspend/resume sequences
These are set commands, no need to verify the current value.
2020-12-11 12:49:31 +01:00
Arnaud Ferraris
ff9b26b831 manager: split modem_suspend() into _pre() and _post() functions
This way we can make sure the AT commands are executed only once 
ModemManager has released the modem, preventing any race condition.
2020-12-11 12:49:31 +01:00
Arnaud Ferraris
8d31e39e89 manager: only start the modem if it isn't already on 2020-12-11 12:49:10 +01:00
5 changed files with 77 additions and 23 deletions

View File

@@ -8,7 +8,7 @@
project (
'eg25manager',
'c',
version : '0.0.1',
version : '0.0.5',
license : 'GPLv3+',
meson_version : '>= 0.50.0',
default_options :
@@ -44,6 +44,7 @@ mgr_deps = [
dependency('glib-2.0'),
dependency('gio-unix-2.0'),
dependency('libgpiod'),
dependency('libusb-1.0'),
dependency('mm-glib'),
]

View File

@@ -31,7 +31,7 @@ static int configure_serial(const char *tty)
struct termios ttycfg;
int fd;
fd = open(tty, O_RDWR | O_NOCTTY);
fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd > 0) {
tcgetattr(fd, &ttycfg);
ttycfg.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
@@ -55,7 +55,9 @@ static gboolean send_at_command(struct EG25Manager *manager)
struct AtCommand *at_cmd = g_list_nth_data(manager->at_cmds, 0);
if (at_cmd) {
if (at_cmd->subcmd == NULL && at_cmd->value == NULL)
if (at_cmd->subcmd == NULL && at_cmd->value == NULL && at_cmd->expected == NULL)
sprintf(command, "AT+%s\r\n", at_cmd->cmd);
else if (at_cmd->subcmd == NULL && at_cmd->value == NULL)
sprintf(command, "AT+%s?\r\n", at_cmd->cmd);
else if (at_cmd->subcmd == NULL && at_cmd->value)
sprintf(command, "AT+%s=%s\r\n", at_cmd->cmd, at_cmd->value);
@@ -143,7 +145,6 @@ static int append_at_command(struct EG25Manager *manager,
if (!at_cmd)
return -1;
at_cmd->retries = 0;
at_cmd->cmd = g_strdup(cmd);
if (subcmd)
at_cmd->subcmd = g_strdup(subcmd);
@@ -157,22 +158,33 @@ static int append_at_command(struct EG25Manager *manager,
return 0;
}
#define READ_BUFFER_SIZE 256
static gboolean modem_response(gint fd,
GIOCondition event,
gpointer data)
{
struct EG25Manager *manager = data;
char response[256];
int ret;
char response[READ_BUFFER_SIZE*4+1];
char tmp[READ_BUFFER_SIZE];
ssize_t ret, pos = 0;
/*
* TODO: several reads can be necessary to get the full response, we could
* loop until we read 0 chars with a reasonable delay between attempts
* Several reads can be necessary to get the full response, so we loop
* until we read 0 chars with a reasonable delay between attempts
* (remember the transfer rate is 115200 here)
*/
ret = read(fd, response, sizeof(response));
if (ret > 0) {
response[ret] = 0;
do {
ret = read(fd, tmp, sizeof(tmp));
if (ret > 0) {
memcpy(&response[pos], tmp, ret);
pos += ret;
usleep(10000);
}
} while (ret > 0 && pos < (sizeof(response) - 1));
if (pos > 0) {
response[pos] = 0;
g_strstrip(response);
if (strlen(response) == 0)
return TRUE;
@@ -181,10 +193,13 @@ static gboolean modem_response(gint fd,
if (strcmp(response, "RDY") == 0)
manager->modem_state = EG25_STATE_STARTED;
else if (strcmp(response, "ERROR") == 0)
else if (strstr(response, "ERROR"))
retry_at_command(manager);
else if (strstr(response, "OK"))
process_at_result(manager, response);
else
// Not a recognized response, try running next command, just in case
next_at_command(manager);
}
return TRUE;
@@ -249,7 +264,7 @@ void at_sequence_configure(struct EG25Manager *manager)
void at_sequence_suspend(struct EG25Manager *manager)
{
append_at_command(manager, "QGPS", NULL, NULL, "0");
append_at_command(manager, "QGPSEND", NULL, NULL, NULL);
append_at_command(manager, "QCFG", "urc/cache", "1", NULL);
send_at_command(manager);
}
@@ -257,7 +272,7 @@ void at_sequence_suspend(struct EG25Manager *manager)
void at_sequence_resume(struct EG25Manager *manager)
{
append_at_command(manager, "QCFG", "urc/cache", "0", NULL);
append_at_command(manager, "QGPS", NULL, NULL, "1");
append_at_command(manager, "QGPS", NULL, "1", NULL);
send_at_command(manager);
}

View File

@@ -57,7 +57,7 @@ int gpio_sequence_poweron(struct EG25Manager *manager)
sleep(1);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 0);
g_message("Executed power-on sequence");
g_message("Executed power-on/off sequence");
return 0;
}
@@ -172,13 +172,16 @@ int gpio_init(struct EG25Manager *manager)
return 0;
}
gboolean gpio_check_poweroff(struct EG25Manager *manager)
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down)
{
if (manager->gpio_in[GPIO_IN_STATUS] &&
gpiod_line_get_value(manager->gpio_in[GPIO_IN_STATUS]) == 1) {
// Asserting RESET line to prevent modem from rebooting
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_RESET], 1);
if (keep_down) {
// Asserting RESET line to prevent modem from rebooting
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_RESET], 1);
}
return TRUE;
}

View File

@@ -16,4 +16,4 @@ int gpio_sequence_shutdown(struct EG25Manager *state);
int gpio_sequence_suspend(struct EG25Manager *state);
int gpio_sequence_resume(struct EG25Manager *state);
gboolean gpio_check_poweroff(struct EG25Manager *manager);
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down);

View File

@@ -16,6 +16,10 @@
#include <unistd.h>
#include <glib-unix.h>
#include <libusb.h>
#define EG25_USB_VID 0x2c7c
#define EG25_USB_PID 0x0125
static gboolean quit_app(struct EG25Manager *manager)
{
@@ -32,7 +36,7 @@ static gboolean quit_app(struct EG25Manager *manager)
gpio_sequence_shutdown(manager);
manager->modem_state = EG25_STATE_FINISHING;
for (i = 0; i < 30; i++) {
if (gpio_check_poweroff(manager))
if (gpio_check_poweroff(manager, TRUE))
break;
sleep(1);
}
@@ -46,9 +50,40 @@ static gboolean quit_app(struct EG25Manager *manager)
static gboolean modem_start(struct EG25Manager *manager)
{
g_message("Starting modem...");
gpio_sequence_poweron(manager);
manager->modem_state = EG25_STATE_POWERED;
ssize_t i, count;
gboolean should_boot = TRUE;
libusb_context *ctx = NULL;
libusb_device **devices = NULL;
struct libusb_device_descriptor desc;
if (manager->braveheart) {
// BH don't have the STATUS line connected, so check if USB device is present
libusb_init(&ctx);
count = libusb_get_device_list(ctx, &devices);
for (i = 0; i < count; i++) {
libusb_get_device_descriptor(devices[i], &desc);
if (desc.idVendor == EG25_USB_VID && desc.idProduct == EG25_USB_PID) {
g_message("Found corresponding USB device, modem already powered");
should_boot = FALSE;
break;
}
}
libusb_free_device_list(devices, 1);
libusb_exit(ctx);
} else if (!gpio_check_poweroff(manager, FALSE)) {
g_message("STATUS is low, modem already powered");
should_boot = FALSE;
}
if (should_boot) {
g_message("Starting modem...");
gpio_sequence_poweron(manager);
manager->modem_state = EG25_STATE_POWERED;
} else {
manager->modem_state = EG25_STATE_STARTED;
}
return FALSE;
}