#pragma once /* * Copyright (C) 2015-2019 Grégoire Passault * Copyright (C) 2019-2025 Adrien Boussicault * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ #include #include #include "serial_print.hpp" namespace terminal_n { enum paramter_type { NONE_PARAMETER, FLOAT_PARAMETER, DOUBLE_PARAMETER, INT_PARAMETER, UINT_PARAMETER, LONGINT_PARAMETER, LONGUINT_PARAMETER, BOOL_PARAMETER }; /** * To defined a new command, use the MACRO * TERMINAL_COMMAND(terminal, name, description) * * @param name : the name of the command, without space, without quotes * @param description : the description of the command, with quote * * use terminal_print() to print on output * use the variables arc and argv to get the string of given arguments * * If you declared the terminal in the following way, in another file : * * #include "terminal.hpp" * terminal_n::Terminal terminal("The terminal\n\r"); * * you can add that command in other file : * * #include "terminal.hpp" * extern terminal_n::Terminal terminal; * * TERMINAL_COMMAND(terminal, hello, "Print a friendly warming welcoming message") * { * if (argc > 0) { * terminal.print("Hello "); * terminal.println(argv[0]); * terminal.print("Other params: "); * for (uint32_t i=1;iwrite(c); } } inline void write(const char* buf, uint32_t len){ if(!silent){ io->write((const uint8_t*)buf, len); } } template inline void print(T v){ if(!silent){ serial_print(io, v); } } template inline void println(T v){ if(!silent){ serial_println(io, v); } } template inline void print_hex(T v){ if(!silent){ serial_print_hex(io, v); } } template inline void println_hex(T v){ if(!silent){ serial_println_hex(io, v); } } inline bool terminal_has_io(){ return io; } inline void print_hexa(uint8_t* buf, uint32_t n){ uint8_t first=0, last=0; for( uint32_t i=0; i> 4; last = buf[i] & 0x0F; print( 'x' ); print( static_cast( (first < 10 ? '0' : 'A'-10) + first ) ); print( static_cast( (last < 10 ? '0' : 'A'-10) + last ) ); } } inline void println_hexa(uint8_t* buf, uint32_t n){ print_hexa(buf,1); println(""); } /** * Resets the terminal */ void reset(); /** * Enable the terminal */ void enable(); /** * Disable the terminal */ void disable(); void print_prompt(); void setup(HardwareSerial* serial); /** * Terminal update * Call this function in your main loop * to fetch serial port and handle terminal */ void update(); const terminal_command * find_command( char *command_name, uint32_t command_name_length ); bool terminal_execute( char *command_name, uint32_t command_name_length, uint32_t argc, char **argv ); void terminal_process(); bool have_to_be_saved_in_eeprom(const terminal_command *command); void check_eeprom_names(); void save_value_to_eeprom(const terminal_command *command); bool save_config_to_eeprom(const char* eeprom_name); void save_config_to_eeprom(); void load_config_from_eeprom(bool enable_print=true); bool load_config_from_eeprom(const char* eeprom_name, bool enable_print); void load_value_from_eeprom( const terminal_command *command, bool enable_print=false ); void print_saved_parameter(const terminal_command *command); void print_value_from_eeprom(const struct terminal_command *command); void print_config_from_eeprom(); bool print_config_from_eeprom(const char* eeprom_name); void reset_to_constructor_config(); bool reset_to_constructor_config(const char* eeprom_name); /** * Registers a command */ void register_command(struct terminal_command *command); /** * Mute the terminal */ void terminal_silent(bool silent); void displayHelp(bool parameter); void terminal_params_show(); void echo_command(uint32_t argc, char *argv[]); void params_command(uint32_t argc, char *argv[]); }; /** * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- */ #define TERMINAL_COMMAND_INTERNAL(term, name, eeprom_name, description, parameter, parameterType, auto_save_after_command, value_ptr) terminal_n::terminal_command_fn terminal_command_ ## name; \ \ char terminal_command_name_ ## name [] = #name; \ char terminal_command_description_ ## name [] = description; \ \ struct terminal_n::terminal_command terminal_command_definition_ ## name = { \ terminal_command_name_ ## name , \ terminal_command_description_ ## name , \ terminal_command_ ## name, \ parameter, \ parameterType, \ auto_save_after_command, \ value_ptr, \ eeprom_name \ }; \ \ __attribute__((constructor)) \ void terminal_command_init_ ## name () { \ term.register_command(&terminal_command_definition_ ## name ); \ } \ \ void terminal_command_ ## name (uint32_t argc, char *argv[]) #define TERMINAL_COMMAND(term, name, description) \ TERMINAL_COMMAND_INTERNAL(term, name, "", description, terminal_n::NONE_PARAMETER, NULL, false, NULL) #define TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, type, enum_type, conversion, auto_save_after_command, filter_function, finish_function) \ volatile static type name = startValue; \ char terminal_parameter_type_ ## name [] = #type; \ \ TERMINAL_COMMAND_INTERNAL(term, name, eeprom_name, description, enum_type, terminal_parameter_type_ ## name, auto_save_after_command, &name) \ { \ type g; \ if (argc) { \ g = conversion(argv[0]); \ if( filter_function(g, name) ){ \ type old = name; \ name = g; \ finish_function(name, old); \ } \ } \ term.print( #name ); \ term.print("="); \ term.println( name ); \ } template inline bool filter_nothing(T & new_value, T old_value){return true;} template inline void do_nothing(T new_value, T old_value){} #define TERMINAL_PARAMETER_FLOAT(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, float, terminal_n::FLOAT_PARAMETER, terminal_n::atof, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_DOUBLE(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, double, terminal_n::DOUBLE_PARAMETER, terminal_n::atof, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_INT(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, int32_t, terminal_n::INT_PARAMETER, atoi, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_UINT(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, uint32_t, terminal_n::UINT_PARAMETER, atoi, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_LONGINT(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, int64_t, terminal_n::LONGINT_PARAMETER, atoi, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_LONGUINT(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, uint64_t, terminal_n::LONGUINT_PARAMETER, atoi, auto_save_after_command, filter_function, finish_function) #define TERMINAL_PARAMETER_BOOL(term, name, eeprom_name, description, startValue, auto_save_after_command, filter_function, finish_function) \ TERMINAL_PARAMETER(term, name, eeprom_name, description, startValue, bool, terminal_n::BOOL_PARAMETER, (bool)atoi, auto_save_after_command, filter_function, finish_function) #define TERMINAL_ADD_DEFAULT_COMMANDS(term) \ TERMINAL_COMMAND(term, save_config, "Save the config to EEPROM (save_config [eeprom_name])") \ { \ if(argc !=0 and argc != 1){ term.println("Invalid parameters"); return; } \ if(argc == 0){ \ term.save_config_to_eeprom(); \ term.println("All is saved."); \ }else{ \ if( \ term.save_config_to_eeprom(argv[0]) \ ){ \ term.println("Saved.");\ }else{ \ term.println("Failed.");\ }; \ } \ } \ \ TERMINAL_COMMAND(term, load_config, "Load config from EEPROM (load_config [eeprom_name])") \ { \ bool print = true; \ if(argc !=0 and argc != 1){ term.println("Invalid parameters"); return; } \ if(argc == 0){ \ term.load_config_from_eeprom(print); \ }else{ \ if( \ ! term.load_config_from_eeprom(argv[0], print) \ ){ \ term.println("Failed.");\ }; \ } \ } \ \ TERMINAL_COMMAND(term, reset_config, "Reset to constructor configuration (reset_config [eeprom_name])") \ { \ if(argc !=0 and argc != 1){ term.println("Invalid parameters"); return; } \ if(argc == 0){ \ term.reset_to_constructor_config(); \ term.println("All is reseted."); \ }else{ \ if( \ term.reset_to_constructor_config(argv[0]) \ ){ \ term.println("Reseted.");\ }else{ \ term.println("Failed.");\ }; \ } \ } \ \ TERMINAL_COMMAND(term, print_config, "Print EEPROM configuration (print_config [eeprom_name])") \ { \ if(argc !=0 and argc != 1){ term.println("Invalid parameters"); return; } \ if(argc == 0){ \ term.print_config_from_eeprom(); \ }else{ \ if( \ ! term.print_config_from_eeprom(argv[0]) \ ){ \ term.println("Failed.");\ }; \ } \ } \ \ TERMINAL_COMMAND(term, help, "Displays the help about commands") \ { \ term.displayHelp(false); \ } \ \ TERMINAL_COMMAND(term, params, "Displays the available parameters. Usage: params [show]") \ { \ term.params_command(argc, argv); \ } \ \ TERMINAL_COMMAND(term, echo, "Switch echo mode. Usage echo [on|off]") \ { \ term.echo_command(argc, argv); \ } }