From da15b3d42309282ab463e4007f798170e46282ec Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 16 Mar 2021 21:36:13 +0100 Subject: [PATCH] Examples: Modem console --- .../modem_console/main/CMakeLists.txt | 3 +- .../modem_console/main/console_helper.cpp | 97 ++++ .../modem_console/main/console_helper.hpp | 76 ++++ .../modem_console/main/modem_console_main.c | 309 ------------- .../modem_console/main/modem_console_main.cpp | 420 ++++++++++++++++++ .../modem_console/main/repeat_helper.inc | 27 ++ .../cxx_include/esp_modem_primitives.hpp | 13 +- esp_modem/include/esp_modem_api.h | 16 +- .../generate/esp_modem_command_declare.inc | 29 +- esp_modem/private_include/exception_stub.hpp | 26 ++ esp_modem/src/esp_modem_api.cpp | 47 +- esp_modem/src/esp_modem_uart.cpp | 13 +- 12 files changed, 712 insertions(+), 364 deletions(-) create mode 100644 esp_modem/examples/modem_console/main/console_helper.cpp create mode 100644 esp_modem/examples/modem_console/main/console_helper.hpp delete mode 100644 esp_modem/examples/modem_console/main/modem_console_main.c create mode 100644 esp_modem/examples/modem_console/main/modem_console_main.cpp create mode 100644 esp_modem/examples/modem_console/main/repeat_helper.inc create mode 100644 esp_modem/private_include/exception_stub.hpp diff --git a/esp_modem/examples/modem_console/main/CMakeLists.txt b/esp_modem/examples/modem_console/main/CMakeLists.txt index 435f5ea3a..ae7fd98d4 100644 --- a/esp_modem/examples/modem_console/main/CMakeLists.txt +++ b/esp_modem/examples/modem_console/main/CMakeLists.txt @@ -1,4 +1,5 @@ -idf_component_register(SRCS "modem_console_main.c" +idf_component_register(SRCS "modem_console_main.cpp" + "console_helper.cpp" "httpget_handle.c" "ping_handle.c" INCLUDE_DIRS ".") diff --git a/esp_modem/examples/modem_console/main/console_helper.cpp b/esp_modem/examples/modem_console/main/console_helper.cpp new file mode 100644 index 000000000..2fa427be9 --- /dev/null +++ b/esp_modem/examples/modem_console/main/console_helper.cpp @@ -0,0 +1,97 @@ +// +// Created by david on 3/17/21. +// + +#include "console_helper.hpp" +#include "esp_log.h" + +static const char *TAG = "modem_console_helper"; + +ConsoleCommand::ConsoleCommand(const char* command, const char* help, std::vector& args, std::function f): + func(std::move(f)) +{ + RegisterCommand(command, help, args); +} + +void ConsoleCommand::RegisterCommand(const char* command, const char* help, std::vector& args) +{ + assert(last_command <= MAX_REPEAT_NR); + void * common_arg = nullptr; + for (auto it: args) { + switch(it.type) { + case ARG_END: + break; + case STR0: + common_arg = arg_str0(it.shortopts, it.longopts, it.datatype, it.glossary); + break; + case STR1: + common_arg = arg_str1(it.shortopts, it.longopts, it.datatype, it.glossary); + break; + case INT0: + common_arg = arg_int0(it.shortopts, it.longopts, it.datatype, it.glossary); + break; + case INT1: + common_arg = arg_int1(it.shortopts, it.longopts, it.datatype, it.glossary); + break; + } + if (common_arg) { + arg_table.emplace_back(common_arg); + } else { + ESP_LOGE(TAG, "Creating argument parser failed for %s", it.glossary); + abort(); + } + } + arg_table.emplace_back( arg_end(1)); + const esp_console_cmd_t command_def = { + .command = command, + .help = help, + .hint = nullptr, + .func = command_func_pts[last_command], + .argtable = &arg_table[0] + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&command_def)); + last_command++; + console_commands.emplace_back(this); +} + +int ConsoleCommand::get_count(int index) +{ + return ((struct arg_str *)arg_table[index])->count; +} + +std::string ConsoleCommand::get_string(int index) +{ + if (get_count(index) > 0) { + return std::string(((struct arg_str *)arg_table[index])->sval[0]); + } + return std::string(); +} + + + +std::vector ConsoleCommand::console_commands; +int ConsoleCommand::last_command = 0; + + + +const esp_console_cmd_func_t ConsoleCommand::command_func_pts[] = { + +#define TEMPLATE(index) ConsoleCommand::command_func_ ## index , + REPEAT_TEMPLATE_DEF(list of function pointers to command_func_XX() ) + +#undef TEMPLATE +}; + + +int ConsoleCommand::command_func(int argc, char **argv) { + void * plain_arg_array = &arg_table[0]; + int nerrors = arg_parse(argc, argv, (void **)plain_arg_array); + if (nerrors != 0) { + arg_print_errors(stderr, (struct arg_end *) arg_table.back(), argv[0]); + return 1; + } + if (func) { + return func(this); + } + return 0; +} diff --git a/esp_modem/examples/modem_console/main/console_helper.hpp b/esp_modem/examples/modem_console/main/console_helper.hpp new file mode 100644 index 000000000..c4006f4a0 --- /dev/null +++ b/esp_modem/examples/modem_console/main/console_helper.hpp @@ -0,0 +1,76 @@ +// +// Created by david on 3/17/21. +// + +#ifndef MODEM_CONSOLE_CONSOLE_HELPER_H +#define MODEM_CONSOLE_CONSOLE_HELPER_H + +#include +#include +#include +#include +#include "argtable3/argtable3.h" +#include "repeat_helper.inc" + +#define MAX_REPEAT_NR 10 + +enum arg_type { + STR0, + STR1, + INT0, + INT1, + ARG_END, +}; + +struct CommandArgs { + CommandArgs(arg_type t, const char * shopts, const char * lopts, const char * data, const char * glos): + type(t), shortopts(shopts), longopts(lopts), datatype(data), glossary(glos) {} + arg_type type; + const char *shortopts; + const char *longopts; + const char *datatype; + const char *glossary; +}; + +class ConsoleCommand { +public: + template explicit ConsoleCommand(const char* command, const char* help, + const T *arg_struct, size_t srg_struct_size , std::function f): + func(std::move(f)) + { + size_t args_plain_size = srg_struct_size / sizeof(CommandArgs); + auto first_arg = reinterpret_cast(arg_struct); + std::vector args(first_arg, first_arg + args_plain_size); + RegisterCommand(command, help, args); + } + + explicit ConsoleCommand(const char* command, const char* help, std::vector& args, std::function f); + int get_count(int index); + template int get_count_of(CommandArgs T::*member) { return get_count(index_arg(member)); } + template std::string get_string_of(CommandArgs T::*member) { return get_string(index_arg(member)); } + + std::string get_string(int index); + +private: + void RegisterCommand(const char* command, const char* help, std::vector& args); + template static constexpr size_t index_arg(CommandArgs T::*member) + { return ((uint8_t *)&((T*)nullptr->*member) - (uint8_t *)nullptr)/sizeof(CommandArgs); } + std::function func; + std::vector arg_table; + + int command_func(int argc, char **argv); + +#define TEMPLATE(index) \ + static inline int command_func_ ## index(int argc, char **argv) \ + { return console_commands[index]->command_func(argc, argv); } + + REPEAT_TEMPLATE_DEF(definition of command_func_XX() ) +#undef TEMPLATE + + static std::vector console_commands; + static int last_command; + const static esp_console_cmd_func_t command_func_pts[]; + +}; + +#endif //MODEM_CONSOLE_CONSOLE_HELPER_H diff --git a/esp_modem/examples/modem_console/main/modem_console_main.c b/esp_modem/examples/modem_console/main/modem_console_main.c deleted file mode 100644 index 1e8f51d3b..000000000 --- a/esp_modem/examples/modem_console/main/modem_console_main.c +++ /dev/null @@ -1,309 +0,0 @@ -/* Modem console example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include -#include -#include -#include "sdkconfig.h" -#include "esp_console.h" -#include "esp_event.h" -#include "nvs_flash.h" -#include "argtable3/argtable3.h" -#include "esp_modem.h" -#include "esp_log.h" - -// utilities to check network connectivity -void modem_console_register_http(void); -void modem_console_register_ping(void); - -static esp_modem_dce_t *s_dce = NULL; -static const char *TAG = "modem_console"; - -static struct { - struct arg_str *command; - struct arg_int *param_int; - struct arg_str *param_str; - struct arg_str *param_pdp; - struct arg_str *param_bool; - struct arg_str *param; - struct arg_str *result; - struct arg_end *end; -} at_args; - -static struct { - struct arg_str *param; - struct arg_end *end; -} modem_args; - - - -static struct { - struct arg_str *command; - struct arg_int *timeout; - struct arg_str *pattern; - struct arg_lit *no_cr; - struct arg_end *end; -} generic_at_args; - -static char s_common_in_str[100]; // used as common string input param holder -static char s_common_out_str[100]; // used as output string/command result holder - -static esp_err_t handle_line_pattern(esp_modem_dce_t *dce, const char *line) -{ - esp_err_t err = ESP_OK; - ESP_LOGI(TAG, "handle_line_pattern: DCE response: %s\n", line); - if (strstr(line, dce->handle_line_ctx)) { - err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS); - } - return err; -} - -static int do_dce(int argc, char **argv) -{ - // specific DCE generic command params - static bool bool_result; - static char pdp_type[10]; - static char pdp_apn[10]; - static esp_modem_dce_pdp_ctx_t pdp = { .type = pdp_type, .apn = pdp_apn }; - static esp_modem_dce_csq_ctx_t csq; - static esp_modem_dce_cbc_ctx_t cbc; - - int nerrors = arg_parse(argc, argv, (void **) &at_args); - if (nerrors != 0) { - arg_print_errors(stderr, at_args.end, argv[0]); - return 1; - } - void * command_param = NULL; - void * command_result = NULL; - - // parse input params - if (at_args.param_int->count > 0) { - command_param = (void*)(at_args.param_int->ival[0]); - } else if (at_args.param_bool->count > 0) { - const char * bool_in_str = at_args.param_bool->sval[0]; - s_common_out_str[0] = '\0'; - command_result = s_common_out_str; - if (strstr(bool_in_str,"true") || strstr(bool_in_str,"1")) { - command_param = (void*)true; - } else { - command_param = (void*)false; - } - } else if (at_args.param_pdp->count > 0) { - // parse out three comma separated sub-arguments - sscanf(at_args.param_pdp->sval[0], "%d,%s", &pdp.cid, pdp_type); - char *str_apn = strchr(pdp_type, ','); - if (str_apn) { - strncpy(pdp_apn, str_apn + 1, sizeof(pdp_apn)); - str_apn[0] = '\0'; - } - command_param = &pdp; - } else if (at_args.param_str->count > 0) { - strncpy(s_common_in_str, at_args.param_str->sval[0], sizeof(s_common_in_str)); - command_param = s_common_in_str; - } else if (at_args.param->count > 0) { // default param is treated as string - strncpy(s_common_in_str, at_args.param->sval[0], sizeof(s_common_in_str)); - command_param = s_common_in_str; - } - - // parse output params - if (at_args.result->count > 0) { - const char *res = at_args.result->sval[0]; - if (strstr(res, "csq")) { - command_result = &csq; - }else if (strstr(res, "cbc")) { - command_result = &cbc; - } else if (strstr(res, "str")) { - command_param = (void*)sizeof(s_common_out_str); - command_result = s_common_out_str; - } else if (strstr(res, "bool")) { - command_result = &bool_result; - } else { - command_param = (void*)sizeof(s_common_out_str); - command_result = s_common_out_str; - } - } - - // by default (if no param/result provided) expect string output - if (command_param == NULL && command_result == NULL) { - s_common_out_str[0] = '\0'; - command_param = (void*)sizeof(s_common_out_str); - command_result = s_common_out_str; - } - - esp_err_t err = esp_modem_command_list_run(s_dce, at_args.command->sval[0], command_param, command_result); - if (err == ESP_OK) { - printf("Command %s succeeded\n", at_args.command->sval[0]); - if (command_result == s_common_out_str && s_common_out_str[0] != '\0') { - ESP_LOGI(TAG, "Command string output: %s", s_common_out_str); - } else if (command_result == &csq) { - ESP_LOGI(TAG, "Command CSQ output: rssi:%d, ber:%d", csq.rssi, csq.ber); - } else if (command_result == &cbc) { - ESP_LOGI(TAG, "Command battery output:%d mV", cbc.battery_status); - } else if (command_result == &bool_result) { - ESP_LOGI(TAG, "Command bool output: %s", bool_result ? "true" : "false"); - } - return 0; - } - ESP_LOGE(TAG, "Command %s failed with %d", at_args.command->sval[0], err); - return 1; -} - - - -static int do_at_command(int argc, char **argv) -{ - int timeout = 1000; - int nerrors = arg_parse(argc, argv, (void **)&generic_at_args); - if (nerrors != 0) { - arg_print_errors(stderr, generic_at_args.end, argv[0]); - return 1; - } - esp_modem_dce_handle_line_t handle_line = esp_modem_dce_handle_response_default; - - strncpy(s_common_in_str, generic_at_args.command->sval[0], sizeof(s_common_in_str) - 2); - if (generic_at_args.no_cr->count == 0) { - size_t cmd_len = strlen(generic_at_args.command->sval[0]); - s_common_in_str[cmd_len] = '\r'; - s_common_in_str[cmd_len + 1] = '\0'; - } - - if (generic_at_args.timeout->count > 0) { - timeout = generic_at_args.timeout->ival[0]; - } - - if (generic_at_args.pattern->count > 0) { - strncpy(s_common_out_str, generic_at_args.pattern->sval[0], sizeof(s_common_out_str)); - handle_line = handle_line_pattern; - } - - if (esp_modem_dce_generic_command(s_dce, s_common_in_str, timeout, handle_line, s_common_out_str) == ESP_OK) { - return 0; - } - - return 1; -} - -static int do_modem_lifecycle(int argc, char **argv) -{ - int nerrors = arg_parse(argc, argv, (void **)&modem_args); - if (nerrors != 0) { - arg_print_errors(stderr, modem_args.end, argv[0]); - return 1; - } - if (modem_args.param->count > 0) { - esp_err_t err = ESP_FAIL; - if (strstr(modem_args.param->sval[0], "PPP")) { - err = esp_modem_start_ppp(s_dce->dte); - } else if (strstr(modem_args.param->sval[0], "CMD")) { - err = esp_modem_stop_ppp(s_dce->dte); - } else { - return 1; - } - if (err == ESP_OK) { - ESP_LOGI(TAG, "set_working_mode %s succeeded", at_args.param->sval[0]); - } else { - ESP_LOGI(TAG, "set_working_mode %s failed with %d", at_args.param->sval[0], err); - } - return 0; - } - return 1; -} - -static void register_dce(void) -{ - at_args.command = arg_str1(NULL, NULL, "", "Symbolic name of DCE command"); - at_args.param_int = arg_int0("i", "int", "", "Input parameter of integer type"); - at_args.param_str = arg_str0("s", "str", "", "Input parameter of string type"); - at_args.param_pdp = arg_str0("p", "pdp", "", "Comma separated string with PDP context"); - at_args.param_bool = arg_str0("b", "bool", "", "Input parameter of bool type"); - at_args.param = arg_str0(NULL, NULL, "", "Default input argument treated as string"); - at_args.result = arg_str0("o", "out", "", "Type of output parameter"); - at_args.end = arg_end(1); - const esp_console_cmd_t at_cmd = { - .command = "dce", - .help = "send symbolic command to the modem", - .hint = NULL, - .func = &do_dce, - .argtable = &at_args - }; - ESP_ERROR_CHECK(esp_console_cmd_register(&at_cmd)); -} -static void register_at_command(void) -{ - generic_at_args.command = arg_str1(NULL, NULL, "", "AT command to send to the modem"); - generic_at_args.timeout = arg_int0("t", "timeout", "", "command timeout"); - generic_at_args.pattern = arg_str0("p", "pattern", "", "command response to wait for"); - generic_at_args.no_cr = arg_litn("n", "no-cr", 0, 1, "not add trailing CR to the command"); - generic_at_args.end = arg_end(1); - - const esp_console_cmd_t at_command = { - .command = "at", - .help = "send generic AT command to the modem", - .hint = NULL, - .func = &do_at_command, - .argtable = &generic_at_args - }; - ESP_ERROR_CHECK(esp_console_cmd_register(&at_command)); -} - -static void register_modem_lifecycle(void) -{ - modem_args.param = arg_str1(NULL, NULL, "", "PPP or CMD"); - modem_args.end = arg_end(1); - const esp_console_cmd_t modem_cmd = { - .command = "modem", - .help = "set modem mode", - .hint = NULL, - .func = &do_modem_lifecycle, - .argtable = &modem_args - }; - ESP_ERROR_CHECK(esp_console_cmd_register(&modem_cmd)); -} - -static esp_console_repl_t *s_repl = NULL; - - -void app_main(void) -{ - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - // init the DTE - esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); - dte_config.pattern_queue_size = 100; - dte_config.event_task_stack_size = 4096; - dte_config.event_task_priority = 15; - esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet"); - dce_config.populate_command_list = true; - esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP(); - - esp_modem_dte_t *dte = esp_modem_dte_new(&dte_config); - s_dce = esp_modem_dce_new(&dce_config); - assert(s_dce != NULL); - - esp_netif_t *esp_netif = esp_netif_new(&ppp_netif_config); - assert(esp_netif); - - ESP_ERROR_CHECK(esp_modem_default_attach(dte, s_dce, esp_netif)); - - esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); - // init console REPL environment - ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); - - register_dce(); - register_at_command(); - register_modem_lifecycle(); - modem_console_register_http(); - modem_console_register_ping(); - - // start console REPL - ESP_ERROR_CHECK(esp_console_start_repl(s_repl)); -} diff --git a/esp_modem/examples/modem_console/main/modem_console_main.cpp b/esp_modem/examples/modem_console/main/modem_console_main.cpp new file mode 100644 index 000000000..86bab7d34 --- /dev/null +++ b/esp_modem/examples/modem_console/main/modem_console_main.cpp @@ -0,0 +1,420 @@ +/* Modem console example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include "sdkconfig.h" +#include "esp_console.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "argtable3/argtable3.h" +#include "cxx_include/esp_modem_dte.hpp" +#include "esp_modem_config.h" +#include "cxx_include/esp_modem_api.hpp" +#include "esp_log.h" +#include +#include +#include +#include +#include "console_helper.hpp" + +// utilities to check network connectivity +extern "C" void modem_console_register_http(void); +extern "C" void modem_console_register_ping(void); + +//static esp_modem_dce_t *s_dce = NULL; +static const char *TAG = "modem_console"; + +//static struct { +// struct arg_str *command; +// struct arg_int *param_int; +// struct arg_str *param_str; +// struct arg_str *param_pdp; +// struct arg_str *param_bool; +// struct arg_str *param; +// struct arg_str *result; +// struct arg_end *end; +//} at_args; +// +//static struct { +// struct arg_str *param; +// struct arg_end *end; +//} modem_args; +// +// +// +//static struct { +// struct arg_str *command; +// struct arg_int *timeout; +// struct arg_str *pattern; +// struct arg_lit *no_cr; +// struct arg_end *end; +//} generic_at_args; + +//static char s_common_in_str[100]; // used as common string input param holder +//static char s_common_out_str[100]; // used as output string/command result holder + +//static esp_err_t handle_line_pattern(esp_modem_dce_t *dce, const char *line) +//{ +// esp_err_t err = ESP_OK; +// ESP_LOGI(TAG, "handle_line_pattern: DCE response: %s\n", line); +// if (strstr(line, dce->handle_line_ctx)) { +// err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS); +// } +// return err; +//} +// +//static int do_dce(int argc, char **argv) +//{ +// // specific DCE generic command params +// static bool bool_result; +// static char pdp_type[10]; +// static char pdp_apn[10]; +// static esp_modem_dce_pdp_ctx_t pdp = { .type = pdp_type, .apn = pdp_apn }; +// static esp_modem_dce_csq_ctx_t csq; +// static esp_modem_dce_cbc_ctx_t cbc; +// +// int nerrors = arg_parse(argc, argv, (void **) &at_args); +// if (nerrors != 0) { +// arg_print_errors(stderr, at_args.end, argv[0]); +// return 1; +// } +// void * command_param = NULL; +// void * command_result = NULL; +// +// // parse input params +// if (at_args.param_int->count > 0) { +// command_param = (void*)(at_args.param_int->ival[0]); +// } else if (at_args.param_bool->count > 0) { +// const char * bool_in_str = at_args.param_bool->sval[0]; +// s_common_out_str[0] = '\0'; +// command_result = s_common_out_str; +// if (strstr(bool_in_str,"true") || strstr(bool_in_str,"1")) { +// command_param = (void*)true; +// } else { +// command_param = (void*)false; +// } +// } else if (at_args.param_pdp->count > 0) { +// // parse out three comma separated sub-arguments +// sscanf(at_args.param_pdp->sval[0], "%d,%s", &pdp.cid, pdp_type); +// char *str_apn = strchr(pdp_type, ','); +// if (str_apn) { +// strncpy(pdp_apn, str_apn + 1, sizeof(pdp_apn)); +// str_apn[0] = '\0'; +// } +// command_param = &pdp; +// } else if (at_args.param_str->count > 0) { +// strncpy(s_common_in_str, at_args.param_str->sval[0], sizeof(s_common_in_str)); +// command_param = s_common_in_str; +// } else if (at_args.param->count > 0) { // default param is treated as string +// strncpy(s_common_in_str, at_args.param->sval[0], sizeof(s_common_in_str)); +// command_param = s_common_in_str; +// } +// +// // parse output params +// if (at_args.result->count > 0) { +// const char *res = at_args.result->sval[0]; +// if (strstr(res, "csq")) { +// command_result = &csq; +// }else if (strstr(res, "cbc")) { +// command_result = &cbc; +// } else if (strstr(res, "str")) { +// command_param = (void*)sizeof(s_common_out_str); +// command_result = s_common_out_str; +// } else if (strstr(res, "bool")) { +// command_result = &bool_result; +// } else { +// command_param = (void*)sizeof(s_common_out_str); +// command_result = s_common_out_str; +// } +// } +// +// // by default (if no param/result provided) expect string output +// if (command_param == NULL && command_result == NULL) { +// s_common_out_str[0] = '\0'; +// command_param = (void*)sizeof(s_common_out_str); +// command_result = s_common_out_str; +// } +// +// esp_err_t err = esp_modem_command_list_run(s_dce, at_args.command->sval[0], command_param, command_result); +// if (err == ESP_OK) { +// printf("Command %s succeeded\n", at_args.command->sval[0]); +// if (command_result == s_common_out_str && s_common_out_str[0] != '\0') { +// ESP_LOGI(TAG, "Command string output: %s", s_common_out_str); +// } else if (command_result == &csq) { +// ESP_LOGI(TAG, "Command CSQ output: rssi:%d, ber:%d", csq.rssi, csq.ber); +// } else if (command_result == &cbc) { +// ESP_LOGI(TAG, "Command battery output:%d mV", cbc.battery_status); +// } else if (command_result == &bool_result) { +// ESP_LOGI(TAG, "Command bool output: %s", bool_result ? "true" : "false"); +// } +// return 0; +// } +// ESP_LOGE(TAG, "Command %s failed with %d", at_args.command->sval[0], err); +// return 1; +//} +// +// +// +//static int do_at_command(int argc, char **argv) +//{ +// int timeout = 1000; +// int nerrors = arg_parse(argc, argv, (void **)&generic_at_args); +// if (nerrors != 0) { +// arg_print_errors(stderr, generic_at_args.end, argv[0]); +// return 1; +// } +// esp_modem_dce_handle_line_t handle_line = esp_modem_dce_handle_response_default; +// +// strncpy(s_common_in_str, generic_at_args.command->sval[0], sizeof(s_common_in_str) - 2); +// if (generic_at_args.no_cr->count == 0) { +// size_t cmd_len = strlen(generic_at_args.command->sval[0]); +// s_common_in_str[cmd_len] = '\r'; +// s_common_in_str[cmd_len + 1] = '\0'; +// } +// +// if (generic_at_args.timeout->count > 0) { +// timeout = generic_at_args.timeout->ival[0]; +// } +// +// if (generic_at_args.pattern->count > 0) { +// strncpy(s_common_out_str, generic_at_args.pattern->sval[0], sizeof(s_common_out_str)); +// handle_line = handle_line_pattern; +// } +// +// if (esp_modem_dce_generic_command(s_dce, s_common_in_str, timeout, handle_line, s_common_out_str) == ESP_OK) { +// return 0; +// } +// +// return 1; +//} + +//static int do_the_work(int argc, char **argv) +//{ +// int nerrors = arg_parse(argc, argv, (void **)&modem_args); +// if (nerrors != 0) { +// arg_print_errors(stderr, modem_args.end, argv[0]); +// return 1; +// } +// +// return 0; +//} + +//static int do_modem_lifecycle(int argc, char **argv) +//{ +// int nerrors = arg_parse(argc, argv, (void **)&modem_args); +// if (nerrors != 0) { +// arg_print_errors(stderr, modem_args.end, argv[0]); +// return 1; +// } +// if (modem_args.param->count > 0) { +// esp_err_t err = ESP_FAIL; +// if (strstr(modem_args.param->sval[0], "PPP")) { +// err = esp_modem_set_mode(s_dce, ESP_MODEM_MODE_DATA); +// } else if (strstr(modem_args.param->sval[0], "CMD")) { +// err = esp_modem_set_mode(s_dce, ESP_MODEM_MODE_COMMAND); +// } else { +// return 1; +// } +// if (err == ESP_OK) { +// ESP_LOGI(TAG, "set_working_mode %s succeeded", at_args.param->sval[0]); +// } else { +// ESP_LOGI(TAG, "set_working_mode %s failed with %d", at_args.param->sval[0], err); +// } +// return 0; +// } +// return 1; +//} + +//static void register_dce(void) +//{ +// at_args.command = arg_str1(NULL, NULL, "", "Symbolic name of DCE command"); +// at_args.param_int = arg_int0("i", "int", "", "Input parameter of integer type"); +// at_args.param_str = arg_str0("s", "str", "", "Input parameter of string type"); +// at_args.param_pdp = arg_str0("p", "pdp", "", "Comma separated string with PDP context"); +// at_args.param_bool = arg_str0("b", "bool", "", "Input parameter of bool type"); +// at_args.param = arg_str0(NULL, NULL, "", "Default input argument treated as string"); +// at_args.result = arg_str0("o", "out", "", "Type of output parameter"); +// at_args.end = arg_end(1); +// const esp_console_cmd_t at_cmd = { +// .command = "dce", +// .help = "send symbolic command to the modem", +// .hint = NULL, +// .func = &do_dce, +// .argtable = &at_args +// }; +// ESP_ERROR_CHECK(esp_console_cmd_register(&at_cmd)); +//} +//static void register_at_command(void) +//{ +// generic_at_args.command = arg_str1(NULL, NULL, "", "AT command to send to the modem"); +// generic_at_args.timeout = arg_int0("t", "timeout", "", "command timeout"); +// generic_at_args.pattern = arg_str0("p", "pattern", "", "command response to wait for"); +// generic_at_args.no_cr = arg_litn("n", "no-cr", 0, 1, "not add trailing CR to the command"); +// generic_at_args.end = arg_end(1); +// +// const esp_console_cmd_t at_command = { +// .command = "at", +// .help = "send generic AT command to the modem", +// .hint = NULL, +// .func = &do_at_command, +// .argtable = &generic_at_args +// }; +// ESP_ERROR_CHECK(esp_console_cmd_register(&at_command)); +//} + +//enum arg_type { +// STR0, +// STR1, +// INT0, +// INT1, +// ARG_END, +//}; +// +//struct CommandArgs { +// CommandArgs(arg_type t, const char * shopts, const char * lopts, const char * data, const char * glos): +// type(t), shortopts(shopts), longopts(lopts), datatype(data), glossary(glos) {} +// arg_type type; +// const char *shortopts; +// const char *longopts; +// const char *datatype; +// const char *glossary; +//}; + + +#define MAX_COMMAND 10 +//#define TEMPLATE(index) _TEMPLATE(index) + + + + +//#define REPEAT(a) _REPEAT(a) +#define MY_REPEAT(a) \ +TEMPLATE(0) \ +TEMPLATE(1) \ +TEMPLATE(2) + + + +//static void register_modem_lifecycle(DCE *dce) +//{ +// modem_args.param = arg_str1(NULL, NULL, "", "PPP or CMD"); +// modem_args.end = arg_end(1); +// const esp_console_cmd_t modem_cmd = { +// .command = "set_mode", +// .help = "set modem mode", +// .hint = nullptr, +// .func = do_the_work, +// .argtable = &modem_args +// }; +// ESP_ERROR_CHECK(esp_console_cmd_register(&modem_cmd)); +//} + +static esp_console_repl_t *s_repl = NULL; + +//template constexpr size_t offset_of(U T::*member) +//{ +// return (char*)&((T*)nullptr->*member) - (char*)nullptr; +//} + + +extern "C" void app_main(void) +{ + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // init the DTE + esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); + dte_config.pattern_queue_size = 100; + dte_config.event_task_stack_size = 4096; + dte_config.event_task_priority = 15; +// esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet"); + esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP(); + + esp_netif_t *esp_netif = esp_netif_new(&ppp_netif_config); + assert(esp_netif); + auto uart_dte = create_uart_dte(&dte_config); + std::string apn = "internet"; + auto dce = create_SIM7600_dce(uart_dte, esp_netif, apn); + assert(dce != NULL); + + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + // init console REPL environment + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); + +// register_dce(); +// register_at_command(); +// register_modem_lifecycle(dce.get()); + modem_console_register_http(); + modem_console_register_ping(); + + const struct SetModeArgs { + SetModeArgs(): mode(STR1, nullptr, nullptr, "", "PPP or CMD") {} + CommandArgs mode; + } set_mode_args; + ConsoleCommand SetModeParser("set_mode", "sets modem mode", &set_mode_args, sizeof(set_mode_args), [&](ConsoleCommand *c){ + if (c->get_count_of(&SetModeArgs::mode)) { + auto mode = c->get_string_of(&SetModeArgs::mode); + if (mode == "CMD") { + ESP_LOGI(TAG, "Switching to command mode..."); + dce->exit_data(); + } else if (mode == "PPP") { + ESP_LOGI(TAG, "Switching to data mode..."); + dce->set_data(); + } else { + ESP_LOGE(TAG, "Unsupported mode: %s", mode.c_str()); + return 1; + } + } + return 0; + }); + + const struct SetPinArgs { + SetPinArgs(): pin(STR1, nullptr, nullptr, "", "PIN") {} + CommandArgs pin; + } set_pin_args; + ConsoleCommand SetPinParser("set_pin", "sets SIM card PIN", &set_pin_args, sizeof(set_pin_args), [&](ConsoleCommand *c){ + if (c->get_count_of(&SetPinArgs::pin)) { + auto pin = c->get_string_of(&SetPinArgs::pin); + ESP_LOGI(TAG, "Setting pin=%s...", pin.c_str()); + auto err = dce->set_pin(pin); + if (err == command_result::OK) { + ESP_LOGI(TAG, "OK"); + } else { + ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT":""); + return 1; + } + } + return 0; + }); + std::vector no_args; + ConsoleCommand ReadPinArgs("read_pin", "checks if SIM is unlocked", no_args, [&](ConsoleCommand *c){ + bool pin_ok; + ESP_LOGI(TAG, "Checking pin..."); + auto err = dce->read_pin(pin_ok); + if (err == command_result::OK) { + ESP_LOGI(TAG, "OK. Pin status: %s", pin_ok ? "true": "false"); + } else { + ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT":""); + return 1; + } + return 0; + }); + + + // start console REPL + ESP_ERROR_CHECK(esp_console_start_repl(s_repl)); + ESP_LOGE(TAG, "Exit console!!!"); + while(1) { + vTaskDelay(pdMS_TO_TICKS(50000)); + ESP_LOGI(TAG, "working!"); + } +} diff --git a/esp_modem/examples/modem_console/main/repeat_helper.inc b/esp_modem/examples/modem_console/main/repeat_helper.inc new file mode 100644 index 000000000..8210ec3aa --- /dev/null +++ b/esp_modem/examples/modem_console/main/repeat_helper.inc @@ -0,0 +1,27 @@ +// +// Created by david on 3/17/21. +// + +#ifndef MODEM_CONSOLE_REPEAT_HELPER_INC_H +#define MODEM_CONSOLE_REPEAT_HELPER_INC_H + +#if MAX_REPEAT_NR < 10 +#define REPEAT_TEMPLATE_DEF(...) REPEAT_10_TIMES(VA_ARG) +#else +#define REPEAT_TEMPLATE_DEF(...) REPEAT_100_TIMES(VA_ARG) +#endif + +#define REPEAT_10_TIMES(a) \ +TEMPLATE(0) \ +TEMPLATE(1) \ +TEMPLATE(2) \ +TEMPLATE(3) \ +TEMPLATE(4) \ +TEMPLATE(5) \ +TEMPLATE(6) \ +TEMPLATE(7) \ +TEMPLATE(8) \ +TEMPLATE(9) + + +#endif //MODEM_CONSOLE_REPEAT_HELPER_INC_H diff --git a/esp_modem/include/cxx_include/esp_modem_primitives.hpp b/esp_modem/include/cxx_include/esp_modem_primitives.hpp index 793a0615a..ba76e2a96 100644 --- a/esp_modem/include/cxx_include/esp_modem_primitives.hpp +++ b/esp_modem/include/cxx_include/esp_modem_primitives.hpp @@ -8,8 +8,8 @@ #include "freertos/event_groups.h" #include "freertos/semphr.h" - - +#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS +#define THROW(exception) throw(exception) class esp_err_exception: virtual public std::exception { public: explicit esp_err_exception(esp_err_t err): esp_err(err) {} @@ -24,25 +24,28 @@ private: esp_err_t esp_err; std::string message; }; +#else +#define THROW(exception) abort() +#endif static inline void throw_if_false(bool condition, std::string message) { if (!condition) { - throw(esp_err_exception(std::move(message))); + THROW(esp_err_exception(std::move(message))); } } static inline void throw_if_esp_fail(esp_err_t err, std::string message) { if (err != ESP_OK) { - throw(esp_err_exception(std::move(message), err)); + THROW(esp_err_exception(std::move(message), err)); } } static inline void throw_if_esp_fail(esp_err_t err) { if (err != ESP_OK) { - throw(esp_err_exception(err)); + THROW(esp_err_exception(err)); } } diff --git a/esp_modem/include/esp_modem_api.h b/esp_modem/include/esp_modem_api.h index f3b4aa1c3..0a26f0e47 100644 --- a/esp_modem/include/esp_modem_api.h +++ b/esp_modem/include/esp_modem_api.h @@ -5,20 +5,28 @@ #ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_API_H #define SIMPLE_CXX_CLIENT_ESP_MODEM_API_H #pragma once +#include "generate/esp_modem_command_declare.inc" #ifdef __cplusplus extern "C" { #endif -typedef struct esp_modem_dce_wrap esp_modem_t; +typedef struct esp_modem_dce_wrap esp_modem_dce_t; +typedef struct esp_modem_dte_config esp_modem_dte_config_t; +typedef enum esp_modem_dce_mode +{ + ESP_MODEM_MODE_COMMAND, + ESP_MODEM_MODE_DATA, +} esp_modem_dce_mode_t; -esp_modem_t *esp_modem_new(const esp_modem_dte_config *config, esp_netif_t *netif, const char* apn); +esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *config, esp_netif_t *netif, const char* apn); -void esp_modem_destroy(esp_modem_t * dce); +void esp_modem_destroy(esp_modem_dce_t * dce); +esp_err_t esp_modem_set_mode(esp_modem_dce_t * dce, esp_modem_dce_mode_t mode); #define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) \ - esp_err_t esp_modem_ ## name(esp_modem_t *dce, ##__VA_ARGS__); + esp_err_t esp_modem_ ## name(esp_modem_dce_t *dce, ##__VA_ARGS__); DECLARE_ALL_COMMAND_APIS(declares esp_modem_(esp_modem_t * dce, ...);) diff --git a/esp_modem/include/generate/esp_modem_command_declare.inc b/esp_modem/include/generate/esp_modem_command_declare.inc index 13b17dc9b..d9bcf01f2 100644 --- a/esp_modem/include/generate/esp_modem_command_declare.inc +++ b/esp_modem/include/generate/esp_modem_command_declare.inc @@ -6,11 +6,20 @@ #define SIMPLE_CXX_CLIENT_ESP_MODEM_COMMAND_DECLARE_INC #ifdef __cplusplus -#define STRING_IN const std::string& -#define STRING_OUT std::string& +#include +#define STRING_IN const std::string& string_in +#define STRING_OUT std::string& string_out +#define BOOL_IN const bool bool_in +#define BOOL_OUT bool& bool_out +#define STRUCT_OUT(struct_name) struct_name& struct_out #else -#define STRING_IN const char* -#define STRING_OUT char* +struct PdpContext; + +#define STRING_IN const char* string_in +#define STRING_OUT char* string_out +#define BOOL_IN const bool bool_in +#define BOOL_OUT bool* bool_out +#define STRUCT_OUT(struct_name) struct struct_name* struct_out #endif @@ -30,28 +39,28 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, TEMPLATE_ARG, MUX_ARG, S * * @param[out] pin_ok Pin */ \ -ESP_MODEM_DECLARE_DCE_COMMAND(read_pin, command_result, TEMPLATE_ARG, MUX_ARG, bool& pin_ok) \ +ESP_MODEM_DECLARE_DCE_COMMAND(read_pin, command_result, TEMPLATE_ARG, MUX_ARG, BOOL_OUT) \ \ -ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, TEMPLATE_ARG, MUX_ARG, bool on) \ +ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, TEMPLATE_ARG, MUX_ARG, BOOL_IN) \ \ ESP_MODEM_DECLARE_DCE_COMMAND(resume_data_mode, command_result, TEMPLATE_ARG, MUX_ARG) \ \ -ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, TEMPLATE_ARG, MUX_ARG, PdpContext& pdp_context) \ +ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, TEMPLATE_ARG, MUX_ARG, STRUCT_OUT(PdpContext)) \ \ ESP_MODEM_DECLARE_DCE_COMMAND(set_command_mode, command_result, TEMPLATE_ARG, MUX_ARG) \ \ ESP_MODEM_DECLARE_DCE_COMMAND(set_cmux, command_result, TEMPLATE_ARG, MUX_ARG) \ \ -ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, TEMPLATE_ARG, MUX_ARG, std::string& imsi_number) \ +ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, TEMPLATE_ARG, MUX_ARG, STRING_OUT) \ \ -ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, TEMPLATE_ARG, MUX_ARG, std::string& imsi_number) \ +ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, TEMPLATE_ARG, MUX_ARG, STRING_OUT) \ \ /** * @brief Reads the module name * * @param[out] module name */ \ -ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, TEMPLATE_ARG, MUX_ARG, std::string& name) \ +ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, TEMPLATE_ARG, MUX_ARG, STRING_OUT) \ \ /** * @brief Sets the modem to data mode diff --git a/esp_modem/private_include/exception_stub.hpp b/esp_modem/private_include/exception_stub.hpp new file mode 100644 index 000000000..6ea9e60dd --- /dev/null +++ b/esp_modem/private_include/exception_stub.hpp @@ -0,0 +1,26 @@ +// +// Created by david on 3/16/21. +// + +#ifndef MODEM_CONSOLE_EXCEPTION_STUB_HPP +#define MODEM_CONSOLE_EXCEPTION_STUB_HPP + +#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS +#define TRY_CATCH_RET_NULL(block) \ + try { block } \ + } catch (std::bad_alloc& e) { \ + ESP_LOGE(TAG, "Out of memory"); \ + return nullptr; \ + } catch (esp_err_exception& e) { \ + esp_err_t err = e.get_err_t(); \ + ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); \ + ESP_LOGE(TAG, "%s", e.what()); \ + return nullptr; \ + } +#else +#define TRY_CATCH_RET_NULL(block) \ + block +#endif + + +#endif //MODEM_CONSOLE_EXCEPTION_STUB_HPP diff --git a/esp_modem/src/esp_modem_api.cpp b/esp_modem/src/esp_modem_api.cpp index 9b111098c..b492056e5 100644 --- a/esp_modem/src/esp_modem_api.cpp +++ b/esp_modem/src/esp_modem_api.cpp @@ -7,41 +7,24 @@ #include "cxx_include/esp_modem_api.hpp" #include "esp_modem_api.h" #include "esp_modem_config.h" +#include "exception_stub.hpp" -static const char *TAG = "dce_factory"; struct PdpContext; std::shared_ptr create_uart_dte(const esp_modem_dte_config *config) { - try { + TRY_CATCH_RET_NULL( auto term = create_uart_terminal(config); return std::make_shared(std::move(term)); - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } - + ) } template std::unique_ptr> create_dce(const std::shared_ptr& dte, const std::shared_ptr& dev, esp_netif_t *netif) { - try { + TRY_CATCH_RET_NULL( return std::make_unique>(dte, dev, netif); - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } + ) } std::unique_ptr> create_generic_dce_from_module(const std::shared_ptr& dte, const std::shared_ptr& dev, esp_netif_t *netif) @@ -86,7 +69,7 @@ static inline esp_err_t command_response_to_esp_err(command_result res) return ESP_ERR_INVALID_ARG; } -extern "C" esp_modem_t *esp_modem_new(const esp_modem_dte_config *config, esp_netif_t *netif, const char* apn) +extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *config, esp_netif_t *netif, const char* apn) { auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap; if (dce_wrap == nullptr) @@ -99,7 +82,7 @@ extern "C" esp_modem_t *esp_modem_new(const esp_modem_dte_config *config, esp_ne return dce_wrap; } -extern "C" void esp_modem_destroy(esp_modem_t * dce) +extern "C" void esp_modem_destroy(esp_modem_dce_t * dce) { assert(dce->modem_type == esp_modem_dce_wrap::MODEM_SIM7600); auto dce_sim7600 = static_cast*>(dce->dce_ptr); @@ -107,7 +90,21 @@ extern "C" void esp_modem_destroy(esp_modem_t * dce) delete dce; } -extern "C" esp_err_t esp_modem_read_pin(esp_modem_t * dce, bool &x) +extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t * dce, esp_modem_dce_mode_t mode) +{ + assert(dce->modem_type == esp_modem_dce_wrap::MODEM_SIM7600); + auto dce_sim7600 = static_cast*>(dce->dce_ptr); + if (mode == ESP_MODEM_MODE_DATA) { + dce_sim7600->set_data(); + } else if (mode == ESP_MODEM_MODE_COMMAND) { + dce_sim7600->set_data(); + } else { + return ESP_ERR_NOT_SUPPORTED; + } + return ESP_OK; +} + +extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t * dce, bool &x) { assert(dce->modem_type == esp_modem_dce_wrap::MODEM_SIM7600); auto dce_sim7600 = static_cast*>(dce->dce_ptr); diff --git a/esp_modem/src/esp_modem_uart.cpp b/esp_modem/src/esp_modem_uart.cpp index 39bcfeb89..9fbf5d77b 100644 --- a/esp_modem/src/esp_modem_uart.cpp +++ b/esp_modem/src/esp_modem_uart.cpp @@ -7,6 +7,7 @@ #include "esp_event.h" #include "driver/uart.h" #include "esp_modem_config.h" +#include "exception_stub.hpp" #define ESP_MODEM_EVENT_QUEUE_SIZE (16) @@ -164,19 +165,11 @@ private: std::unique_ptr create_uart_terminal(const esp_modem_dte_config *config) { - try { + TRY_CATCH_RET_NULL( auto term = std::make_unique(config); term->start(); return term; - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } + ) } void uart_terminal::task()