/*! @page q_atcli AT Command Line Interface (CLI)
* @tableofcontents
*
* @section q_atcli_overview Overview
* A command-line interface (CLI) is a way to interact directly with the software
* of an embedded system in the form of text commands and responses. It can be
* seen as a typed set of commands to produce a result, but here, the commands
* are typed in real-time by a user through a specific interface, for example,
* UART, USB, LAN, etc.
*
* A CLI is often developed to aid initial driver development and debugging. This
* CLI might become the interface (or one of the interfaces) used by a
* sophisticated end-user to interact with the product. Think of typing commands
* to control a machine, or perhaps for low-level access to the control system as
* a development tool, tweaking time-constants and monitoring low-level system
* performance during testing.
*
* @section q_atcli_components The components of the CLI
* The provided development API parses and handles input commands, following a
* simplified form of the extended AT-commands syntax.
*
* <center>
* @htmlonly
* <!DOCTYPE html>
* <html>
* <head>
* <title>atcli</title>
* <meta charset="utf-8"/>
* </head>
* <body><div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;zoom&quot;:1.5,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers tags lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;app.diagrams.net\&quot; modified=\&quot;2022-10-19T19:31:39.234Z\&quot; agent=\&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36\&quot; etag=\&quot;iXCP-aXpe9eB9d0tPXyv\&quot; version=\&quot;20.4.1\&quot; type=\&quot;google\&quot;&gt;&lt;diagram id=\&quot;o9YKW9kYFg2IcPfcP6fb\&quot; name=\&quot;Página-1\&quot;&gt; &lt;/diagram&gt;&lt;/mxfile&gt;&quot;}"></div>
* <script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
* </body>
* </html>
* @endhtmlonly
* <em>AT CLI implementation</em>
* </center>
*
* As seen in the figure, the CLI has a few components described below:
*
* - <b>Input Handler</b> : It is responsible for collecting incoming data from
* the input in the form of ASCII characters inside a buffer. When this buffer is
* ready by receiving an EOL(End-Of-Line) byte, it notifies the validator to
* perform the initial checks.
* - <b>Validator</b> : Take the input string and perform three checks over it:
*   -# The input matches one of the subscribed commands.
*   -# The input matches one of the default commands.
*   -# The input is unknown
* - <b>Pre-Parser</b> : Takes the input if the validator asserts the first check.
* It is responsible for syntax validation and classification. Also, prepares the
* input argument for the next component.
* - <b>Callback or Post-Parser</b> : If input at the pre-parser is valid, the
* respective command callback is invoked. Here, the application writer is free
* to handle the command execution and the output response.
* - <b>Output printer</b> : Takes all the return status of the previous
* components to print out a response at the output.
*
* @remark Here, @a Input and @a Output should be provided by the application
* writer, for example, if a UART interface is chosen, the input should take
* the received bytes from an ISR and the output is a function to print out a
* single byte.
*
* @section q_atcli_syntax Supported syntax
* The syntax is straightforward and the rules are provided below:
*
* - All command lines must start with AT and end with an @c EOL character. By
* default, the CLI uses the carriage return character. (We will use @c CR to
* represent a carriage return character in this document).
* - AT commands are case-insensitive
* - Only four types of AT commands are allowed:
*     - Acting (@c cli::commandType::ACT) : This is the simplest type of commands
*     that can be subscribed. It's normally used to execute the action that the
*     command should do. This type does not take arguments or modifiers, for
*     example : @c AT+CMD
*     - Read (@c cli::commandType::READ) : This type of command allows you to read
*     or test a value already configured for the specified parameter. Only one
*     argument is allowed. for example @c "AT+CMD?" or @c "AT+CMD?PARAM1"
*     - Test (@c cli::commandType::TEST) : These types of commands allow you to get
*     the values that can be set for its parameters. No parameters are allowed
*     here. Example @c "AT+CMD=?"
*     - Parameter Set (@c cli::commandType::PARA) : These types of commands allow
*     n arguments to be passed for setting parameters, for example: @c AT+CMD=x,y
*  If none of the types is given at the input, the command response will be
*  @c ERROR
* - The possible output responses are:
*     - @c OK: Indicates the successful execution of the command.
*     - @c ERROR: A generalized message to indicate failure in executing the command.
*     - @c UNKNOWN : The input command is not subscribed.
*     - <tt>NOT ALLOWED</tt> : The command syntax is not one of the allowed types.
*     - User-defined: A custom output message defined by the application writer.
*     - @c NONE : No response.
*
* All responses are followed by a @c CR @c LF
*
* Errors generated during the execution of these AT commands could be due to the
* following reasons:
* - Incorrect syntax/parameters of the AT command
* - Bad parameters or not allowed operations defined by the application writer.
*
* In case of an error, the string @c ERROR or @c "ERROR:<error_no>" are displayed.
*
* @section q_atcli_setup Setting up an AT-CLI instance
* Before starting the CLI development, the corresponding instance must be
* defined; a variable of class qOS::commandLineInterface. The instance should be
* initialized using the qOS::commandLineInterface::setup() method.
*
* @section q_atcli_sub_commands  Subscribing commands to the parser
* The AT CLI is able to subscribe to any number of custom AT commands. For this, the
* qOS::commandLineInterface::add() method should be used.
*
* This function subscribes the CLI instance to a specific command with an associated
* callback function, so that the next time the required command is sent to the CLI input,
* the callback function will be executed. The CLI parser only analyzes commands that
* follow the simplified AT-Commands syntax already described.
*
* @section q_atcli_cmd_callback Writing a command callback
* The command callback should be coded by the application writer. Here, the
* following prototype should be used:
*
*  @code{.c}
*  cli::response CMD_Callback( cli::handler_t h ) {
*      /* TODO : The command callback */
*  }
*  @endcode
*
* The callback takes one argument of type qOS::cli::handler_t and returns a
* single value. The input argument it's just a pointer to public data of the CLI
* instance where the command it subscribed to. From the callback context, can be
* used to print out extra information as a command response, parse the command
* parameters, and query properties with crucial information about the detected
* command, like the type, the number of arguments, and the subsequent string
* after the command text. To see more details please check the
* qOS::cli::handler_t class reference.
*
* The return value (an enum of type qOS::cli::response ) determines the
* response shown by the Output printer component. The possible allowed values are:
*
* - @c cli::response::OK : as expected, print out the OK string.
* - @c cli::response::ERROR : as expected, print out the ERROR string.
* - @c cli::ERROR_CODE(no) : Used to indicate an error code. This code is
* defined by the application writer and should be a value between @c 1 and
* @c 32766. For example, a return value of @c cli::ERROR_CODE(15), will print
* out the string @c ERROR:15.
* - @c cli::response::NO_RESPONSE : No response will be printed out.
*
* A simple example of how the command callback should be coded is shown below:
*
*  @code{.c}
*  cli::response CMD_Callback( cli::handler_t h ) {
*      cli::response Response = cli::response::NO_RESPONSE;
*      int arg1 = 0;
*      float arg2 = 0;
*      /*check the command-type*/
*      switch ( h.getType() ) {
*          case cli::commandType::PARA:
*              if ( h.getNumArgs() > 0 ) {
*                   arg1 = h.getArgInt( 1 ); /*get the first argument as integer*/
*                   if ( h.getNumArgs() > 1 ) {
*                       arg2 = h.getArgFlt( 2 ); /*get the second argument as float*/
*                       sprintf( h.output, "arg1 = %d arg2 = %f", arg1, arg2 );
*                       Response = cli::response::NO_RESPONSE;
*              }
*              else {
*                   Response = cli::response::ERROR;
*              }
*              break;
*          case cli::commandType::TEST:
*              h.writeOut( "inmediate message" );
*              Response = cli::response::OK;
*              break;
*          case cli::commandType::READ:
*              strcpy( h.output , "Test message after the callback" );
*              Response = cli::response::OK;
*              break;
*          case cli::commandType::ACT:
*              Response = cli::response::OK;
*              break;
*          default:
*              Response = cli::response::ERROR;
*              break;
*      }
*      return Response;
*  }
*  @endcode
*
* @section q_atcli_inputh Handling the input
* Input handling is simplified using the provided methods of this class. The
* qOS::commandLineInterface::isrHandler() function are intended to be used from the
* interrupt context. This avoids any kind of polling implementation and allows
* the CLI application to be designed using an event-driven pattern.
*
* The two overloads for this method feed the parser input, the first one with a
* single character and the second with a string. The application writer should
* call one of these functions from the desired hardware interface, for example,
* from a UART receive ISR.
*
* If there is no intention to feed the input from the ISR context, the methods
* qOS::commandLineInterface::raise() or qOS::commandLineInterface::exec() can be called at
* demand from the base context.
* As expected, both functions send the string to the specified CLI. The
* difference between both methods is that qOS::commandLineInterface::raise() sends the
* command through the input, marking it as ready for parsing and acting as the
* Input handler component.
*
* The qOS::commandLineInterface::exec(), on the other hand, executes the components
* of Pre-parsing and Postparsing bypassing the other components, including the
* Output printer, so that it must be handled by the application writer.
*
* @note All functions involved with the component Input-handler, ignores
* non-graphic characters and cast any uppercase to lowercase.
*
* @section q_atcli_run Running the CLI parser
* The parser can be invoked directly using the qOS::commandLineInterface::run()
* method. Almost all the components that make up the CLI are performed by this
* method, except for the Input Handler, which should be managed by the
* application writer itself.
*
* In this way, the writer of the application must implement the logic that leads
* this function to be called when the input-ready condition is given.
*
* The simple approach for this is to check the return value of any of the input
* feeder APIs and set a notification variable when they report a ready input.
* Later in the base context, a polling job should be performed over this
* notification variable, running the parser when their value is true, then
* clearing the value after to avoid unnecessary overhead.
*
* The recommended implementation is to leave this job handled by a task
* instead of coding the logic to know when the CLI should run. For this, an
* overload of qOS::core::add() is provided accepting an instance of the CLI.
* This overload adds a task to the scheduling scheme running an AT Command Line
* Interface and is treated as an event-triggered task.
* The address of the parser instance will be stored in the @c TaskData
* storage-Pointer.
*
* After invoked, both CLI and task are linked together in such a way that when
* an input-ready condition is given, a notification event is sent to the task
* launching the CLI components. As the task is event-triggered, there is no
* additional overhead and the writer of the application can assign a priority
* value to balance the application against other tasks in the scheduling scheme.
*
* @section q_atcli_example1 A CLI example
* The following example demonstrates the usage of a simple command-line interface
* using the UART peripheral with two subscribed commands :
* - A command to write and read the state of a GPIO pin @c "at+gpio".
* - A command to retrieve the compilation timestamp @c "at+info".
* First, let's get started defining the required objects to set up the CLI instance:
*
*  @code{.c}
*  #define CLI_MAX_INPUT_BUFF_SIZE         ( 128 )
*  #define CLI_MAX_OUTPUT_BUFF_SIZE        ( 128 )
*
*  task CLI_Task;
*  commandLineInterface CLI_Object;
*  cli::command AT_GPIO, AT_INFO;
*
*  char CLI_Input[ CLI_MAX_INPUT_BUFF_SIZE ];
*  char CLI_Output[ CLI_MAX_OUTPUT_BUFF_SIZE ];
*
*  /*Command callbacks*/
*  cli::response AT_GPIO_Callback( cli::handler_t h );
*  cli::response AT_INFO_Callback( cli::handler_t h );
*  @endcode
*
* Then the CLI instance is configured by subscribing commands and adding the task
* to the OS. A wrapper function is required here to make the UART output-function
* compatible with the CLI API.
*
*  @code{.c}
*  void CLI_OutputChar_Wrapper( void *sp, const char c ) { /*CLI output function*/
*      (void)sp; /*unused*/
*      HAL_UART_WriteChar( UART1, c );
*  }
*  /*==================================================================*/
*  int main( void ) {
*      HAL_Setup();
*      os.init( HAL_GetTick, nullptr );
*      CLI_Object.setup( BSP_UART_PUTC, CLI_Input, sizeof(CLI_Input),
*                        CLI_Output, sizeof(CLI_Output) );
*
*      CLI_Object.add( AT_GPIO, "at+gpio", AT_GPIO_Callback,
*                      QATCLI_CMDTYPE_ACT | QATCLI_CMDTYPE_READ |
*                      QATCLI_CMDTYPE_TEST | QATCLI_CMDTYPE_PARA | 0x22 );
*      CLI_Object.add( AT_INFO, "at+info", AT_INFO_Callback,
*                      QATCLI_CMDTYPE_ACT );
*      os.add( CLI_Task, CLI_Object, core::LOWEST_PRIORITY );
*      os.run();
*
*      return 0;
*  }
*  @endcode
*
* The CLI input is feeded from the interrupt context by using the UART receive
* ISR:
*
*  @code{.c}
*  void interrupt HAL_UART_RxInterrupt( void ) {
*      char received;
*
*      received = HAL_HUART_GetChar( UART1 );
*      CLI_Object.isrHandler( received ); /*Feed the CLI input*/
*  }
*  @endcode
*
* Finally, the command callbacks are later defined to perform the requested
* operations.
*
*  @code{.c}
*  cli::response AT_GPIO_Callback( cli::handler_t h ) {
*      cli::response RetValue = cli::response::ERROR;
*      int pin, value;
*
*      switch ( h.getType() ) {
*          case cli::commandType::ACT: /*< AT+gpio */
*              RetValue = cli::response::OK;
*              break;
*          case cli::commandType::TEST: /*< AT+gpio=? */
*              h.writeOut( "+gpio=<pin>,<value>\r\n" );
*              h.writeOut( "+gpio?\r\n" );
*              RetValue = cli::response::NO_RESPONSE;
*              break;
*          case cli::commandType::READ: /*< AT+gpio? */
*              sprintf( h.Output, "0x%08X", HAL_GPIO_Read( GPIOA ) );
*              RetValue = cli::response::NO_RESPONSE;
*              break;
*          case cli::commandType::PARA: /*< AT+gpio=<pin>,<value> */
*              pin = h.getArgInt( 1 );
*              value = h.getArgInt( 2 );
*              HAL_GPIO_WRITE( GPIOA, pin, value );
*              RetValue = cli::response::OK;
*              break;
*          default : break;
*      }
*
*      return RetValue;
*  }
*  /*==================================================================*/
*  cli::response AT_INFO_Callback( cli::handler_t h ) {
*      cli::response RetValue = cli::response::ERROR;
*
*      switch ( param.getType() ) {
*          case cli::commandType::ACT: /*< AT+info */
*              util::strcpy( h.output, "Compilation: " __DATE__ " " __TIME__ );
*              RetValue = cli::response::NO_RESPONSE;
*              break;
*          default :
*              break;
*      }
*
*      return RetValue;
*  }
*  @endcode
*
*/