mirror of
https://gitlab.com/mobian1/eg25-manager.git
synced 2025-08-30 15:52:11 +02:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b000a75238 | ||
|
541aa00198 | ||
|
b53702ad0b | ||
|
1482899888 | ||
|
c4b3b75047 | ||
|
3c5d455f20 | ||
|
1acd15ca2f |
@@ -8,7 +8,7 @@
|
|||||||
project (
|
project (
|
||||||
'eg25-manager',
|
'eg25-manager',
|
||||||
'c',
|
'c',
|
||||||
version : '0.5.0',
|
version : '0.5.1',
|
||||||
license : 'GPLv3+',
|
license : 'GPLv3+',
|
||||||
meson_version : '>= 0.58.0',
|
meson_version : '>= 0.58.0',
|
||||||
default_options :
|
default_options :
|
||||||
|
@@ -327,7 +327,7 @@ 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)
|
||||||
{
|
{
|
||||||
gint error;
|
gint error;
|
||||||
glong written_total = 0;
|
off_t written_total = 0;
|
||||||
gint ret;
|
gint ret;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
|
52
src/gpio.c
52
src/gpio.c
@@ -74,19 +74,49 @@ int gpio_line_set_value(struct EG25Manager *manager, int line, enum gpiod_line_v
|
|||||||
|
|
||||||
int gpio_sequence_poweron(struct EG25Manager *manager)
|
int gpio_sequence_poweron(struct EG25Manager *manager)
|
||||||
{
|
{
|
||||||
|
/* Disable airplane mode in case it was enabled by other software. The
|
||||||
|
* W_DISABLE pin is active-low, so we set it to high here. */
|
||||||
|
gpio_line_set_value(manager, GPIO_OUT_DISABLE, GPIOD_LINE_VALUE_ACTIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force the modem to poweroff using the RESET_N pin before attempting to
|
||||||
|
* boot in case the it got into a bad state.
|
||||||
|
*
|
||||||
|
* If the modem was on, this will cause it to start booting, so press the
|
||||||
|
* power button while in reset to avoid a (probably only theoretical) race
|
||||||
|
* condition where it starts booting after reset, and then powers off from
|
||||||
|
* the power key.
|
||||||
|
*/
|
||||||
|
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_ACTIVE);
|
||||||
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE);
|
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The datasheet says to pull the pin low for between 150 and 460 ms. usleep
|
||||||
|
* should always sleep for at least the specified amount of time, so use
|
||||||
|
* 200ms because it's closer to the bottom of that range.
|
||||||
|
*/
|
||||||
|
usleep(200000);
|
||||||
|
|
||||||
|
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_INACTIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The modem has finished it's reset, now we wait to allow it a chance to
|
||||||
|
* react to the power key
|
||||||
|
*/
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
|
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
|
||||||
|
|
||||||
g_message("Executed power-on/off sequence");
|
g_message("Executed power-on sequence");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_sequence_shutdown(struct EG25Manager *manager)
|
int gpio_sequence_shutdown(struct EG25Manager *manager)
|
||||||
{
|
{
|
||||||
gpio_line_set_value(manager, GPIO_OUT_DISABLE, GPIOD_LINE_VALUE_ACTIVE);
|
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE);
|
||||||
gpio_sequence_poweron(manager);
|
sleep(1);
|
||||||
|
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
|
||||||
|
|
||||||
g_message("Executed power-off sequence");
|
g_message("Executed power-off sequence");
|
||||||
|
|
||||||
@@ -406,16 +436,18 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down)
|
void gpio_force_off(struct EG25Manager *manager)
|
||||||
|
{
|
||||||
|
if (manager->gpio_out[GPIO_OUT_RESET]) {
|
||||||
|
g_message("Setting the reset pin to ensure the modem stays off");
|
||||||
|
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean gpio_check_poweroff(struct EG25Manager *manager)
|
||||||
{
|
{
|
||||||
if (manager->gpio_in[GPIO_IN_STATUS] &&
|
if (manager->gpio_in[GPIO_IN_STATUS] &&
|
||||||
gpio_line_get_value(manager, GPIO_IN_STATUS) == GPIOD_LINE_VALUE_ACTIVE) {
|
gpio_line_get_value(manager, GPIO_IN_STATUS) == GPIOD_LINE_VALUE_ACTIVE) {
|
||||||
|
|
||||||
if (keep_down && manager->gpio_out[GPIO_OUT_RESET]) {
|
|
||||||
// Asserting RESET line to prevent modem from rebooting
|
|
||||||
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_ACTIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,4 +18,5 @@ int gpio_sequence_resume(struct EG25Manager *state);
|
|||||||
int gpio_sequence_wake(struct EG25Manager *state);
|
int gpio_sequence_wake(struct EG25Manager *state);
|
||||||
int gpio_sequence_sleep(struct EG25Manager *state);
|
int gpio_sequence_sleep(struct EG25Manager *state);
|
||||||
|
|
||||||
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down);
|
void gpio_force_off(struct EG25Manager *manager);
|
||||||
|
gboolean gpio_check_poweroff(struct EG25Manager *manager);
|
||||||
|
@@ -62,13 +62,17 @@ static gboolean quit_app(struct EG25Manager *manager)
|
|||||||
gpio_sequence_shutdown(manager);
|
gpio_sequence_shutdown(manager);
|
||||||
manager->modem_state = EG25_STATE_FINISHING;
|
manager->modem_state = EG25_STATE_FINISHING;
|
||||||
for (i = 0; i < 30; i++) {
|
for (i = 0; i < 30; i++) {
|
||||||
if (gpio_check_poweroff(manager, TRUE))
|
if (gpio_check_poweroff(manager)) {
|
||||||
|
g_message("Modem successfully powered down");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_message("Modem down, quitting...");
|
|
||||||
|
|
||||||
|
gpio_force_off(manager);
|
||||||
|
|
||||||
|
g_message("Modem down, quitting...");
|
||||||
g_main_loop_quit(manager->loop);
|
g_main_loop_quit(manager->loop);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -98,7 +102,7 @@ static gboolean modem_start(struct EG25Manager *manager)
|
|||||||
|
|
||||||
libusb_free_device_list(devices, 1);
|
libusb_free_device_list(devices, 1);
|
||||||
libusb_exit(ctx);
|
libusb_exit(ctx);
|
||||||
} else if (!gpio_check_poweroff(manager, FALSE)) {
|
} else if (!gpio_check_poweroff(manager)) {
|
||||||
g_message("STATUS is low, modem already powered");
|
g_message("STATUS is low, modem already powered");
|
||||||
should_boot = FALSE;
|
should_boot = FALSE;
|
||||||
}
|
}
|
||||||
@@ -141,7 +145,35 @@ void modem_configure(struct EG25Manager *manager)
|
|||||||
at_sequence_configure(manager);
|
at_sequence_configure(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean modem_reset_done(struct EG25Manager* manager)
|
static gboolean modem_gpio_reset_done(struct EG25Manager *manager)
|
||||||
|
{
|
||||||
|
gpio_sequence_poweron(manager);
|
||||||
|
manager->modem_state = EG25_STATE_POWERED;
|
||||||
|
manager->complete_reset_timer = 0;
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean modem_at_reset_done(struct EG25Manager* manager)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the modem was successfully rebooted, then we should have received
|
||||||
|
* "RDY" by now which will transition the state to started.
|
||||||
|
*/
|
||||||
|
if (manager->modem_state != EG25_STATE_RESETTING) {
|
||||||
|
manager->complete_reset_timer = 0;
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_message("AT reset failed, falling back to GPIO reset");
|
||||||
|
|
||||||
|
gpio_sequence_shutdown(manager);
|
||||||
|
manager->complete_reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_gpio_reset_done), manager);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean modem_rebind_done(struct EG25Manager* manager)
|
||||||
{
|
{
|
||||||
manager->modem_state = EG25_STATE_RESUMING;
|
manager->modem_state = EG25_STATE_RESUMING;
|
||||||
manager->complete_reset_timer = 0;
|
manager->complete_reset_timer = 0;
|
||||||
@@ -194,24 +226,26 @@ gboolean modem_reset(struct EG25Manager *manager)
|
|||||||
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
|
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = write(fd, manager->modem_usb_id, len);
|
ret = write(fd, manager->modem_usb_id, len);
|
||||||
|
close(fd);
|
||||||
if (ret < len) {
|
if (ret < len) {
|
||||||
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
|
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
|
|
||||||
fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY);
|
fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
|
g_warning("Unable to open /sys/bus/usb/drivers/usb/bind");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = write(fd, manager->modem_usb_id, len);
|
ret = write(fd, manager->modem_usb_id, len);
|
||||||
|
close(fd);
|
||||||
if (ret < len) {
|
if (ret < len) {
|
||||||
g_warning("Couldn't bind modem: wrote %d/%d bytes", ret, len);
|
g_warning("Couldn't bind modem: wrote %d/%d bytes", ret, len);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
|
|
||||||
g_message("Successfully reset modem's USB connection");
|
g_message("Successfully reset modem's USB connection");
|
||||||
|
|
||||||
@@ -219,7 +253,7 @@ gboolean modem_reset(struct EG25Manager *manager)
|
|||||||
* 3s is long enough to make sure the modem has been bound back and
|
* 3s is long enough to make sure the modem has been bound back and
|
||||||
* short enough to ensure it hasn't been acquired by ModemManager
|
* short enough to ensure it hasn't been acquired by ModemManager
|
||||||
*/
|
*/
|
||||||
manager->complete_reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_reset_done), manager);
|
manager->complete_reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_rebind_done), manager);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
|
|
||||||
@@ -237,7 +271,7 @@ error:
|
|||||||
at_sequence_reset(manager);
|
at_sequence_reset(manager);
|
||||||
|
|
||||||
// Setup timer for making sure we don't queue other reset commands
|
// Setup timer for making sure we don't queue other reset commands
|
||||||
manager->complete_reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_reset_done), manager);
|
manager->complete_reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_at_reset_done), manager);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user