Merge branch 'config' into 'master'

Implement config file

Closes #6

See merge request mobian1/devices/eg25-manager!8
This commit is contained in:
Arnaud Ferraris
2021-02-20 16:16:45 +00:00
20 changed files with 2847 additions and 117 deletions

13
data/meson.build Normal file
View File

@@ -0,0 +1,13 @@
#
# Copyright (C) 2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
conf_files = [
'pine64,pinephone-1.0.toml',
'pine64,pinephone-1.1.toml',
'pine64,pinephone-1.2.toml',
]
install_data(conf_files)

View File

@@ -0,0 +1,54 @@
[manager]
need_libusb = true
usb_vid = 0x2c7c
usb_pid = 0x0125
# Uncomment the following if you need to change the modem detection timeout on
# resume and/or the time during which suspend is blocked after modem boot
#[suspend]
#boot_timeout = 120
#recovery_timeout = 9
[gpio]
dtr = 358
pwrkey = 35
reset = 68
apready = 231
disable = 232
[at]
uart = "/dev/ttyS2"
configure = [
# Each command has 4 possible elements:
# * `cmd` : the AT command itself, which will be translated to "AT+`cmd`"
# * `subcmd`: the subcommand in case a single AT command can be used
# to change multiple parameters, such as QCFG (optional)
# * `value` : the commands, argument, usually used to set the value of
# a specific parameter (optional)
# * `expect`: the expected return value; the command is first executed
# without any value in order to query the current state. This
# state is then compared to the `expect` string; if they don't
# match, the command is then executed with value `expect` in
# order to set the parameter to the configured value (optional)
# A command can have `expect` OR `value` configured, but it shouldn't have both
{ cmd = "QDAI", expect = "1,1,0,1,0,0,1,1" },
{ 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/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"usbat\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" }
]
suspend = [
{ cmd = "QGPSEND" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "1" }
]
resume = [
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" },
{ cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]

View File

@@ -0,0 +1,54 @@
[manager]
need_libusb = true
usb_vid = 0x2c7c
usb_pid = 0x0125
# Uncomment the following if you need to change the modem detection timeout on
# resume and/or the time during which suspend is blocked after modem boot
#[suspend]
#boot_timeout = 120
#recovery_timeout = 9
[gpio]
dtr = 358
pwrkey = 35
reset = 68
apready = 231
disable = 232
[at]
uart = "/dev/ttyS2"
configure = [
# Each command has 4 possible elements:
# * `cmd` : the AT command itself, which will be translated to "AT+`cmd`"
# * `subcmd`: the subcommand in case a single AT command can be used
# to change multiple parameters, such as QCFG (optional)
# * `value` : the commands, argument, usually used to set the value of
# a specific parameter (optional)
# * `expect`: the expected return value; the command is first executed
# without any value in order to query the current state. This
# state is then compared to the `expect` string; if they don't
# match, the command is then executed with value `expect` in
# order to set the parameter to the configured value (optional)
# A command can have `expect` OR `value` configured, but it shouldn't have both
{ cmd = "QDAI", expect = "1,1,0,1,0,0,1,1" },
{ 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/delay", expect = "1" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"usbat\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" }
]
suspend = [
{ cmd = "QGPSEND" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "1" }
]
resume = [
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" },
{ cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]

View File

@@ -0,0 +1,47 @@
# Uncomment the following if you need to change the modem detection timeout on
# resume and/or the time during which suspend is blocked after modem boot
#[suspend]
#boot_timeout = 120
#recovery_timeout = 9
[gpio]
dtr = 34
pwrkey = 35
reset = 68
apready = 231
disable = 232
status = 233
[at]
uart = "/dev/ttyS2"
configure = [
# Each command has 4 possible elements:
# * `cmd` : the AT command itself, which will be translated to "AT+`cmd`"
# * `subcmd`: the subcommand in case a single AT command can be used
# to change multiple parameters, such as QCFG (optional)
# * `value` : the commands, argument, usually used to set the value of
# a specific parameter (optional)
# * `expect`: the expected return value; the command is first executed
# without any value in order to query the current state. This
# state is then compared to the `expect` string; if they don't
# match, the command is then executed with value `expect` in
# order to set the parameter to the configured value (optional)
# A command can have `expect` OR `value` configured, but it shouldn't have both
{ cmd = "QDAI", expect = "1,1,0,1,0,0,1,1" },
{ cmd = "QCFG", subcmd = "risignaltype", expect = "\"physical\"" },
{ cmd = "QCFG", subcmd = "ims", expect = "1" },
{ cmd = "QCFG", subcmd = "apready", expect = "1,0,500" },
{ cmd = "QURCCFG", subcmd = "urcport", expect = "\"usbat\"" },
{ cmd = "QGPS", value = "1" },
{ cmd = "QSCLK", value = "1" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" }
]
suspend = [
{ cmd = "QGPSEND" },
{ cmd = "QCFG", subcmd = "urc/cache", value = "1" }
]
resume = [
{ cmd = "QCFG", subcmd = "urc/cache", value = "0" },
{ cmd = "QGPS", value = "1" }
]
reset = [ { cmd = "CFUN", value = "1,1" } ]

View File

@@ -6,7 +6,7 @@
#
project (
'eg25manager',
'eg25-manager',
'c',
version : '0.1.2',
license : 'GPLv3+',
@@ -41,6 +41,12 @@ else
full_sysconfdir = join_paths(prefix, sysconfdir)
endif
eg25_confdir = join_paths(full_sysconfdir, meson.project_name())
eg25_datadir = join_paths(full_datadir, meson.project_name())
add_global_arguments('-D@0@="@1@"'.format('EG25_CONFDIR', eg25_confdir), language : 'c')
add_global_arguments('-D@0@="@1@"'.format('EG25_DATADIR', eg25_datadir), language : 'c')
mgr_deps = [
dependency('glib-2.0'),
dependency('gio-unix-2.0'),
@@ -50,5 +56,6 @@ mgr_deps = [
dependency('mm-glib'),
]
subdir('data')
subdir('src')
subdir('udev')

144
src/at.c
View File

@@ -16,8 +16,6 @@
#include <glib-unix.h>
#define MODEM_UART "/dev/ttyS2"
struct AtCommand {
char *cmd;
char *subcmd;
@@ -26,6 +24,11 @@ struct AtCommand {
int retries;
};
static GArray *configure_commands = NULL;
static GArray *suspend_commands = NULL;
static GArray *resume_commands = NULL;
static GArray *reset_commands = NULL;
static int configure_serial(const char *tty)
{
struct termios ttycfg;
@@ -218,16 +221,86 @@ static gboolean modem_response(gint fd,
return TRUE;
}
int at_init(struct EG25Manager *manager)
static void parse_commands_list(toml_array_t *array, GArray **cmds)
{
manager->at_fd = configure_serial(MODEM_UART);
int len;
len = toml_array_nelem(array);
*cmds = g_array_new(FALSE, TRUE, sizeof(struct AtCommand));
g_array_set_size(*cmds, (guint)len);
for (int i = 0; i < len; i++) {
struct AtCommand *cmd = &g_array_index(*cmds, struct AtCommand, i);
toml_table_t *table = toml_table_at(array, i);
toml_datum_t value;
if (!table)
continue;
value = toml_string_in(table, "cmd");
if (value.ok) {
cmd->cmd = g_strdup(value.u.s);
free(value.u.s);
}
value = toml_string_in(table, "subcmd");
if (value.ok) {
cmd->subcmd = g_strdup(value.u.s);
free(value.u.s);
}
value = toml_string_in(table, "value");
if (value.ok) {
cmd->value = g_strdup(value.u.s);
free(value.u.s);
}
value = toml_string_in(table, "expect");
if (value.ok) {
cmd->expected = g_strdup(value.u.s);
free(value.u.s);
}
}
}
int at_init(struct EG25Manager *manager, toml_table_t *config)
{
toml_array_t *commands;
toml_datum_t uart_port;
uart_port = toml_string_in(config, "uart");
if (!uart_port.ok)
g_error("Configuration file lacks UART port definition");
manager->at_fd = configure_serial(uart_port.u.s);
if (manager->at_fd < 0) {
g_critical("Unable to configure %s", MODEM_UART);
g_critical("Unable to configure %s", uart_port.u.s);
free(uart_port.u.s);
return 1;
}
free(uart_port.u.s);
manager->at_source = g_unix_fd_add(manager->at_fd, G_IO_IN, modem_response, manager);
commands = toml_array_in(config, "configure");
if (!commands)
g_error("Configuration file lacks initial AT commands list");
parse_commands_list(commands, &configure_commands);
commands = toml_array_in(config, "suspend");
if (!commands)
g_error("Configuration file lacks suspend AT commands list");
parse_commands_list(commands, &suspend_commands);
commands = toml_array_in(config, "resume");
if (!commands)
g_error("Configuration file lacks resume AT commands list");
parse_commands_list(commands, &resume_commands);
commands = toml_array_in(config, "reset");
if (!commands)
g_error("Configuration file lacks reset AT commands list");
parse_commands_list(commands, &reset_commands);
return 0;
}
@@ -236,66 +309,45 @@ void at_destroy(struct EG25Manager *manager)
g_source_remove(manager->at_source);
if (manager->at_fd > 0)
close(manager->at_fd);
g_array_free(configure_commands, TRUE);
g_array_free(suspend_commands, TRUE);
g_array_free(resume_commands, TRUE);
g_array_free(reset_commands, TRUE);
}
void at_sequence_configure(struct EG25Manager *manager)
{
/*
* Default parameters in megi's driver which differ with our own:
* - urc/ri/x are always set the same way on both BH and CE
* - urc/ri/x pulse duration is 1 ms and urc/delay is 0 (no need to delay
* URCs if the pulse is that short, so this is expected)
* - apready is disabled
*
* Parameters set in megi's kernel but not here:
* - sleepind/level = 0
* - wakeupin/level = 0
* - ApRstLevel = 0
* - ModemRstLevel = 0
* - airplanecontrol = 1
* - fast/poweroff = 1
* (those would need to be researched to check their usefulness for our
* use-case)
*/
append_at_command(manager, "QDAI", NULL, NULL, "1,1,0,1,0,0,1,1");
append_at_command(manager, "QCFG", "risignaltype", NULL, "\"physical\"");
append_at_command(manager, "QCFG", "ims", NULL, "1");
if (manager->braveheart) {
append_at_command(manager, "QCFG", "urc/ri/ring", NULL, "\"pulse\",2000,1000,5000,\"off\",1");
append_at_command(manager, "QCFG", "urc/ri/smsincoming", NULL, "\"pulse\",2000");
append_at_command(manager, "QCFG", "urc/ri/other", NULL, "\"off\",1");
append_at_command(manager, "QCFG", "urc/delay", NULL, "1");
} else {
append_at_command(manager, "QCFG", "apready", NULL, "1,0,500");
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->expected, cmd->value);
}
append_at_command(manager, "QURCCFG", "urcport", NULL, "\"usbat\"");
if (manager->manage_gnss)
append_at_command(manager, "QGPS", NULL, NULL, "1");
append_at_command(manager, "QSCLK", NULL, "1", NULL);
// Make sure URC cache is disabled
append_at_command(manager, "QCFG", "urc/cache", "0", NULL);
send_at_command(manager);
}
void at_sequence_suspend(struct EG25Manager *manager)
{
if (manager->manage_gnss)
append_at_command(manager, "QGPSEND", NULL, NULL, NULL);
append_at_command(manager, "QCFG", "urc/cache", "1", NULL);
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->expected, cmd->value);
}
send_at_command(manager);
}
void at_sequence_resume(struct EG25Manager *manager)
{
append_at_command(manager, "QCFG", "urc/cache", "0", NULL);
if (manager->manage_gnss)
append_at_command(manager, "QGPS", NULL, "1", NULL);
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->expected, cmd->value);
}
send_at_command(manager);
}
void at_sequence_reset(struct EG25Manager *manager)
{
append_at_command(manager, "CFUN", NULL, "1,1", NULL);
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->expected, cmd->value);
}
send_at_command(manager);
}

View File

@@ -8,7 +8,7 @@
#include "manager.h"
int at_init(struct EG25Manager *data);
int at_init(struct EG25Manager *data, toml_table_t *config);
void at_destroy(struct EG25Manager *data);
void at_sequence_configure(struct EG25Manager *data);

View File

@@ -22,35 +22,12 @@ enum {
GPIO_OUT_COUNT
};
static unsigned gpio_out_idx_bh[] = {
358,
35,
68,
231,
232
};
static unsigned gpio_out_idx_ce[] = {
34,
35,
68,
231,
232
};
enum {
GPIO_IN_STATUS = 0,
GPIO_IN_COUNT
};
static unsigned gpio_in_idx_bh[] = {
GPIO_IDX_INVAL,
};
static unsigned gpio_in_idx_ce[] = {
233,
};
int gpio_sequence_poweron(struct EG25Manager *manager)
{
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 1);
@@ -92,11 +69,24 @@ int gpio_sequence_resume(struct EG25Manager *manager)
return 0;
}
int gpio_init(struct EG25Manager *manager)
static guint get_config_gpio(toml_table_t *config, const char *id)
{
toml_datum_t value = toml_int_in(config, id);
guint gpio;
if (!value.ok)
return GPIO_IDX_INVAL;
gpio = (guint)value.u.i;
return gpio;
}
int gpio_init(struct EG25Manager *manager, toml_table_t *config)
{
int i, ret;
unsigned *gpio_in_idx;
unsigned *gpio_out_idx;
guint gpio_out_idx[GPIO_OUT_COUNT];
guint gpio_in_idx[GPIO_IN_COUNT];
manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL);
if (!manager->gpiochip[0]) {
@@ -110,16 +100,15 @@ int gpio_init(struct EG25Manager *manager)
return 1;
}
if (manager->braveheart) {
gpio_in_idx = gpio_in_idx_bh;
gpio_out_idx = gpio_out_idx_bh;
} else {
gpio_in_idx = gpio_in_idx_ce;
gpio_out_idx = gpio_out_idx_ce;
}
gpio_out_idx[GPIO_OUT_DTR] = get_config_gpio(config, "dtr");
gpio_out_idx[GPIO_OUT_PWRKEY] = get_config_gpio(config, "pwrkey");
gpio_out_idx[GPIO_OUT_RESET] = get_config_gpio(config, "reset");
gpio_out_idx[GPIO_OUT_APREADY] = get_config_gpio(config, "apready");
gpio_out_idx[GPIO_OUT_DISABLE] = get_config_gpio(config, "disable");
gpio_in_idx[GPIO_IN_STATUS] = get_config_gpio(config, "status");
for (i = 0; i < GPIO_OUT_COUNT; i++) {
unsigned int offset, chipidx;
guint offset, chipidx;
if (gpio_out_idx[i] < MAX_GPIOCHIP_LINES) {
offset = gpio_out_idx[i];
@@ -143,7 +132,7 @@ int gpio_init(struct EG25Manager *manager)
}
for (i = 0; i < GPIO_IN_COUNT; i++) {
unsigned int offset, chipidx;
guint offset, chipidx;
if (gpio_in_idx[i] == GPIO_IDX_INVAL)
continue;

View File

@@ -8,7 +8,7 @@
#include "manager.h"
int gpio_init(struct EG25Manager *state);
int gpio_init(struct EG25Manager *state, toml_table_t *config);
void gpio_destroy(struct EG25Manager *state);
int gpio_sequence_poweron(struct EG25Manager *state);

View File

@@ -19,8 +19,13 @@
#include <glib-unix.h>
#include <libusb.h>
#define EG25_USB_VID 0x2c7c
#define EG25_USB_PID 0x0125
#ifndef EG25_CONFDIR
#define EG25_CONFDIR "/etc/eg25-manager"
#endif
#ifndef EG25_DATADIR
#define EG25_DATADIR "/usr/share/eg25-manager"
#endif
static gboolean quit_app(struct EG25Manager *manager)
{
@@ -58,14 +63,14 @@ static gboolean modem_start(struct EG25Manager *manager)
libusb_device **devices = NULL;
struct libusb_device_descriptor desc;
if (manager->braveheart) {
if (manager->use_libusb) {
// 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) {
if (desc.idVendor == manager->usb_vid && desc.idProduct == manager->usb_pid) {
g_message("Found corresponding USB device, modem already powered");
should_boot = FALSE;
break;
@@ -198,15 +203,71 @@ void modem_resume_post(struct EG25Manager *manager)
at_sequence_resume(manager);
}
static toml_table_t *parse_config_file(char *config_file)
{
toml_table_t *toml_config;
gchar *compatible;
gchar error[256];
gsize len;
FILE *f = NULL;
if (config_file) {
f = fopen(config_file, "r");
} else if (g_file_get_contents("/proc/device-tree/compatible", &compatible, &len, NULL)) {
g_autoptr (GPtrArray) compat = g_ptr_array_new();
gsize pos = 0;
/*
* `compatible` file is a list of NULL-terminated strings, convert it
* to an array
*/
do {
g_ptr_array_add(compat, &compatible[pos]);
pos += strlen(&compatible[pos]) + 1;
} while (pos < len);
for (pos = 0; pos < compat->len; pos++) {
g_autofree gchar *filename = g_strdup_printf(EG25_CONFDIR "/%s.toml", (gchar *)g_ptr_array_index(compat, pos));
if (access(filename, F_OK) == 0) {
g_message("Opening config file: %s", filename);
f = fopen(filename, "r");
break;
}
}
if (!f) {
for (pos = 0; pos < compat->len; pos++) {
g_autofree gchar *filename = g_strdup_printf(EG25_DATADIR "/%s.toml", (gchar *)g_ptr_array_index(compat, pos));
if (access(filename, F_OK) == 0) {
g_message("Opening config file: %s", filename);
f = fopen(filename, "r");
break;
}
}
}
}
if (!f)
g_error("unable to find a suitable config file!");
toml_config = toml_parse_file(f, error, sizeof(error));
if (!toml_config)
g_error("unable to parse config file: %s", error);
return toml_config;
}
int main(int argc, char *argv[])
{
g_autoptr(GOptionContext) opt_context = NULL;
g_autoptr(GError) err = NULL;
struct EG25Manager manager;
char compatible[32];
int fd, ret;
gchar *config_file = NULL;
toml_table_t *toml_config;
toml_table_t *toml_manager;
toml_datum_t toml_value;
const GOptionEntry options[] = {
{ "gnss", 'g', 0, G_OPTION_ARG_NONE, &manager.manage_gnss, "Manage the GNSS feature.", NULL },
{ "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file to use.", NULL },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
@@ -224,21 +285,28 @@ int main(int argc, char *argv[])
manager.loop = g_main_loop_new(NULL, FALSE);
fd = open("/proc/device-tree/compatible", O_RDONLY);
if (fd < 0) {
g_critical("Unable to read 'compatible' string from device tree");
return 1;
}
ret = read(fd, compatible, sizeof(compatible));
if (ret > 0 && !strstr(compatible, "pine64,pinephone-1.2"))
manager.braveheart = TRUE;
close(fd);
toml_config = parse_config_file(config_file);
at_init(&manager);
gpio_init(&manager);
mm_iface_init(&manager);
suspend_init(&manager);
udev_init(&manager);
toml_manager = toml_table_in(toml_config, "manager");
if (toml_manager) {
toml_value = toml_bool_in(toml_manager, "need_libusb");
if (toml_value.ok)
manager.use_libusb = toml_value.u.b;
toml_value = toml_int_in(toml_manager, "usb_vid");
if (toml_value.ok)
manager.usb_vid = toml_value.u.i;
toml_value = toml_int_in(toml_manager, "usb_pid");
if (toml_value.ok)
manager.usb_pid = toml_value.u.i;
}
at_init(&manager, toml_table_in(toml_config, "at"));
gpio_init(&manager, toml_table_in(toml_config, "gpio"));
mm_iface_init(&manager, toml_table_in(toml_config, "mm-iface"));
suspend_init(&manager, toml_table_in(toml_config, "suspend"));
udev_init(&manager, toml_table_in(toml_config, "udev"));
g_idle_add(G_SOURCE_FUNC(modem_start), &manager);

View File

@@ -11,6 +11,8 @@
#include <gudev/gudev.h>
#include <libmm-glib.h>
#include "toml.h"
enum EG25State {
EG25_STATE_INIT = 0,
EG25_STATE_POWERED, // Power-on sequence has been executed, but the modem isn't on yet
@@ -28,7 +30,9 @@ enum EG25State {
struct EG25Manager {
GMainLoop *loop;
guint reset_timer;
gboolean manage_gnss;
gboolean use_libusb;
guint usb_vid;
guint usb_pid;
int at_fd;
guint at_source;
@@ -36,7 +40,6 @@ struct EG25Manager {
enum EG25State modem_state;
gchar *modem_usb_id;
gboolean braveheart;
guint mm_watch;
MMManager *mm_manager;
@@ -47,7 +50,9 @@ struct EG25Manager {
int suspend_block_fd;
guint modem_recovery_timer;
guint modem_recovery_timeout;
guint modem_boot_timer;
guint modem_boot_timeout;
GUdevClient *udev;

View File

@@ -12,6 +12,7 @@ executable (
'manager.c', 'manager.h',
'mm-iface.c', 'mm-iface.h',
'suspend.c', 'suspend.h',
'toml.c', 'toml.h',
'udev.c', 'udev.h',
],
dependencies : mgr_deps,

View File

@@ -187,7 +187,7 @@ static void mm_vanished_cb(GDBusConnection *connection,
mm_iface_clean(manager);
}
void mm_iface_init(struct EG25Manager *manager)
void mm_iface_init(struct EG25Manager *manager, toml_table_t *config)
{
manager->mm_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM, MM_DBUS_SERVICE,
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,

View File

@@ -8,5 +8,5 @@
#include "manager.h"
void mm_iface_init(struct EG25Manager *data);
void mm_iface_init(struct EG25Manager *data, toml_table_t *config);
void mm_iface_destroy(struct EG25Manager *data);

View File

@@ -16,7 +16,6 @@
#define SD_NAME "org.freedesktop.login1"
#define SD_PATH "/org/freedesktop/login1"
#define SD_INTERFACE "org.freedesktop.login1.Manager"
#define FULL_BOOT_DELAY 120
static gboolean check_modem_resume(struct EG25Manager *manager)
{
@@ -107,7 +106,7 @@ static void inhibit_done_block(GObject *source,
*/
static gboolean modem_fully_booted(struct EG25Manager *manager)
{
g_message("Modem is up for %d seconds and fully ready", FULL_BOOT_DELAY);
g_message("Modem is up for %u seconds and fully ready", manager->modem_boot_timeout);
manager->modem_boot_timer = 0;
drop_inhibitor(manager, TRUE);
@@ -130,7 +129,7 @@ static void take_inhibitor(struct EG25Manager *manager, gboolean block)
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit",
variant_arg, 0, G_MAXINT, NULL, NULL,
inhibit_done_block, manager);
manager->modem_boot_timer = g_timeout_add_seconds(FULL_BOOT_DELAY,
manager->modem_boot_timer = g_timeout_add_seconds(manager->modem_boot_timeout,
G_SOURCE_FUNC(modem_fully_booted),
manager);
}
@@ -181,7 +180,7 @@ static void signal_cb(GDBusProxy *proxy,
modem_resume_post(manager);
} else {
manager->modem_state = EG25_STATE_RESUMING;
manager->modem_recovery_timer = g_timeout_add_seconds(9,
manager->modem_recovery_timer = g_timeout_add_seconds(manager->modem_recovery_timeout,
G_SOURCE_FUNC(check_modem_resume),
manager);
}
@@ -232,8 +231,25 @@ static void on_proxy_acquired(GObject *object,
}
}
void suspend_init(struct EG25Manager *manager)
void suspend_init(struct EG25Manager *manager, toml_table_t *config)
{
toml_datum_t timeout_value;
if (config) {
timeout_value = toml_int_in(config, "boot_timeout");
if (timeout_value.ok)
manager->modem_boot_timeout = (guint)timeout_value.u.i;
timeout_value = toml_int_in(config, "recovery_timeout");
if (timeout_value.ok)
manager->modem_recovery_timeout = (guint)timeout_value.u.i;
}
if (manager->modem_boot_timeout == 0)
manager->modem_boot_timeout = 120;
if (manager->modem_recovery_timeout == 0)
manager->modem_recovery_timeout = 9;
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,

View File

@@ -8,7 +8,7 @@
#include "manager.h"
void suspend_init (struct EG25Manager *data);
void suspend_init (struct EG25Manager *data, toml_table_t *config);
void suspend_destroy (struct EG25Manager *data);
void suspend_inhibit (struct EG25Manager *data, gboolean inhibit, gboolean block);

2249
src/toml.c Normal file

File diff suppressed because it is too large Load Diff

175
src/toml.h Normal file
View File

@@ -0,0 +1,175 @@
/*
MIT License
Copyright (c) 2017 - 2019 CK Tan
https://github.com/cktan/tomlc99
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef TOML_H
#define TOML_H
#include <stdio.h>
#include <stdint.h>
#ifdef __cplusplus
#define TOML_EXTERN extern "C"
#else
#define TOML_EXTERN extern
#endif
typedef struct toml_timestamp_t toml_timestamp_t;
typedef struct toml_table_t toml_table_t;
typedef struct toml_array_t toml_array_t;
typedef struct toml_datum_t toml_datum_t;
/* Parse a file. Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp,
char* errbuf,
int errbufsz);
/* Parse a string containing the full config.
* Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */
char* errbuf,
int errbufsz);
/* Free the table returned by toml_parse() or toml_parse_file(). Once
* this function is called, any handles accessed through this tab
* directly or indirectly are no longer valid.
*/
TOML_EXTERN void toml_free(toml_table_t* tab);
/* Timestamp types. The year, month, day, hour, minute, second, z
* fields may be NULL if they are not relevant. e.g. In a DATE
* type, the hour, minute, second and z fields will be NULLs.
*/
struct toml_timestamp_t {
struct { /* internal. do not use. */
int year, month, day;
int hour, minute, second, millisec;
char z[10];
} __buffer;
int *year, *month, *day;
int *hour, *minute, *second, *millisec;
char* z;
};
/*-----------------------------------------------------------------
* Enhanced access methods
*/
struct toml_datum_t {
int ok;
union {
toml_timestamp_t* ts; /* ts must be freed after use */
char* s; /* string value. s must be freed after use */
int b; /* bool value */
int64_t i; /* int value */
double d; /* double value */
} u;
};
/* on arrays: */
/* ... retrieve size of array. */
TOML_EXTERN int toml_array_nelem(const toml_array_t* arr);
/* ... retrieve values using index. */
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx);
/* ... retrieve array or table using index. */
TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx);
/* on tables: */
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx);
/* ... retrieve values using key. */
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key);
/* .. retrieve array or table using key. */
TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab,
const char* key);
TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
const char* key);
/*-----------------------------------------------------------------
* lesser used
*/
/* Return the array kind: 't'able, 'a'rray, 'v'alue */
TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
/* For array kind 'v'alue, return the type of values
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp
0 if unknown
*/
TOML_EXTERN char toml_array_type(const toml_array_t* arr);
/* Return the key of an array */
TOML_EXTERN const char* toml_array_key(const toml_array_t* arr);
/* Return the number of key-values in a table */
TOML_EXTERN int toml_table_nkval(const toml_table_t* tab);
/* Return the number of arrays in a table */
TOML_EXTERN int toml_table_narr(const toml_table_t* tab);
/* Return the number of sub-tables in a table */
TOML_EXTERN int toml_table_ntab(const toml_table_t* tab);
/* Return the key of a table*/
TOML_EXTERN const char* toml_table_key(const toml_table_t* tab);
/*--------------------------------------------------------------
* misc
*/
TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret);
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t),
void (*xxfree)(void*));
/*--------------------------------------------------------------
* deprecated
*/
/* A raw value, must be processed by toml_rto* before using. */
typedef const char* toml_raw_t;
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key);
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx);
TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret);
TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret);
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret);
TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret);
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen);
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret);
#endif /* TOML_H */

View File

@@ -25,7 +25,7 @@ static void udev_event_cb(GUdevClient *client, gchar *action, GUdevDevice *devic
}
}
void udev_init (struct EG25Manager *manager)
void udev_init (struct EG25Manager *manager, toml_table_t *config)
{
const char * const subsystems[] = { "usb", NULL };

View File

@@ -8,5 +8,5 @@
#include "manager.h"
void udev_init (struct EG25Manager *data);
void udev_init (struct EG25Manager *data, toml_table_t *config);
void udev_destroy (struct EG25Manager *data);