From 21d10011bc4b009d7a09131b955953fa7aba3815 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 31 Oct 2013 19:49:22 +0100 Subject: [PATCH] add code to load/save configuration in eeprom --- Makefile | 1 + cmdline.c | 7 +- cmdline.h | 2 + commands.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++- eeprom_config.c | 157 +++++++++++++++++++++++++++++++++++ eeprom_config.h | 48 +++++++++++ main.c | 5 +- 7 files changed, 427 insertions(+), 7 deletions(-) create mode 100644 eeprom_config.c create mode 100644 eeprom_config.h diff --git a/Makefile b/Makefile index 4883bb4..24f4f92 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ SRC += parse_atcmd.c SRC += parse_monitor.c SRC += cmdline.c SRC += beep.c +SRC += eeprom_config.c CFLAGS += -W -Wall -Werror diff --git a/cmdline.c b/cmdline.c index 5745b9c..0b0c606 100644 --- a/cmdline.c +++ b/cmdline.c @@ -79,8 +79,7 @@ int xbee_dev_recv(FILE* f) return c; } -static void -valid_buffer(const char *buf, uint8_t size) +void cmdline_valid_buffer(const char *buf, uint8_t size) { int8_t ret; PGM_P ctx = (PGM_P)main_ctx; @@ -104,7 +103,7 @@ complete_buffer(const char *buf, char *dstbuf, uint8_t dstsize, } -static void write_char(char c) +void cmdline_write_char(char c) { cmdline_dev_send(c, NULL); } @@ -112,7 +111,7 @@ static void write_char(char c) void cmdline_init(void) { - rdline_init(&xbeeboard.rdl, write_char, valid_buffer, complete_buffer); + rdline_init(&xbeeboard.rdl, cmdline_write_char, cmdline_valid_buffer, complete_buffer); snprintf_P(xbeeboard.prompt, sizeof(xbeeboard.prompt), PSTR("mainboard > ")); } diff --git a/cmdline.h b/cmdline.h index 58798a3..034244a 100644 --- a/cmdline.h +++ b/cmdline.h @@ -39,6 +39,8 @@ int cmdline_poll(void); int cmdline_dev_send(char c, FILE* f); int cmdline_dev_recv(FILE* f); +void cmdline_write_char(char c); +void cmdline_valid_buffer(const char *buf, uint8_t size); int xbee_dev_send(char c, FILE* f); int xbee_dev_recv(FILE* f); diff --git a/commands.c b/commands.c index b58594a..eff413d 100644 --- a/commands.c +++ b/commands.c @@ -52,6 +52,7 @@ #include "main.h" #include "cmdline.h" #include "beep.h" +#include "eeprom_config.h" /* commands_gen.c */ extern const parse_inst_t PROGMEM cmd_reset; @@ -1463,7 +1464,7 @@ static void cmd_test_spi_parsed(void * parsed_result, void *data) /* stress test: send many commands, no wait between each servo * of a series, and a variable delay between series */ printf_P(PSTR("stress test\r\n")); - while (!cmdline_keypressed()) { + while (!cmdline_keypressed()) { wait_time++; if (wait_time > 20) @@ -1550,6 +1551,212 @@ const parse_inst_t PROGMEM cmd_test_spi = { }, }; +/**********************************************************/ + +/* this structure is filled when cmd_test_eeprom_config is parsed successfully */ +struct cmd_test_eeprom_config_result { + fixed_string_t arg0; +}; + +static void cmd_test_eeprom_config_parsed(void *parsed_result, void *data) +{ + (void)parsed_result; + (void)data; + + eeprom_dump_cmds(); + eeprom_append_cmd("salut1\n"); + eeprom_dump_cmds(); + eeprom_append_cmd("salut2\n"); + eeprom_append_cmd("salut3\n"); + eeprom_append_cmd("salut4\n"); + eeprom_dump_cmds(); + eeprom_insert_cmd_before("coin\n", 0); + eeprom_insert_cmd_before("coin2\n", 2); + eeprom_dump_cmds(); + eeprom_delete_cmd(2); + eeprom_delete_cmd(0); + eeprom_dump_cmds(); +} + +const char PROGMEM str_test_eeprom_config_arg0[] = "test_eeprom_config"; +const parse_token_string_t PROGMEM cmd_test_eeprom_config_arg0 = + TOKEN_STRING_INITIALIZER(struct cmd_test_eeprom_config_result, arg0, + str_test_eeprom_config_arg0); + +const char PROGMEM help_test_eeprom_config[] = "Test the eeprom configuration"; +const parse_inst_t PROGMEM cmd_test_eeprom_config = { + .f = cmd_test_eeprom_config_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = help_test_eeprom_config, + .tokens = { /* token list, NULL terminated */ + (PGM_P)&cmd_test_eeprom_config_arg0, + NULL, + }, +}; + +/* ************* */ + +struct cmd_eeprom_del_result { + fixed_string_t cmd; + fixed_string_t action; + uint8_t n; +}; + +static void cmd_eeprom_del_parsed(void *parsed_result, + void *data) +{ + struct cmd_eeprom_del_result *res = parsed_result; + + (void)data; + if (eeprom_delete_cmd(res->n) < 0) + printf_P(PSTR("cannot delete command\n")); + eeprom_dump_cmds(); +} + +const char PROGMEM str_eeprom_del_eeprom[] = "eeprom"; +const parse_token_string_t PROGMEM cmd_eeprom_del_cmd = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, cmd, + str_eeprom_del_eeprom); +const char PROGMEM str_eeprom_del_del[] = "del"; +const parse_token_string_t PROGMEM cmd_eeprom_del_action = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_del_result, action, + str_eeprom_del_del); +const parse_token_num_t PROGMEM cmd_eeprom_del_num = + TOKEN_NUM_INITIALIZER(struct cmd_eeprom_del_result, n, + UINT8); + +const char PROGMEM help_eeprom_del[] = "delete an eeprom init command"; +const parse_inst_t PROGMEM cmd_eeprom_del = { + .f = cmd_eeprom_del_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = help_eeprom_del, + .tokens = { /* token list, NULL terminated */ + (PGM_P)&cmd_eeprom_del_cmd, + (PGM_P)&cmd_eeprom_del_action, + (PGM_P)&cmd_eeprom_del_num, + NULL, + }, +}; + +/* ************* */ + +struct cmd_eeprom_add_result { + fixed_string_t cmd; + fixed_string_t action; + uint8_t n; +}; + +static void cmd_eeprom_add_parsed(void *parsed_result, + void *data) +{ + struct cmd_eeprom_add_result *res = parsed_result; + struct rdline rdl; + const char *buffer; + int8_t ret; + int16_t c; + + rdline_init(&rdl, cmdline_write_char, NULL, NULL); + rdline_newline(&rdl, "> "); + + /* XXX bad: we should not block as we do not serve callout */ + while (1) { + c = cmdline_dev_recv(NULL); + if (c < 0) + continue; + + ret = rdline_char_in(&rdl, c); + if (ret == -2) { + printf_P(PSTR("abort\n")); + return; + } + if (ret == 1) + break; + } + + buffer = rdline_get_buffer(&rdl); + if (data == NULL) + eeprom_insert_cmd_before(buffer, res->n); + else + eeprom_append_cmd(buffer); + eeprom_dump_cmds(); +} + +const char PROGMEM str_eeprom_add_eeprom[] = "eeprom"; +const parse_token_string_t PROGMEM cmd_eeprom_add_cmd = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, cmd, + str_eeprom_add_eeprom); +const char PROGMEM str_eeprom_add_add[] = "add"; +const parse_token_string_t PROGMEM cmd_eeprom_add_action = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_add_result, action, + str_eeprom_add_add); +const parse_token_num_t PROGMEM cmd_eeprom_add_num = + TOKEN_NUM_INITIALIZER(struct cmd_eeprom_add_result, n, + UINT8); + +const char PROGMEM help_eeprom_add[] = "insert an eeprom init command"; +const parse_inst_t PROGMEM cmd_eeprom_add = { + .f = cmd_eeprom_add_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = help_eeprom_add, + .tokens = { /* token list, NULL terminated */ + (PGM_P)&cmd_eeprom_add_cmd, + (PGM_P)&cmd_eeprom_add_action, + (PGM_P)&cmd_eeprom_add_num, + NULL, + }, +}; + +const char PROGMEM help_eeprom_add2[] = "append an eeprom init command"; +const parse_inst_t PROGMEM cmd_eeprom_add2 = { + .f = cmd_eeprom_add_parsed, /* function to call */ + .data = (void *)1, /* 2nd arg of func */ + .help_str = help_eeprom_add2, + .tokens = { /* token list, NULL terminated */ + (PGM_P)&cmd_eeprom_add_cmd, + (PGM_P)&cmd_eeprom_add_action, + NULL, + }, +}; + +/* ************* */ + +struct cmd_eeprom_list_result { + fixed_string_t cmd; + fixed_string_t action; +}; + +static void cmd_eeprom_list_parsed(void *parsed_result, + void *data) +{ + (void)parsed_result; + (void)data; + eeprom_dump_cmds(); +} + +const char PROGMEM str_eeprom_list_eeprom[] = "eeprom"; +const parse_token_string_t PROGMEM cmd_eeprom_list_cmd = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, cmd, + str_eeprom_list_eeprom); +const char PROGMEM str_eeprom_list_list[] = "list"; +const parse_token_string_t PROGMEM cmd_eeprom_list_action = + TOKEN_STRING_INITIALIZER(struct cmd_eeprom_list_result, action, + str_eeprom_list_list); + +const char PROGMEM help_eeprom_list[] = "list all eeprom init commands"; +const parse_inst_t PROGMEM cmd_eeprom_list = { + .f = cmd_eeprom_list_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = help_eeprom_list, + .tokens = { /* token list, NULL terminated */ + (PGM_P)&cmd_eeprom_list_cmd, + (PGM_P)&cmd_eeprom_list_action, + NULL, + }, +}; + + +/* ************* */ + /* in progmem */ const parse_ctx_t PROGMEM main_ctx[] = { @@ -1591,5 +1798,10 @@ const parse_ctx_t PROGMEM main_ctx[] = { &cmd_servo_bypassppm, &cmd_servo_show, &cmd_test_spi, + &cmd_test_eeprom_config, + &cmd_eeprom_del, + &cmd_eeprom_add, + &cmd_eeprom_add2, + &cmd_eeprom_list, NULL, }; diff --git a/eeprom_config.c b/eeprom_config.c new file mode 100644 index 0000000..f3274d8 --- /dev/null +++ b/eeprom_config.c @@ -0,0 +1,157 @@ +/* + * Copyright 2013 Olivier Matz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include +#include +#include + +#include + + +#include "cmdline.h" +#include "eeprom_config.h" + +/* load configuration from eeprom */ +int8_t eeprom_load_config(void) +{ + struct eeprom_config *e = NULL; + struct eeprom_cmd cmd; + uint32_t magic; + uint8_t i, max; + + eeprom_read_block(&magic, &e->magic, sizeof(magic)); + if (magic != EEPROM_CONFIG_MAGIC) { + printf_P(PSTR("no EEPROM config\n")); + eeprom_set_ncmds(0); + return 0; + } + + max = eeprom_get_ncmds(); + for (i = 0; i < max; i++) { + eeprom_get_cmd(&cmd, i); + printf_P(PSTR("%s"), cmd.buf); + cmdline_valid_buffer(cmd.buf, strlen(cmd.buf)); + } + + return -1; +} + +uint8_t eeprom_get_ncmds(void) +{ + struct eeprom_config *e = NULL; + uint8_t ncmds; + + eeprom_read_block(&ncmds, &e->ncmds, sizeof(ncmds)); + return ncmds; +} + +void eeprom_set_ncmds(uint8_t ncmds) +{ + struct eeprom_config *e = NULL; + uint32_t magic = EEPROM_CONFIG_MAGIC; + eeprom_update_block(&ncmds, &e->ncmds, sizeof(ncmds)); + eeprom_update_block(&magic, &e->magic, sizeof(magic)); +} + +/* fill cmd struct with the n-th command from eeprom, no check is done + * on index or size. The \0 is added at the end of the string. */ +void eeprom_get_cmd(struct eeprom_cmd *cmd, uint8_t n) +{ + struct eeprom_config *e = NULL; + + eeprom_read_block(cmd, &e->cmds[n], sizeof(*cmd)); + cmd->buf[EEPROM_CMD_SIZE-1] = '\0'; +} + +/* fill n-th command of eeprom from struct, no check is done on index + * or size */ +void eeprom_set_cmd(struct eeprom_cmd *cmd, uint8_t n) +{ + struct eeprom_config *e = NULL; + + eeprom_update_block(cmd, &e->cmds[n], sizeof(*cmd)); +} + +void eeprom_dump_cmds(void) +{ + uint8_t i, max; + struct eeprom_cmd cmd; + + printf_P(PSTR("init commands:\n")); + max = eeprom_get_ncmds(); + for (i = 0; i < max; i++) { + eeprom_get_cmd(&cmd, i); + printf_P(PSTR("%.2d: %s"), i, cmd.buf); + } +} + +int8_t eeprom_insert_cmd_before(const char *str, uint8_t n) +{ + uint8_t i, max; + struct eeprom_cmd cmd; + + if (strlen(str) >= EEPROM_CMD_SIZE) + return -1; + + max = eeprom_get_ncmds(); + if (n > max) + return -1; + if (max >= EEPROM_N_CMD_MAX) + return -1; + + for (i = max; i > n; i--) { + eeprom_get_cmd(&cmd, i-1); + eeprom_set_cmd(&cmd, i); + } + + snprintf(cmd.buf, sizeof(cmd.buf), "%s", str); + eeprom_set_cmd(&cmd, n); + eeprom_set_ncmds(max + 1); + return 0; +} + +int8_t eeprom_append_cmd(const char *str) +{ + uint8_t max; + + max = eeprom_get_ncmds(); + return eeprom_insert_cmd_before(str, max); +} + +int8_t eeprom_delete_cmd(uint8_t n) +{ + uint8_t i, max; + struct eeprom_cmd cmd; + + max = eeprom_get_ncmds(); + if (n >= max) + return -1; + + for (i = n; i < max-1; i++) { + eeprom_get_cmd(&cmd, i+1); + eeprom_set_cmd(&cmd, i); + } + + eeprom_set_ncmds(max - 1); + return 0; +} diff --git a/eeprom_config.h b/eeprom_config.h new file mode 100644 index 0000000..7aff867 --- /dev/null +++ b/eeprom_config.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013 Olivier Matz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _EEPROM_CONFIG_H_ +#define _EEPROM_CONFIG_H_ + +#define EEPROM_CONFIG_MAGIC 0x666bea57 +#define EEPROM_CMD_SIZE 64 +#define EEPROM_N_CMD_MAX 16 + +struct eeprom_cmd { + char buf[EEPROM_CMD_SIZE]; +}; + +struct eeprom_config +{ + uint32_t magic; + uint8_t ncmds; + struct eeprom_cmd cmds[EEPROM_N_CMD_MAX]; +}; + +int8_t eeprom_load_config(void); +uint8_t eeprom_get_ncmds(void); +void eeprom_set_ncmds(uint8_t ncmds); +void eeprom_get_cmd(struct eeprom_cmd *cmd, uint8_t n); +void eeprom_set_cmd(struct eeprom_cmd *cmd, uint8_t n); +void eeprom_dump_cmds(void); +int8_t eeprom_insert_cmd_before(const char *str, uint8_t n); +int8_t eeprom_append_cmd(const char *str); +int8_t eeprom_delete_cmd(uint8_t n); + +#endif diff --git a/main.c b/main.c index 8e2aa0e..20e26b0 100644 --- a/main.c +++ b/main.c @@ -52,6 +52,7 @@ #include #include +#include "eeprom_config.h" #include "beep.h" #include "main.h" @@ -247,7 +248,7 @@ int xbee_recv_data(struct xbee_recv_hdr *recvframe, unsigned len) val += 512; spi_servo_set(0, val); break; - } + } case RC_PROTO_TYPE_RANGE: { struct rc_proto_range *rcr = (struct rc_proto_range *) recvframe->data; @@ -660,9 +661,9 @@ int main(void) fprintf(stderr, "cannot register default channel\n"); return -1; } - sei(); + eeprom_load_config(); xbee_mainloop(); return 0; } -- 2.20.1