at: parse config file

The AT commands list for each stage is now configured per-device, as 
well as the UART port to be used.

As this list can be changed by the user, there is no more need for a 
special GNSS-related option
This commit is contained in:
Arnaud Ferraris
2021-02-20 15:42:50 +01:00
parent cfbbbd0167
commit 042de572ea
3 changed files with 97 additions and 47 deletions

142
src/at.c
View File

@@ -16,8 +16,6 @@
#include <glib-unix.h> #include <glib-unix.h>
#define MODEM_UART "/dev/ttyS2"
struct AtCommand { struct AtCommand {
char *cmd; char *cmd;
char *subcmd; char *subcmd;
@@ -26,6 +24,11 @@ struct AtCommand {
int retries; 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) static int configure_serial(const char *tty)
{ {
struct termios ttycfg; struct termios ttycfg;
@@ -218,16 +221,86 @@ static gboolean modem_response(gint fd,
return TRUE; return TRUE;
} }
static void parse_commands_list(toml_array_t *array, GArray **cmds)
{
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) int at_init(struct EG25Manager *manager, toml_table_t *config)
{ {
manager->at_fd = configure_serial(MODEM_UART); 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) { 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; return 1;
} }
free(uart_port.u.s);
manager->at_source = g_unix_fd_add(manager->at_fd, G_IO_IN, modem_response, manager); 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; return 0;
} }
@@ -236,66 +309,45 @@ void at_destroy(struct EG25Manager *manager)
g_source_remove(manager->at_source); g_source_remove(manager->at_source);
if (manager->at_fd > 0) if (manager->at_fd > 0)
close(manager->at_fd); 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) void at_sequence_configure(struct EG25Manager *manager)
{ {
/* for (guint i = 0; i < configure_commands->len; i++) {
* Default parameters in megi's driver which differ with our own: struct AtCommand *cmd = &g_array_index(configure_commands, struct AtCommand, i);
* - urc/ri/x are always set the same way on both BH and CE append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->expected, cmd->value);
* - 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");
} }
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); send_at_command(manager);
} }
void at_sequence_suspend(struct EG25Manager *manager) void at_sequence_suspend(struct EG25Manager *manager)
{ {
if (manager->manage_gnss) for (guint i = 0; i < suspend_commands->len; i++) {
append_at_command(manager, "QGPSEND", NULL, NULL, NULL); struct AtCommand *cmd = &g_array_index(suspend_commands, struct AtCommand, i);
append_at_command(manager, "QCFG", "urc/cache", "1", NULL); append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->expected, cmd->value);
}
send_at_command(manager); send_at_command(manager);
} }
void at_sequence_resume(struct EG25Manager *manager) void at_sequence_resume(struct EG25Manager *manager)
{ {
append_at_command(manager, "QCFG", "urc/cache", "0", NULL); for (guint i = 0; i < resume_commands->len; i++) {
if (manager->manage_gnss) struct AtCommand *cmd = &g_array_index(resume_commands, struct AtCommand, i);
append_at_command(manager, "QGPS", NULL, "1", NULL); append_at_command(manager, cmd->cmd, cmd->subcmd, cmd->expected, cmd->value);
}
send_at_command(manager); send_at_command(manager);
} }
void at_sequence_reset(struct EG25Manager *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); send_at_command(manager);
} }

View File

@@ -267,7 +267,6 @@ int main(int argc, char *argv[])
toml_table_t *toml_manager; toml_table_t *toml_manager;
toml_datum_t toml_value; toml_datum_t toml_value;
const GOptionEntry options[] = { 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 }, { "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file to use.", NULL },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
}; };

View File

@@ -30,7 +30,6 @@ enum EG25State {
struct EG25Manager { struct EG25Manager {
GMainLoop *loop; GMainLoop *loop;
guint reset_timer; guint reset_timer;
gboolean manage_gnss;
gboolean use_libusb; gboolean use_libusb;
guint usb_vid; guint usb_vid;
guint usb_pid; guint usb_pid;