OS
v7.3.3
Documentation
|
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.
The provided development API parses and handles input commands, following a simplified form of the extended AT-commands syntax.
As seen in the figure, the CLI has a few components described below:
The syntax is straightforward and the rules are provided below:
EOL
character. By default, the CLI uses the carriage return character. (We will use CR
to represent a carriage return character in this document).AT+CMD
"AT+CMD?"
or "AT+CMD?PARAM1"
"AT+CMD=?"
AT+CMD=x
,y If none of the types is given at the input, the command response will be ERROR
OK:
Indicates the successful execution of the command.ERROR:
A generalized message to indicate failure in executing the command.UNKNOWN
: The input command is not subscribed.NOT ALLOWED
: The command syntax is not one of the allowed types.NONE
: No response.All responses are followed by a CR
LF
Errors generated during the execution of these AT commands could be due to the following reasons:
In case of an error, the string ERROR
or "ERROR:<error_no>"
are displayed.
Before starting the CLI development, the corresponding instance must be defined; a data structure of type qATCLI_t. The instance should be initialized using the qATCLI_Setup() API.
The AT CLI is able to subscribe to any number of custom AT commands. For this, the qATCLI_CmdSubscribe() API 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.
The command callback should be coded by the application writer. Here, the following prototype should be used:
The callback takes one argument of type qATCLI_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 qATCLI_Handler_t struct reference.
The return value (an enum of type qATCLI_Response_t) determines the response shown by the Output printer component. The possible allowed values are:
1
and 32766
. For example, a return value of QATCLI_ERROR_CODE(15)
, will print out the string ERROR:15
.A simple example of how the command callback should be coded is shown below:
Input handling is simplified using the provided APIs. The qATCLI_ISRHandler() and qATCLI_ISRHandlerBlock() functions 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.
Both functions 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 APIs qATCLI_Raise() or qATCLI_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 APIs is that qATCLI_Raise() sends the command through the input, marking it as ready for parsing and acting as the Input handler component.
The qATCLI_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.
The parser can be invoked directly using the qATCLI_Run() API. Almost all the components that make up the CLI are performed by this API, 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, the qOS_Add_ATCLITask() is provided. This API 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 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.
The following example demonstrates the usage of a simple command-line interface using the UART peripheral with two subscribed commands :
"at+gpio"
.A command to retrieve the compilation timestamp "at+info"
. First, let's get started defining the required objects to set up the CLI instance:
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.
The CLI input is feeded from the interrupt context by using the UART receive ISR:
Finally, the command callbacks are later defined to perform the requested operations.